Compare commits
870 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ceab957db5 | |||
| ac21859587 | |||
| fc6fb4030b | |||
| 039ec7b958 | |||
| 5659ab5fc0 | |||
| f6b2888c26 | |||
| e41e017fa3 | |||
| 63eccb4909 | |||
| 4f9ddfeb7a | |||
| c19a8fa602 | |||
| 17529b90b6 | |||
| 2371a40a8a | |||
| d2ae358a3d | |||
| f30416d20f | |||
| ef16e6c72f | |||
| 51c459d654 | |||
| 01b21dc9eb | |||
| bcf20f9f3f | |||
| fed8f51de8 | |||
| d9e18859e9 | |||
| ea73ecd9cb | |||
| 1c4129fd64 | |||
| 5a690bcf33 | |||
| 4be6e21257 | |||
| 7e36a6b6e1 | |||
| aa4bcdd040 | |||
| c9f29a443d | |||
| 725ef52243 | |||
| 6bc41f53ee | |||
| 11366558c9 | |||
| 11c02eba49 | |||
| 2617124ee8 | |||
| 74df45a056 | |||
| cf342ece45 | |||
| fbeff81128 | |||
| 787f304de7 | |||
| 2a52c584f8 | |||
| e6cc5a5736 | |||
| 1c423245e2 | |||
| eb3bd9f89c | |||
| 7f964beebf | |||
| 8b0767b41f | |||
| 68e84c6c59 | |||
| 38d6244611 | |||
| d321721a5e | |||
| 23e85920ef | |||
| c36197a01c | |||
| 9ab423a280 | |||
| 4895b5a2a8 | |||
| 102bf79320 | |||
| 47733b2bbe | |||
| e9ae2c0836 | |||
| 82b59c8f8d | |||
| 2d53aca29c | |||
| f342b80e86 | |||
| be9f0c066e | |||
| b84c2007ef | |||
| 87ce3806f9 | |||
| eb181b220f | |||
| 8d7456dfe7 | |||
| 9c25131958 | |||
| 8d72705265 | |||
| 2adf2838f6 | |||
| b19ed4c039 | |||
| d3fcdff418 | |||
| 8cd7f26431 | |||
| 89653183dd | |||
| 5bbb54d6d0 | |||
| 1d72800c80 | |||
| 1c6afe9cea | |||
| 637ca85ae0 | |||
| 6cf510a9be | |||
| 485b69743f | |||
| eb0936c3a7 | |||
| 2738cd41cd | |||
| c8cb724508 | |||
| 548bdb6f02 | |||
| 136ef8f844 | |||
| bc0da04470 | |||
| 365eb6497f | |||
| 065aebac5b | |||
| 94de454264 | |||
| 2cd5b63555 | |||
| e1381e4e70 | |||
| 8cda966388 | |||
| 45d339928a | |||
| 1d078965b9 | |||
| 2ef48a3355 | |||
| 37967973a0 | |||
| a348177126 | |||
| 1c7609d5e0 | |||
| b75a9cc34b | |||
| 5836c061fa | |||
| 998bc73a90 | |||
| b7ff856073 | |||
| 5363cafd7f | |||
| 1533acc219 | |||
| 04e6e43fee | |||
| 7e7d93c815 | |||
| 2671709991 | |||
| 68f2396ff5 | |||
| 34f0576a90 | |||
| 76e8b4871b | |||
| 520ee92b4f | |||
| e671300dc0 | |||
| 31c7af1737 | |||
| 20c624915f | |||
| ac2d8633af | |||
| 76bc312842 | |||
| b4176ca7df | |||
| 9342a7e897 | |||
| e4bd459da4 | |||
| 083ca23d93 | |||
| b2c5d7270e | |||
| 59a81f4d12 | |||
| 60c4d670da | |||
| c1ad4aa560 | |||
| 7dc4cb7962 | |||
| 7cbd2f1aad | |||
| 19a1ca64f6 | |||
| 35f49962ca | |||
| 65db15487e | |||
| c722e57914 | |||
| c1f35e6991 | |||
| 767719357e | |||
| 7b29bd67f3 | |||
| e97bb0b354 | |||
| 72c173dbee | |||
| 7e0e84ae21 | |||
| 453769b1e7 | |||
| 2b9211c56d | |||
| a79132e922 | |||
| adcf09c99b | |||
| 177eb3d360 | |||
| 336182d8b7 | |||
| acb2e58a5c | |||
| 523c48d4fd | |||
| 90c62bddd9 | |||
| 719b777188 | |||
| 1ead3f9b6a | |||
| ab6a26445e | |||
| 881dab1612 | |||
| dc4a0fec80 | |||
| 4c3d700c54 | |||
| bfbed0249e | |||
| ea38f7a998 | |||
| b704220133 | |||
| 67903d7590 | |||
| 06d3f15fa0 | |||
| 00f8472cfc | |||
| db1ae58f96 | |||
| d981058498 | |||
| 81d2aac0d2 | |||
| ce509638e1 | |||
| 00d0d5e046 | |||
| b0b785954f | |||
| ed80f75c1c | |||
| cf1cbb5f94 | |||
| 7f56c79a8d | |||
| 69e445239a | |||
| 21f0e60061 | |||
| 8b5eefafdb | |||
| 54e4866325 | |||
| 5ce6ec124a | |||
| 4f79b8bf45 | |||
| 451004d45e | |||
| e5879a4c70 | |||
| bb5dad8c1d | |||
| 51aefd2b6b | |||
| 5c7f551015 | |||
| 35f842f7ba | |||
| e4f8f6ebd5 | |||
| 46ba9718ff | |||
| 68b955e611 | |||
| 5be7ed7d58 | |||
| 201e28513a | |||
| ca8e840195 | |||
| b30a479f86 | |||
| 95d98b132a | |||
| ca0db38870 | |||
| 3272be6a35 | |||
| 2b4957d4f2 | |||
| abb28250f8 | |||
| d922846a7e | |||
| 70491bb6e6 | |||
| d8a8556598 | |||
| a7f5576fee | |||
| 1860f3f953 | |||
| 968a94f281 | |||
| 3d7f7db396 | |||
| ff7116ac57 | |||
| d62aae0205 | |||
| 37464e5f0f | |||
| d96de90cd9 | |||
| aca550a9b4 | |||
| e862ffcb1b | |||
| 0cac739b50 | |||
| 3d44c78585 | |||
| 8588cbb836 | |||
| f5a2f87038 | |||
| 2075311773 | |||
| 151e20240a | |||
| fc2e605fd8 | |||
| 6ee867c01b | |||
| 0a677a3b54 | |||
| 0aab5e435a | |||
| c75a7817cf | |||
| 7716413015 | |||
| e69559238d | |||
| 6b5326ccbd | |||
| eb622504f2 | |||
| 228230d46b | |||
| 6263b07087 | |||
| 75dfde3bc5 | |||
| 7c9f742b4d | |||
| 025e7eba1d | |||
| 2b7a9389b4 | |||
| 3110b199c6 | |||
| e707506303 | |||
| 49d5791825 | |||
| 660e89a46c | |||
| fea90482b6 | |||
| 6cfb864055 | |||
| d0ef627532 | |||
| 7fd823c9e9 | |||
| 89c5d5d613 | |||
| 73b7729b82 | |||
| c66d49dbfe | |||
| ecf73a6230 | |||
| a915dff4a8 | |||
| 9a3b70149c | |||
| 98cc1c63ce | |||
| 757086b7bd | |||
| ab36687c85 | |||
| d86654fa6b | |||
| 128a08f169 | |||
| 4487e686d7 | |||
| 7679b36f13 | |||
| 716def8d33 | |||
| 4ceb16e20d | |||
| 61318df0b4 | |||
| 822117e453 | |||
| d09b34dd03 | |||
| ab8d0c6504 | |||
| c5c1946d1b | |||
| 5b6fd83f21 | |||
| 2587b06361 | |||
| e507ad4ace | |||
| 7636f17ba9 | |||
| 36ffd41007 | |||
| b5e06a6552 | |||
| 165caa5aba | |||
| a5d6cfd812 | |||
| 638a614a24 | |||
| a3c3e220a0 | |||
| 8d724ff2f7 | |||
| f13fd59059 | |||
| c03b839bb1 | |||
| 055cf5da3a | |||
| d8de1c5b1b | |||
| 04ab76e5a9 | |||
| 22da0c85f7 | |||
| 440d26d982 | |||
| 2891f96006 | |||
| 7d885e8af0 | |||
| 7d35ad124a | |||
| 45cf5d88cf | |||
| ee5e0a9b7e | |||
| 865d8e633e | |||
| 69a0de20d7 | |||
| 13f1c80329 | |||
| 9a36d40623 | |||
| db4bcab192 | |||
| be3288af44 | |||
| 322ad6ca26 | |||
| 617d7dcea1 | |||
| 0510773dc5 | |||
| 2325052d69 | |||
| 00486eeaa7 | |||
| ae32968efd | |||
| dc3c517697 | |||
| 36a472b79a | |||
| 99766e3f22 | |||
| 937e7f9004 | |||
| d82fd3dd04 | |||
| b94f2aba70 | |||
| 01c601f87e | |||
| 3ba05aca8f | |||
| d4a069451f | |||
| 547361a185 | |||
| 736339ad1c | |||
| c1778918b5 | |||
| 3f5fdf840a | |||
| 90c76ae465 | |||
| 680a4b9570 | |||
| 2243452261 | |||
| 4427554752 | |||
| 16be7a2971 | |||
| 35a03a1e58 | |||
| d258fc5a9f | |||
| 17e1020724 | |||
| 24858dfdfc | |||
| 2a9a7ee9c5 | |||
| 00690d011a | |||
| 4b5284fd7b | |||
| a286f358be | |||
| 0b65b3b4a1 | |||
| 48ef1aab1c | |||
| 652f1e52ec | |||
| 5a682c44bc | |||
| 70a1704b35 | |||
| d8ff1e97b3 | |||
| 39eb0351c0 | |||
| 49df332734 | |||
| 3af8354a93 | |||
| a39d41b1b7 | |||
| d9a1d3438b | |||
| 9000ece7d1 | |||
| 2b8c566e65 | |||
| aedb17781b | |||
| ba6ba15732 | |||
| 291f526368 | |||
| 6fd05ab6be | |||
| fca605287b | |||
| 5e63077a32 | |||
| ff61812e65 | |||
| d20ea58467 | |||
| c6431bde3f | |||
| c737c43fa2 | |||
| c4f3dae317 | |||
| a663cad110 | |||
| e0c1b5cd8d | |||
| b95575572d | |||
| 92c7b4446b | |||
| 844f4490fe | |||
| 4d5b330567 | |||
| e18b00ef25 | |||
| 3cef9d9186 | |||
| 8188f66892 | |||
| a87e699f8d | |||
| 40287fd427 | |||
| 5d5f7a4516 | |||
| ac6aaedf3e | |||
| 61ef83c748 | |||
| f82329b371 | |||
| 0fee434ac2 | |||
| 3aab41b1e4 | |||
| e0e5aef43e | |||
| fd6046ebb6 | |||
| 2a7844d031 | |||
| dc0f4757a2 | |||
| d6bd3354cf | |||
| e94f8da3e8 | |||
| d28cdf3bdc | |||
| 1ac2ccb8c2 | |||
| 3be2af15ee | |||
| aef7525354 | |||
| eef44e97c5 | |||
| 1f65f02f49 | |||
| 87cacaf92c | |||
| b3830067ca | |||
| ff40de7c29 | |||
| 3f76a130f1 | |||
| 205d5f7d71 | |||
| 100ab5643a | |||
| f9ad06be29 | |||
| 699c651daa | |||
| 79299175c1 | |||
| 14e3976e88 | |||
| 76c86daf24 | |||
| a1ef40e4be | |||
| e4a0904de6 | |||
| 6cca01718d | |||
| 6b259c8147 | |||
| cb727bf6e6 | |||
| 6400e7988f | |||
| 93d44df72b | |||
| 2267ac4534 | |||
| 7a3e9facd0 | |||
| 7c881a29ae | |||
| 607a52883a | |||
| 4651dfc763 | |||
| da74c0a163 | |||
| 8d9f741a6a | |||
| c42170cf6b | |||
| 35545019a5 | |||
| 0312b947e1 | |||
| e7162d46ce | |||
| dfec3965ab | |||
| fbb7f18f23 | |||
| e2e40a3356 | |||
| 754ed06d86 | |||
| 171de064f6 | |||
| e7176c40df | |||
| 51cb4ca371 | |||
| d9c42e2aca | |||
| df25edfaf6 | |||
| af43b35d17 | |||
| 72ea43758d | |||
| d41188598a | |||
| 2ed7fc06ea | |||
| 5f1c69bc13 | |||
| ee5af4998f | |||
| 4740e5f0c7 | |||
| 4b36dcc13b | |||
| b92f5c4719 | |||
| 11441fb1b1 | |||
| 377879d081 | |||
| 738cc81439 | |||
| 14ba484fc1 | |||
| 0f894da7a6 | |||
| 52640a94ee | |||
| 133e2fdba7 | |||
| e6ef1c2506 | |||
| 565a020acf | |||
| 7718adfca1 | |||
| afe3ace32e | |||
| 9a0679d41c | |||
| a54b2297c7 | |||
| 871e390c5e | |||
| 34875855db | |||
| 6c0fb765f0 | |||
| 69367e0cda | |||
| 15bbe1b829 | |||
| f95ec4d8f4 | |||
| 4a6f0a791e | |||
| 3779ba38cb | |||
| c459a893a5 | |||
| 2c6eeb7193 | |||
| 6c5849cca9 | |||
| 671b94dd06 | |||
| bc9dc911ed | |||
| cc8298d83c | |||
| 42dd48a3d1 | |||
| d97a98f45d | |||
| 8d892bd099 | |||
| 886ab32f27 | |||
| 937b308444 | |||
| ee4c0cbfc3 | |||
| 3ba9f87d93 | |||
| 626f21aecd | |||
| 2f6637dcc4 | |||
| 21de6dfd00 | |||
| a3b0714a9d | |||
| b9975ad1f5 | |||
| b63135771e | |||
| bc828176d1 | |||
| 13dcfbbd2b | |||
| 3d8138f3ef | |||
| e67f85695c | |||
| 088253ebfd | |||
| dc542a4ae7 | |||
| 219a46f736 | |||
| 7599a68c90 | |||
| a5522188ca | |||
| 36bc2473bf | |||
| abf8aa7ea3 | |||
| e0da6f2dec | |||
| 8a8b09141f | |||
| 18ea5b3768 | |||
| 0e392843dd | |||
| faaa408201 | |||
| 9514654ca4 | |||
| e34e63db51 | |||
| c6c07b3861 | |||
| 6f39f190a4 | |||
| e2c06852d5 | |||
| f45d25c09a | |||
| 2ec96a9123 | |||
| 2cea2e1b41 | |||
| 59f711f802 | |||
| 0d4ee6e5d1 | |||
| f9319c0db9 | |||
| 3ff4930e8a | |||
| ee3fb3745c | |||
| b512376c5c | |||
| d97ae3fbd2 | |||
| a3e4eaa2e4 | |||
| a2df4ea742 | |||
| 79f7ea60f2 | |||
| 52aac5ba10 | |||
| 63a4e00f52 | |||
| 5df30ac0cc | |||
| cb8c1a31cb | |||
| 8ad4ee4e58 | |||
| 6c77749e32 | |||
| 4170713e29 | |||
| 8917a5ad92 | |||
| 49110ffaf7 | |||
| a3bca42117 | |||
| 7919a39bb6 | |||
| 80488e012f | |||
| 0856173c9c | |||
| 98832357bf | |||
| 0843388a41 | |||
| 71e6ea70b2 | |||
| a87b37d6ca | |||
| 0594bafa5b | |||
| 2214916fed | |||
| 8618947d62 | |||
| 912a111f14 | |||
| 47c7f9bfda | |||
| d844c33a2d | |||
| fac71dfd11 | |||
| 1e6b80e45e | |||
| 31d3b88a5b | |||
| de14a6dad7 | |||
| e3102cf95b | |||
| ce97350d76 | |||
| a5b597e2f7 | |||
| 2b76d4b22d | |||
| d7b732ba4b | |||
| 2d3cf3da23 | |||
| 2ff5b63089 | |||
| 530f88aa11 | |||
| c42e957c4c | |||
| 659cba563a | |||
| d255b3a6a3 | |||
| ba7713fb93 | |||
| d5498cc66e | |||
| a023ddb76b | |||
| f7c49758e1 | |||
| 95a834b8b6 | |||
| 5d71e08922 | |||
| e51b43084b | |||
| f299fe76e4 | |||
| 128cceaf91 | |||
| ccedd6757b | |||
| a94f61702f | |||
| 2b2cf48fdb | |||
| 858135175e | |||
| de8b69a399 | |||
| 27e6e9b91c | |||
| 1c13a896eb | |||
| f8d6c85779 | |||
| 09b7186713 | |||
| c6389852ea | |||
| 49f10ccd32 | |||
| a8b037f2e0 | |||
| 3c38b335a6 | |||
| 3a8bbcc8fc | |||
| 1ecb864e5f | |||
| d281f97659 | |||
| 38761e1413 | |||
| f85f418d52 | |||
| 0184b396be | |||
| 8b2e2f8447 | |||
| 2fc8244f71 | |||
| 7c5b6851a1 | |||
| a2ebb1b06f | |||
| 196ce492be | |||
| a5848a17c5 | |||
| 31535e3bd8 | |||
| dfc3e468c4 | |||
| 90ec849b5f | |||
| 30f147a9d3 | |||
| e7a238b2bc | |||
| 17c055472d | |||
| dd4827493b | |||
| 572e23d307 | |||
| febff1560e | |||
| 7b14e8eacc | |||
| 881d922f30 | |||
| 8b358da2f0 | |||
| 19d96ac0e2 | |||
| 3a33a39411 | |||
| 883a662240 | |||
| e6908c7678 | |||
| 0b8b413f2f | |||
| 38a5b49ea3 | |||
| 6a43972267 | |||
| d102db795e | |||
| 6f2a7180d8 | |||
| 6cec665f7d | |||
| d0cd8ba346 | |||
| 16bce4248d | |||
| a2e9ec0412 | |||
| 11c9abf359 | |||
| 4b942dcc32 | |||
| 12b7a9d874 | |||
| ec4eeb5de6 | |||
| f676ce6ac2 | |||
| aa0bb166a8 | |||
| 60a81ac879 | |||
| a9bc67538d | |||
| c0a7a9a427 | |||
| df909983db | |||
| 1a9e5f20a8 | |||
| a90f32035d | |||
| 33b09c80aa | |||
| b2980cedc6 | |||
| 34b7f86b8b | |||
| 130f6d3a42 | |||
| 3ff9d6adbc | |||
| fd5de171c9 | |||
| 45ad51b8df | |||
| b02657f32c | |||
| 9f3784aaed | |||
| 2ab2a5a9f3 | |||
| 2d83ba06a5 | |||
| 06d5c60803 | |||
| fe18722e1f | |||
| c2e7fc2f10 | |||
| e31dd688bf | |||
| 5060dab7a5 | |||
| c8fa22c767 | |||
| 418a29cbbf | |||
| 0b907d4ae3 | |||
| 765ed9687a | |||
| 66e7a6322a | |||
| b595ec4d88 | |||
| 7425e070d2 | |||
| 3cb70f67c9 | |||
| a029d98209 | |||
| db6b8930ab | |||
| 4d8a3f4453 | |||
| f1f5374b81 | |||
| 961928105c | |||
| c6229f131a | |||
| ff3aebd4b1 | |||
| ad6e4ae745 | |||
| b462082ed9 | |||
| 95f120e98f | |||
| a42bd4dbf0 | |||
| 21d6209793 | |||
| 9ee1584ede | |||
| a3d77b7e72 | |||
| 14e1e741ed | |||
| 94f72b3938 | |||
| 20ab14beb4 | |||
| e14e5bee95 | |||
| 9e1364db42 | |||
| 1902bc4807 | |||
| a264342bcc | |||
| 08660704cc | |||
| 4c13dbf8b7 | |||
| 9a10863760 | |||
| 74e414d858 | |||
| 6a1072e918 | |||
| fb1ea4b880 | |||
| cbe566302c | |||
| 4ace6e10db | |||
| bd32c7cc4a | |||
| 25a0c595e7 | |||
| 3d3be5ecbc | |||
| 1730005a58 | |||
| b9257fceeb | |||
| e2f9b1c7d9 | |||
| 03b1c9e5ee | |||
| 85098b84f7 | |||
| 936be3934b | |||
| ed8f22c371 | |||
| 969abb5057 | |||
| 21c0152131 | |||
| 86430f1b01 | |||
| 55247fe31d | |||
| 6ac724951b | |||
| b0dfc90557 | |||
| b09a743beb | |||
| 2ed4206f93 | |||
| a806f40093 | |||
| 4283734a94 | |||
| 6c20815210 | |||
| a371ebe841 | |||
| 92a32a8f8d | |||
| bb1a47aa81 | |||
| 6126a52156 | |||
| 24020cfea3 | |||
| 1b2f0246e8 | |||
| 9ec30860b0 | |||
| 19784e04bf | |||
| 3ee4399fca | |||
| 06206c60d9 | |||
| 5937a7e976 | |||
| f64b8d680d | |||
| f9663a9e80 | |||
| c604cc5c2f | |||
| dc42c1ebb7 | |||
| 92efd6d645 | |||
| 6560865f61 | |||
| 8f53bea3d7 | |||
| 89f7a31bef | |||
| 424b8cd408 | |||
| 65898411e7 | |||
| 759a3619ca | |||
| 520ebc3394 | |||
| e6bb999d83 | |||
| cdd1a0a4cb | |||
| 5e0fbe5634 | |||
| e5b3ca1907 | |||
| efb4a6652d | |||
| 9b43a86b94 | |||
| 1090248223 | |||
| 880077f6e9 | |||
| ffc1b62b8a | |||
| 17f2602ca2 | |||
| a71e255468 | |||
| f2458b833e | |||
| 2b2d986371 | |||
| 1ed21a3ffb | |||
| 1f32373bd2 | |||
| 5b1c626714 | |||
| ce30153830 | |||
| 727f3a804d | |||
| be7179b962 | |||
| 7eee954d4d | |||
| 36cb078073 | |||
| 8b6171bb13 | |||
| 917d5b39ec | |||
| 65f809a0fb | |||
| bad4d0c6e6 | |||
| 2a1e3dc2f8 | |||
| 5199a5dc99 | |||
| 2e8a8e3623 | |||
| 1ec74a5ae8 | |||
| 6c02eadd88 | |||
| 60c4307f2e | |||
| e1c0e70d07 | |||
| 9ddee615cc | |||
| 2c88c7c971 | |||
| 9e361b7669 | |||
| e64eb05dcd | |||
| 0898638e33 | |||
| 5dd9510d69 | |||
| 229b770447 | |||
| 434e194ba7 | |||
| 9c96b247be | |||
| 74f6a34651 | |||
| 7dee2802fe | |||
| 15d25ebb3d | |||
| fbe388a616 | |||
| 891955f164 | |||
| f7103c97cf | |||
| a90e96d066 | |||
| 4e56d88eb5 | |||
| 770514919d | |||
| 31a5951626 | |||
| 76b7b131a9 | |||
| 4602a6b989 | |||
| e27a0e2bd2 | |||
| e5c7a35e8f | |||
| 6277bc379e | |||
| 2bb279d8f7 | |||
| a8f87d6dc1 | |||
| bb350035ef | |||
| 6f6c33a721 | |||
| 7451e83c73 | |||
| 79e35d5c06 | |||
| 59196020bb | |||
| fc1e4f959e | |||
| 146aca31a0 | |||
| c928769911 | |||
| cdbc02354d | |||
| bd3cdd83f6 | |||
| 5a757f129c | |||
| 987c4401a3 | |||
| dee067d071 | |||
| d901f4d4f1 | |||
| 081457ddc8 | |||
| 4f98a1b0c8 | |||
| 7668c3bafa | |||
| 5238293c09 | |||
| 226e35d65a | |||
| 05f7ede26a | |||
| ea638c37b7 | |||
| bfa7ab788b | |||
| 5a15c93195 | |||
| 77777c8007 | |||
| 85e2c3e5b1 | |||
| 47d124a41b | |||
| ca56539c65 | |||
| 8b25210895 | |||
| 9c4dc838a5 | |||
| 57511b9c5a | |||
| cdda69c4cd | |||
| 472ef6e48c | |||
| 9ff74b39f8 | |||
| 5aa01e78ab | |||
| a21bee6683 | |||
| 0cff484113 | |||
| 3e9afcfc41 | |||
| 830fde372e | |||
| ac2a4a1e0a | |||
| 5ffca11c5b | |||
| 35f65a2c64 | |||
| e5320f0abd | |||
| 965a7fc500 | |||
| abbf8aeb42 | |||
| 328ada2f38 | |||
| 767252cdf1 | |||
| 010d47c68b | |||
| 56f1062db8 | |||
| a11e947f96 | |||
| 0be07f467f | |||
| 1a9ced80f9 | |||
| 33599a15a2 | |||
| 42f9427e24 | |||
| e0878fdd9f | |||
| fb3bad90d6 | |||
| 590838302b | |||
| c9aac96c1a | |||
| bbdce28951 | |||
| cf6ecf5bc9 | |||
| 4df79ce55b | |||
| 15d2021786 | |||
| a8f6b9eeb9 | |||
| 3d4b403c0e | |||
| 957760d29a | |||
| 928f7a1ed0 | |||
| a7603747a6 | |||
| e7754213f1 | |||
| ea82e9c67e | |||
| 182cc1ace7 | |||
| 205b9889f2 | |||
| 4a58fbfa1d | |||
| af534e87f3 | |||
| 53c753b8d9 | |||
| a8a2c706ba | |||
| b6777e4635 | |||
| a3d674f574 | |||
| 9a66948857 | |||
| 82c784d560 | |||
| 30095000e6 | |||
| 5d224cca9b | |||
| c5c1a7ddfc | |||
| b5022bb183 | |||
| 2e9bc3bb2b | |||
| 98e487753f | |||
| ce15d46a5e | |||
| 02ffebde49 | |||
| 2e06c61a4f | |||
| 36d6e4b4da | |||
| 725b938de1 | |||
| 042973ce19 | |||
| f9022d8189 | |||
| 7f4a98883b | |||
| 8ff0307a95 | |||
| 917c514fab | |||
| 2ef4b77bd9 | |||
| c7ac4eea2f | |||
| fae9fc6e2d | |||
| 000e278e48 | |||
| bcfb562dde | |||
| 3ca8b356ee | |||
| 6c32cf9529 | |||
| d925f856ae | |||
| 3de2196e01 | |||
| ac2d010df3 | |||
| eb4317a9c1 | |||
| c3caf7ff04 | |||
| f9cae9c4d8 | |||
| dd16af0989 | |||
| c118990a4c | |||
| 7a541ba489 | |||
| a785cd1569 | |||
| 1e786ac311 | |||
| 0c28e01347 | |||
| 08566f32de | |||
| 16ec58f338 | |||
| e8fd6a6ece | |||
| ee4f4440d5 | |||
| f4d060f3eb | |||
| 85cb7fadfc | |||
| ac19ac7a6b | |||
| 0415a31d0e | |||
| 912716f889 | |||
| 5dc9bb752e | |||
| cf435011df | |||
| f63514e8ea | |||
| 1ddf2fa365 |
@@ -103,3 +103,6 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/*
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
|
||||
|
||||
src/Umbraco.Web.UI/[Cc]onfig/appSettings.config
|
||||
src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config
|
||||
src/Umbraco.Web.UI/umbraco/plugins/*
|
||||
|
||||
+32
-32
@@ -1,32 +1,32 @@
|
||||
@ECHO OFF
|
||||
SET release=7.0.0
|
||||
SET comment=alpha
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
|
||||
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
|
||||
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Code\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Data\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Plugins\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\css\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\macroScripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\masterpages\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\media\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\scripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\usercontrols\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
|
||||
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
IF ERRORLEVEL 1 GOTO :showerror
|
||||
|
||||
GOTO :EOF
|
||||
|
||||
:showerror
|
||||
PAUSE
|
||||
@ECHO OFF
|
||||
SET release=7.0.0
|
||||
SET comment=RC
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
|
||||
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
|
||||
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Code\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Data\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\App_Plugins\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\css\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\macroScripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\masterpages\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\media\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\scripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\usercontrols\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
|
||||
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
IF ERRORLEVEL 1 GOTO :showerror
|
||||
|
||||
GOTO :EOF
|
||||
|
||||
:showerror
|
||||
PAUSE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Core</id>
|
||||
@@ -20,13 +20,14 @@
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1]" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.7.0, 1.7.1)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0, 1.7.1)" />
|
||||
<dependency id="AutoMapper" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.7.0, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[5.0.0, 6.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -59,8 +60,6 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.dll" target="lib\umbraco.macroRenderings.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.xml" target="lib\umbraco.macroRenderings.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms</id>
|
||||
|
||||
@@ -22,6 +22,12 @@ if ($project) {
|
||||
$umbracoFilesPath = Join-Path $rootPath "UmbracoFiles\*"
|
||||
Copy-Item $umbracoFilesPath $projectDestinationPath -recurse -force
|
||||
|
||||
# Remove Newtonsoft.Json if present in the bin folder
|
||||
# If we don't do this, the correct version never gets copied in
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
$jsonDllFile = Join-Path $projectDestinationPath "bin\Newtonsoft.Json.dll"
|
||||
Remove-Item $jsonDllFile -Confirm:$false
|
||||
|
||||
# Open readme.txt file
|
||||
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
|
||||
}
|
||||
@@ -28,12 +28,11 @@ namespace Umbraco.Core
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
ApplicationCache = cache;
|
||||
@@ -43,12 +42,60 @@ namespace Umbraco.Core
|
||||
/// Creates a basic app context
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
internal ApplicationContext(CacheHelper cache)
|
||||
public ApplicationContext(CacheHelper cache)
|
||||
{
|
||||
ApplicationCache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// A method used to set and/or ensure that a global ApplicationContext singleton is created.
|
||||
/// </summary>
|
||||
/// <param name="appContext">
|
||||
/// The instance to set on the global application singleton
|
||||
/// </param>
|
||||
/// <param name="replaceContext">If set to true and the singleton is already set, it will be replaced</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(ApplicationContext appContext, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
ApplicationContext.Current = appContext;
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method used to create and ensure that a global ApplicationContext singleton is created.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="replaceContext">
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// startup if for some reason the boot manager is not the umbraco boot manager.
|
||||
/// </param>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
var ctx = new ApplicationContext(dbContext, serviceContext, cache);
|
||||
ApplicationContext.Current = ctx;
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Singleton accessor
|
||||
/// </summary>
|
||||
public static ApplicationContext Current { get; internal set; }
|
||||
@@ -99,7 +146,7 @@ namespace Umbraco.Core
|
||||
//
|
||||
public bool IsConfigured
|
||||
{
|
||||
// fixme - we should not do this - ok for now
|
||||
// todo - we should not do this - ok for now
|
||||
get
|
||||
{
|
||||
return Configured;
|
||||
|
||||
@@ -47,6 +47,5 @@ namespace Umbraco.Core.Cache
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// Good for unit testing
|
||||
/// </remarks>
|
||||
internal static CacheHelper CreateDisabledCacheHelper()
|
||||
public static CacheHelper CreateDisabledCacheHelper()
|
||||
{
|
||||
return new CacheHelper(null, null, null, false);
|
||||
}
|
||||
@@ -74,14 +74,6 @@ namespace Umbraco.Core
|
||||
{
|
||||
}
|
||||
|
||||
internal void ClearStaticCacheObjectTypes<T>(Func<string, T, bool> predicate)
|
||||
{
|
||||
if (_enableCache)
|
||||
_staticCache.ClearCacheObjectTypes(predicate);
|
||||
else
|
||||
_nullStaticCache.ClearCacheObjectTypes(predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private ctor used for creating a disabled cache helper
|
||||
/// </summary>
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.BaseRest
|
||||
{
|
||||
[ConfigurationKey("BaseRestExtensions")]
|
||||
|
||||
internal class BaseRestSection : UmbracoConfigurationSection, IBaseRestSection
|
||||
{
|
||||
private const string KeyEnabled = "enabled";
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UmbracoSettings.ObjectExtensions.DisposeIfDisposable(_stringEnumerator);
|
||||
ObjectExtensions.DisposeIfDisposable(_stringEnumerator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the configuration key for a section or a group.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ConfigurationKeyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigurationKeyAttribute"/> class with a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="configurationKey">The configurationkey.</param>
|
||||
public ConfigurationKeyAttribute(string configurationKey)
|
||||
{
|
||||
ConfigurationKey = configurationKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration key.
|
||||
/// </summary>
|
||||
public string ConfigurationKey { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AccessElement : RawXmlConfigurationElement, IAccess
|
||||
{
|
||||
public AccessElement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AccessElement(XElement rawXml)
|
||||
:base(rawXml)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<IAccessItem> Rules
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = new List<AccessItem>();
|
||||
if (RawXml != null)
|
||||
{
|
||||
result.AddRange(RawXml.Elements("deny").Select(x => new AccessItem {Action = AccessType.Deny, Value = x.Value }));
|
||||
result.AddRange(RawXml.Elements("grant").Select(x => new AccessItem { Action = AccessType.Grant, Value = x.Value }));
|
||||
result.AddRange(RawXml.Elements("grantBySection").Select(x => new AccessItem { Action = AccessType.GrantBySection, Value = x.Value }));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AccessItem : IAccessItem
|
||||
{
|
||||
/// <summary>
|
||||
/// This can be grant, deny or grantBySection
|
||||
/// </summary>
|
||||
public AccessType Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the action
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public enum AccessType
|
||||
{
|
||||
Grant,
|
||||
Deny,
|
||||
GrantBySection
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreaCollection : ConfigurationElementCollection, IEnumerable<IArea>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new AreaElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((AreaElement) element).Value;
|
||||
}
|
||||
|
||||
IEnumerator<IArea> IEnumerable<IArea>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IArea;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreaElement : InnerTextConfigurationElement<string>, IArea
|
||||
{
|
||||
string IArea.AreaName
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class AreasElement : ConfigurationElement
|
||||
{
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "area")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public AreaCollection AreaCollection
|
||||
{
|
||||
get { return (AreaCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class ControlCollection : ConfigurationElementCollection, IEnumerable<IDashboardControl>
|
||||
{
|
||||
internal void Add(ControlElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new ControlElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((ControlElement)element).ControlPath;
|
||||
}
|
||||
|
||||
IEnumerator<IDashboardControl> IEnumerable<IDashboardControl>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IDashboardControl;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
|
||||
internal class ControlElement : RawXmlConfigurationElement, IDashboardControl
|
||||
{
|
||||
public bool ShowOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return RawXml.Attribute("showOnce") == null
|
||||
? false
|
||||
: bool.Parse(RawXml.Attribute("showOnce").Value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddPanel
|
||||
{
|
||||
get
|
||||
{
|
||||
return RawXml.Attribute("addPanel") == null
|
||||
? true
|
||||
: bool.Parse(RawXml.Attribute("addPanel").Value);
|
||||
}
|
||||
}
|
||||
|
||||
public string PanelCaption
|
||||
{
|
||||
get
|
||||
{
|
||||
return RawXml.Attribute("panelCaption") == null
|
||||
? ""
|
||||
: RawXml.Attribute("panelCaption").Value;
|
||||
}
|
||||
}
|
||||
|
||||
public AccessElement Access
|
||||
{
|
||||
get
|
||||
{
|
||||
var access = RawXml.Element("access");
|
||||
if (access == null)
|
||||
{
|
||||
return new AccessElement();
|
||||
}
|
||||
return new AccessElement(access);
|
||||
}
|
||||
}
|
||||
|
||||
public string ControlPath
|
||||
{
|
||||
get
|
||||
{
|
||||
//we need to return the first (and only) text element of the children (wtf... who designed this configuration ! :P )
|
||||
var txt = RawXml.Nodes().OfType<XText>().FirstOrDefault();
|
||||
if (txt == null)
|
||||
{
|
||||
throw new ConfigurationErrorsException("The control element must contain a text node indicating the control path");
|
||||
}
|
||||
return txt.Value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IAccess IDashboardControl.AccessRights
|
||||
{
|
||||
get { return Access; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class DashboardSection : ConfigurationSection, IDashboardSection
|
||||
{
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "section")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public SectionCollection SectionCollection
|
||||
{
|
||||
get { return (SectionCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<ISection> IDashboardSection.Sections
|
||||
{
|
||||
get { return SectionCollection; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IAccess
|
||||
{
|
||||
IEnumerable<IAccessItem> Rules { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IAccessItem
|
||||
{
|
||||
/// <summary>
|
||||
/// This can be grant, deny or grantBySection
|
||||
/// </summary>
|
||||
AccessType Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the action
|
||||
/// </summary>
|
||||
string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IArea
|
||||
{
|
||||
string AreaName { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardControl
|
||||
{
|
||||
bool ShowOnce { get; }
|
||||
|
||||
bool AddPanel { get; }
|
||||
|
||||
string PanelCaption { get; }
|
||||
|
||||
string ControlPath { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardSection
|
||||
{
|
||||
IEnumerable<ISection> Sections { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface IDashboardTab
|
||||
{
|
||||
string Caption { get; }
|
||||
|
||||
IEnumerable<IDashboardControl> Controls { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
public interface ISection
|
||||
{
|
||||
string Alias { get; }
|
||||
|
||||
IEnumerable<string> Areas { get; }
|
||||
|
||||
IEnumerable<IDashboardTab> Tabs { get; }
|
||||
|
||||
IAccess AccessRights { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class SectionCollection : ConfigurationElementCollection, IEnumerable<ISection>
|
||||
{
|
||||
internal void Add(SectionElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new SectionElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((SectionElement)element).Alias;
|
||||
}
|
||||
|
||||
IEnumerator<ISection> IEnumerable<ISection>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as ISection;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class SectionElement : ConfigurationElement, ISection
|
||||
{
|
||||
[ConfigurationProperty("alias", IsRequired = true)]
|
||||
public string Alias
|
||||
{
|
||||
get { return (string) this["alias"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("areas", IsRequired = true)]
|
||||
public AreasElement Areas
|
||||
{
|
||||
get { return (AreasElement)this["areas"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("access")]
|
||||
public AccessElement Access
|
||||
{
|
||||
get { return (AccessElement)this["access"]; }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(SectionCollection), AddItemName = "tab")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public TabCollection TabCollection
|
||||
{
|
||||
get { return (TabCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<IDashboardTab> ISection.Tabs
|
||||
{
|
||||
get { return TabCollection; }
|
||||
}
|
||||
|
||||
IEnumerable<string> ISection.Areas
|
||||
{
|
||||
get { return Areas.AreaCollection.Cast<AreaElement>().Select(x => x.Value); }
|
||||
}
|
||||
|
||||
IAccess ISection.AccessRights
|
||||
{
|
||||
get { return Access; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class TabCollection : ConfigurationElementCollection, IEnumerable<IDashboardTab>
|
||||
{
|
||||
internal void Add(TabElement c)
|
||||
{
|
||||
BaseAdd(c);
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new TabElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((TabElement)element).Caption;
|
||||
}
|
||||
|
||||
IEnumerator<IDashboardTab> IEnumerable<IDashboardTab>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as IDashboardTab;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Dashboard
|
||||
{
|
||||
internal class TabElement : ConfigurationElement, IDashboardTab
|
||||
{
|
||||
[ConfigurationProperty("caption", IsRequired = true)]
|
||||
public string Caption
|
||||
{
|
||||
get { return (string)this["caption"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("access")]
|
||||
public AccessElement Access
|
||||
{
|
||||
get { return (AccessElement)this["access"]; }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(ControlCollection), AddItemName = "control")]
|
||||
[ConfigurationProperty("", IsDefaultCollection = true)]
|
||||
public ControlCollection ControlCollection
|
||||
{
|
||||
get { return (ControlCollection)base[""]; }
|
||||
set { base[""] = value; }
|
||||
}
|
||||
|
||||
IEnumerable<IDashboardControl> IDashboardTab.Controls
|
||||
{
|
||||
get { return ControlCollection; }
|
||||
}
|
||||
|
||||
IAccess IDashboardTab.AccessRights
|
||||
{
|
||||
get { return Access; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,10 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
|
||||
}
|
||||
return Path.TrimStart(SystemDirectories.Root).TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
|
||||
var path = Path;
|
||||
if (path.StartsWith(SystemDirectories.Root)) // beware of TrimStart, see U4-2518
|
||||
path = path.Substring(SystemDirectories.Root.Length);
|
||||
return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,10 +268,10 @@ namespace Umbraco.Core.Configuration
|
||||
/// <param name="value">Value of the setting to be saved.</param>
|
||||
internal static void SaveSetting(string key, string value)
|
||||
{
|
||||
var fileName = GetFullWebConfigFileName();
|
||||
var fileName = IOHelper.MapPath(string.Format("{0}/appSettings.config", SystemDirectories.Config));
|
||||
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
|
||||
|
||||
var appSettings = xml.Root.Descendants("appSettings").Single();
|
||||
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
|
||||
|
||||
// Update appSetting if it exists, or else create a new appSetting for the given key and value
|
||||
var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
|
||||
@@ -287,10 +290,10 @@ namespace Umbraco.Core.Configuration
|
||||
/// <param name="key">Key of the setting to be removed.</param>
|
||||
internal static void RemoveSetting(string key)
|
||||
{
|
||||
var fileName = GetFullWebConfigFileName();
|
||||
var fileName = IOHelper.MapPath(string.Format("{0}/appSettings.config", SystemDirectories.Config));
|
||||
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
|
||||
|
||||
var appSettings = xml.Root.Descendants("appSettings").Single();
|
||||
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
|
||||
var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
|
||||
|
||||
if (setting != null)
|
||||
@@ -301,21 +304,6 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetFullWebConfigFileName()
|
||||
{
|
||||
var webConfig = new WebConfigurationFileMap();
|
||||
var vDir = FullpathToRoot;
|
||||
|
||||
foreach (VirtualDirectoryMapping v in webConfig.VirtualDirectories)
|
||||
{
|
||||
if (v.IsAppRoot)
|
||||
vDir = v.PhysicalDirectory;
|
||||
}
|
||||
|
||||
var fileName = System.IO.Path.Combine(vDir, "web.config");
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to root.
|
||||
/// </summary>
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Umbraco.Core.Configuration
|
||||
//now validate and set the raw value
|
||||
if (RawXml.HasElements)
|
||||
throw new InvalidOperationException("An InnerTextConfigurationElement cannot contain any child elements, only attributes and a value");
|
||||
RawValue = RawXml.Value;
|
||||
|
||||
RawValue = RawXml.Value.Trim();
|
||||
|
||||
//RawValue = reader.ReadElementContentAsString();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
var converted = UmbracoSettings.ObjectExtensions.TryConvertTo<T>(RawValue);
|
||||
var converted = ObjectExtensions.TryConvertTo<T>(RawValue);
|
||||
if (converted.Success == false)
|
||||
throw new InvalidCastException("Could not convert value " + RawValue + " to type " + typeof(T));
|
||||
return converted.Result;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration.BaseRest;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -31,7 +32,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// </summary>
|
||||
private UmbracoConfig()
|
||||
{
|
||||
if (UmbracoSettings() == null)
|
||||
if (_umbracoSettings == null)
|
||||
{
|
||||
var umbracoSettings = ConfigurationManager.GetSection("umbracoConfiguration/settings") as IUmbracoSettingsSection;
|
||||
if (umbracoSettings == null)
|
||||
@@ -41,7 +42,7 @@ namespace Umbraco.Core.Configuration
|
||||
SetUmbracoSettings(umbracoSettings);
|
||||
}
|
||||
|
||||
if (BaseRestExtensions() == null)
|
||||
if (_baseRestExtensions == null)
|
||||
{
|
||||
var baseRestExtensions = ConfigurationManager.GetSection("umbracoConfiguration/BaseRestExtensions") as IBaseRestSection;
|
||||
if (baseRestExtensions == null)
|
||||
@@ -50,6 +51,16 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
SetBaseRestExtensions(baseRestExtensions);
|
||||
}
|
||||
|
||||
if (_dashboardSection == null)
|
||||
{
|
||||
var dashboardConfig = ConfigurationManager.GetSection("umbracoConfiguration/dashBoard") as IDashboardSection;
|
||||
if (dashboardConfig == null)
|
||||
{
|
||||
LogHelper.Warn<UmbracoConfig>("Could not load the " + typeof(IDashboardSection) + " from config file!");
|
||||
}
|
||||
SetDashboardSettings(dashboardConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,13 +68,31 @@ namespace Umbraco.Core.Configuration
|
||||
/// </summary>
|
||||
/// <param name="umbracoSettings"></param>
|
||||
/// <param name="baseRestSettings"></param>
|
||||
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings)
|
||||
/// <param name="dashboardSettings"></param>
|
||||
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings)
|
||||
{
|
||||
SetUmbracoSettings(umbracoSettings);
|
||||
SetBaseRestExtensions(baseRestSettings);
|
||||
SetDashboardSettings(dashboardSettings);
|
||||
}
|
||||
|
||||
private IDashboardSection _dashboardSection;
|
||||
private IUmbracoSettingsSection _umbracoSettings;
|
||||
private IBaseRestSection _baseRestExtensions;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IDashboardSection
|
||||
/// </summary>
|
||||
public IDashboardSection DashboardSettings()
|
||||
{
|
||||
return _dashboardSection;
|
||||
}
|
||||
|
||||
//ONLY for unit testing
|
||||
internal void SetDashboardSettings(IDashboardSection value)
|
||||
{
|
||||
_dashboardSection = value;
|
||||
}
|
||||
|
||||
//ONLY for unit testing
|
||||
internal void SetUmbracoSettings(IUmbracoSettingsSection value)
|
||||
@@ -78,9 +107,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
return _umbracoSettings;
|
||||
}
|
||||
|
||||
private IBaseRestSection _baseRestExtensions;
|
||||
|
||||
|
||||
//ONLY for unit testing
|
||||
public void SetBaseRestExtensions(IBaseRestSection value)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[ConfigurationKey("umbracoConfiguration/settings/content")]
|
||||
|
||||
internal class ContentElement : ConfigurationElement, IContentSection
|
||||
{
|
||||
[ConfigurationProperty("imaging")]
|
||||
@@ -217,18 +217,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty("DocumentTypeIconList")]
|
||||
internal InnerTextConfigurationElement<IconPickerBehaviour> DocumentTypeIconList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<IconPickerBehaviour>(
|
||||
(InnerTextConfigurationElement<IconPickerBehaviour>)this["DocumentTypeIconList"],
|
||||
//set the default
|
||||
IconPickerBehaviour.HideFileDuplicates);
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disallowedUploadFiles")]
|
||||
internal CommaDelimitedConfigurationElement DisallowedUploadFiles
|
||||
{
|
||||
@@ -392,12 +380,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
get { return MacroErrors; }
|
||||
}
|
||||
|
||||
IconPickerBehaviour IContentSection.IconPickerBehaviour
|
||||
{
|
||||
get { return DocumentTypeIconList; }
|
||||
}
|
||||
|
||||
|
||||
IEnumerable<string> IContentSection.DisallowedUploadFiles
|
||||
{
|
||||
get { return DisallowedUploadFiles; }
|
||||
|
||||
@@ -51,9 +51,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
int UmbracoLibraryCacheDuration { get; }
|
||||
|
||||
MacroErrorBehaviour MacroErrorBehaviour { get; }
|
||||
|
||||
IconPickerBehaviour IconPickerBehaviour { get; }
|
||||
|
||||
|
||||
IEnumerable<string> DisallowedUploadFiles { get; }
|
||||
|
||||
bool CloneXmlContent { get; }
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
|
||||
internal static class ObjectExtensions
|
||||
{
|
||||
|
||||
//private static readonly ConcurrentDictionary<Type, Func<object>> ObjectFactoryCache = new ConcurrentDictionary<Type, Func<object>>();
|
||||
|
||||
public static IEnumerable<T> AsEnumerableOfOne<T>(this T input)
|
||||
{
|
||||
return Enumerable.Repeat(input, 1);
|
||||
}
|
||||
|
||||
public static void DisposeIfDisposable(this object input)
|
||||
{
|
||||
var disposable = input as IDisposable;
|
||||
if (disposable != null) disposable.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a shortcut way of safely casting an input when you cannot guarantee the <typeparam name="T"></typeparam> is an instance type (i.e., when the C# AS keyword is not applicable)
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
public static T SafeCast<T>(this object input)
|
||||
{
|
||||
if (ReferenceEquals(null, input) || ReferenceEquals(default(T), input)) return default(T);
|
||||
if (input is T) return (T)input;
|
||||
return default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert the input object to the output type using TypeConverters
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static Attempt<T> TryConvertTo<T>(this object input)
|
||||
{
|
||||
var result = TryConvertTo(input, typeof(T));
|
||||
if (!result.Success)
|
||||
{
|
||||
//just try a straight up conversion
|
||||
try
|
||||
{
|
||||
var converted = (T)input;
|
||||
return Attempt.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<T>.Fail(e);
|
||||
}
|
||||
}
|
||||
return !result.Success ? Attempt<T>.Fail() : Attempt.Succeed((T)result.Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert the input object to the output type using TypeConverters. If the destination type is a superclass of the input type,
|
||||
/// if will use <see cref="Convert.ChangeType(object,System.Type)"/>.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="destinationType">Type of the destination.</param>
|
||||
/// <returns></returns>
|
||||
public static Attempt<object> TryConvertTo(this object input, Type destinationType)
|
||||
{
|
||||
if (input == null) return Attempt<object>.Fail();
|
||||
|
||||
if (destinationType == typeof(object)) return Attempt.Succeed(input);
|
||||
|
||||
if (input.GetType() == destinationType) return Attempt.Succeed(input);
|
||||
|
||||
if (input is string && destinationType.IsEnum)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = Enum.Parse(destinationType, (string)input, true);
|
||||
return Attempt.Succeed(output);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Succeed(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>))
|
||||
{
|
||||
//TODO: Do a check for destination type being IEnumerable<T> and source type implementing IEnumerable<T> with
|
||||
// the same 'T', then we'd have to find the extension method for the type AsEnumerable() and execute it.
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom(destinationType, input.GetType())
|
||||
&& TypeHelper.IsTypeAssignableFrom<IConvertible>(input))
|
||||
{
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return Attempt<object>.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inputConverter = TypeDescriptor.GetConverter(input);
|
||||
if (inputConverter.CanConvertTo(destinationType))
|
||||
{
|
||||
try
|
||||
{
|
||||
var converted = inputConverter.ConvertTo(input, destinationType);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (destinationType == typeof(bool))
|
||||
{
|
||||
var boolConverter = new CustomBooleanTypeConverter();
|
||||
if (boolConverter.CanConvertFrom(input.GetType()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var converted = boolConverter.ConvertFrom(input);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var outputConverter = TypeDescriptor.GetConverter(destinationType);
|
||||
if (outputConverter.CanConvertFrom(input.GetType()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var converted = outputConverter.ConvertFrom(input);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IConvertible>(input))
|
||||
{
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return Attempt<object>.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
public static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname)
|
||||
{
|
||||
//TODO: Localise this exception
|
||||
if (isDisposed)
|
||||
throw new ObjectDisposedException(objectname);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turns object into dictionary
|
||||
/// </summary>
|
||||
/// <param name="o"></param>
|
||||
/// <param name="ignoreProperties">Properties to ignore</param>
|
||||
/// <returns></returns>
|
||||
public static IDictionary<string, TVal> ToDictionary<TVal>(this object o, params string[] ignoreProperties)
|
||||
{
|
||||
if (o != null)
|
||||
{
|
||||
var props = TypeDescriptor.GetProperties(o);
|
||||
var d = new Dictionary<string, TVal>();
|
||||
foreach (var prop in props.Cast<PropertyDescriptor>().Where(x => !ignoreProperties.Contains(x.Name)))
|
||||
{
|
||||
var val = prop.GetValue(o);
|
||||
if (val != null)
|
||||
{
|
||||
d.Add(prop.Name, (TVal)val);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
return new Dictionary<string, TVal>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[ConfigurationKey("umbracoConfiguration/settings")]
|
||||
|
||||
public class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
|
||||
{
|
||||
[ConfigurationProperty("content")]
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "alpha"; } }
|
||||
public static string CurrentComment { get { return "RC"; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
/// </summary>
|
||||
public const string Content = "content";
|
||||
|
||||
/// <summary>
|
||||
/// alias for the media tree.
|
||||
/// </summary>
|
||||
public const string Members = "member";
|
||||
|
||||
/// <summary>
|
||||
/// alias for the media tree.
|
||||
/// </summary>
|
||||
|
||||
@@ -99,6 +99,15 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Member
|
||||
{
|
||||
/// <summary>
|
||||
/// if a role starts with __umbracoRole we won't show it as it's an internal role used for public access
|
||||
/// </summary>
|
||||
public static readonly string InternalRolePrefix = "__umbracoRole";
|
||||
|
||||
public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
|
||||
|
||||
public static readonly string UmbracoRoleProviderName = "UmbracoRoleProvider";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for a Members Password Question
|
||||
/// </summary>
|
||||
|
||||
@@ -74,12 +74,7 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
|
||||
public const string DictionaryPicker = "17B70066-F764-407D-AB05-3717F1E1C513";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Dictionary Picker datatype.
|
||||
/// </summary>
|
||||
public const string DictionaryPickerAlias = "Umbraco.DictionaryPicker";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list datatype.
|
||||
/// </summary>
|
||||
@@ -141,10 +136,10 @@ namespace Umbraco.Core
|
||||
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
|
||||
public const string ImageCropper = "7A2D436C-34C2-410F-898F-4A23B3D79F54";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Image Cropper datatype.
|
||||
/// </summary>
|
||||
public const string ImageCropperAlias = "Umbraco.ImageCropper";
|
||||
///// <summary>
|
||||
///// Alias for the Image Cropper datatype.
|
||||
///// </summary>
|
||||
//public const string ImageCropperAlias = "Umbraco.ImageCropper";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Integer datatype.
|
||||
@@ -202,6 +197,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string MemberPickerAlias = "Umbraco.MemberPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Member Group Picker datatype.
|
||||
/// </summary>
|
||||
public const string MemberGroupPickerAlias = "Umbraco.MemberGroupPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multi-Node Tree Picker datatype
|
||||
/// </summary>
|
||||
@@ -339,12 +339,7 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
|
||||
public const string UltimatePicker = "CDBF0B5D-5CB2-445F-BC12-FCAAEC07CF2C";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Ultimate Picker datatype.
|
||||
/// </summary>
|
||||
public const string UltimatePickerAlias = "Umbraco.UltimatePicker";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the UltraSimpleEditor datatype.
|
||||
/// </summary>
|
||||
@@ -352,21 +347,16 @@ namespace Umbraco.Core
|
||||
public const string UltraSimpleEditor = "60B7DABF-99CD-41EB-B8E9-4D2E669BBDE9";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the UltraSimpleEditor datatype.
|
||||
/// Alias for the MarkdownEditor datatype.
|
||||
/// </summary>
|
||||
public const string UltraSimpleEditorAlias = "Umbraco.UltraSimpleEditor";
|
||||
public const string MarkdownEditorAlias = "Umbraco.MarkdownEditor";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Umbraco Usercontrol Wrapper datatype.
|
||||
/// </summary>
|
||||
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
|
||||
public const string UmbracoUserControlWrapper = "D15E1281-E456-4B24-AA86-1DDA3E4299D5";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Umbraco Usercontrol Wrapper datatype.
|
||||
/// </summary>
|
||||
public const string UmbracoUserControlWrapperAlias = "Umbraco.UmbracoUserControlWrapper";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Upload field datatype.
|
||||
/// </summary>
|
||||
@@ -411,6 +401,11 @@ namespace Umbraco.Core
|
||||
/// Alias for the XPath DropDownList datatype.
|
||||
/// </summary>
|
||||
public const string XPathDropDownListAlias = "Umbraco.XPathDropDownList";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the email address property editor
|
||||
/// </summary>
|
||||
public const string EmailAddressAlias = "Umbraco.EmailAddress";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -17,6 +18,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Macros;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -67,6 +69,7 @@ namespace Umbraco.Core
|
||||
|
||||
//Create the legacy prop-eds mapping
|
||||
LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors();
|
||||
LegacyParameterEditorAliasConverter.CreateMappingsForCoreEditors();
|
||||
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName);
|
||||
@@ -308,25 +311,35 @@ namespace Umbraco.Core
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
() => PluginManager.Current.ResolveMigrationTypes());
|
||||
|
||||
//NOTE: These are legacy in v7+ and will eventually need to be removed.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
|
||||
//add the internal ones, these are not public currently so need to add them manually
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyValueConverters());
|
||||
// fixme - why not use the following syntax?
|
||||
//PluginManager.Current.ResolveTypes<IPropertyValueConverter>());
|
||||
|
||||
// this is how we'd switch over to DefaultShortStringHelper _and_ still use
|
||||
// UmbracoSettings UrlReplaceCharacters...
|
||||
//ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
// new DefaultShortStringHelper().WithConfig(DefaultShortStringHelper.ApplyUrlReplaceCharacters));
|
||||
|
||||
// use the Legacy one for now
|
||||
// use the new DefaultShortStringHelper but sort-of remain compatible
|
||||
// - use UmbracoSettings UrlReplaceCharacters
|
||||
// - allow underscores in terms, allow leading digits
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
new LegacyShortStringHelper());
|
||||
new DefaultShortStringHelper()
|
||||
.WithConfig(CleanStringType.Url, DefaultShortStringHelper.ApplyUrlReplaceCharacters,
|
||||
allowUnderscoreInTerm: true, allowLeadingDigits: true));
|
||||
|
||||
// that was the old one
|
||||
//ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
// new LegacyShortStringHelper());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
typeof (DefaultUrlSegmentProvider));
|
||||
|
||||
// keep it internal for now
|
||||
PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
|
||||
// new PublishedContentModelFactoryImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core
|
||||
if (value is string)
|
||||
{
|
||||
var str = (string)value;
|
||||
if (str == null || str.Length == 0 || str == "0") return false;
|
||||
if (str == "1") return true;
|
||||
if (str == "0" || str == "") return false;
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Web.Configuration;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
@@ -28,7 +29,7 @@ namespace Umbraco.Core
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
|
||||
internal DatabaseContext(IDatabaseFactory factory)
|
||||
public DatabaseContext(IDatabaseFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
@@ -112,7 +113,7 @@ namespace Umbraco.Core
|
||||
public void ConfigureEmbeddedDatabaseConnection()
|
||||
{
|
||||
const string providerName = "System.Data.SqlServerCe.4.0";
|
||||
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;File Access Retry Timeout=10";
|
||||
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
|
||||
|
||||
SaveConnectionString(connectionString, providerName);
|
||||
|
||||
@@ -248,20 +249,10 @@ namespace Umbraco.Core
|
||||
|
||||
_connectionString = connectionString;
|
||||
_providerName = providerName;
|
||||
|
||||
var webConfig = new WebConfigurationFileMap();
|
||||
var vDir = GlobalSettings.FullpathToRoot;
|
||||
foreach (VirtualDirectoryMapping v in webConfig.VirtualDirectories)
|
||||
{
|
||||
if (v.IsAppRoot)
|
||||
{
|
||||
vDir = v.PhysicalDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
var fileName = Path.Combine(vDir, "web.config");
|
||||
|
||||
var fileName = IOHelper.MapPath(string.Format("{0}/connectionStrings.config", SystemDirectories.Config));
|
||||
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
|
||||
var connectionstrings = xml.Root.Descendants("connectionStrings").Single();
|
||||
var connectionstrings = xml.Root.DescendantsAndSelf("connectionStrings").Single();
|
||||
|
||||
// Update connectionString if it exists, or else create a new appSetting for the given key and value
|
||||
var setting = connectionstrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == GlobalSettings.UmbracoConnectionName);
|
||||
|
||||
@@ -112,7 +112,8 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
//don't log here, we return this exception because the caller may need to do something specific when
|
||||
//this exception occurs.
|
||||
return Attempt<TryInvokeMemberResult>.Fail(ext);
|
||||
var mresult = new TryInvokeMemberResult(null, TryInvokeMemberSuccessReason.FoundExtensionMethod);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(mresult, ext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -124,7 +125,8 @@ namespace Umbraco.Core.Dynamics
|
||||
sb.Append(t + ",");
|
||||
}
|
||||
LogHelper.Error<DynamicInstanceHelper>(sb.ToString(), ex);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(ex);
|
||||
var mresult = new TryInvokeMemberResult(null, TryInvokeMemberSuccessReason.FoundExtensionMethod);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(mresult, ex);
|
||||
}
|
||||
}
|
||||
return Attempt<TryInvokeMemberResult>.Fail();
|
||||
|
||||
@@ -11,78 +11,101 @@ namespace Umbraco.Core.Dynamics
|
||||
//Because it's IEnumerable, if the user is actually trying @Model.TextPages or similar
|
||||
//it will still return an enumerable object (assuming the call actually failed because there were no children of that type)
|
||||
//but in .Where, if they use a property that doesn't exist, the lambda will bypass this and return false
|
||||
|
||||
// returned when TryGetMember fails on a DynamicPublishedContent
|
||||
//
|
||||
// so if user does @CurrentPage.TextPages it will get something that is enumerable (but empty)
|
||||
// note - not sure I understand the stuff about .Where, though
|
||||
|
||||
public class DynamicNull : DynamicObject, IEnumerable, IHtmlString
|
||||
{
|
||||
public static readonly DynamicNull Null = new DynamicNull();
|
||||
|
||||
private DynamicNull() {}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return (new List<DynamicNull>()).GetEnumerator();
|
||||
}
|
||||
|
||||
public DynamicNull Where(string predicate, params object[] values)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicNull OrderBy(string orderBy)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicNull ToContentSet()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
result = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
||||
{
|
||||
result = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
|
||||
{
|
||||
result = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsNull()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasValue()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
get { return string.Empty; }
|
||||
}
|
||||
|
||||
public int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public static implicit operator bool(DynamicNull n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static implicit operator DateTime(DynamicNull n)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
|
||||
public static implicit operator int(DynamicNull n)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static implicit operator string(DynamicNull n)
|
||||
{
|
||||
return string.Empty;
|
||||
@@ -92,6 +115,5 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace Umbraco.Core.Dynamics
|
||||
if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
|
||||
&& attempt.Exception != null && attempt.Exception is TargetInvocationException)
|
||||
{
|
||||
result = new DynamicNull();
|
||||
result = DynamicNull.Null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,96 @@ namespace Umbraco.Core.Dynamics
|
||||
/// Utility class for finding extension methods on a type to execute
|
||||
/// </summary>
|
||||
internal static class ExtensionMethodFinder
|
||||
{
|
||||
{
|
||||
private static readonly MethodInfo[] AllExtensionMethods;
|
||||
|
||||
static ExtensionMethodFinder()
|
||||
{
|
||||
AllExtensionMethods = TypeFinder.GetAssembliesWithKnownExclusions()
|
||||
// assemblies that contain extension methods
|
||||
.Where(a => a.IsDefined(typeof(ExtensionAttribute), false))
|
||||
// types that contain extension methods
|
||||
.SelectMany(a => a.GetTypes()
|
||||
.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)
|
||||
.Where(m => m.IsDefined(typeof(ExtensionAttribute), false)))
|
||||
// and also IEnumerable<T> extension methods - because the assembly is excluded
|
||||
.Concat(typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// ORIGINAL CODE IS NOT COMPLETE, DOES NOT HANDLE GENERICS, ETC...
|
||||
|
||||
// so this is an attempt at fixing things, but it's not done yet
|
||||
// and do we really want to do this? extension methods are not supported on dynamics, period
|
||||
// we should use strongly typed content instead of dynamics.
|
||||
|
||||
/*
|
||||
|
||||
// get all extension methods for type thisType, with name name,
|
||||
// accepting argsCount arguments (not counting the instance of thisType).
|
||||
private static IEnumerable<MethodInfo> GetExtensionMethods(Type thisType, string name, int argsCount)
|
||||
{
|
||||
var key = string.Format("{0}.{1}::{2}", thisType.FullName, name, argsCount);
|
||||
|
||||
var types = thisType.GetBaseTypes(true); // either do this OR have MatchFirstParameter handle the stuff... F*XME
|
||||
|
||||
var methods = AllExtensionMethods
|
||||
.Where(m => m.Name == name)
|
||||
.Where(m => m.GetParameters().Length == argsCount)
|
||||
.Where(m => MatchFirstParameter(thisType, m.GetParameters()[0].ParameterType));
|
||||
|
||||
// f*xme - is this what we should cache?
|
||||
return methods;
|
||||
}
|
||||
|
||||
// find out whether the first parameter is a match for thisType
|
||||
private static bool MatchFirstParameter(Type thisType, Type firstParameterType)
|
||||
{
|
||||
return MethodArgZeroHasCorrectTargetType(null, firstParameterType, thisType);
|
||||
}
|
||||
|
||||
// get the single extension method for type thisType, with name name,
|
||||
// that accepts the arguments in args (which does not contain the instance of thisType).
|
||||
public static MethodInfo GetExtensionMethod(Type thisType, string name, object[] args)
|
||||
{
|
||||
MethodInfo result = null;
|
||||
foreach (var method in GetExtensionMethods(thisType, name, args.Length).Where(m => MatchParameters(m, args)))
|
||||
{
|
||||
if (result == null)
|
||||
result = method;
|
||||
else
|
||||
throw new AmbiguousMatchException("More than one matching extension method was found.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// find out whether the method can accept the arguments
|
||||
private static bool MatchParameters(MethodInfo method, IList<object> args)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
|
||||
var i = 0;
|
||||
for (; i < parameters.Length; ++i)
|
||||
{
|
||||
if (MatchParameter(parameters[i].ParameterType, args[i].GetType()) == false)
|
||||
break;
|
||||
}
|
||||
return (i == parameters.Length);
|
||||
}
|
||||
|
||||
internal static bool MatchParameter(Type parameterType, Type argumentType)
|
||||
{
|
||||
// public static int DoSomething<T>(Foo foo, T t1, T t2)
|
||||
// DoSomething(foo, t1, t2) => how can we match?!
|
||||
return parameterType == argumentType; // f*xme of course!
|
||||
}
|
||||
*
|
||||
*/
|
||||
|
||||
// BELOW IS THE ORIGINAL CODE...
|
||||
|
||||
/// <summary>
|
||||
/// Returns all extension methods found matching the definition
|
||||
/// </summary>
|
||||
@@ -27,6 +116,10 @@ namespace Umbraco.Core.Dynamics
|
||||
/// </remarks>
|
||||
private static IEnumerable<MethodInfo> GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
|
||||
{
|
||||
// at *least* we can cache the extension methods discovery
|
||||
var candidates = AllExtensionMethods;
|
||||
|
||||
/*
|
||||
//only scan assemblies we know to contain extension methods (user assemblies)
|
||||
var assembliesToScan = TypeFinder.GetAssembliesWithKnownExclusions();
|
||||
|
||||
@@ -45,6 +138,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
//add the extension methods defined in IEnumerable
|
||||
candidates = candidates.Concat(typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public));
|
||||
*/
|
||||
|
||||
//filter by name
|
||||
var methodsByName = candidates.Where(m => m.Name == name);
|
||||
|
||||
@@ -1,60 +1,46 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.interfaces;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
internal class PropertyResult : IPublishedContentProperty, IHtmlString
|
||||
{
|
||||
internal PropertyResult(IPublishedContentProperty source, PropertyResultType type)
|
||||
internal class PropertyResult : IPublishedProperty, IHtmlString
|
||||
{
|
||||
private readonly IPublishedProperty _source;
|
||||
private readonly string _alias;
|
||||
private readonly object _value;
|
||||
private readonly PropertyResultType _type;
|
||||
|
||||
internal PropertyResult(IPublishedProperty source, PropertyResultType type)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
|
||||
Alias = source.Alias;
|
||||
Value = source.Value;
|
||||
PropertyType = type;
|
||||
|
||||
_type = type;
|
||||
_source = source;
|
||||
}
|
||||
|
||||
internal PropertyResult(string alias, object value, PropertyResultType type)
|
||||
{
|
||||
if (alias == null) throw new ArgumentNullException("alias");
|
||||
if (value == null) throw new ArgumentNullException("value");
|
||||
|
||||
Alias = alias;
|
||||
Value = value;
|
||||
PropertyType = type;
|
||||
_type = type;
|
||||
_alias = alias;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
internal PropertyResultType PropertyType { get; private set; }
|
||||
|
||||
public string Alias { get; private set; }
|
||||
internal PropertyResultType PropertyType { get { return _type; } }
|
||||
|
||||
public object Value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value as a string output, this is used in the final rendering process of a property
|
||||
/// </summary>
|
||||
internal string ValueAsString
|
||||
{
|
||||
get
|
||||
{
|
||||
return Value == null ? "" : Convert.ToString(Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Id of the document for which this property belongs to
|
||||
/// </summary>
|
||||
public int DocumentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The alias of the document type alias for which this property belongs to
|
||||
/// </summary>
|
||||
public string DocumentTypeAlias { get; set; }
|
||||
public string PropertyTypeAlias { get { return _source == null ? _alias : _source.PropertyTypeAlias; } }
|
||||
public object DataValue { get { return _source == null ? _value : _source.DataValue; } }
|
||||
public bool HasValue { get { return _source == null || _source.HasValue; } }
|
||||
public object Value { get { return _source == null ? _value : _source.Value; } }
|
||||
public object XPathValue { get { return Value == null ? null : Value.ToString(); } }
|
||||
|
||||
public string ToHtmlString()
|
||||
{
|
||||
return ValueAsString;
|
||||
var value = Value;
|
||||
return value == null ? string.Empty : value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,45 @@ namespace Umbraco.Core
|
||||
{
|
||||
public static IEnumerable<IEnumerable<T>> InGroupsOf<T>(this IEnumerable<T> source, int groupSize)
|
||||
{
|
||||
var i = 0;
|
||||
var length = source.Count();
|
||||
if (source == null)
|
||||
throw new NullReferenceException("source");
|
||||
|
||||
while ((i * groupSize) < length)
|
||||
{
|
||||
yield return source.Skip(i * groupSize).Take(groupSize);
|
||||
i++;
|
||||
}
|
||||
// enumerate the source only once!
|
||||
return new InGroupsEnumerator<T>(source, groupSize).Groups();
|
||||
}
|
||||
|
||||
// this class makes sure that the source is enumerated only ONCE
|
||||
// which means that when it is enumerated, the actual groups content
|
||||
// has to be evaluated at the same time, and stored in an array.
|
||||
private class InGroupsEnumerator<T>
|
||||
{
|
||||
private readonly IEnumerator<T> _source;
|
||||
private readonly int _count;
|
||||
private bool _mightHaveNext;
|
||||
|
||||
public InGroupsEnumerator(IEnumerable<T> source, int count)
|
||||
{
|
||||
_source = source.GetEnumerator();
|
||||
_count = count;
|
||||
_mightHaveNext = true;
|
||||
}
|
||||
|
||||
public IEnumerable<IEnumerable<T>> Groups()
|
||||
{
|
||||
while (_mightHaveNext && _source.MoveNext())
|
||||
yield return Group().ToArray(); // see note above
|
||||
}
|
||||
|
||||
private IEnumerable<T> Group()
|
||||
{
|
||||
var c = 0;
|
||||
do
|
||||
{
|
||||
yield return _source.Current;
|
||||
} while (++c < _count && _source.MoveNext());
|
||||
_mightHaveNext = c == _count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The distinct by.</summary>
|
||||
/// <param name="source">The source.</param>
|
||||
@@ -243,23 +272,45 @@ namespace Umbraco.Core
|
||||
});
|
||||
}
|
||||
|
||||
///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
|
||||
///<param name="items">The enumerable to search.</param>
|
||||
///<param name="predicate">The expression to test the items against.</param>
|
||||
///<returns>The index of the first matching item, or -1 if no items match.</returns>
|
||||
/// <summary>
|
||||
/// Finds the index of the first item matching an expression in an enumerable.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the enumerated objects.</typeparam>
|
||||
/// <param name="items">The enumerable to search.</param>
|
||||
/// <param name="predicate">The expression to test the items against.</param>
|
||||
/// <returns>The index of the first matching item, or -1.</returns>
|
||||
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate)
|
||||
{
|
||||
return FindIndex(items, 0, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the index of the first item matching an expression in an enumerable.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the enumerated objects.</typeparam>
|
||||
/// <param name="items">The enumerable to search.</param>
|
||||
/// <param name="startIndex">The index to start at.</param>
|
||||
/// <param name="predicate">The expression to test the items against.</param>
|
||||
/// <returns>The index of the first matching item, or -1.</returns>
|
||||
public static int FindIndex<T>(this IEnumerable<T> items, int startIndex, Func<T, bool> predicate)
|
||||
{
|
||||
if (items == null) throw new ArgumentNullException("items");
|
||||
if (predicate == null) throw new ArgumentNullException("predicate");
|
||||
if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
|
||||
|
||||
var index = startIndex;
|
||||
if (index > 0)
|
||||
items = items.Skip(index);
|
||||
|
||||
var retVal = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (predicate(item)) return retVal;
|
||||
retVal++;
|
||||
if (predicate(item)) return index;
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
///<summary>Finds the index of the first occurence of an item in an enumerable.</summary>
|
||||
///<param name="items">The enumerable to search.</param>
|
||||
///<param name="item">The item to find.</param>
|
||||
|
||||
@@ -177,8 +177,21 @@ namespace Umbraco.Core
|
||||
public static MethodInfo GetMethodInfo<T1, T2>(Expression<Func<T1, T2>> fromExpression)
|
||||
{
|
||||
if (fromExpression == null) return null;
|
||||
var body = fromExpression.Body as MethodCallExpression;
|
||||
return body != null ? body.Method : null;
|
||||
|
||||
MethodCallExpression me;
|
||||
switch (fromExpression.Body.NodeType)
|
||||
{
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
var ue = fromExpression.Body as UnaryExpression;
|
||||
me = ((ue != null) ? ue.Operand : null) as MethodCallExpression;
|
||||
break;
|
||||
default:
|
||||
me = fromExpression.Body as MethodCallExpression;
|
||||
break;
|
||||
}
|
||||
|
||||
return me != null ? me.Method : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Any class implementing this interface that is added to the httpcontext.items keys or values will be disposed of at the end of the request.
|
||||
/// </summary>
|
||||
public interface IDisposeOnRequestEnd : IDisposable
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -45,11 +45,11 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IEnumerable<string> GetThumbnails(string path)
|
||||
{
|
||||
var parentDirectory = System.IO.Path.GetDirectoryName(path);
|
||||
var extension = System.IO.Path.GetExtension(path);
|
||||
var parentDirectory = Path.GetDirectoryName(path);
|
||||
var extension = Path.GetExtension(path);
|
||||
|
||||
return GetFiles(parentDirectory)
|
||||
.Where(x => x.StartsWith(path.TrimEnd(extension) + "_thumb"))
|
||||
.Where(x => x.StartsWith(path.TrimEnd(extension) + "_thumb") || x.StartsWith(path.TrimEnd(extension) + "_big-thumb"))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
DeleteFile(path);
|
||||
|
||||
if (!deleteThumbnails)
|
||||
if (deleteThumbnails == false)
|
||||
return;
|
||||
|
||||
DeleteThumbnails(path);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace Umbraco.Core
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
[Obsolete("This is no longer used and will be removed from the core in future versions")]
|
||||
public enum IconPickerBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Macros
|
||||
/// </summary>
|
||||
internal class MacroTagParser
|
||||
{
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<div class=[""']umb-macro-holder.+?[""'].*?>.*?<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(.*?</div>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<div.*?>.*?<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(.*?</div>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""'](\w+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
@@ -18,7 +19,8 @@ namespace Umbraco.Core.Manifest
|
||||
private readonly DirectoryInfo _pluginsDir;
|
||||
|
||||
//used to strip comments
|
||||
private static readonly Regex Comments = new Regex("(/\\*.*\\*/)", RegexOptions.Compiled);
|
||||
private static readonly Regex CommentsSurround = new Regex(@"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/", RegexOptions.Compiled);
|
||||
private static readonly Regex CommentsLine = new Regex(@"//.*?$", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
public ManifestParser(DirectoryInfo pluginsDir)
|
||||
{
|
||||
@@ -116,11 +118,20 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
if (m.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
//remove any comments first, NOTE: I think JSON.Net will do this for us! but we'll leave it here for now
|
||||
Comments.Replace(m, match => "");
|
||||
//remove any comments first
|
||||
var replaced = CommentsSurround.Replace(m, match => " ");
|
||||
replaced = CommentsLine.Replace(replaced, match => "");
|
||||
|
||||
|
||||
var deserialized = JsonConvert.DeserializeObject<JObject>(m);
|
||||
JObject deserialized;
|
||||
try
|
||||
{
|
||||
deserialized = JsonConvert.DeserializeObject<JObject>(replaced);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + m, ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
//validate the javascript
|
||||
var init = deserialized.Properties().Where(x => x.Name == "javascript").ToArray();
|
||||
@@ -128,7 +139,14 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'javascript' element");
|
||||
}
|
||||
|
||||
|
||||
//validate the css
|
||||
var cssinit = deserialized.Properties().Where(x => x.Name == "css").ToArray();
|
||||
if (cssinit.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'css' element");
|
||||
}
|
||||
|
||||
//validate the property editors section
|
||||
var propEditors = deserialized.Properties().Where(x => x.Name == "propertyEditors").ToArray();
|
||||
if (propEditors.Length > 1)
|
||||
@@ -139,6 +157,9 @@ namespace Umbraco.Core.Manifest
|
||||
var jConfig = init.Any() ? (JArray)deserialized["javascript"] : new JArray();
|
||||
ReplaceVirtualPaths(jConfig);
|
||||
|
||||
var cssConfig = cssinit.Any() ? (JArray)deserialized["css"] : new JArray();
|
||||
ReplaceVirtualPaths(cssConfig);
|
||||
|
||||
//replace virtual paths for each property editor
|
||||
if (deserialized["propertyEditors"] != null)
|
||||
{
|
||||
@@ -158,6 +179,7 @@ namespace Umbraco.Core.Manifest
|
||||
var manifest = new PackageManifest()
|
||||
{
|
||||
JavaScriptInitialize = jConfig,
|
||||
StylesheetInitialize = cssConfig,
|
||||
PropertyEditors = propEditors.Any() ? (JArray)deserialized["propertyEditors"] : new JArray(),
|
||||
ParameterEditors = propEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray()
|
||||
};
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
public JArray JavaScriptInitialize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The json array used to initialize the application with the CSS dependencies required
|
||||
/// </summary>
|
||||
public JArray StylesheetInitialize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The json array of property editors
|
||||
/// </summary>
|
||||
|
||||
@@ -16,8 +16,15 @@ namespace Umbraco.Core.Media
|
||||
/// <summary>
|
||||
/// A helper class used for imaging
|
||||
/// </summary>
|
||||
internal class ImageHelper
|
||||
internal static class ImageHelper
|
||||
{
|
||||
public static string GetMimeType(this Image image)
|
||||
{
|
||||
var format = image.RawFormat;
|
||||
var codec = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == format.Guid);
|
||||
return codec.MimeType;
|
||||
}
|
||||
|
||||
internal static IEnumerable<ResizedImage> GenerateMediaThumbnails(
|
||||
IFileSystem fs,
|
||||
string fileName,
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Diagnostics;
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
[DebuggerDisplay("Tree - {Title} ({ApplicationAlias})")]
|
||||
internal class ApplicationTree
|
||||
public class ApplicationTree
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationTree"/> class.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="iconClosed">The icon closed.</param>
|
||||
/// <param name="iconOpened">The icon opened.</param>
|
||||
/// <param name="type">The tree type.</param>
|
||||
public ApplicationTree(bool initialize, byte sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type)
|
||||
public ApplicationTree(bool initialize, int sortOrder, string applicationAlias, string alias, string title, string iconClosed, string iconOpened, string type)
|
||||
{
|
||||
this.Initialize = initialize;
|
||||
this.SortOrder = sortOrder;
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or sets the sort order.
|
||||
/// </summary>
|
||||
/// <value>The sort order.</value>
|
||||
public byte SortOrder { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application alias.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -50,6 +51,7 @@ namespace Umbraco.Core.Models
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,6 +75,7 @@ namespace Umbraco.Core.Models
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentBase, string>(x => x.Name);
|
||||
@@ -253,6 +256,16 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IDictionary<string, object> IUmbracoEntity.AdditionalData
|
||||
{
|
||||
get { return _additionalData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this Content object
|
||||
/// </summary>
|
||||
@@ -446,7 +459,7 @@ namespace Umbraco.Core.Models
|
||||
/// also reset the dirty changes made to the content's Properties (user defined)
|
||||
/// </summary>
|
||||
/// <param name="rememberPreviouslyChangedProperties"></param>
|
||||
internal override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Models
|
||||
internal static bool ShouldCreateNewVersion(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
var dirtyEntity = (ICanBeDirty)entity;
|
||||
|
||||
|
||||
//check if the published state has changed or the language
|
||||
var contentChanged =
|
||||
(dirtyEntity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished)
|
||||
@@ -71,9 +71,9 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
//check if any user prop has changed
|
||||
var propertyValueChanged = ((Content) entity).IsAnyUserPropertyDirty();
|
||||
var propertyValueChanged = ((Content)entity).IsAnyUserPropertyDirty();
|
||||
//check if any content prop has changed
|
||||
var contentDataChanged = ((Content) entity).IsEntityDirty();
|
||||
var contentDataChanged = ((Content)entity).IsEntityDirty();
|
||||
|
||||
//return true if the item is published and a property has changed or if any content property has changed
|
||||
return (propertyValueChanged && publishedState == PublishedState.Published) || contentDataChanged;
|
||||
@@ -296,7 +296,7 @@ namespace Umbraco.Core.Models
|
||||
.Select(propertyType => propertyType.Id)
|
||||
.Contains(property.PropertyTypeId))
|
||||
.OrderBy(x => x.PropertyType.SortOrder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set property values by alias with an annonymous object
|
||||
@@ -334,6 +334,8 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
#region SetValue for setting file contents
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
|
||||
/// </summary>
|
||||
@@ -380,7 +382,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
SetValue(content, propertyTypeAlias, (HttpPostedFileBase)value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a <see cref="Stream"/> as the property value
|
||||
/// </summary>
|
||||
@@ -416,7 +418,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
fs.AddFile(fileName, fileStream);
|
||||
|
||||
|
||||
//Check if file supports resizing and create thumbnails
|
||||
var supportsResizing = UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.InvariantContains(extension);
|
||||
|
||||
@@ -461,14 +463,14 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
ImageHelper.GenerateMediaThumbnails(fs, fileName, extension, originalImage, additionalSizes);
|
||||
|
||||
|
||||
//while the image is still open, we'll check if we need to auto-populate the image properties
|
||||
if (uploadFieldConfigNode != null)
|
||||
{
|
||||
content.SetValue(uploadFieldConfigNode.WidthFieldAlias, originalImage.Width.ToString(CultureInfo.InvariantCulture));
|
||||
content.SetValue(uploadFieldConfigNode.HeightFieldAlias, originalImage.Height.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,12 +484,15 @@ namespace Umbraco.Core.Models
|
||||
//Set the value of the property to that of the uploaded file's url
|
||||
property.Value = fs.GetUrl(fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IMedia media)
|
||||
{
|
||||
|
||||
#endregion
|
||||
|
||||
#region User/Profile methods
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(media.CreatorId);
|
||||
}
|
||||
|
||||
@@ -506,6 +511,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(content.WriterId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IContent"/> item has any published versions
|
||||
@@ -519,7 +525,92 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
}
|
||||
|
||||
#region Tag methods
|
||||
|
||||
///// <summary>
|
||||
///// Returns the tags for the given property
|
||||
///// </summary>
|
||||
///// <param name="content"></param>
|
||||
///// <param name="propertyTypeAlias"></param>
|
||||
///// <param name="tagGroup"></param>
|
||||
///// <returns></returns>
|
||||
///// <remarks>
|
||||
///// The tags returned are only relavent for published content & saved media or members
|
||||
///// </remarks>
|
||||
//public static IEnumerable<ITag> GetTags(this IContentBase content, string propertyTypeAlias, string tagGroup = "default")
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Sets tags for the property - will add tags to the tags table and set the property value to be the comma delimited value of the tags.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item to assign the tags to</param>
|
||||
/// <param name="propertyTypeAlias">The property alias to assign the tags to</param>
|
||||
/// <param name="tags">The tags to assign</param>
|
||||
/// <param name="replaceTags">True to replace the tags on the current property with the tags specified or false to merge them with the currently assigned ones</param>
|
||||
/// <param name="tagGroup">The group/category to assign the tags, the default value is "default"</param>
|
||||
/// <returns></returns>
|
||||
public static void SetTags(this IContentBase content, string propertyTypeAlias, IEnumerable<string> tags, bool replaceTags, string tagGroup = "default")
|
||||
{
|
||||
var property = content.Properties[propertyTypeAlias];
|
||||
if (property == null)
|
||||
{
|
||||
throw new IndexOutOfRangeException("No property exists with name " + propertyTypeAlias);
|
||||
}
|
||||
|
||||
var trimmedTags = tags.Select(x => x.Trim()).ToArray();
|
||||
|
||||
property.TagSupport.Enable = true;
|
||||
property.TagSupport.Tags = trimmedTags.Select(x => new Tuple<string, string>(x, tagGroup));
|
||||
property.TagSupport.Behavior = replaceTags ? PropertyTagBehavior.Replace : PropertyTagBehavior.Merge;
|
||||
|
||||
//ensure the property value is set to the same thing
|
||||
if (replaceTags)
|
||||
{
|
||||
property.Value = string.Join(",", trimmedTags);
|
||||
}
|
||||
else
|
||||
{
|
||||
var currTags = property.Value.ToString().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim());
|
||||
property.Value = string.Join(",", trimmedTags.Union(currTags));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove any of the tags specified in the collection from the property if they are currently assigned.
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="propertyTypeAlias"></param>
|
||||
/// <param name="tags"></param>
|
||||
/// <param name="tagGroup">The group/category that the tags are currently assigned to, the default value is "default"</param>
|
||||
public static void RemoveTags(this IContentBase content, string propertyTypeAlias, IEnumerable<string> tags, string tagGroup = "default")
|
||||
{
|
||||
var property = content.Properties[propertyTypeAlias];
|
||||
if (property == null)
|
||||
{
|
||||
throw new IndexOutOfRangeException("No property exists with name " + propertyTypeAlias);
|
||||
}
|
||||
|
||||
var trimmedTags = tags.Select(x => x.Trim()).ToArray();
|
||||
|
||||
property.TagSupport.Behavior = PropertyTagBehavior.Remove;
|
||||
property.TagSupport.Enable = true;
|
||||
property.TagSupport.Tags = trimmedTags.Select(x => new Tuple<string, string>(x, tagGroup));
|
||||
|
||||
//set the property value
|
||||
var currTags = property.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim());
|
||||
|
||||
property.Value = string.Join(",", currTags.Except(trimmedTags));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region XML methods
|
||||
/// <summary>
|
||||
/// Creates the full xml representation for the <see cref="IContent"/> object and all of it's descendants
|
||||
/// </summary>
|
||||
@@ -555,6 +646,16 @@ namespace Umbraco.Core.Models
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(media, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="member"><see cref="IContent"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
public static XElement ToXml(this IMember member)
|
||||
{
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -567,5 +668,10 @@ namespace Umbraco.Core.Models
|
||||
//If current IContent is published we should get latest unpublished version
|
||||
return content.ToXml();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -42,6 +43,7 @@ namespace Umbraco.Core.Models
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
_propertyTypes = new PropertyTypeCollection();
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
protected ContentTypeBase(IContentTypeBase parent)
|
||||
@@ -52,6 +54,7 @@ namespace Umbraco.Core.Models
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
_propertyTypes = new PropertyTypeCollection();
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Name);
|
||||
@@ -314,6 +317,21 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IDictionary<string, object> IUmbracoEntity.AdditionalData
|
||||
{
|
||||
get { return _additionalData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -32,13 +36,23 @@ namespace Umbraco.Core.Models
|
||||
public DataTypeDefinition(int parentId, Guid controlId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_propertyEditorAlias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(controlId, true);
|
||||
}
|
||||
|
||||
_propertyEditorAlias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(controlId, false);
|
||||
if (_propertyEditorAlias == null)
|
||||
{
|
||||
//convert to Label!
|
||||
LogHelper.Warn<DataTypeDefinition>("Could not find a GUID -> Alias mapping for the legacy property editor with id " + controlId + ". The DataType has been converted to a Label.");
|
||||
_propertyEditorAlias = Constants.PropertyEditors.NoEditAlias;
|
||||
}
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
public DataTypeDefinition(int parentId, string propertyEditorAlias)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_propertyEditorAlias = propertyEditorAlias;
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, string>(x => x.Name);
|
||||
@@ -170,9 +184,11 @@ namespace Umbraco.Core.Models
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
|
||||
_additionalData["Trashed"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DataMember]
|
||||
public string PropertyEditorAlias
|
||||
{
|
||||
@@ -184,6 +200,8 @@ namespace Umbraco.Core.Models
|
||||
_propertyEditorAlias = value;
|
||||
return _propertyEditorAlias;
|
||||
}, _propertyEditorAlias, PropertyEditorAliasSelector);
|
||||
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
|
||||
_additionalData["DatabaseType"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +221,8 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
var alias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(value, true);
|
||||
PropertyEditorAlias = alias;
|
||||
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
|
||||
_additionalData["ControlId"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,9 +240,27 @@ namespace Umbraco.Core.Models
|
||||
_databaseType = value;
|
||||
return _databaseType;
|
||||
}, _databaseType, DatabaseTypeSelector);
|
||||
|
||||
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
|
||||
_additionalData["DatabaseType"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IDictionary<string, object> IUmbracoEntity.AdditionalData
|
||||
{
|
||||
get { return _additionalData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalData { get; private set; }
|
||||
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
@@ -231,4 +269,4 @@ namespace Umbraco.Core.Models
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@
|
||||
bool WasDirty();
|
||||
bool WasPropertyDirty(string propertyName);
|
||||
void ForgetPreviouslyDirtyProperties();
|
||||
void ResetDirtyProperties(bool rememberPreviouslyChangedProperties);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
public interface IUmbracoEntity : IAggregateRoot
|
||||
{
|
||||
@@ -41,5 +43,10 @@
|
||||
/// Not all entities support being trashed, they'll always return false.
|
||||
/// </remarks>
|
||||
bool Trashed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
IDictionary<string, object> AdditionalData { get; }
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
internal virtual void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
public virtual void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
if (rememberPreviouslyChangedProperties)
|
||||
{
|
||||
|
||||
@@ -1,20 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a published item in Umbraco
|
||||
/// Represents a cached content.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A replacement for INode which needs to occur since INode doesn't contain the document type alias
|
||||
/// and INode is poorly formatted with mutable properties (i.e. Lists instead of IEnumerable)
|
||||
/// <para>SD: A replacement for INode which needs to occur since INode doesn't contain the document type alias
|
||||
/// and INode is poorly formatted with mutable properties (i.e. Lists instead of IEnumerable).</para>
|
||||
/// <para>Stephan: initially, that was for cached published content only. Now, we're using it also for
|
||||
/// cached preview (so, maybe unpublished) content. A better name would therefore be ICachedContent, as
|
||||
/// has been suggested. However, can't change now. Maybe in v7?</para>
|
||||
/// </remarks>
|
||||
public interface IPublishedContent
|
||||
{
|
||||
int Id { get; }
|
||||
public interface IPublishedContent
|
||||
{
|
||||
#region ContentSet
|
||||
|
||||
// Because of http://issues.umbraco.org/issue/U4-1797 and in order to implement
|
||||
// Index() and methods that derive from it such as IsFirst(), IsLast(), etc... all
|
||||
// content items must know about their containing content set.
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content set to which the content belongs.
|
||||
/// </summary>
|
||||
/// <remarks>The default set consists in the siblings of the content (including the content
|
||||
/// itself) ordered by <c>sortOrder</c>.</remarks>
|
||||
IEnumerable<IPublishedContent> ContentSet { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ContentType
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type.
|
||||
/// </summary>
|
||||
PublishedContentType ContentType { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content
|
||||
|
||||
int Id { get; }
|
||||
int TemplateId { get; }
|
||||
int SortOrder { get; }
|
||||
string Name { get; }
|
||||
@@ -31,32 +59,97 @@ namespace Umbraco.Core.Models
|
||||
Guid Version { get; }
|
||||
int Level { get; }
|
||||
string Url { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content is a content (aka a document) or a media.
|
||||
/// </summary>
|
||||
PublishedItemType ItemType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content is draft.
|
||||
/// </summary>
|
||||
/// <remarks>A content is draft when it is the unpublished version of a content, which may
|
||||
/// have a published version, or not.</remarks>
|
||||
bool IsDraft { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the published content within its current owning content set.
|
||||
/// </summary>
|
||||
/// <returns>The index of the published content within its current owning content set.</returns>
|
||||
int GetIndex();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tree
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent of the content.
|
||||
/// </summary>
|
||||
/// <remarks>The parent of root content is <c>null</c>.</remarks>
|
||||
IPublishedContent Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content.
|
||||
/// </summary>
|
||||
/// <remarks>Children are sorted by their sortOrder.</remarks>
|
||||
IEnumerable<IPublishedContent> Children { get; }
|
||||
|
||||
ICollection<IPublishedContentProperty> Properties { get; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns the property value for the property alias specified
|
||||
/// </summary>
|
||||
/// <param name="propertyAlias"></param>
|
||||
/// <returns></returns>
|
||||
object this[string propertyAlias] { get; }
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns a property on the object based on an alias
|
||||
/// <summary>
|
||||
/// Gets the properties of the content.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Contains one <c>IPublishedProperty</c> for each property defined for the content type, including
|
||||
/// inherited properties. Some properties may have no value.</para>
|
||||
/// <para>The properties collection of an IPublishedContent instance should be read-only ie it is illegal
|
||||
/// to add properties to the collection.</para>
|
||||
/// </remarks>
|
||||
ICollection<IPublishedProperty> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property identified by its alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The property alias.</param>
|
||||
/// <returns>The property identified by the alias.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If the content type has no property with that alias, including inherited properties, returns <c>null</c>,</para>
|
||||
/// <para>otherwise return a property -- that may have no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
||||
/// <para>The alias is case-insensitive.</para>
|
||||
/// </remarks>
|
||||
IPublishedProperty GetProperty(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property identified by its alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The property alias.</param>
|
||||
/// <param name="recurse">A value indicating whether to navigate the tree upwards until a property with a value is found.</param>
|
||||
/// <returns>The property identified by the alias.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Navigate the tree upwards and look for a property with that alias and with a value (ie <c>HasValue</c> is <c>true</c>).
|
||||
/// If found, return the property. If no property with that alias is found, having a value or not, return <c>null</c>. Otherwise
|
||||
/// return the first property that was found with the alias but had no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
||||
/// <para>The alias is case-insensitive.</para>
|
||||
/// </remarks>
|
||||
IPublishedProperty GetProperty(string alias, bool recurse);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a property identified by its alias.
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Although we do have a a property to return Properties of the object, in some cases a custom implementation may not know
|
||||
/// about all properties until specifically asked for one by alias.
|
||||
///
|
||||
/// This method is mostly used in places such as DynamicPublishedContent when trying to resolve a property based on an alias.
|
||||
/// In some cases Pulish Stores, a property value may exist in multiple places and we need to fallback to different cached locations
|
||||
/// therefore sometimes the 'Properties' collection may not be sufficient.
|
||||
/// </remarks>
|
||||
IPublishedContentProperty GetProperty(string alias);
|
||||
}
|
||||
/// <param name="alias">The property alias.</param>
|
||||
/// <returns>The value of the property identified by the alias.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <c>GetProperty(alias)</c> is <c>null</c> then returns <c>null</c> else return <c>GetProperty(alias).Value</c>.</para>
|
||||
/// <para>So if the property has no value, returns the default value for that property type.</para>
|
||||
/// <para>This one is defined here really because we cannot define index extension methods, but all it should do is:
|
||||
/// <code>var p = GetProperty(alias); return p == null ? null : p.Value;</code> and nothing else.</para>
|
||||
/// <para>The recursive syntax (eg "_title") is _not_ supported here.</para>
|
||||
/// <para>The alias is case-insensitive.</para>
|
||||
/// </remarks>
|
||||
object this[string alias] { get; } // todo - should obsolete this[alias] (when?)
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IPublishedContentProperty
|
||||
{
|
||||
string Alias { get; }
|
||||
object Value { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a property of an <c>IPublishedContent</c>.
|
||||
/// </summary>
|
||||
public interface IPublishedProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the alias of the property.
|
||||
/// </summary>
|
||||
string PropertyTypeAlias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property has a value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This is somewhat implementation-dependent -- depending on whatever IPublishedCache considers
|
||||
/// a missing value.</para>
|
||||
/// <para>The XmlPublishedCache raw values are strings, and it will consider missing, null or empty (and
|
||||
/// that includes whitespace-only) strings as "no value".</para>
|
||||
/// <para>Other caches that get their raw value from the database would consider that a property has "no
|
||||
/// value" if it is missing, null, or an empty string (including whitespace-only).</para>
|
||||
/// </remarks>
|
||||
bool HasValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data value of the property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The data value is whatever was passed to the property when it was instanciated, and it is
|
||||
/// somewhat implementation-dependent -- depending on how the IPublishedCache is implemented.</para>
|
||||
/// <para>The XmlPublishedCache raw values are strings exclusively since they come from the Xml cache.</para>
|
||||
/// <para>For other caches that get their raw value from the database, it would be either a string,
|
||||
/// an integer (Int32), or a date and time (DateTime).</para>
|
||||
/// <para>If you're using that value, you're probably wrong, unless you're doing some internal
|
||||
/// Umbraco stuff.</para>
|
||||
/// </remarks>
|
||||
object DataValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object value of the property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The value is what you want to use when rendering content in an MVC view ie in C#.</para>
|
||||
/// <para>It can be null, or any type of CLR object.</para>
|
||||
/// <para>It has been fully prepared and processed by the appropriate converter.</para>
|
||||
/// </remarks>
|
||||
object Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XPath value of the property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The XPath value is what you want to use when navigating content via XPath eg in the XSLT engine.</para>
|
||||
/// <para>It must be either null, or a string, or an XPathNavigator.</para>
|
||||
/// <para>It has been fully prepared and processed by the appropriate converter.</para>
|
||||
/// </remarks>
|
||||
object XPathValue { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IRelation : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Parent Id of the Relation (Source)
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child Id of the Relation (Destination)
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
int ChildId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="RelationType"/> for the Relation
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
IRelationType RelationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a comment for the Relation
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Id of the <see cref="RelationType"/> that this Relation is based on.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
int RelationTypeId { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IRelationType : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the RelationType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Alias of the RelationType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the RelationType is Bidirectional (true) or Parent to Child (false)
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
bool IsBidirectional { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Parents object type id
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
Guid ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Childs object type id
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember]
|
||||
Guid ChildObjectType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface ITag : IAggregateRoot
|
||||
{
|
||||
[DataMember]
|
||||
string Text { get; set; }
|
||||
|
||||
[DataMember]
|
||||
string Group { get; set; }
|
||||
|
||||
//TODO: enable this at some stage
|
||||
//int ParentId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ namespace Umbraco.Core.Models
|
||||
OnPropertyChanged(PropertiesSelector);
|
||||
}
|
||||
|
||||
internal override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
_addedProperties.Clear();
|
||||
_removedProperties.Clear();
|
||||
|
||||
@@ -20,19 +20,37 @@ namespace Umbraco.Core.Models
|
||||
private object _providerUserKey;
|
||||
private Type _userTypeKey;
|
||||
|
||||
public Member(string name, int parentId, IMemberType contentType, PropertyCollection properties) : base(name, parentId, contentType, properties)
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Member(string name, IMemberType contentType)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentType = contentType;
|
||||
}
|
||||
|
||||
public Member(string name, IContentBase parent, IMemberType contentType, PropertyCollection properties)
|
||||
: base(name, parent, contentType, properties)
|
||||
public Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
|
||||
: base(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentType = contentType;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
public Member(string name, string email, string username, string password, IContentBase parent, IMemberType contentType)
|
||||
: base(name, parent, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentType = contentType;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo DefaultContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.ContentTypeAlias);
|
||||
@@ -420,7 +438,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
throw new NotImplementedException("Members can't be trashed as no Recycle Bin exists, so use of this method is invalid");
|
||||
throw new NotSupportedException("Members can't be trashed as no Recycle Bin exists, so use of this method is invalid");
|
||||
}
|
||||
|
||||
/* Internal experiment - only used for mapping queries.
|
||||
|
||||
@@ -114,5 +114,26 @@ namespace Umbraco.Core.Models
|
||||
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being saved
|
||||
/// </summary>
|
||||
/// <remarks>Created date is set and a Unique key is assigned</remarks>
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
|
||||
if (Key == Guid.Empty)
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being updated
|
||||
/// </summary>
|
||||
/// <remarks>Modified Date is set and a new Version guid is set</remarks>
|
||||
internal override void UpdatingEntity()
|
||||
{
|
||||
base.UpdatingEntity();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
//TODO: THere's still a bunch of properties that don't exist in this use that need to be mapped somehow.
|
||||
|
||||
internal class UmbracoMembershipMember : MembershipUser
|
||||
{
|
||||
private readonly IMember _member;
|
||||
@@ -21,5 +23,44 @@ namespace Umbraco.Core.Models.Membership
|
||||
get { return _member.Email; }
|
||||
set { _member.Email = value; }
|
||||
}
|
||||
|
||||
public override object ProviderUserKey
|
||||
{
|
||||
get { return _member.Key; }
|
||||
}
|
||||
|
||||
public override System.DateTime CreationDate
|
||||
{
|
||||
get { return _member.CreateDate; }
|
||||
}
|
||||
|
||||
public override string UserName
|
||||
{
|
||||
get { return _member.Username; }
|
||||
}
|
||||
|
||||
public override string Comment
|
||||
{
|
||||
get { return _member.Comments; }
|
||||
set { _member.Comments = value; }
|
||||
}
|
||||
|
||||
public override bool IsApproved
|
||||
{
|
||||
get { return _member.IsApproved; }
|
||||
set { _member.IsApproved = value; }
|
||||
}
|
||||
|
||||
public override bool IsLockedOut
|
||||
{
|
||||
get { return _member.IsLockedOut; }
|
||||
}
|
||||
|
||||
public override System.DateTime LastLoginDate
|
||||
{
|
||||
get { return _member.LastLoginDate; }
|
||||
set { _member.LastLoginDate = value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// be flagged as dirty.
|
||||
/// </summary>
|
||||
/// <param name="rememberPreviouslyChangedProperties"></param>
|
||||
internal override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
_addedSections.Clear();
|
||||
_removedSections.Clear();
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a paged result for a model collection
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
{
|
||||
TotalItems = totalItems;
|
||||
PageNumber = pageNumber;
|
||||
PageSize = pageSize;
|
||||
|
||||
if (pageSize > 0)
|
||||
{
|
||||
TotalPages = (long) Math.Ceiling(totalItems/(Decimal) pageSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
TotalPages = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Name = "pageNumber")]
|
||||
public long PageNumber { get; private set; }
|
||||
|
||||
[DataMember(Name = "pageSize")]
|
||||
public long PageSize { get; private set; }
|
||||
|
||||
[DataMember(Name = "totalPages")]
|
||||
public long TotalPages { get; private set; }
|
||||
|
||||
[DataMember(Name = "totalItems")]
|
||||
public long TotalItems { get; private set; }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the skip size based on the paged parameters specified
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns 0 if the page number or page size is zero
|
||||
/// </remarks>
|
||||
internal int SkipSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PageNumber > 0 && PageSize > 0)
|
||||
{
|
||||
return Convert.ToInt32((PageNumber - 1)*PageSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a paged result for a model collection
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
{
|
||||
TotalItems = totalItems;
|
||||
PageNumber = pageNumber;
|
||||
PageSize = pageSize;
|
||||
|
||||
if (pageSize > 0)
|
||||
{
|
||||
TotalPages = (long) Math.Ceiling(totalItems/(Decimal) pageSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
TotalPages = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember(Name = "pageNumber")]
|
||||
public long PageNumber { get; private set; }
|
||||
|
||||
[DataMember(Name = "pageSize")]
|
||||
public long PageSize { get; private set; }
|
||||
|
||||
[DataMember(Name = "totalPages")]
|
||||
public long TotalPages { get; private set; }
|
||||
|
||||
[DataMember(Name = "totalItems")]
|
||||
public long TotalItems { get; private set; }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the skip size based on the paged parameters specified
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns 0 if the page number or page size is zero
|
||||
/// </remarks>
|
||||
internal int SkipSize
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PageNumber > 0 && PageSize > 0)
|
||||
{
|
||||
return Convert.ToInt32((PageNumber - 1)*PageSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,11 @@
|
||||
{
|
||||
Value = value;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public PreValue(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Models
|
||||
private readonly PropertyType _propertyType;
|
||||
private Guid _version;
|
||||
private object _value;
|
||||
private readonly PropertyTags _tagSupport = new PropertyTags();
|
||||
|
||||
protected Property()
|
||||
{
|
||||
@@ -44,6 +45,14 @@ namespace Umbraco.Core.Models
|
||||
private static readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo<Property, object>(x => x.Value);
|
||||
private static readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo<Property, Guid>(x => x.Version);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the instance of the tag support, by default tags are not enabled
|
||||
/// </summary>
|
||||
internal PropertyTags TagSupport
|
||||
{
|
||||
get { return _tagSupport; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Alias of the PropertyType, which this Property is based on
|
||||
/// </summary>
|
||||
|
||||
@@ -20,48 +20,34 @@ namespace Umbraco.Core.Models
|
||||
return property.ToXml(ApplicationContext.Current.Services.DataTypeService);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="Property"/> object
|
||||
/// </summary>
|
||||
/// <param name="property"><see cref="Property"/> to generate xml for</param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <returns>Xml of the property and its value</returns>
|
||||
internal static XElement ToXml(this Property property, IDataTypeService dataTypeService)
|
||||
{
|
||||
var nodeName = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema ? "data" : property.Alias.ToSafeAlias();
|
||||
|
||||
var xd = new XmlDocument();
|
||||
var xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
|
||||
var xElement = new XElement(nodeName);
|
||||
|
||||
//Add the property alias to the legacy schema
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema)
|
||||
{
|
||||
var alias = xd.CreateAttribute("alias");
|
||||
alias.Value = property.Alias.ToSafeAlias();
|
||||
xmlNode.Attributes.Append(alias);
|
||||
var a = new XAttribute("alias", property.Alias.ToSafeAlias());
|
||||
xElement.Add(a);
|
||||
}
|
||||
|
||||
// * Get the XML result from the property editor if there is one, otherwise just construct a simple
|
||||
// XML construct from the value returned from the Property Editor.
|
||||
// More details discussed here: https://groups.google.com/forum/?fromgroups=#!topic/umbraco-dev/fieWZzHj7oY
|
||||
|
||||
//Get the property editor for thsi property and let it convert it to the xml structure
|
||||
var propertyEditor = PropertyEditorResolver.Current.GetByAlias(property.PropertyType.PropertyEditorAlias);
|
||||
if (propertyEditor != null)
|
||||
{
|
||||
var cacheValue = propertyEditor.ValueEditor.FormatValueForCache(property);
|
||||
|
||||
switch (property.PropertyType.DataTypeDatabaseType)
|
||||
{
|
||||
case DataTypeDatabaseType.Date:
|
||||
case DataTypeDatabaseType.Integer:
|
||||
xmlNode.AppendChild(xd.CreateTextNode(cacheValue.ToString()));
|
||||
break;
|
||||
case DataTypeDatabaseType.Nvarchar:
|
||||
case DataTypeDatabaseType.Ntext:
|
||||
//put text in cdata
|
||||
xmlNode.AppendChild(xd.CreateCDataSection(cacheValue.ToString()));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var xmlValue = propertyEditor.ValueEditor.ConvertDbToXml(property);
|
||||
xElement.Add(xmlValue);
|
||||
}
|
||||
|
||||
var element = xmlNode.GetXElement();
|
||||
return element;
|
||||
|
||||
return xElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A property extension class that allows us to enable tags for any given property
|
||||
/// </summary>
|
||||
internal class PropertyTags
|
||||
{
|
||||
public PropertyTags()
|
||||
{
|
||||
Enable = false;
|
||||
Behavior = PropertyTagBehavior.Merge;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The behavior of how to save the tags assigned -
|
||||
/// Merge (keep existing and append new),
|
||||
/// Remove (remove any of the tags in the Tags property that are currently assigned,
|
||||
/// Replace (replace the currently assigned tags with the ones specified)
|
||||
/// </summary>
|
||||
public PropertyTagBehavior Behavior { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags the property to have tagging enabled
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual tags to associate - tag/group
|
||||
/// </summary>
|
||||
public IEnumerable<Tuple<string, string>> Tags { get; set; }
|
||||
|
||||
}
|
||||
|
||||
internal enum PropertyTagBehavior
|
||||
{
|
||||
Replace,
|
||||
Remove,
|
||||
Merge
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to handle extended content.
|
||||
/// </summary>
|
||||
internal interface IPublishedContentExtended : IPublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a property to the extended content.
|
||||
/// </summary>
|
||||
/// <param name="property">The property to add.</param>
|
||||
void AddProperty(IPublishedProperty property);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether properties were added to the extended content.
|
||||
/// </summary>
|
||||
bool HasAddedProperties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content set of the extended content.
|
||||
/// </summary>
|
||||
/// <param name="contentSet"></param>
|
||||
void SetContentSet(IEnumerable<IPublishedContent> contentSet);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the content set of the extended content.
|
||||
/// </summary>
|
||||
void ClearContentSet();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the index of the extended content.
|
||||
/// </summary>
|
||||
/// <param name="value">The index value.</param>
|
||||
void SetIndex(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the index of the extended content.
|
||||
/// </summary>
|
||||
void ClearIndex();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the model creation service.
|
||||
/// </summary>
|
||||
internal interface IPublishedContentModelFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a strongly-typed model representing a published content.
|
||||
/// </summary>
|
||||
/// <param name="content">The original published content.</param>
|
||||
/// <returns>The strongly-typed model representing the published content, or the published content
|
||||
/// itself it the factory has no model for that content type.</returns>
|
||||
IPublishedContent CreateModel(IPublishedContent content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
|
||||
public class PublishedContentExtended : PublishedContentWrapped, IPublishedContentExtended
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
// protected for models, private for our static Extend method
|
||||
protected PublishedContentExtended(IPublishedContent content)
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Index
|
||||
|
||||
private int? _index;
|
||||
|
||||
public override int GetIndex()
|
||||
{
|
||||
// fast
|
||||
if (_index.HasValue) return _index.Value;
|
||||
|
||||
// slow -- and don't cache, not in a set
|
||||
if (_contentSet == null) return Content.GetIndex();
|
||||
|
||||
// slow -- but cache for next time
|
||||
var index = _contentSet.FindIndex(x => x.Id == Id);
|
||||
if (index < 0)
|
||||
throw new IndexOutOfRangeException("Could not find content in the content set.");
|
||||
_index = index;
|
||||
return index;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extend
|
||||
|
||||
internal static IPublishedContentExtended Extend(IPublishedContent content, IEnumerable<IPublishedContent> contentSet)
|
||||
{
|
||||
var wrapped = content as PublishedContentExtended;
|
||||
while (wrapped != null && ((IPublishedContentExtended)wrapped).HasAddedProperties == false)
|
||||
wrapped = (content = wrapped.Unwrap()) as PublishedContentExtended;
|
||||
|
||||
// if the factory returns something else than content it means it has created
|
||||
// a model, and then that model has to inherit from PublishedContentExtended,
|
||||
// => implements the internal IPublishedContentExtended.
|
||||
|
||||
var model = PublishedContentModelFactory.CreateModel(content);
|
||||
var extended = model == content // == means the factory did not create a model
|
||||
? new PublishedContentExtended(content) // so we have to extend
|
||||
: model; // else we can use what the factory returned
|
||||
|
||||
var extended2 = extended as IPublishedContentExtended;
|
||||
if (extended2 != null) // always true, but keeps Resharper happy
|
||||
extended2.SetContentSet(contentSet);
|
||||
return extended2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IPublishedContentExtended
|
||||
|
||||
void IPublishedContentExtended.AddProperty(IPublishedProperty property)
|
||||
{
|
||||
if (_properties == null)
|
||||
_properties = new Collection<IPublishedProperty>();
|
||||
_properties.Add(property);
|
||||
}
|
||||
|
||||
bool IPublishedContentExtended.HasAddedProperties
|
||||
{
|
||||
get { return _properties != null; }
|
||||
}
|
||||
|
||||
void IPublishedContentExtended.SetContentSet(IEnumerable<IPublishedContent> contentSet)
|
||||
{
|
||||
_contentSet = contentSet;
|
||||
}
|
||||
|
||||
void IPublishedContentExtended.ClearContentSet()
|
||||
{
|
||||
_contentSet = null;
|
||||
}
|
||||
|
||||
void IPublishedContentExtended.SetIndex(int value)
|
||||
{
|
||||
_index = value;
|
||||
}
|
||||
|
||||
void IPublishedContentExtended.ClearIndex()
|
||||
{
|
||||
_index = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content set
|
||||
|
||||
private IEnumerable<IPublishedContent> _contentSet;
|
||||
|
||||
public override IEnumerable<IPublishedContent> ContentSet
|
||||
{
|
||||
get { return _contentSet ?? Content.ContentSet; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
private ICollection<IPublishedProperty> _properties;
|
||||
|
||||
public override ICollection<IPublishedProperty> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return _properties == null
|
||||
? Content.Properties
|
||||
: Content.Properties.Union(_properties).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public override object this[string alias]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_properties != null)
|
||||
{
|
||||
var property = _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias));
|
||||
if (property != null) return property.HasValue ? property.Value : null;
|
||||
}
|
||||
return Content[alias];
|
||||
}
|
||||
}
|
||||
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return _properties == null
|
||||
? Content.GetProperty(alias)
|
||||
: _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias)) ?? Content.GetProperty(alias);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a strongly-typed published content.
|
||||
/// </summary>
|
||||
/// <remarks>Every strongly-typed published content class should inherit from <c>PublishedContentModel</c>
|
||||
/// (or inherit from a class that inherits from... etc.) so they are picked by the factory.</remarks>
|
||||
internal abstract class PublishedContentModel : PublishedContentExtended
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentModel"/> class with
|
||||
/// an original <see cref="IPublishedContent"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="content">The original content.</param>
|
||||
protected PublishedContentModel(IPublishedContent content)
|
||||
: base(content)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the class is a published content model for a specified content type.
|
||||
/// </summary>
|
||||
/// <remarks>By default, the name of the class is assumed to be the content type alias. The
|
||||
/// <c>PublishedContentModelAttribute</c> can be used to indicate a different alias.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal sealed class PublishedContentModelAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentModelAttribute"/> class with a content type alias.
|
||||
/// </summary>
|
||||
/// <param name="contentTypeAlias">The content type alias.</param>
|
||||
public PublishedContentModelAttribute(string contentTypeAlias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias))
|
||||
throw new ArgumentException("Argument cannot be null nor empty.", "contentTypeAlias");
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content type alias.
|
||||
/// </summary>
|
||||
public string ContentTypeAlias { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides strongly typed published content models services.
|
||||
/// </summary>
|
||||
internal static class PublishedContentModelFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a strongly typed published content model for an internal published content.
|
||||
/// </summary>
|
||||
/// <param name="content">The internal published content.</param>
|
||||
/// <returns>The strongly typed published content model.</returns>
|
||||
public static IPublishedContent CreateModel(IPublishedContent content)
|
||||
{
|
||||
return PublishedContentModelFactoryResolver.Current.HasValue
|
||||
? PublishedContentModelFactoryResolver.Current.Factory.CreateModel(content)
|
||||
: content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a strongly typed content model factory
|
||||
/// </summary>
|
||||
internal class PublishedContentModelFactoryImpl : IPublishedContentModelFactory
|
||||
{
|
||||
//private readonly Dictionary<string, ConstructorInfo> _constructors
|
||||
// = new Dictionary<string, ConstructorInfo>();
|
||||
|
||||
private readonly Dictionary<string, Func<IPublishedContent, IPublishedContent>> _constructors
|
||||
= new Dictionary<string, Func<IPublishedContent, IPublishedContent>>();
|
||||
|
||||
public PublishedContentModelFactoryImpl()
|
||||
{
|
||||
var types = PluginManager.Current.ResolveTypes<PublishedContentModel>();
|
||||
var ctorArgTypes = new[] { typeof(IPublishedContent) };
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var constructor = type.GetConstructor(ctorArgTypes);
|
||||
if (constructor == null)
|
||||
throw new InvalidOperationException(string.Format("Type {0} is missing a public constructor with one argument of type IPublishedContent.", type.FullName));
|
||||
var attribute = type.GetCustomAttribute<PublishedContentModelAttribute>(false);
|
||||
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
|
||||
typeName = typeName.ToLowerInvariant();
|
||||
|
||||
if (_constructors.ContainsKey(typeName))
|
||||
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
|
||||
|
||||
// should work everywhere, but slow
|
||||
//_constructors[typeName] = constructor;
|
||||
|
||||
// much faster with a dynamic method but potential MediumTrust issues
|
||||
// here http://stackoverflow.com/questions/16363838/how-do-you-call-a-constructor-via-an-expression-tree-on-an-existing-object
|
||||
|
||||
// fast enough and works in MediumTrust
|
||||
// read http://boxbinary.com/2011/10/how-to-run-a-unit-test-in-medium-trust-with-nunitpart-three-umbraco-framework-testing/
|
||||
var exprArg = Expression.Parameter(typeof(IPublishedContent), "content");
|
||||
var exprNew = Expression.New(constructor, exprArg);
|
||||
var expr = Expression.Lambda<Func<IPublishedContent, IPublishedContent>>(exprNew, exprArg);
|
||||
var func = expr.Compile();
|
||||
_constructors[typeName] = func;
|
||||
}
|
||||
}
|
||||
|
||||
public IPublishedContent CreateModel(IPublishedContent content)
|
||||
{
|
||||
// be case-insensitive
|
||||
var contentTypeAlias = content.DocumentTypeAlias.ToLowerInvariant();
|
||||
|
||||
//ConstructorInfo constructor;
|
||||
//return _constructors.TryGetValue(contentTypeAlias, out constructor)
|
||||
// ? (IPublishedContent) constructor.Invoke(new object[] { content })
|
||||
// : content;
|
||||
|
||||
Func<IPublishedContent, IPublishedContent> constructor;
|
||||
return _constructors.TryGetValue(contentTypeAlias, out constructor)
|
||||
? constructor(content)
|
||||
: content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves the IPublishedContentModelFactory object.
|
||||
/// </summary>
|
||||
internal class PublishedContentModelFactoryResolver : SingleObjectResolverBase<PublishedContentModelFactoryResolver, IPublishedContentModelFactory>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentModelFactoryResolver"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The resolver is created by the <c>WebBootManager</c> and thus the constructor remains internal.</remarks>
|
||||
internal PublishedContentModelFactoryResolver()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentModelFactoryResolver"/> with a factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <remarks>The resolver is created by the <c>WebBootManager</c> and thus the constructor remains internal.</remarks>
|
||||
internal PublishedContentModelFactoryResolver(IPublishedContentModelFactory factory)
|
||||
: base(factory)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <remarks>For developers, at application startup.</remarks>
|
||||
public void SetFactory(IPublishedContentModelFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the factory.
|
||||
/// </summary>
|
||||
public IPublishedContentModelFactory Factory
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an ordered set of <see cref="IPublishedContent"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content.</typeparam>
|
||||
public class PublishedContentOrderedSet<T> : PublishedContentSet<T>, IOrderedEnumerable<T>
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
// ReSharper disable ParameterTypeCanBeEnumerable.Local
|
||||
internal PublishedContentOrderedSet(IOrderedEnumerable<T> content)
|
||||
// ReSharper restore ParameterTypeCanBeEnumerable.Local
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
// note: because we implement IOrderedEnumerable, we don't need to implement the ThenBy nor
|
||||
// ThenByDescending methods here, only CreateOrderedEnumerable and that does it.
|
||||
|
||||
#region IOrderedEnumerable<T>
|
||||
|
||||
public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
|
||||
{
|
||||
return new PublishedContentOrderedSet<T>(((IOrderedEnumerable<T>)Source).CreateOrderedEnumerable(keySelector, comparer, descending));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a set of <see cref="IPublishedContent"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of content.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>A <c>ContentSet{T}</c> is created from an <c>IEnumerable{T}</c> using the <c>ToContentSet</c>
|
||||
/// extension method.</para>
|
||||
/// <para>The content set source is enumerated only once. Same as what you get
|
||||
/// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
|
||||
/// created, whereas a content set enumerates its source only when the content set itself
|
||||
/// is enumerated.</para>
|
||||
/// </remarks>
|
||||
public class PublishedContentSet<T> : IEnumerable<T>
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
// used by <c>ToContentSet</c> extension method to initialize a new set from an IEnumerable.
|
||||
internal PublishedContentSet(IEnumerable<T> source)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
Source = source;
|
||||
}
|
||||
|
||||
#region Source
|
||||
|
||||
protected readonly IEnumerable<T> Source;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enumerated
|
||||
|
||||
// cache the enumeration so we don't enumerate more than once. Same as what you get
|
||||
// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
|
||||
// created, whereas a content set enumerates its source only when the content set itself
|
||||
// is enumerated.
|
||||
|
||||
// cache the wrapped items so if we reset the enumeration, we do not re-wrap everything (only new items).
|
||||
|
||||
private T[] _enumerated;
|
||||
private readonly Dictionary<T, IPublishedContentExtended> _xContent = new Dictionary<T, IPublishedContentExtended>();
|
||||
|
||||
// wrap an item, ie create the actual clone for this set
|
||||
private T MapContentAsT(T t)
|
||||
{
|
||||
return MapContent(t) as T;
|
||||
}
|
||||
|
||||
internal IPublishedContentExtended MapContent(T t)
|
||||
{
|
||||
IPublishedContentExtended extend;
|
||||
if (_xContent.TryGetValue(t, out extend)) return extend;
|
||||
|
||||
extend = PublishedContentExtended.Extend(t, this);
|
||||
var asT = extend as T;
|
||||
if (asT == null)
|
||||
throw new InvalidOperationException(string.Format("Failed extend a published content of type {0}."
|
||||
+ "Got {1} when expecting {2}.", t.GetType().FullName, extend.GetType().FullName, typeof(T).FullName));
|
||||
_xContent[t] = extend;
|
||||
return extend;
|
||||
}
|
||||
|
||||
private T[] Enumerated
|
||||
{
|
||||
get
|
||||
{
|
||||
// enumerate the source and cache the result
|
||||
// tell clones about their index within the set (for perfs purposes)
|
||||
var index = 0;
|
||||
return _enumerated ?? (_enumerated = Source.Select(t =>
|
||||
{
|
||||
var extend = MapContent(t);
|
||||
extend.SetIndex(index++);
|
||||
return extend as T;
|
||||
}).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
// indicates that the source has changed
|
||||
// so the set can clear its inner caches
|
||||
// should only be used by DynamicPublishedContentList
|
||||
internal void SourceChanged()
|
||||
{
|
||||
// reset the cached enumeration so it's enumerated again
|
||||
if (_enumerated == null) return;
|
||||
_enumerated = null;
|
||||
|
||||
foreach (var item in _xContent.Values)
|
||||
item.ClearIndex();
|
||||
|
||||
var removed = _xContent.Keys.Except(Source);
|
||||
foreach (var content in removed)
|
||||
{
|
||||
_xContent[content].ClearContentSet();
|
||||
_xContent.Remove(content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of items in the set.
|
||||
/// </summary>
|
||||
/// <returns>The number of items in the set.</returns>
|
||||
/// <remarks>Will cause the set to be enumerated if it hasn't been already.</remarks>
|
||||
public virtual int Count
|
||||
{
|
||||
get { return Enumerated.Length; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<T>
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<T>)Enumerated).GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wrap methods returning T
|
||||
|
||||
public T ElementAt(int index)
|
||||
{
|
||||
return MapContentAsT(Source.ElementAt(index));
|
||||
}
|
||||
|
||||
public T ElementAtOrDefault(int index)
|
||||
{
|
||||
var element = Source.ElementAtOrDefault(index);
|
||||
return element == null ? null : MapContentAsT(element);
|
||||
}
|
||||
|
||||
public T First()
|
||||
{
|
||||
return MapContentAsT(Source.First());
|
||||
}
|
||||
|
||||
public T First(Func<T, bool> predicate)
|
||||
{
|
||||
return MapContentAsT(Source.First(predicate));
|
||||
}
|
||||
|
||||
public T FirstOrDefault()
|
||||
{
|
||||
var first = Source.FirstOrDefault();
|
||||
return first == null ? null : MapContentAsT(first);
|
||||
}
|
||||
|
||||
public T FirstOrDefault(Func<T, bool> predicate)
|
||||
{
|
||||
var first = Source.FirstOrDefault(predicate);
|
||||
return first == null ? null : MapContentAsT(first);
|
||||
}
|
||||
|
||||
public T Last()
|
||||
{
|
||||
return MapContentAsT(Source.Last());
|
||||
}
|
||||
|
||||
public T Last(Func<T, bool> predicate)
|
||||
{
|
||||
return MapContentAsT(Source.Last(predicate));
|
||||
}
|
||||
|
||||
public T LastOrDefault()
|
||||
{
|
||||
var last = Source.LastOrDefault();
|
||||
return last == null ? null : MapContentAsT(last);
|
||||
}
|
||||
|
||||
public T LastOrDefault(Func<T, bool> predicate)
|
||||
{
|
||||
var last = Source.LastOrDefault(predicate);
|
||||
return last == null ? null : MapContentAsT(last);
|
||||
}
|
||||
|
||||
public T Single()
|
||||
{
|
||||
return MapContentAsT(Source.Single());
|
||||
}
|
||||
|
||||
public T Single(Func<T, bool> predicate)
|
||||
{
|
||||
return MapContentAsT(Source.Single(predicate));
|
||||
}
|
||||
|
||||
public T SingleOrDefault()
|
||||
{
|
||||
var single = Source.SingleOrDefault();
|
||||
return single == null ? null : MapContentAsT(single);
|
||||
}
|
||||
|
||||
public T SingleOrDefault(Func<T, bool> predicate)
|
||||
{
|
||||
var single = Source.SingleOrDefault(predicate);
|
||||
return single == null ? null : MapContentAsT(single);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wrap methods returning IOrderedEnumerable<T>
|
||||
|
||||
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector));
|
||||
}
|
||||
|
||||
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector, comparer));
|
||||
}
|
||||
|
||||
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector));
|
||||
}
|
||||
|
||||
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector, comparer));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IPublishedContent"/> type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances of the <see cref="PublishedContentType"/> class are immutable, ie
|
||||
/// if the content type changes, then a new class needs to be created.</remarks>
|
||||
public class PublishedContentType
|
||||
{
|
||||
private readonly PublishedPropertyType[] _propertyTypes;
|
||||
|
||||
// fast alias-to-index xref containing both the raw alias and its lowercase version
|
||||
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
|
||||
|
||||
// internal so it can be used by PublishedNoCache which does _not_ want to cache anything and so will never
|
||||
// use the static cache getter PublishedContentType.GetPublishedContentType(alias) below - anything else
|
||||
// should use it.
|
||||
internal PublishedContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
Id = contentType.Id;
|
||||
Alias = contentType.Alias;
|
||||
_propertyTypes = contentType.CompositionPropertyTypes
|
||||
.Select(x => new PublishedPropertyType(this, x))
|
||||
.ToArray();
|
||||
InitializeIndexes();
|
||||
}
|
||||
|
||||
// internal so it can be used for unit tests
|
||||
internal PublishedContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
{
|
||||
Id = id;
|
||||
Alias = alias;
|
||||
_propertyTypes = propertyTypes.ToArray();
|
||||
foreach (var propertyType in _propertyTypes)
|
||||
propertyType.ContentType = this;
|
||||
InitializeIndexes();
|
||||
}
|
||||
|
||||
private void InitializeIndexes()
|
||||
{
|
||||
for (var i = 0; i < _propertyTypes.Length; i++)
|
||||
{
|
||||
var propertyType = _propertyTypes[i];
|
||||
_indexes[propertyType.PropertyTypeAlias] = i;
|
||||
_indexes[propertyType.PropertyTypeAlias.ToLowerInvariant()] = i;
|
||||
}
|
||||
}
|
||||
|
||||
#region Content type
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Alias { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public IEnumerable<PublishedPropertyType> PropertyTypes
|
||||
{
|
||||
get { return _propertyTypes; }
|
||||
}
|
||||
|
||||
// alias is case-insensitive
|
||||
// this is the ONLY place where we compare ALIASES!
|
||||
public int GetPropertyIndex(string alias)
|
||||
{
|
||||
int index;
|
||||
if (_indexes.TryGetValue(alias, out index)) return index; // fastest
|
||||
if (_indexes.TryGetValue(alias.ToLowerInvariant(), out index)) return index; // slower
|
||||
return -1;
|
||||
}
|
||||
|
||||
// virtual for unit tests
|
||||
public virtual PublishedPropertyType GetPropertyType(string alias)
|
||||
{
|
||||
var index = GetPropertyIndex(alias);
|
||||
return GetPropertyType(index);
|
||||
}
|
||||
|
||||
// virtual for unit tests
|
||||
public virtual PublishedPropertyType GetPropertyType(int index)
|
||||
{
|
||||
return index >= 0 && index < _propertyTypes.Length ? _propertyTypes[index] : null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cache
|
||||
|
||||
// these methods are called by ContentTypeCacheRefresher and DataTypeCacheRefresher
|
||||
|
||||
internal static void ClearAll()
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear all.");
|
||||
// ok and faster to do it by types, assuming noone else caches PublishedContentType instances
|
||||
//ApplicationContext.Current.ApplicationCache.ClearStaticCacheByKeySearch("PublishedContentType_");
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>();
|
||||
}
|
||||
|
||||
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
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.Id == id);
|
||||
}
|
||||
|
||||
internal static void ClearDataType(int id)
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear data type w/id {0}.", () => id);
|
||||
// there is no recursion to handle here because a PublishedContentType contains *all* its
|
||||
// properties ie both its own properties and those that were inherited (it's based upon an
|
||||
// IContentTypeComposition) and so every PublishedContentType having a property based upon
|
||||
// the cleared data type, be it local or inherited, will be cleared.
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.PropertyTypes.Any(x => x.DataTypeId == id));
|
||||
}
|
||||
|
||||
public static PublishedContentType Get(PublishedItemType itemType, string alias)
|
||||
{
|
||||
var key = string.Format("PublishedContentType_{0}_{1}",
|
||||
itemType == PublishedItemType.Content ? "content" : "media", alias.ToLowerInvariant());
|
||||
|
||||
var type = ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItem<PublishedContentType>(key,
|
||||
() => CreatePublishedContentType(itemType, alias));
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private static PublishedContentType CreatePublishedContentType(PublishedItemType itemType, string alias)
|
||||
{
|
||||
if (GetPublishedContentTypeCallback != null)
|
||||
return GetPublishedContentTypeCallback(alias);
|
||||
|
||||
var contentType = itemType == PublishedItemType.Content
|
||||
? (IContentTypeComposition) ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias)
|
||||
: (IContentTypeComposition) ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias);
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("ContentTypeService failed to find a {0} type with alias \"{1}\".",
|
||||
itemType.ToString().ToLower(), alias));
|
||||
|
||||
return new PublishedContentType(contentType);
|
||||
}
|
||||
|
||||
// for unit tests - changing the callback must reset the cache obviously
|
||||
private static Func<string, PublishedContentType> _getPublishedContentTypeCallBack;
|
||||
internal static Func<string, PublishedContentType> GetPublishedContentTypeCallback
|
||||
{
|
||||
get { return _getPublishedContentTypeCallBack; }
|
||||
set
|
||||
{
|
||||
// see note above
|
||||
//ClearAll();
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheByKeySearch("PublishedContentType_");
|
||||
|
||||
_getPublishedContentTypeCallBack = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
//
|
||||
// This class has two purposes.
|
||||
//
|
||||
// - First, we cannot implement strongly-typed content by inheriting from some sort
|
||||
// of "master content" because that master content depends on the actual content cache
|
||||
// that is being used. It can be an XmlPublishedContent with the XmlPublishedCache,
|
||||
// or just anything else.
|
||||
//
|
||||
// So we implement strongly-typed content by encapsulating whatever content is
|
||||
// returned by the content cache, and providing extra properties (mostly) or
|
||||
// methods or whatever. This class provides the base for such encapsulation.
|
||||
//
|
||||
// - Second, any time a content is used in a content set obtained from
|
||||
// IEnumerable<IPublishedContent>.ToContentSet(), it needs to be cloned and extended
|
||||
// in order to know about its position in the set. This class provides the base
|
||||
// for implementing such extension.
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Provides an abstract base class for <c>IPublishedContent</c> implementations that
|
||||
/// wrap and extend another <c>IPublishedContent</c>.
|
||||
/// </summary>
|
||||
public abstract class PublishedContentWrapped : IPublishedContent
|
||||
{
|
||||
protected readonly IPublishedContent Content;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="PublishedContentWrapped"/> class
|
||||
/// with an <c>IPublishedContent</c> instance to wrap and extend.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to wrap and extend.</param>
|
||||
protected PublishedContentWrapped(IPublishedContent content)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the wrapped content.
|
||||
/// </summary>
|
||||
/// <returns>The wrapped content, that was passed as an argument to the constructor.</returns>
|
||||
public IPublishedContent Unwrap()
|
||||
{
|
||||
return Content;
|
||||
}
|
||||
|
||||
#region ContentSet
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> ContentSet
|
||||
{
|
||||
get { return Content.ContentSet; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ContentType
|
||||
|
||||
public virtual PublishedContentType ContentType { get { return Content.ContentType; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content
|
||||
|
||||
public virtual int Id
|
||||
{
|
||||
get { return Content.Id; }
|
||||
}
|
||||
|
||||
public virtual int TemplateId
|
||||
{
|
||||
get { return Content.TemplateId; }
|
||||
}
|
||||
|
||||
public virtual int SortOrder
|
||||
{
|
||||
get { return Content.SortOrder; }
|
||||
}
|
||||
|
||||
public virtual string Name
|
||||
{
|
||||
get { return Content.Name; }
|
||||
}
|
||||
|
||||
public virtual string UrlName
|
||||
{
|
||||
get { return Content.UrlName; }
|
||||
}
|
||||
|
||||
public virtual string DocumentTypeAlias
|
||||
{
|
||||
get { return Content.DocumentTypeAlias; }
|
||||
}
|
||||
|
||||
public virtual int DocumentTypeId
|
||||
{
|
||||
get { return Content.DocumentTypeId; }
|
||||
}
|
||||
|
||||
public virtual string WriterName
|
||||
{
|
||||
get { return Content.WriterName; }
|
||||
}
|
||||
|
||||
public virtual string CreatorName
|
||||
{
|
||||
get { return Content.CreatorName; }
|
||||
}
|
||||
|
||||
public virtual int WriterId
|
||||
{
|
||||
get { return Content.WriterId; }
|
||||
}
|
||||
|
||||
public virtual int CreatorId
|
||||
{
|
||||
get { return Content.CreatorId; }
|
||||
}
|
||||
|
||||
public virtual string Path
|
||||
{
|
||||
get { return Content.Path; }
|
||||
}
|
||||
|
||||
public virtual DateTime CreateDate
|
||||
{
|
||||
get { return Content.CreateDate; }
|
||||
}
|
||||
|
||||
public virtual DateTime UpdateDate
|
||||
{
|
||||
get { return Content.UpdateDate; }
|
||||
}
|
||||
|
||||
public virtual Guid Version
|
||||
{
|
||||
get { return Content.Version; }
|
||||
}
|
||||
|
||||
public virtual int Level
|
||||
{
|
||||
get { return Content.Level; }
|
||||
}
|
||||
|
||||
public virtual string Url
|
||||
{
|
||||
get { return Content.Url; }
|
||||
}
|
||||
|
||||
public virtual PublishedItemType ItemType
|
||||
{
|
||||
get { return Content.ItemType; }
|
||||
}
|
||||
|
||||
public virtual bool IsDraft
|
||||
{
|
||||
get { return Content.IsDraft; }
|
||||
}
|
||||
|
||||
public virtual int GetIndex()
|
||||
{
|
||||
return Content.GetIndex();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tree
|
||||
|
||||
public virtual IPublishedContent Parent
|
||||
{
|
||||
get { return Content.Parent; }
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> Children
|
||||
{
|
||||
get { return Content.Children; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public virtual ICollection<IPublishedProperty> Properties
|
||||
{
|
||||
get { return Content.Properties; }
|
||||
}
|
||||
|
||||
public virtual object this[string alias]
|
||||
{
|
||||
get { return Content[alias]; }
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return Content.GetProperty(alias);
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias, bool recurse)
|
||||
{
|
||||
return Content.GetProperty(alias, recurse);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for <c>IPublishedProperty</c> implementations which converts and caches
|
||||
/// the value source to the actual value to use when rendering content.
|
||||
/// </summary>
|
||||
internal abstract class PublishedPropertyBase : IPublishedProperty
|
||||
{
|
||||
public readonly PublishedPropertyType PropertyType;
|
||||
|
||||
protected PublishedPropertyBase(PublishedPropertyType propertyType)
|
||||
{
|
||||
if (propertyType == null)
|
||||
throw new ArgumentNullException("propertyType");
|
||||
PropertyType = propertyType;
|
||||
}
|
||||
|
||||
public string PropertyTypeAlias
|
||||
{
|
||||
get { return PropertyType.PropertyTypeAlias; }
|
||||
}
|
||||
|
||||
// these have to be provided by the actual implementation
|
||||
public abstract bool HasValue { get; }
|
||||
public abstract object DataValue { get; }
|
||||
public abstract object Value { get; }
|
||||
public abstract object XPathValue { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IPublishedProperty"/> type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances of the <see cref="PublishedPropertyType"/> class are immutable, ie
|
||||
/// if the property type changes, then a new class needs to be created.</remarks>
|
||||
public class PublishedPropertyType
|
||||
{
|
||||
public PublishedPropertyType(PublishedContentType contentType, PropertyType propertyType)
|
||||
{
|
||||
// PropertyEditor [1:n] DataTypeDefinition [1:n] PropertyType
|
||||
|
||||
ContentType = contentType;
|
||||
PropertyTypeAlias = propertyType.Alias;
|
||||
|
||||
DataTypeId = propertyType.DataTypeDefinitionId;
|
||||
PropertyEditorAlias = propertyType.PropertyEditorAlias;
|
||||
|
||||
InitializeConverters();
|
||||
}
|
||||
|
||||
// for unit tests
|
||||
internal PublishedPropertyType(string propertyTypeAlias, int dataTypeDefinitionId, string propertyEditorAlias)
|
||||
{
|
||||
// ContentType to be set by PublishedContentType when creating it
|
||||
PropertyTypeAlias = propertyTypeAlias;
|
||||
|
||||
DataTypeId = dataTypeDefinitionId;
|
||||
PropertyEditorAlias = propertyEditorAlias;
|
||||
|
||||
InitializeConverters();
|
||||
}
|
||||
|
||||
#region Property type
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the published content type containing the property type.
|
||||
/// </summary>
|
||||
// internally set by PublishedContentType constructor
|
||||
public PublishedContentType ContentType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias uniquely identifying the property type.
|
||||
/// </summary>
|
||||
public string PropertyTypeAlias { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the identifier uniquely identifying the data type supporting the property type.
|
||||
/// </summary>
|
||||
public int DataTypeId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias uniquely identifying the property editor for the property type.
|
||||
/// </summary>
|
||||
public string PropertyEditorAlias { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Converters
|
||||
|
||||
private IPropertyValueConverter _converter;
|
||||
|
||||
private PropertyCacheLevel _sourceCacheLevel;
|
||||
private PropertyCacheLevel _objectCacheLevel;
|
||||
private PropertyCacheLevel _xpathCacheLevel;
|
||||
|
||||
private Type _clrType = typeof (object);
|
||||
|
||||
private void InitializeConverters()
|
||||
{
|
||||
var converters = PropertyValueConvertersResolver.Current.Converters.ToArray();
|
||||
|
||||
// todo: remove Union() once we drop IPropertyEditorValueConverter support.
|
||||
_converter = null;
|
||||
foreach (var converter in converters.Union(GetCompatConverters()).Where(x => x.IsConverter(this)))
|
||||
{
|
||||
if (_converter == null)
|
||||
{
|
||||
_converter = converter;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("More than one converter for property type {0}.{1}",
|
||||
ContentType.Alias, PropertyTypeAlias));
|
||||
}
|
||||
}
|
||||
|
||||
// get the cache levels, quietely fixing the inconsistencies (no need to throw, really)
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
|
||||
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
|
||||
|
||||
if (_converter != null)
|
||||
{
|
||||
var attr = _converter.GetType().GetCustomAttribute<PropertyValueTypeAttribute>(false);
|
||||
if (attr != null)
|
||||
_clrType = attr.Type;
|
||||
}
|
||||
}
|
||||
|
||||
static PropertyCacheLevel GetCacheLevel(IPropertyValueConverter converter, PropertyCacheValue value)
|
||||
{
|
||||
if (converter == null)
|
||||
return PropertyCacheLevel.Request;
|
||||
|
||||
var attr = converter.GetType().GetCustomAttributes<PropertyValueCacheAttribute>(false)
|
||||
.FirstOrDefault(x => x.Value == value || x.Value == PropertyCacheValue.All);
|
||||
|
||||
return attr == null ? PropertyCacheLevel.Request : attr.Level;
|
||||
}
|
||||
|
||||
// converts the raw value into the source value
|
||||
// uses converters, else falls back to dark (& performance-wise expensive) magic
|
||||
// source: the property raw value
|
||||
// preview: whether we are previewing or not
|
||||
public object ConvertDataToSource(object source, bool preview)
|
||||
{
|
||||
// use the converter else use dark (& performance-wise expensive) magic
|
||||
return _converter != null
|
||||
? _converter.ConvertDataToSource(this, source, preview)
|
||||
: ConvertUsingDarkMagic(source);
|
||||
}
|
||||
|
||||
// gets the source cache level
|
||||
public PropertyCacheLevel SourceCacheLevel { get { return _sourceCacheLevel; } }
|
||||
|
||||
// converts the source value into the clr value
|
||||
// uses converters, else returns the source value
|
||||
// source: the property source value
|
||||
// preview: whether we are previewing or not
|
||||
public object ConvertSourceToObject(object source, bool preview)
|
||||
{
|
||||
// use the converter if any
|
||||
// else just return the source value
|
||||
return _converter != null
|
||||
? _converter.ConvertSourceToObject(this, source, preview)
|
||||
: source;
|
||||
}
|
||||
|
||||
// gets the value cache level
|
||||
public PropertyCacheLevel ObjectCacheLevel { get { return _objectCacheLevel; } }
|
||||
|
||||
// converts the source value into the xpath value
|
||||
// uses the converter else returns the source value as a string
|
||||
// if successful, returns either a string or an XPathNavigator
|
||||
// source: the property source value
|
||||
// preview: whether we are previewing or not
|
||||
public object ConvertSourceToXPath(object source, bool preview)
|
||||
{
|
||||
// use the converter if any
|
||||
if (_converter != null)
|
||||
return _converter.ConvertSourceToXPath(this, source, preview);
|
||||
|
||||
// else just return the source value as a string or an XPathNavigator
|
||||
if (source == null) return null;
|
||||
var xElement = source as XElement;
|
||||
if (xElement != null)
|
||||
return xElement.CreateNavigator();
|
||||
return source.ToString().Trim();
|
||||
}
|
||||
|
||||
// gets the xpath cache level
|
||||
public PropertyCacheLevel XPathCacheLevel { get { return _xpathCacheLevel; } }
|
||||
|
||||
internal static object ConvertUsingDarkMagic(object source)
|
||||
{
|
||||
// convert to string
|
||||
var stringSource = source as string;
|
||||
if (stringSource == null) return source; // not a string => return the object
|
||||
stringSource = stringSource.Trim();
|
||||
if (stringSource.Length == 0) return null; // empty string => return null
|
||||
|
||||
// try numbers and booleans
|
||||
// make sure we use the invariant culture ie a dot decimal point, comma is for csv
|
||||
// NOTE far from perfect: "01a" is returned as a string but "012" is returned as an integer...
|
||||
int i;
|
||||
if (int.TryParse(stringSource, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
|
||||
return i;
|
||||
float f;
|
||||
if (float.TryParse(stringSource, NumberStyles.Float, CultureInfo.InvariantCulture, out f))
|
||||
return f;
|
||||
bool b;
|
||||
if (bool.TryParse(stringSource, out b))
|
||||
return b;
|
||||
|
||||
//TODO: We can change this just like we do for the JSON converter - but to maintain compatibility might mean this still has to remain here
|
||||
|
||||
// try xml - that is expensive, performance-wise
|
||||
XElement elt;
|
||||
if (XmlHelper.TryCreateXElementFromPropertyValue(stringSource, out elt))
|
||||
return new DynamicXml(elt); // xml => return DynamicXml for compatiblity's sake
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// gets the property CLR type
|
||||
public Type ClrType { get { return _clrType; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Compat
|
||||
|
||||
// backward-compatibility: support IPropertyEditorValueConverter while we have to
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
|
||||
IEnumerable<IPropertyValueConverter> GetCompatConverters()
|
||||
{
|
||||
var propertyEditorGuid = LegacyPropertyEditorIdToAliasConverter.GetLegacyIdFromAlias(PropertyEditorAlias, LegacyPropertyEditorIdToAliasConverter.NotFoundLegacyIdResponseBehavior.ReturnNull);
|
||||
return PropertyEditorValueConvertersResolver.HasCurrent && propertyEditorGuid.HasValue
|
||||
? PropertyEditorValueConvertersResolver.Current.Converters
|
||||
.Where(x => x.IsConverterFor(propertyEditorGuid.Value, ContentType.Alias, PropertyTypeAlias))
|
||||
.Select(x => new CompatConverter(x))
|
||||
: Enumerable.Empty<IPropertyValueConverter>();
|
||||
}
|
||||
|
||||
class CompatConverter : PropertyValueConverterBase
|
||||
{
|
||||
private readonly IPropertyEditorValueConverter _converter;
|
||||
|
||||
public CompatConverter(IPropertyEditorValueConverter converter)
|
||||
{
|
||||
_converter = converter;
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// NOTE: ignore preview, because IPropertyEditorValueConverter does not support it
|
||||
return _converter.ConvertPropertyValue(source).Result;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,18 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of published item
|
||||
/// The type of published content, ie whether it is a content or a media.
|
||||
/// </summary>
|
||||
public enum PublishedItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// A content, ie what was formerly known as a document.
|
||||
/// </summary>
|
||||
Content,
|
||||
|
||||
/// <summary>
|
||||
/// A media.
|
||||
/// </summary>
|
||||
Media
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The definition of a published property
|
||||
/// </summary>
|
||||
public class PublishedPropertyDefinition
|
||||
{
|
||||
public PublishedPropertyDefinition(string propertyTypeAlias, string documentTypeAlias, string propertyEditorAlias)
|
||||
{
|
||||
//PropertyId = propertyId;
|
||||
DocumentTypeAlias = documentTypeAlias;
|
||||
PropertyTypeAlias = propertyTypeAlias;
|
||||
PropertyEditorAlias = propertyEditorAlias;
|
||||
//ItemType = itemType;
|
||||
}
|
||||
|
||||
//public int PropertyId { get; private set; }
|
||||
public string DocumentTypeAlias { get; private set; }
|
||||
public string PropertyTypeAlias { get; private set; }
|
||||
public string PropertyEditorAlias { get; private set; }
|
||||
//public PublishedItemType ItemType { get; private set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user