Compare commits
846 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 858156bab2 | |||
| cf5dac0ddd | |||
| fa68f7fafe | |||
| 2ae96f3810 | |||
| f6045a49b5 | |||
| 1f66ebff1f | |||
| c4850199f7 | |||
| 02c609747d | |||
| 413e70db7d | |||
| c2cbac7ef9 | |||
| a4a079cd1b | |||
| 22fc9c617c | |||
| 0bcdfc8820 | |||
| b868c06e79 | |||
| fcfb9afc22 | |||
| 05818f6262 | |||
| 1788682af9 | |||
| a5f689385a | |||
| a551881ce2 | |||
| 1607e51270 | |||
| 2f31175db5 | |||
| 044b43f6e1 | |||
| c2722d8120 | |||
| 76725aa0d8 | |||
| 9178e7afcf | |||
| b18945e630 | |||
| 4640cf56d1 | |||
| eae1ce7012 | |||
| e900711180 | |||
| 040e45ca70 | |||
| bd3d626147 | |||
| 47d08e69a4 | |||
| df182674b4 | |||
| 6ec9a2ae45 | |||
| bf00f7a663 | |||
| 74d8341620 | |||
| 70207e5374 | |||
| 93f4d65227 | |||
| a4c0342bda | |||
| 095633ba27 | |||
| c63156fcd8 | |||
| c59a226d56 | |||
| 0c25c36af0 | |||
| 84a90884e3 | |||
| d29b7311fa | |||
| 17b59cc20f | |||
| 4423571eaa | |||
| e76c42f874 | |||
| 151c35bc47 | |||
| 84265a9716 | |||
| 6618388973 | |||
| 1f22191bbc | |||
| 25088042a9 | |||
| 527f98189a | |||
| 78c289a559 | |||
| 646abb3aea | |||
| 2af59471a2 | |||
| 090f89e5b6 | |||
| 4870afd2d3 | |||
| 80257b6684 | |||
| 8f3a0b6919 | |||
| 9fd2f34343 | |||
| e774717346 | |||
| 7cd540c37e | |||
| 83595ecaf5 | |||
| f2819f61e5 | |||
| 2107e9d9e3 | |||
| c623b448ba | |||
| 1e8bdc8f0c | |||
| 8bb49f57e8 | |||
| da0b1c2f23 | |||
| a288fc62eb | |||
| 82e50ccd3a | |||
| 15b0dc9f29 | |||
| 8057d09fc2 | |||
| 8877100bf0 | |||
| 41c96e6e26 | |||
| abdd117264 | |||
| 6272dac698 | |||
| 7a4b5fa796 | |||
| c962132ee0 | |||
| 0780979469 | |||
| a42e568fdf | |||
| e62661cc6a | |||
| 6841b2ac61 | |||
| f7f4276485 | |||
| bb9e23ca3e | |||
| 7d5d69e2e3 | |||
| ee75158dd0 | |||
| c022397d86 | |||
| d104525a50 | |||
| b0a64aa4b5 | |||
| ca86385269 | |||
| ef4322a9b3 | |||
| 4ab1c51327 | |||
| e007a37c36 | |||
| 2f67008987 | |||
| 1672e284c5 | |||
| 60ce36a7f2 | |||
| 72e2cacc87 | |||
| 4285102422 | |||
| abbcf0e26b | |||
| 347b25472f | |||
| b745948dc6 | |||
| 8007c8869f | |||
| b51a328ead | |||
| f3b8f2eb5f | |||
| de4628f450 | |||
| b0a64655b4 | |||
| 48d88ec8fa | |||
| 7ca151a3fa | |||
| 363c8fab2c | |||
| 8d4fd9d1cf | |||
| 24071eb3b1 | |||
| 62ffbe7cf0 | |||
| f2d6b47e47 | |||
| f3541908c7 | |||
| 4e57e1cc18 | |||
| 410afffaa9 | |||
| 936e94789d | |||
| 468a56e5de | |||
| 468ec8824a | |||
| cad913b7a1 | |||
| 382103d99d | |||
| cbb6b9bca0 | |||
| a1b90a50cd | |||
| 9ea5855073 | |||
| 4a37433042 | |||
| 91469812d3 | |||
| 68a8eb7f3f | |||
| 2e7baabb94 | |||
| 57745fe71d | |||
| de6f9236e7 | |||
| a00c59e8b5 | |||
| 05c2da807f | |||
| 0fd8ca43d6 | |||
| 87f09b2ee6 | |||
| e466878925 | |||
| 319acc199e | |||
| 2a982f21a7 | |||
| 3ff455f11d | |||
| 41ad1bf27b | |||
| f49d939a2d | |||
| 7e1e83b493 | |||
| 23be0134e7 | |||
| 355fb64d8b | |||
| 42959a1db5 | |||
| a1cd22208b | |||
| c3116d5df7 | |||
| b0b874212e | |||
| 19086ab3a1 | |||
| 069594c3ac | |||
| 0bc4c7e2aa | |||
| 7f12cff3bd | |||
| 83294b6594 | |||
| e0c89eb1ea | |||
| 9ad8e6a876 | |||
| 14b58386e5 | |||
| e26cbccfe0 | |||
| 7dc06c1bea | |||
| effa984bdc | |||
| fa058f348d | |||
| 62d9a1a132 | |||
| 9284269428 | |||
| f8c4481eb1 | |||
| d7f2041ee9 | |||
| 9f6e6e4701 | |||
| 34ba3f3351 | |||
| dcfb8b94d8 | |||
| 0876004d9a | |||
| d3ad61835a | |||
| ad882ab5be | |||
| 774f333c70 | |||
| 700b71f9fb | |||
| bba58ea0c0 | |||
| d0d4885812 | |||
| ce11a377e6 | |||
| c6443c477f | |||
| eb94572361 | |||
| fd8317493e | |||
| 3642ff72a4 | |||
| 6e830c1171 | |||
| 22ff1bcaa0 | |||
| ab523baf4f | |||
| 2dec03f441 | |||
| 9ada0d9c97 | |||
| c3be9004f6 | |||
| 11fa015b64 | |||
| df553140e8 | |||
| 0b898f2e32 | |||
| 4c9be2cc49 | |||
| 1aad4e50d5 | |||
| f5f3676a56 | |||
| f69f68e2b5 | |||
| 3858656015 | |||
| a5ec5f46ac | |||
| ea70e18a91 | |||
| 0cfd5773c3 | |||
| b15def99c7 | |||
| 8c8b6984c2 | |||
| bc828fc6f3 | |||
| dc7b83ca6c | |||
| 8188e4ff55 | |||
| fcf9dcd803 | |||
| 070fa11f8c | |||
| f52a84937b | |||
| 7e9f55f517 | |||
| 3556043b55 | |||
| 3e8fb11abd | |||
| 5181988a41 | |||
| 5169310258 | |||
| f987640462 | |||
| 55e97dad74 | |||
| 8c70578764 | |||
| 5cb2dd0036 | |||
| a9713dc6fc | |||
| b32e7d4ccc | |||
| 8d4958e395 | |||
| d2f3e162f1 | |||
| 9883757704 | |||
| 7404e20a19 | |||
| 0310782d7d | |||
| 744ff0cf33 | |||
| afd0018dd6 | |||
| c36aec624b | |||
| c81e14758d | |||
| 1ba86f361a | |||
| 9b33c94437 | |||
| 2a30fd238e | |||
| 3cb4128c0f | |||
| 79958e0fe0 | |||
| f238f9fcea | |||
| 7c545410cc | |||
| e5a21625ea | |||
| dcf5fff3f0 | |||
| 1dc88658e8 | |||
| efd3d6937a | |||
| e17f75a18a | |||
| 6d46c2204d | |||
| 27b9385df5 | |||
| 88c20c7c5f | |||
| bd9adffaa5 | |||
| ea6d81f7ac | |||
| 0ce059d5bd | |||
| 773ef1d168 | |||
| 1f7de81cd2 | |||
| fef9e3fde0 | |||
| e849d2d0d0 | |||
| 9a6123579f | |||
| f56bd731b7 | |||
| bee0642417 | |||
| 43abb08e59 | |||
| 17db5709f1 | |||
| 2fc6d9b7df | |||
| 591a881283 | |||
| e4561851a4 | |||
| c6daf2e111 | |||
| 1554d52ea9 | |||
| 883366f741 | |||
| cac331adbc | |||
| 18318ecabf | |||
| 6b9ef6df7a | |||
| fcaf78ef29 | |||
| 833b4c552c | |||
| c678b7f6d9 | |||
| e320840a29 | |||
| b664fc5e94 | |||
| b87346bee5 | |||
| 6029306fe9 | |||
| f979792290 | |||
| 5f82fc6e20 | |||
| b1a0ca98ea | |||
| f4f99c2922 | |||
| 6f55b84c65 | |||
| 43f369f96f | |||
| c1b3da869d | |||
| e39158d5e5 | |||
| aed476de0a | |||
| ddd9c8ef7d | |||
| 9e2c7d16a6 | |||
| 44db4e7a48 | |||
| 680d97c630 | |||
| 89347b359b | |||
| 8053cea92d | |||
| f44b158c15 | |||
| 1ff66d0c3a | |||
| ae07f34215 | |||
| aba2c2a79e | |||
| 9f62dfc087 | |||
| a21912dc41 | |||
| 733b4a770f | |||
| 2e097b7e46 | |||
| e1b6997ef7 | |||
| b6b7b9f433 | |||
| 8181f88cb0 | |||
| 3a4865ef7d | |||
| 37f6dbfa6b | |||
| 131fea3ba4 | |||
| b0661218a0 | |||
| 50335723b0 | |||
| 6f1bd3fd71 | |||
| fb99b101d8 | |||
| 91e658c41c | |||
| 0ce7efc978 | |||
| 3b8a2d7d65 | |||
| 61b9ab5c7b | |||
| cfda04b6ed | |||
| 11bdfbba19 | |||
| 9694831638 | |||
| a20844b55b | |||
| 158e40d7f6 | |||
| 6939cc757e | |||
| 2baec8a129 | |||
| 93a1fc1eba | |||
| fe67a09ccb | |||
| 1c4e1db054 | |||
| 5d694a73a3 | |||
| af369fa6c7 | |||
| 901036535d | |||
| 5d6cbee196 | |||
| 9e9ae09ec2 | |||
| 58697eaa04 | |||
| ce58ad91b5 | |||
| e49d14d687 | |||
| 3c98d9d2e1 | |||
| e010ff2a8c | |||
| 8d14a3ef2c | |||
| 2f3d9c9509 | |||
| 6e8f3b6e13 | |||
| b9cbdbd9a7 | |||
| ebf35356a8 | |||
| 00cec3267c | |||
| 4bfb2d219b | |||
| f3ba1fa7ed | |||
| 7eca99e249 | |||
| 80c61110df | |||
| 837bb83d48 | |||
| 054ac78970 | |||
| 8e47f91ba5 | |||
| 31f6bd4c02 | |||
| 3e5744dbb7 | |||
| 5982a868ea | |||
| 69a42e26a9 | |||
| d9ed420ed4 | |||
| 2b3397120f | |||
| cb0d8320e6 | |||
| 53d9b65e64 | |||
| df0fe62fca | |||
| 1f41aa7d81 | |||
| dad77fc506 | |||
| 350f5c88c7 | |||
| 928c0dc535 | |||
| 483a2c7c02 | |||
| cc7a28db65 | |||
| 065e764957 | |||
| 000ba73887 | |||
| 084fde885a | |||
| 08b81d991b | |||
| 4937f87c0d | |||
| 50a5679b5c | |||
| 2c248791e1 | |||
| 6b6a7fe231 | |||
| 6fd197d1bf | |||
| 00aa59c9c6 | |||
| 06254ba462 | |||
| 684cb19a7c | |||
| 9c5da12653 | |||
| 83f229abc6 | |||
| 3405a1f600 | |||
| 8be02ff7b0 | |||
| c371f00315 | |||
| 0ccf798f14 | |||
| 6ca94074f3 | |||
| 8236eee7a6 | |||
| 8bdeca6374 | |||
| e37bbdfcf4 | |||
| dac882ce9f | |||
| 5678be0db9 | |||
| 2dc11f6fa1 | |||
| fe2e689865 | |||
| ece5fecf12 | |||
| b21dea84d9 | |||
| 492b0aadc8 | |||
| b399630202 | |||
| b9b1fc3a70 | |||
| 1d52f59657 | |||
| 78f6b8d8bc | |||
| 0afee71e9e | |||
| dc67d82671 | |||
| c7d9683fc4 | |||
| ed7675bdcd | |||
| 3c7c6b4ad7 | |||
| 838d7975c9 | |||
| 5af9712d51 | |||
| ffa7b922e8 | |||
| e2c2b8534f | |||
| cfd3cc5187 | |||
| e6de9e0004 | |||
| 1f29418ea5 | |||
| 977b30c51a | |||
| 66a849dd12 | |||
| 637abc384b | |||
| 8959b81f6a | |||
| 32bb8ac5a4 | |||
| 016caba35f | |||
| 9290f61f94 | |||
| d522dd7a31 | |||
| 95f632e1ea | |||
| e72ec171f7 | |||
| 2538e2e9c9 | |||
| 08aff2654a | |||
| cd0fdae47b | |||
| 0f3a76809b | |||
| 4f88da2c26 | |||
| e14aba3875 | |||
| b1ceeb23b3 | |||
| 46d0807fa4 | |||
| 579c572dd8 | |||
| bbf4c18825 | |||
| 9a94ac5317 | |||
| 0b904e82b5 | |||
| c816558936 | |||
| 4ce0553630 | |||
| b1b285b673 | |||
| c773714e2d | |||
| 51fec0c7d3 | |||
| 2a90478ba7 | |||
| 87ace12a4f | |||
| 77162e4b51 | |||
| 93756a62f4 | |||
| 2343004be1 | |||
| d6fe350a4a | |||
| 23321f8ac9 | |||
| 71902f3b9b | |||
| 13b544521d | |||
| 2cf8c1207d | |||
| 632f84904f | |||
| a1fd73cdb0 | |||
| a53866953e | |||
| e72758e04a | |||
| 9d373c194d | |||
| 856e123ec2 | |||
| 0b2af6b48f | |||
| ff996b05f0 | |||
| 403502ef1b | |||
| ee4ad36e70 | |||
| 4f2650277a | |||
| 0231a6037e | |||
| db51a5bb44 | |||
| d1b7063e44 | |||
| 364d4b11e8 | |||
| c1769aa299 | |||
| a571eee945 | |||
| ab8653d3de | |||
| 143d127fb9 | |||
| 748a3c167e | |||
| 01cf2e240a | |||
| 49689d5057 | |||
| f722d7731d | |||
| 5b93b35882 | |||
| b29ee4df60 | |||
| d8fe3c6faf | |||
| 74ba3261ff | |||
| ac42f335c2 | |||
| f0eefbd5af | |||
| ed48f29e3a | |||
| 03c5d5197b | |||
| 7f0921bd96 | |||
| c38b49b1cf | |||
| c4dfbd4a1c | |||
| 9b1e5d7649 | |||
| 9260f943ff | |||
| dcdaa8d62d | |||
| 360665c082 | |||
| c07b96ade7 | |||
| 576a790e2f | |||
| 9b7a9fc988 | |||
| 62485157ad | |||
| 4ce7b089ca | |||
| 9e91098ebd | |||
| 49356b31a1 | |||
| 29f93160b7 | |||
| 507c2353e9 | |||
| 827e79c705 | |||
| d02139bbcd | |||
| 8a19b97900 | |||
| 981fad1ec8 | |||
| 019147c1a1 | |||
| 782d6100f0 | |||
| ff98b5f321 | |||
| f6ea317dd1 | |||
| 68e8ca8d8e | |||
| bcae131545 | |||
| c6d686eabd | |||
| a8b660bfbf | |||
| 1f60486df8 | |||
| c066280990 | |||
| ba747ea579 | |||
| 0df7767f4a | |||
| 6f857b16ee | |||
| 27115e5794 | |||
| 92378095a2 | |||
| 13e6a81bbe | |||
| bd2a794b59 | |||
| 576ffce9aa | |||
| 3bfdaa7e10 | |||
| dc7b5bae9b | |||
| 422be31c4e | |||
| 8d8fb76694 | |||
| 80d605beac | |||
| bb9a0258df | |||
| daa0741802 | |||
| 69258fee7b | |||
| 1fd7569c6e | |||
| 3a1f19ee0a | |||
| 90bc7f5829 | |||
| 30b391f3fb | |||
| 089f488c15 | |||
| 99b99ce3cd | |||
| 10ca1239b6 | |||
| f4fc3c4db4 | |||
| e17690fbed | |||
| eaa8ca5fdc | |||
| 234c0680d8 | |||
| ea8c6af028 | |||
| d7d1b3f2a0 | |||
| 5f31c70cbe | |||
| 579a04d179 | |||
| ff3b7963b1 | |||
| e85d212891 | |||
| 5b19d5e0d8 | |||
| 7c21889239 | |||
| 52d35c06eb | |||
| 52c3ea24d5 | |||
| 03756ab894 | |||
| ef40ecfefd | |||
| 8e35d904cb | |||
| 73b2d31298 | |||
| 9808492509 | |||
| 81788338e3 | |||
| 3ffe1517e0 | |||
| 641e74b747 | |||
| 49c316e13d | |||
| 5235053523 | |||
| 8676a99b3a | |||
| af6d2df823 | |||
| bbe80d882a | |||
| 408ec17201 | |||
| a4ef487fab | |||
| 8208f8de51 | |||
| e8ea7f9d29 | |||
| e431a41fc1 | |||
| 84b380028c | |||
| 0b2cfe956d | |||
| 1f5c9d2e1b | |||
| 372f981d33 | |||
| 6f03e221c6 | |||
| 90a5adec8f | |||
| 62939385a0 | |||
| d4729e1483 | |||
| 9de35f0202 | |||
| 773d249d36 | |||
| d12a492cb6 | |||
| ef0b521083 | |||
| 6261447923 | |||
| d18881c8ad | |||
| 89596dbe0b | |||
| 358536ffaa | |||
| 4592f8e8d8 | |||
| 0038d173a2 | |||
| 68e6ad76fb | |||
| 6462329494 | |||
| 2fdd1c0bd2 | |||
| 006deb22db | |||
| 40624255ca | |||
| 891bea81bf | |||
| f71577f86e | |||
| e3e88b3679 | |||
| 5dc993890d | |||
| a2025c14b1 | |||
| 24900fb9f8 | |||
| 594c473134 | |||
| 34f811c128 | |||
| 7e4c284abb | |||
| 664d0c5160 | |||
| eb26fb901f | |||
| 3141b04376 | |||
| 201fb5dc01 | |||
| 15e668c056 | |||
| a42f425971 | |||
| 3f4774855e | |||
| 28f995cea6 | |||
| cfb14d7089 | |||
| ef4d41c80a | |||
| 584e47f51f | |||
| 66e40fcbb0 | |||
| 49d54f8ca5 | |||
| 4ed236249a | |||
| 00a4287945 | |||
| 92d52bf99b | |||
| 2e611c20d4 | |||
| ae10f3d21f | |||
| 7a9b392f69 | |||
| 493d71dba9 | |||
| 55d4e4072a | |||
| f687b34c14 | |||
| 507517c1ad | |||
| ae8cfb2b23 | |||
| 731e380445 | |||
| 9048252826 | |||
| e76819a570 | |||
| 87c311d6e7 | |||
| 86d8eae984 | |||
| 6aac216763 | |||
| b7c3fb7f30 | |||
| a0a3b7e9c9 | |||
| d98db5e6bc | |||
| 48adc4c98d | |||
| bd0edb322d | |||
| 79d4562cb1 | |||
| f48263e5a2 | |||
| 63196d7e53 | |||
| e0e9823a03 | |||
| 72a0d614af | |||
| f766057e50 | |||
| f0b5c831f1 | |||
| d3232a09fb | |||
| 586c59949a | |||
| 7cbaecc53a | |||
| 4f8bb7fb51 | |||
| 1c883be16b | |||
| 73d681d674 | |||
| e84a963d66 | |||
| 8daa558997 | |||
| b78fd0f6ac | |||
| 58c180d6cc | |||
| 831eb3ef5e | |||
| fa68bee762 | |||
| 796700b4fe | |||
| ab09042fdc | |||
| 041d4a4a8b | |||
| ee79d7ecdc | |||
| 18e377f159 | |||
| e33456d168 | |||
| df2c104002 | |||
| f265fa683c | |||
| 7e7f9902f6 | |||
| a36184a261 | |||
| dcd2630d6b | |||
| b70f543790 | |||
| 24c1c15b66 | |||
| 4a0cd7228b | |||
| 12093ae7ea | |||
| 6a980e64eb | |||
| edfe212227 | |||
| 37071ada78 | |||
| 3c7e820773 | |||
| 203837aa84 | |||
| e3bc98a155 | |||
| f85532f15e | |||
| 5fe63c2c1a | |||
| 2c1d85989f | |||
| d518ab908e | |||
| bc32ff31d4 | |||
| 7804677f2b | |||
| b04d71ca5f | |||
| 27c884f4eb | |||
| ab4de382f3 | |||
| a293c633fc | |||
| 507e3ece98 | |||
| b77826fd3d | |||
| 4c7358d63b | |||
| 4814612102 | |||
| 6dae4396bb | |||
| a966f63bbd | |||
| 76f9e6baee | |||
| dd5560f00b | |||
| b56575fc50 | |||
| b06d30c0f9 | |||
| 49f17be9df | |||
| 9c50e1c48d | |||
| 0688835ac0 | |||
| 353b8f21cd | |||
| 30a0d553d5 | |||
| d0fbc362b2 | |||
| 39c534ef54 | |||
| 7f86166abf | |||
| 838e86469a | |||
| 24b147e2a6 | |||
| 11342ff1df | |||
| bf20af9345 | |||
| c69774e3f2 | |||
| 7de8f5a59a | |||
| 8a114a105e | |||
| 909e3788ea | |||
| 09a92ef6ce | |||
| 7d9c2bcce9 | |||
| 529ae961ff | |||
| 5f9865cc73 | |||
| b891b18b20 | |||
| bc461b1646 | |||
| b0eeaecf1c | |||
| 2708f11fcd | |||
| fd8daa398f | |||
| c59ac4ee0e | |||
| a03aa9cbab | |||
| 89b714c960 | |||
| d9b0b0112e | |||
| 6640039cdf | |||
| 70deffd418 | |||
| f31d5b12da | |||
| 7fd6155807 | |||
| 043c677ddc | |||
| f634d9f8b1 | |||
| db637d9c31 | |||
| 24b521881c | |||
| 0b3a38ec8f | |||
| 330673bef9 | |||
| 661ff0e726 | |||
| e1c45fda9a | |||
| b45a4a18f2 | |||
| 1456e7028a | |||
| b38ee33e5a | |||
| 903a9f93c3 | |||
| b08376651a | |||
| 75514c7c42 | |||
| ea6f561c96 | |||
| 053544a578 | |||
| 464a227af1 | |||
| 4e6d60b755 | |||
| 4308718c88 | |||
| 1b59ca0412 | |||
| 282cc0c722 | |||
| 4584abaa72 | |||
| c1ca0c9c2f | |||
| 27c260cd03 | |||
| 73a5c55547 | |||
| b8831c253e | |||
| b2d3e75566 | |||
| cb526170e2 | |||
| 93237bfdb8 | |||
| 1c39c741b6 | |||
| ec2589f517 | |||
| 2ca6e8be9a | |||
| b9d1a776cb | |||
| 5eb609d8a0 | |||
| 4d5069726b | |||
| 3a98d63bf1 | |||
| 0da8644e77 | |||
| ac65af772a | |||
| e643189b10 | |||
| 97716d5570 | |||
| 5517252200 | |||
| 92a5c31ce6 | |||
| 345c038e8b | |||
| 59defa6b11 | |||
| 7e0d7ebbd4 | |||
| c13d4ed235 | |||
| a47b5035fe | |||
| f6be389f4f | |||
| 252f0fe88e | |||
| 387faca71e | |||
| 6c172702be | |||
| 62cda02ded | |||
| 3e2a6424bd | |||
| c0f695bcf9 | |||
| 2e1e2e4325 | |||
| 1316bb5d5b | |||
| fe97860694 | |||
| 98b4aa6bae | |||
| eb7f4e74f2 | |||
| 4a9e326267 | |||
| 67edc6cf9a | |||
| e740838ef7 | |||
| dec44b1288 | |||
| 98a0729549 | |||
| 97868593f8 | |||
| dcdfb074af | |||
| a36b1097c5 | |||
| e268a05f6e | |||
| fb7d22dca8 | |||
| bac53bc241 | |||
| ce690acda0 | |||
| cb8157dfca | |||
| 4c7c6e37d1 | |||
| 116e53e07d | |||
| a74c4433f7 | |||
| 2ccf74a921 | |||
| f3a81d82be | |||
| 5451d28fe4 | |||
| db57268440 | |||
| ac265067e8 | |||
| 5330830362 | |||
| 4b6b24b2f5 | |||
| 7d5d89e9cb | |||
| ab85cbf599 | |||
| c6937618c2 | |||
| ef84d63982 | |||
| 280a7445f4 | |||
| 5ae8a47f4b | |||
| bc148d08fa | |||
| 57a1e73383 | |||
| c7b9a57795 | |||
| eb1edf94d3 | |||
| c0b230a95e | |||
| 607c2cc8e7 | |||
| 48d3a3defd | |||
| 8509285aae | |||
| 2413e9951f | |||
| 1a444fd703 | |||
| bd68a140ba | |||
| 7b34211bb1 | |||
| fa78223229 | |||
| 39c19dc1d4 | |||
| 7b4b6357cb | |||
| 4454290820 | |||
| d94cd9dc8d | |||
| 8c07af9505 | |||
| d32fb44187 | |||
| dd38480ce2 | |||
| 08e8e3918e | |||
| 7a3591d1bd | |||
| 59ab7f5c8d | |||
| c2b2182182 | |||
| 66b656f058 | |||
| c8f7ecabf4 | |||
| 9137249510 | |||
| 7367c8ef67 | |||
| ed480e1e6e | |||
| 841074fc27 | |||
| 64f477f90e | |||
| 813741bc3d | |||
| 7566546fd7 | |||
| a4f83e0125 | |||
| 7b08c0dde6 | |||
| 59b8b397b7 | |||
| 361ef2a475 | |||
| d382fcc919 | |||
| aac8451627 | |||
| c96c09f42f | |||
| 50f8f18503 | |||
| 7c72e70967 | |||
| 75b74a6687 | |||
| 9001cd8a6f | |||
| 7dcb4435d8 | |||
| 1279fd234f |
+11
-5
@@ -1,10 +1,16 @@
|
||||
root=true
|
||||
# editorconfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Default settings:
|
||||
# A newline ending every file
|
||||
# Use 4 spaces as indentation
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{cs,cshtml,csx,vb,vbx,vbhtml,fs,fsx,txt,ps1,sql}]
|
||||
indent_size = 4
|
||||
# Trim trailing whitespace, limited support.
|
||||
# https://github.com/editorconfig/editorconfig/wiki/Property-research:-Trim-trailing-spaces
|
||||
trim_trailing_whitespace = true
|
||||
@@ -0,0 +1,49 @@
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
*.jpg binary
|
||||
*.png binary
|
||||
*.gif binary
|
||||
|
||||
*.cs text=auto diff=csharp
|
||||
*.vb text=auto
|
||||
*.c text=auto
|
||||
*.cpp text=auto
|
||||
*.cxx text=auto
|
||||
*.h text=auto
|
||||
*.hxx text=auto
|
||||
*.py text=auto
|
||||
*.rb text=auto
|
||||
*.java text=auto
|
||||
*.html text=auto
|
||||
*.htm text=auto
|
||||
*.css text=auto
|
||||
*.scss text=auto
|
||||
*.sass text=auto
|
||||
*.less text=auto
|
||||
*.js text=auto
|
||||
*.lisp text=auto
|
||||
*.clj text=auto
|
||||
*.sql text=auto
|
||||
*.php text=auto
|
||||
*.lua text=auto
|
||||
*.m text=auto
|
||||
*.asm text=auto
|
||||
*.erl text=auto
|
||||
*.fs text=auto
|
||||
*.fsx text=auto
|
||||
*.hs text=auto
|
||||
|
||||
*.csproj text=auto merge=union
|
||||
*.vbproj text=auto merge=union
|
||||
*.fsproj text=auto merge=union
|
||||
*.dbproj text=auto merge=union
|
||||
*.sln text=auto eol=crlf merge=union
|
||||
@@ -14,6 +14,43 @@ By default, this builds the current version. It is possible to specify a differe
|
||||
|
||||
Valid version strings are defined in the `Set-UmbracoVersion` documentation below.
|
||||
|
||||
## PowerShell Quirks
|
||||
|
||||
There is a good chance that running `build.ps1` ends up in error, with messages such as
|
||||
|
||||
>The file ...\build\build.ps1 is not digitally signed. You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies.
|
||||
|
||||
PowerShell has *Execution Policies* that may prevent the script from running. You can check the current policies with:
|
||||
|
||||
PS> Get-ExecutionPolicy -List
|
||||
|
||||
Scope ExecutionPolicy
|
||||
----- ---------------
|
||||
MachinePolicy Undefined
|
||||
UserPolicy Undefined
|
||||
Process Undefined
|
||||
CurrentUser Undefined
|
||||
LocalMachine RemoteSigned
|
||||
|
||||
Policies can be `Restricted`, `AllSigned`, `RemoteSigned`, `Unrestricted` and `Bypass`. Scopes can be `MachinePolicy`, `UserPolicy`, `Process`, `CurrentUser`, `LocalMachine`. You need the current policy to be `RemoteSigned`—as long as it is `Undefined`, the script cannot run. You can change the current user policy with:
|
||||
|
||||
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
|
||||
|
||||
Alternatively, you can do it at machine level, from within an elevated PowerShell session:
|
||||
|
||||
PS> Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned
|
||||
|
||||
And *then* the script should run. It *might* however still complain about executing scripts, with messages such as:
|
||||
|
||||
>Security warning - Run only scripts that you trust. While scripts from the internet can be useful, this script can potentially harm your computer. If you trust this script, use the Unblock-File cmdlet to allow the script to run without this warning message. Do you want to run ...\build\build.ps1?
|
||||
[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"):
|
||||
|
||||
This is usually caused by the scripts being *blocked*. And that usually happens when the source code has been downloaded as a Zip file. When Windows downloads Zip files, they are marked as *blocked* (technically, they have a Zone.Identifier alternate data stream, with a value of "3" to indicate that they were downloaded from the Internet). And when such a Zip file is un-zipped, each and every single file is also marked as blocked.
|
||||
|
||||
The best solution is to unblock the Zip file before un-zipping: right-click the files, open *Properties*, and there should be a *Unblock* checkbox at the bottom of the dialog. If, however, the Zip file has already been un-zipped, it is possible to recursively unblock all files from PowerShell with:
|
||||
|
||||
PS> Get-ChildItem -Recurse *.* | Unblock-File
|
||||
|
||||
## Notes
|
||||
|
||||
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Umbraco CMS
|
||||
===========
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 390,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 443,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
|
||||
[](https://vimeo.com/172382998/)
|
||||
|
||||
@@ -12,7 +12,7 @@ Umbraco is a free open source Content Management System built on the ASP.NET pla
|
||||
|
||||
## Building Umbraco from source ##
|
||||
|
||||
The easiest way to get started is to run `build/build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`.
|
||||
The easiest way to get started is to run `build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
|
||||
Note that you can always [download a nightly build](http://nightly.umbraco.org/?container=umbraco-750) so you don't have to build the code yourself.
|
||||
|
||||
@@ -26,7 +26,7 @@ For the first time on the Microsoft platform, there is a free user and developer
|
||||
|
||||
Umbraco is not only loved by developers, but is a content editors dream. Enjoy intuitive editing tools, media management, responsive views and approval workflows to send your content live.
|
||||
|
||||
Used by more than 350,000 active websites including Carlsberg, Segway, Amazon and Heinz and **The Official ASP.NET and IIS.NET website from Microsoft** ([https://asp.net](https://asp.net) / [https://iis.net](https://iis.net)), you can be sure that the technology is proven, stable and scales. Backed by the team at Umbraco HQ, and supported by a dedicated community of over 200,000 craftspeople globally, you can trust that Umbraco is a safe choice and is here to stay.
|
||||
Used by more than 443,000 active websites including Carlsberg, Segway, Amazon and Heinz and **The Official ASP.NET and IIS.NET website from Microsoft** ([https://asp.net](https://asp.net) / [https://iis.net](https://iis.net)), you can be sure that the technology is proven, stable and scales. Backed by the team at Umbraco HQ, and supported by a dedicated community of over 220,000 craftspeople globally, you can trust that Umbraco is a safe choice and is here to stay.
|
||||
|
||||
To view more examples, please visit [https://umbraco.com/why-umbraco/#caseStudies](https://umbraco.com/why-umbraco/#caseStudies)
|
||||
|
||||
|
||||
@@ -10,6 +10,5 @@ IF ERRORLEVEL 1 (
|
||||
:error
|
||||
ECHO.
|
||||
ECHO Can not run build\build.ps1.
|
||||
ECHO If this is due to a SecurityError then make sure to run the following command from an administrator command prompt:
|
||||
ECHO If this is due to a SecurityError then please refer to BUILD.md for help!
|
||||
ECHO.
|
||||
ECHO powershell Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
|
||||
@@ -239,18 +239,18 @@ function Prepare-Tests
|
||||
|
||||
# data
|
||||
Write-Host "Copy data files"
|
||||
if( -Not (Test-Path -Path "$tmp\tests\Packaging" ) )
|
||||
if (-Not (Test-Path -Path "$tmp\tests\Packaging" ) )
|
||||
{
|
||||
Write-Host "Create packaging directory"
|
||||
New-Item -ItemType directory -Path "$tmp\tests\Packaging"
|
||||
mkdir "$tmp\tests\Packaging" > $null
|
||||
}
|
||||
Copy-Files "$src\Umbraco.Tests\Packaging\Packages" "*" "$tmp\tests\Packaging\Packages"
|
||||
|
||||
# required for package install tests
|
||||
if( -Not (Test-Path -Path "$tmp\tests\bin" ) )
|
||||
if (-Not (Test-Path -Path "$tmp\tests\bin" ) )
|
||||
{
|
||||
Write-Host "Create bin directory"
|
||||
New-Item -ItemType directory -Path "$tmp\tests\bin"
|
||||
mkdir "$tmp\tests\bin" > $null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,17 +29,17 @@
|
||||
<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.9.9, 7.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.6, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.85, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.3, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.3, 5.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.89, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.6, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.7, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 3.0.0)" />
|
||||
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
|
||||
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.7, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.10, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -49,11 +49,9 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.7.3")]
|
||||
[assembly: AssemblyInformationalVersion("7.7.3")]
|
||||
[assembly: AssemblyFileVersion("7.7.13")]
|
||||
[assembly: AssemblyInformationalVersion("7.7.13")]
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -260,7 +261,7 @@ namespace Umbraco.Core
|
||||
/// - http://issues.umbraco.org/issue/U4-5728
|
||||
/// - http://issues.umbraco.org/issue/U4-5391
|
||||
/// </remarks>
|
||||
internal string UmbracoApplicationUrl
|
||||
public string UmbracoApplicationUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -268,9 +269,21 @@ namespace Umbraco.Core
|
||||
return _umbracoApplicationUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the url.
|
||||
/// </summary>
|
||||
public void ResetUmbracoApplicationUrl()
|
||||
{
|
||||
_umbracoApplicationUrl = null;
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
internal string _umbracoApplicationUrl;
|
||||
internal string _umbracoApplicationUrl;
|
||||
|
||||
internal List<string> _umbracoApplicationDomains = new List<string>();
|
||||
|
||||
internal string _umbracoApplicationDeploymentId;
|
||||
|
||||
private Lazy<bool> _configured;
|
||||
internal MainDom MainDom { get; private set; }
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a composite key of (Type, Type) for fast dictionaries.
|
||||
/// </summary>
|
||||
internal struct CompositeTypeTypeKey : IEquatable<CompositeTypeTypeKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CompositeTypeTypeKey"/> struct.
|
||||
/// </summary>
|
||||
public CompositeTypeTypeKey(Type type1, Type type2) : this()
|
||||
{
|
||||
Type1 = type1;
|
||||
Type2 = type2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first type.
|
||||
/// </summary>
|
||||
public Type Type1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second type.
|
||||
/// </summary>
|
||||
public Type Type2 { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(CompositeTypeTypeKey other)
|
||||
{
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = obj is CompositeTypeTypeKey ? (CompositeTypeTypeKey)obj : default(CompositeTypeTypeKey);
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
public static bool operator ==(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
{
|
||||
return key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
|
||||
}
|
||||
|
||||
public static bool operator !=(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
{
|
||||
return key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Type1.GetHashCode() * 397) ^ Type2.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
using ClientDependency.Core.CompositeFiles.Providers;
|
||||
using ClientDependency.Core.Config;
|
||||
using Semver;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -24,10 +28,74 @@ namespace Umbraco.Core.Configuration
|
||||
_logger = logger;
|
||||
_fileName = IOHelper.MapPath(string.Format("{0}/ClientDependency.config", SystemDirectories.Config));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the version number in ClientDependency.config to a hashed value for the version and the DateTime.Day
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="SemVersion">version</see> of Umbraco we're upgrading to</param>
|
||||
/// <param name="date">A <see cref="DateTime">date</see> value to use in the hash to prevent this method from updating the version on each startup</param>
|
||||
/// <param name="dateFormat">Allows the developer to specify the <see cref="string">date precision</see> for the hash (i.e. "yyyyMMdd" would be a precision for the day)</param>
|
||||
/// <returns>Boolean to indicate succesful update of the ClientDependency.config file</returns>
|
||||
public bool UpdateVersionNumber(SemVersion version, DateTime date, string dateFormat)
|
||||
{
|
||||
var byteContents = Encoding.Unicode.GetBytes(version + date.ToString(dateFormat));
|
||||
|
||||
//This is a way to convert a string to a long
|
||||
//see https://www.codeproject.com/Articles/34309/Convert-String-to-bit-Integer
|
||||
//We could much more easily use MD5 which would create us an INT but since that is not compliant with
|
||||
//hashing standards we have to use SHA
|
||||
int intHash;
|
||||
using (var hash = SHA256.Create())
|
||||
{
|
||||
var bytes = hash.ComputeHash(byteContents);
|
||||
|
||||
var longResult = new[] { 0, 8, 16, 24 }
|
||||
.Select(i => BitConverter.ToInt64(bytes, i))
|
||||
.Aggregate((x, y) => x ^ y);
|
||||
|
||||
//CDF requires an INT, and although this isn't fail safe, it will work for our purposes. We are not hashing for crypto purposes
|
||||
//so there could be some collisions with this conversion but it's not a problem for our purposes
|
||||
//It's also important to note that the long.GetHashCode() implementation in .NET is this: return (int) this ^ (int) (this >> 32);
|
||||
//which means that this value will not change per appdomain like some GetHashCode implementations.
|
||||
intHash = longResult.GetHashCode();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var clientDependencyConfigXml = XDocument.Load(_fileName, LoadOptions.PreserveWhitespace);
|
||||
if (clientDependencyConfigXml.Root != null)
|
||||
{
|
||||
|
||||
var versionAttribute = clientDependencyConfigXml.Root.Attribute("version");
|
||||
|
||||
//Set the new version to the hashcode of now
|
||||
var oldVersion = versionAttribute.Value;
|
||||
var newVersion = Math.Abs(intHash).ToString();
|
||||
|
||||
//don't update if it's the same version
|
||||
if (oldVersion == newVersion)
|
||||
return false;
|
||||
|
||||
versionAttribute.SetValue(newVersion);
|
||||
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
_logger.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the version number in ClientDependency.config to a random value to avoid stale caches
|
||||
/// </summary>
|
||||
/// <seealso cref="UpdateVersionNumber(SemVersion, DateTime, string)" />
|
||||
[Obsolete("Use the UpdateVersionNumber method specifying the version, date and dateFormat instead")]
|
||||
public bool IncreaseVersionNumber()
|
||||
{
|
||||
try
|
||||
@@ -107,4 +175,4 @@ namespace Umbraco.Core.Configuration
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.7.3");
|
||||
private static readonly Version Version = new Version("7.7.13");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Umbraco.Core
|
||||
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
|
||||
{
|
||||
if (truncateTo == DateTruncate.Year)
|
||||
return new DateTime(dt.Year, 0, 0);
|
||||
return new DateTime(dt.Year, 1, 1);
|
||||
if (truncateTo == DateTruncate.Month)
|
||||
return new DateTime(dt.Year, dt.Month, 0);
|
||||
return new DateTime(dt.Year, dt.Month, 1);
|
||||
if (truncateTo == DateTruncate.Day)
|
||||
return new DateTime(dt.Year, dt.Month, dt.Day);
|
||||
if (truncateTo == DateTruncate.Hour)
|
||||
@@ -41,43 +41,43 @@ namespace Umbraco.Core
|
||||
Hour,
|
||||
Minute,
|
||||
Second
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
|
||||
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
|
||||
/// date time is before the time, calculate onto next day)
|
||||
/// </summary>
|
||||
/// <param name="fromDateTime">Date to start from</param>
|
||||
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
|
||||
/// <returns></returns>
|
||||
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
|
||||
{
|
||||
// Ensure time provided is 4 digits long
|
||||
if (scheduledTime.Length == 3)
|
||||
{
|
||||
scheduledTime = "0" + scheduledTime;
|
||||
}
|
||||
|
||||
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
|
||||
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
|
||||
|
||||
DateTime scheduledDateTime;
|
||||
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
|
||||
{
|
||||
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextDay = fromDateTime.AddDays(1);
|
||||
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
|
||||
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
|
||||
}
|
||||
|
||||
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
|
||||
{
|
||||
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
|
||||
/// <returns></returns>
|
||||
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
|
||||
{
|
||||
// Ensure time provided is 4 digits long
|
||||
if (scheduledTime.Length == 3)
|
||||
{
|
||||
scheduledTime = "0" + scheduledTime;
|
||||
}
|
||||
|
||||
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
|
||||
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
|
||||
|
||||
DateTime scheduledDateTime;
|
||||
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
|
||||
{
|
||||
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextDay = fromDateTime.AddDays(1);
|
||||
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
|
||||
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
|
||||
}
|
||||
|
||||
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
|
||||
{
|
||||
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
@@ -7,18 +8,27 @@ namespace Umbraco.Core.Events
|
||||
public class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying packageMetaData instead")]
|
||||
public ImportPackageEventArgs(TEntity eventObject, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
}
|
||||
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: base(new[] { eventObject })
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
if (packageMetaData == null) throw new ArgumentNullException("packageMetaData");
|
||||
_packageMetaData = packageMetaData;
|
||||
}
|
||||
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: this(eventObject, packageMetaData, true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MetaData PackageMetaData
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
|
||||
@@ -76,260 +76,257 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
if (_events == null)
|
||||
return Enumerable.Empty<IEventDefinition>();
|
||||
|
||||
|
||||
IReadOnlyList<IEventDefinition> events;
|
||||
switch (filter)
|
||||
{
|
||||
case EventDefinitionFilter.All:
|
||||
return FilterSupersededAndUpdateToLatestEntity(_events);
|
||||
events = _events;
|
||||
break;
|
||||
case EventDefinitionFilter.FirstIn:
|
||||
var l1 = new OrderedHashSet<IEventDefinition>();
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l1.Add(e);
|
||||
}
|
||||
return FilterSupersededAndUpdateToLatestEntity(l1);
|
||||
events = l1;
|
||||
break;
|
||||
case EventDefinitionFilter.LastIn:
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l2.Add(e);
|
||||
}
|
||||
return FilterSupersededAndUpdateToLatestEntity(l2);
|
||||
events = l2;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("filter", filter, null);
|
||||
}
|
||||
|
||||
return FilterSupersededAndUpdateToLatestEntity(events);
|
||||
}
|
||||
|
||||
private class EventDefinitionTypeData
|
||||
|
||||
private class EventDefinitionInfos
|
||||
{
|
||||
public IEventDefinition EventDefinition { get; set; }
|
||||
public Type EventArgType { get; set; }
|
||||
public SupersedeEventAttribute[] SupersedeAttributes { get; set; }
|
||||
public Type[] SupersedeTypes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will iterate over the events (latest first) and filter out any events or entities in event args that are included
|
||||
/// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
|
||||
/// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
|
||||
/// </summary>
|
||||
/// <param name="events"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
|
||||
|
||||
// fixme
|
||||
// this is way too convoluted, the superceede attribute is used only on DeleteEventargs to specify
|
||||
// that it superceeds save, publish, move and copy - BUT - publish event args is also used for
|
||||
// unpublishing and should NOT be superceeded - so really it should not be managed at event args
|
||||
// level but at event level
|
||||
//
|
||||
// what we want is:
|
||||
// if an entity is deleted, then all Saved, Moved, Copied, Published events prior to this should
|
||||
// not trigger for the entity - and even though, does it make any sense? making a copy of an entity
|
||||
// should ... trigger?
|
||||
//
|
||||
// not going to refactor it all - we probably want to *always* trigger event but tell people that
|
||||
// due to scopes, they should not expected eg a saved entity to still be around - however, now,
|
||||
// going to write a ugly condition to deal with U4-10764
|
||||
|
||||
// iterates over the events (latest first) and filter out any events or entities in event args that are included
|
||||
// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
|
||||
// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
|
||||
internal static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
|
||||
{
|
||||
//used to keep the 'latest' entity and associated event definition data
|
||||
var allEntities = new List<Tuple<IEntity, EventDefinitionTypeData>>();
|
||||
|
||||
//tracks all CancellableObjectEventArgs instances in the events which is the only type of args we can work with
|
||||
var cancelableArgs = new List<CancellableObjectEventArgs>();
|
||||
// keeps the 'latest' entity and associated event data
|
||||
var entities = new List<Tuple<IEntity, EventDefinitionInfos>>();
|
||||
|
||||
// collects the event definitions
|
||||
// collects the arguments in result, that require their entities to be updated
|
||||
var result = new List<IEventDefinition>();
|
||||
var resultArgs = new List<CancellableObjectEventArgs>();
|
||||
|
||||
//This will eagerly load all of the event arg types and their attributes so we don't have to continuously look this data up
|
||||
var allArgTypesWithAttributes = events.Select(x => x.Args.GetType())
|
||||
// eagerly fetch superceeded arg types for each arg type
|
||||
var argTypeSuperceeding = events.Select(x => x.Args.GetType())
|
||||
.Distinct()
|
||||
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).ToArray());
|
||||
|
||||
//Iterate all events and collect the actual entities in them and relates them to their corresponding EventDefinitionTypeData
|
||||
//we'll process the list in reverse because events are added in the order they are raised and we want to filter out
|
||||
//any entities from event args that are not longer relevant
|
||||
//(i.e. if an item is Deleted after it's Saved, we won't include the item in the Saved args)
|
||||
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).Select(y => y.SupersededEventArgsType).ToArray());
|
||||
|
||||
// iterate over all events and filter
|
||||
//
|
||||
// process the list in reverse, because events are added in the order they are raised and we want to keep
|
||||
// the latest (most recent) entities and filter out what is not relevant anymore (too old), eg if an entity
|
||||
// is Deleted after being Saved, we want to filter out the Saved event
|
||||
for (var index = events.Count - 1; index >= 0; index--)
|
||||
{
|
||||
var eventDefinition = events[index];
|
||||
var def = events[index];
|
||||
|
||||
var argType = eventDefinition.Args.GetType();
|
||||
var attributes = allArgTypesWithAttributes[eventDefinition.Args.GetType()];
|
||||
|
||||
var meta = new EventDefinitionTypeData
|
||||
var infos = new EventDefinitionInfos
|
||||
{
|
||||
EventDefinition = eventDefinition,
|
||||
EventArgType = argType,
|
||||
SupersedeAttributes = attributes
|
||||
EventDefinition = def,
|
||||
SupersedeTypes = argTypeSuperceeding[def.Args.GetType()]
|
||||
};
|
||||
|
||||
var args = eventDefinition.Args as CancellableObjectEventArgs;
|
||||
if (args != null)
|
||||
var args = def.Args as CancellableObjectEventArgs;
|
||||
if (args == null)
|
||||
{
|
||||
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
|
||||
if (list == null)
|
||||
// not a cancellable event arg, include event definition in result
|
||||
result.Add(def);
|
||||
}
|
||||
else
|
||||
{
|
||||
// event object can either be a single object or an enumerable of objects
|
||||
// try to get as an enumerable, get null if it's not
|
||||
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
if (eventObjects == null)
|
||||
{
|
||||
//extract the event object
|
||||
var obj = args.EventObject as IEntity;
|
||||
if (obj != null)
|
||||
// single object, cast as an IEntity
|
||||
// if cannot cast, cannot filter, nothing - just include event definition in result
|
||||
var eventEntity = args.EventObject as IEntity;
|
||||
if (eventEntity == null)
|
||||
{
|
||||
//Now check if this entity already exists in other event args that supersede this current event arg type
|
||||
if (IsFiltered(obj, meta, allEntities) == false)
|
||||
{
|
||||
//if it's not filtered we can adde these args to the response
|
||||
cancelableArgs.Add(args);
|
||||
result.Add(eventDefinition);
|
||||
//track the entity
|
||||
allEntities.Add(Tuple.Create(obj, meta));
|
||||
}
|
||||
result.Add(def);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
// look for this entity in superceding event args
|
||||
// found = must be removed (ie not added), else track
|
||||
if (IsSuperceeded(eventEntity, infos, entities) == false)
|
||||
{
|
||||
//Can't retrieve the entity so cant' filter or inspect, just add to the output
|
||||
result.Add(eventDefinition);
|
||||
// track
|
||||
entities.Add(Tuple.Create(eventEntity, infos));
|
||||
|
||||
// track result arguments
|
||||
// include event definition in result
|
||||
resultArgs.Add(args);
|
||||
result.Add(def);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// enumerable of objects
|
||||
var toRemove = new List<IEntity>();
|
||||
foreach (var entity in list)
|
||||
foreach (var eventObject in eventObjects)
|
||||
{
|
||||
//extract the event object
|
||||
var obj = entity as IEntity;
|
||||
if (obj != null)
|
||||
{
|
||||
//Now check if this entity already exists in other event args that supersede this current event arg type
|
||||
if (IsFiltered(obj, meta, allEntities))
|
||||
{
|
||||
//track it to be removed
|
||||
toRemove.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
//track the entity, it's not filtered
|
||||
allEntities.Add(Tuple.Create(obj, meta));
|
||||
}
|
||||
}
|
||||
// extract the event object, cast as an IEntity
|
||||
// if cannot cast, cannot filter, nothing to do - just leave it in the list & continue
|
||||
var eventEntity = eventObject as IEntity;
|
||||
if (eventEntity == null)
|
||||
continue;
|
||||
|
||||
// look for this entity in superceding event args
|
||||
// found = must be removed, else track
|
||||
if (IsSuperceeded(eventEntity, infos, entities))
|
||||
toRemove.Add(eventEntity);
|
||||
else
|
||||
{
|
||||
//we don't need to do anything here, we can't cast to IEntity so we cannot filter, so it will just remain in the list
|
||||
}
|
||||
entities.Add(Tuple.Create(eventEntity, infos));
|
||||
}
|
||||
|
||||
//remove anything that has been filtered
|
||||
// remove superceded entities
|
||||
foreach (var entity in toRemove)
|
||||
{
|
||||
list.Remove(entity);
|
||||
}
|
||||
eventObjects.Remove(entity);
|
||||
|
||||
//track the event and include in the response if there's still entities remaining in the list
|
||||
if (list.Count > 0)
|
||||
// if there are still entities in the list, keep the event definition
|
||||
if (eventObjects.Count > 0)
|
||||
{
|
||||
if (toRemove.Count > 0)
|
||||
{
|
||||
//re-assign if the items have changed
|
||||
args.EventObject = list;
|
||||
// re-assign if changed
|
||||
args.EventObject = eventObjects;
|
||||
}
|
||||
cancelableArgs.Add(args);
|
||||
result.Add(eventDefinition);
|
||||
|
||||
// track result arguments
|
||||
// include event definition in result
|
||||
resultArgs.Add(args);
|
||||
result.Add(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//it's not a cancelable event arg so we just include it in the result
|
||||
result.Add(eventDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
|
||||
UpdateToLatestEntities(allEntities, cancelableArgs);
|
||||
// go over all args in result, and update them with the latest instanceof each entity
|
||||
UpdateToLatestEntities(entities, resultArgs);
|
||||
|
||||
//we need to reverse the result since we've been adding by latest added events first!
|
||||
// reverse, since we processed the list in reverse
|
||||
result.Reverse();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionTypeData>> allEntities, IEnumerable<CancellableObjectEventArgs> cancelableArgs)
|
||||
// edits event args to use the latest instance of each entity
|
||||
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionInfos>> entities, IEnumerable<CancellableObjectEventArgs> args)
|
||||
{
|
||||
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
|
||||
|
||||
// get the latest entities
|
||||
// ordered hash set + keepOldest will keep the latest inserted entity (in case of duplicates)
|
||||
var latestEntities = new OrderedHashSet<IEntity>(keepOldest: true);
|
||||
foreach (var entity in allEntities.OrderByDescending(entity => entity.Item1.UpdateDate))
|
||||
{
|
||||
foreach (var entity in entities.OrderByDescending(entity => entity.Item1.UpdateDate))
|
||||
latestEntities.Add(entity.Item1);
|
||||
}
|
||||
|
||||
foreach (var args in cancelableArgs)
|
||||
foreach (var arg in args)
|
||||
{
|
||||
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
if (list == null)
|
||||
// event object can either be a single object or an enumerable of objects
|
||||
// try to get as an enumerable, get null if it's not
|
||||
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(arg.EventObject);
|
||||
if (eventObjects == null)
|
||||
{
|
||||
//try to find the args entity in the latest entity - based on the equality operators, this will
|
||||
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
|
||||
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, args.EventObject));
|
||||
// single object
|
||||
// look for a more recent entity for that object, and replace if any
|
||||
// works by "equalling" entities ie the more recent one "equals" this one (though different object)
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, arg.EventObject));
|
||||
if (foundEntity != null)
|
||||
{
|
||||
args.EventObject = foundEntity;
|
||||
}
|
||||
arg.EventObject = foundEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
// enumerable of objects
|
||||
// same as above but for each object
|
||||
var updated = false;
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
for (var i = 0; i < eventObjects.Count; i++)
|
||||
{
|
||||
//try to find the args entity in the latest entity - based on the equality operators, this will
|
||||
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
|
||||
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, list[i]));
|
||||
if (foundEntity != null)
|
||||
{
|
||||
list[i] = foundEntity;
|
||||
updated = true;
|
||||
}
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, eventObjects[i]));
|
||||
if (foundEntity == null) continue;
|
||||
eventObjects[i] = foundEntity;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
args.EventObject = list;
|
||||
}
|
||||
arg.EventObject = eventObjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will check against all of the processed entity/events (allEntities) to see if this entity already exists in
|
||||
/// event args that supersede the event args being passed in and if so returns true.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="eventDef"></param>
|
||||
/// <param name="allEntities"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsFiltered(
|
||||
IEntity entity,
|
||||
EventDefinitionTypeData eventDef,
|
||||
List<Tuple<IEntity, EventDefinitionTypeData>> allEntities)
|
||||
// determines if a given entity, appearing in a given event definition, should be filtered out,
|
||||
// considering the entities that have already been visited - an entity is filtered out if it
|
||||
// appears in another even definition, which superceedes this event definition.
|
||||
private static bool IsSuperceeded(IEntity entity, EventDefinitionInfos infos, List<Tuple<IEntity, EventDefinitionInfos>> entities)
|
||||
{
|
||||
var argType = eventDef.EventDefinition.Args.GetType();
|
||||
//var argType = meta.EventArgsType;
|
||||
var argType = infos.EventDefinition.Args.GetType();
|
||||
|
||||
//check if the entity is found in any processed event data that could possible supersede this one
|
||||
var foundByEntity = allEntities
|
||||
.Where(x => x.Item2.SupersedeAttributes.Length > 0
|
||||
//if it's the same arg type than it cannot supersede
|
||||
&& x.Item2.EventArgType != argType
|
||||
&& Equals(x.Item1, entity))
|
||||
// look for other instances of the same entity, coming from an event args that supercedes other event args,
|
||||
// ie is marked with the attribute, and is not this event args (cannot supersede itself)
|
||||
var superceeding = entities
|
||||
.Where(x => x.Item2.SupersedeTypes.Length > 0 // has the attribute
|
||||
&& x.Item2.EventDefinition.Args.GetType() != argType // is not the same
|
||||
&& Equals(x.Item1, entity)) // same entity
|
||||
.ToArray();
|
||||
|
||||
//no args have been processed with this entity so it should not be filtered
|
||||
if (foundByEntity.Length == 0)
|
||||
// first time we see this entity = not filtered
|
||||
if (superceeding.Length == 0)
|
||||
return false;
|
||||
|
||||
// fixme see notes above
|
||||
// delete event args does NOT superceedes 'unpublished' event
|
||||
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "UnPublished")
|
||||
return false;
|
||||
|
||||
// found occurences, need to determine if this event args is superceded
|
||||
if (argType.IsGenericType)
|
||||
{
|
||||
var supercededBy = foundByEntity
|
||||
.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeAttributes.Any(y =>
|
||||
//if the attribute type is a generic type def then compare with the generic type def of the event arg
|
||||
(y.SupersededEventArgsType.IsGenericTypeDefinition && y.SupersededEventArgsType == argType.GetGenericTypeDefinition())
|
||||
//if the attribute type is not a generic type def then compare with the normal type of the event arg
|
||||
|| (y.SupersededEventArgsType.IsGenericTypeDefinition == false && y.SupersededEventArgsType == argType)));
|
||||
// generic, must compare type arguments
|
||||
var supercededBy = superceeding.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeTypes.Any(y =>
|
||||
// superceeding a generic type which has the same generic type definition
|
||||
// fixme no matter the generic type parameters? could be different?
|
||||
y.IsGenericTypeDefinition && y == argType.GetGenericTypeDefinition()
|
||||
// or superceeding a non-generic type which is ... fixme how is this ever possible? argType *is* generic?
|
||||
|| y.IsGenericTypeDefinition == false && y == argType));
|
||||
return supercededBy != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var supercededBy = foundByEntity
|
||||
.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeAttributes.Any(y =>
|
||||
//since the event arg type is not a generic type, then we just compare type 1:1
|
||||
y.SupersededEventArgsType == argType));
|
||||
// non-generic, can compare types 1:1
|
||||
var supercededBy = superceeding.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeTypes.Any(y => y == argType));
|
||||
return supercededBy != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,28 @@ using Umbraco.Core.Configuration;
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public static class IOHelper
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value forcing Umbraco to consider it is non-hosted.
|
||||
/// </summary>
|
||||
/// <remarks>This should always be false, unless unit testing.</remarks>
|
||||
public static bool ForceNotHosted { get; set; }
|
||||
|
||||
private static string _rootDir = "";
|
||||
|
||||
// static compiled regex for faster performance
|
||||
private readonly static Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether Umbraco is hosted.
|
||||
/// </summary>
|
||||
public static bool IsHosted
|
||||
{
|
||||
get
|
||||
{
|
||||
return ForceNotHosted == false && (HttpContext.Current != null || HostingEnvironment.IsHosted);
|
||||
}
|
||||
}
|
||||
|
||||
public static char DirSepChar
|
||||
{
|
||||
@@ -72,14 +89,14 @@ namespace Umbraco.Core.IO
|
||||
internal static string ResolveUrlsFromTextString(string text)
|
||||
{
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.ResolveUrlsFromTextString)
|
||||
{
|
||||
{
|
||||
using (DisposableTimer.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
|
||||
{
|
||||
// find all relative urls (ie. urls that contain ~)
|
||||
var tags = ResolveUrlPattern.Matches(text);
|
||||
|
||||
|
||||
foreach (Match tag in tags)
|
||||
{
|
||||
{
|
||||
string url = "";
|
||||
if (tag.Groups[1].Success)
|
||||
url = tag.Groups[1].Value;
|
||||
@@ -97,7 +114,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public static string MapPath(string path, bool useHttpContext)
|
||||
{
|
||||
if (path == null) throw new ArgumentNullException("path");
|
||||
if (path == null) throw new ArgumentNullException("path");
|
||||
useHttpContext = useHttpContext && IsHosted;
|
||||
|
||||
// Check if the path is already mapped
|
||||
if ((path.Length >= 2 && path[1] == Path.VolumeSeparatorChar)
|
||||
@@ -303,7 +321,7 @@ namespace Umbraco.Core.IO
|
||||
var debugFolder = Path.Combine(binFolder, "debug");
|
||||
if (Directory.Exists(debugFolder))
|
||||
return debugFolder;
|
||||
#endif
|
||||
#endif
|
||||
var releaseFolder = Path.Combine(binFolder, "release");
|
||||
if (Directory.Exists(releaseFolder))
|
||||
return releaseFolder;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using log4net.Appender;
|
||||
using log4net.Util;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// This class will do the exact same thing as the RollingFileAppender that comes from log4net
|
||||
/// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens
|
||||
///
|
||||
/// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when
|
||||
/// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender
|
||||
/// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements
|
||||
/// to the configuration i.e.:
|
||||
///
|
||||
/// <example>
|
||||
/// <appender name="rollingFile" type="Log4netAwesomeness.CustomRollingFileAppender, Log4netAwesomeness">
|
||||
/// <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
|
||||
/// <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
|
||||
/// <appendToFile value="true" />
|
||||
/// <rollingStyle value="Date" />
|
||||
/// <maximumFileSize value="5MB" />
|
||||
/// <maxLogFileDays value="5"/>
|
||||
/// <basefilePattern value="UmbracoTraceLog.*.txt.*"/>
|
||||
/// <layout type="log4net.Layout.PatternLayout">
|
||||
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
|
||||
/// </layout>
|
||||
/// <layout type="log4net.Layout.PatternLayout">
|
||||
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
|
||||
/// </layout>
|
||||
/// <encoding value="utf-8" />
|
||||
/// </appender>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
public class RollingFileCleanupAppender : RollingFileAppender
|
||||
{
|
||||
public int MaxLogFileDays { get; set; }
|
||||
public string BaseFilePattern { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This override will delete logs older than the specified amount of days
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="append"></param>
|
||||
protected override void OpenFile(string fileName, bool append)
|
||||
{
|
||||
bool cleanup = true;
|
||||
// Validate settings and input
|
||||
if (MaxLogFileDays <= 0)
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup");
|
||||
cleanup = false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(BaseFilePattern))
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup");
|
||||
cleanup = false;
|
||||
}
|
||||
// grab the directory we are logging to, as this is were we will search for older logfiles
|
||||
var logFolder = Path.GetDirectoryName(fileName);
|
||||
if (Directory.Exists(logFolder) == false)
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder));
|
||||
cleanup = false;
|
||||
}
|
||||
// If everything is validated, we can do the actual cleanup
|
||||
if (cleanup)
|
||||
{
|
||||
Cleanup(logFolder);
|
||||
}
|
||||
|
||||
base.OpenFile(fileName, append);
|
||||
}
|
||||
|
||||
private void Cleanup(string directoryPath)
|
||||
{
|
||||
// only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.*
|
||||
string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern);
|
||||
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern));
|
||||
|
||||
foreach (var logFile in logFiles)
|
||||
{
|
||||
DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile);
|
||||
// take the value from the config file
|
||||
if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays))
|
||||
{
|
||||
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays));
|
||||
base.DeleteFile(logFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,8 +95,10 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedTemplates; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
|
||||
Ps.Value.TemplateComparer);
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector, Ps.Value.TemplateComparer);
|
||||
|
||||
if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false)
|
||||
DefaultTemplateId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,15 @@ namespace Umbraco.Core.Models.Identity
|
||||
.ForMember(user => user.CalculatedContentStartNodeIds, expression => expression.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
|
||||
.ForMember(user => user.CalculatedMediaStartNodeIds, expression => expression.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()))
|
||||
|
||||
.ForMember(user => user.LockoutEnabled, expression => expression.Ignore())
|
||||
.ForMember(user => user.Logins, expression => expression.Ignore())
|
||||
.ForMember(user => user.Roles, expression => expression.Ignore())
|
||||
.ForMember(user => user.PhoneNumber, expression => expression.Ignore())
|
||||
.ForMember(user => user.PhoneNumberConfirmed, expression => expression.Ignore())
|
||||
.ForMember(user => user.TwoFactorEnabled, expression => expression.Ignore())
|
||||
.ForMember(user => user.Claims, expression => expression.Ignore())
|
||||
|
||||
.AfterMap((user, identityUser) =>
|
||||
{
|
||||
identityUser.ResetDirtyProperties(true);
|
||||
@@ -60,4 +69,4 @@ namespace Umbraco.Core.Models.Identity
|
||||
return storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
|
||||
|
||||
if (constructors.ContainsKey(typeName))
|
||||
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
|
||||
throw new InvalidOperationException(string.Format("More than one type wants to be a model for content type {0}.", typeName));
|
||||
|
||||
// should work everywhere, but slow
|
||||
//_constructors[typeName] = constructor;
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace Umbraco.Core.Models
|
||||
Language,
|
||||
|
||||
/// <summary>
|
||||
/// Document
|
||||
/// Document Blueprint
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentBlueprint, typeof(IContent))]
|
||||
[FriendlyName("DocumentBlueprint")]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentTypeDto>()
|
||||
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId);
|
||||
//TODO: IF we want to enable querying on content type information this will need to be joined
|
||||
//.InnerJoin<ContentTypeDto>(SqlSyntax)
|
||||
//.On<ContentDto, ContentTypeDto>(SqlSyntax, left => left.ContentTypeId, right => right.NodeId, SqlSyntax);
|
||||
@@ -833,11 +835,21 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
}
|
||||
|
||||
public int CountPublished()
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
public int CountPublished(string contentTypeAlias = null)
|
||||
{
|
||||
if (contentTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReplaceContentPermissions(EntityPermissionSet permissionSet)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <remarks>
|
||||
/// We require this on the repo because the IQuery{IContent} cannot supply the 'newest' parameter
|
||||
/// </remarks>
|
||||
int CountPublished();
|
||||
int CountPublished(string contentTypeAlias = null);
|
||||
|
||||
/// <summary>
|
||||
/// Used to bulk update the permissions set for a content item. This will replace all permissions
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public IMemberGroup GetByName(string name)
|
||||
{
|
||||
return IsolatedCache.GetCacheItem<IMemberGroup>(
|
||||
string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name),
|
||||
string.Format("{0}.{1}", typeof(IMemberGroup).FullName, name),
|
||||
() =>
|
||||
{
|
||||
var qry = new Query<IMemberGroup>().Where(group => group.Name.Equals(name));
|
||||
@@ -140,7 +140,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return result.FirstOrDefault();
|
||||
},
|
||||
//cache for 5 mins since that is the default in the RuntimeCacheProvider
|
||||
TimeSpan.FromMinutes(5),
|
||||
TimeSpan.FromMinutes(5),
|
||||
//sliding is true
|
||||
true);
|
||||
}
|
||||
@@ -183,17 +183,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username)
|
||||
{
|
||||
var sql = new Sql()
|
||||
{
|
||||
var sql = new Sql()
|
||||
.Select("un.*")
|
||||
.From("umbracoNode AS un")
|
||||
.InnerJoin("cmsMember2MemberGroup")
|
||||
.On("un.id = cmsMember2MemberGroup.MemberGroup")
|
||||
.LeftJoin("(SELECT umbracoNode.id, cmsMember.LoginName FROM umbracoNode INNER JOIN cmsMember ON umbracoNode.id = cmsMember.nodeId) AS member")
|
||||
.On("member.id = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new {objectType = NodeObjectTypeId })
|
||||
.Where("member.LoginName=@loginName", new {loginName = username});
|
||||
|
||||
.On("cmsMember2MemberGroup.MemberGroup = un.id")
|
||||
.InnerJoin("cmsMember")
|
||||
.On("cmsMember.nodeId = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new { objectType = NodeObjectTypeId })
|
||||
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
|
||||
|
||||
return Database.Fetch<NodeDto>(sql)
|
||||
.DistinctBy(dto => dto.NodeId)
|
||||
.Select(x => _modelFactory.BuildEntity(x));
|
||||
@@ -337,4 +337,4 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
internal static event TypedEventHandler<IMemberGroupRepository, SaveEventArgs<IMemberGroup>> SavedMemberGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var name = Name;
|
||||
|
||||
// cater for instances where node has no name.
|
||||
if(string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return _numPos;
|
||||
}
|
||||
|
||||
if (name[name.Length - 1] != ')')
|
||||
return _numPos = -1;
|
||||
|
||||
@@ -106,7 +112,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
|
||||
return uniqueing || string.IsNullOrWhiteSpace(nodeName) ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,11 +191,11 @@ ORDER BY colName";
|
||||
|
||||
return new Dictionary<UserState, int>
|
||||
{
|
||||
{UserState.All, result[0].num},
|
||||
{UserState.Active, result[1].num},
|
||||
{UserState.Disabled, result[2].num},
|
||||
{UserState.LockedOut, result[3].num},
|
||||
{UserState.Invited, result[4].num}
|
||||
{UserState.All, (int)result[0].num},
|
||||
{UserState.Active, (int)result[1].num},
|
||||
{UserState.Disabled, (int)result[2].num},
|
||||
{UserState.LockedOut, (int)result[3].num},
|
||||
{UserState.Invited, (int)result[4].num}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace Umbraco.Core
|
||||
return _currentAssembliesHash;
|
||||
|
||||
_currentAssembliesHash = GetFileHash(new List<Tuple<FileSystemInfo, bool>>
|
||||
{
|
||||
{
|
||||
// the bin folder and everything in it
|
||||
new Tuple<FileSystemInfo, bool>(new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Bin)), false),
|
||||
// the app code folder and everything in it
|
||||
@@ -216,7 +216,7 @@ namespace Umbraco.Core
|
||||
new Tuple<FileSystemInfo, bool>(new FileInfo(IOHelper.MapPath("~/global.asax")), false),
|
||||
// trees.config - use the contents to create the hash since this gets resaved on every app startup!
|
||||
new Tuple<FileSystemInfo, bool>(new FileInfo(IOHelper.MapPath(SystemDirectories.Config + "/trees.config")), true)
|
||||
}, _logger);
|
||||
}, _logger);
|
||||
|
||||
return _currentAssembliesHash;
|
||||
}
|
||||
@@ -601,7 +601,7 @@ namespace Umbraco.Core
|
||||
if (cache == false || typeof(IDiscoverable).IsAssignableFrom(typeof(T)) == false)
|
||||
{
|
||||
return ResolveTypesInternal(
|
||||
typeof (T), null,
|
||||
typeof(T), null,
|
||||
() => TypeFinder.FindClassesOfType<T>(specificAssemblies ?? AssembliesToScan),
|
||||
cache);
|
||||
}
|
||||
@@ -610,14 +610,14 @@ namespace Umbraco.Core
|
||||
// filter the cached discovered types (and cache the result)
|
||||
|
||||
var discovered = ResolveTypesInternal(
|
||||
typeof (IDiscoverable), null,
|
||||
typeof(IDiscoverable), null,
|
||||
() => TypeFinder.FindClassesOfType<IDiscoverable>(AssembliesToScan),
|
||||
true);
|
||||
|
||||
return ResolveTypesInternal(
|
||||
typeof (T), null,
|
||||
typeof(T), null,
|
||||
() => discovered
|
||||
.Where(x => typeof (T).IsAssignableFrom(x)),
|
||||
.Where(x => typeof(T).IsAssignableFrom(x)),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ namespace Umbraco.Core
|
||||
if (cache == false || typeof(IDiscoverable).IsAssignableFrom(typeof(T)) == false)
|
||||
{
|
||||
return ResolveTypesInternal(
|
||||
typeof (T), typeof (TAttribute),
|
||||
typeof(T), typeof(TAttribute),
|
||||
() => TypeFinder.FindClassesOfTypeWithAttribute<T, TAttribute>(specificAssemblies ?? AssembliesToScan),
|
||||
cache);
|
||||
}
|
||||
@@ -649,12 +649,12 @@ namespace Umbraco.Core
|
||||
// filter the cached discovered types (and cache the result)
|
||||
|
||||
var discovered = ResolveTypesInternal(
|
||||
typeof (IDiscoverable), null,
|
||||
typeof(IDiscoverable), null,
|
||||
() => TypeFinder.FindClassesOfType<IDiscoverable>(AssembliesToScan),
|
||||
true);
|
||||
|
||||
return ResolveTypesInternal(
|
||||
typeof (T), typeof (TAttribute),
|
||||
typeof(T), typeof(TAttribute),
|
||||
() => discovered
|
||||
.Where(x => typeof(T).IsAssignableFrom(x))
|
||||
.Where(x => x.GetCustomAttributes<TAttribute>(false).Any()),
|
||||
@@ -676,7 +676,7 @@ namespace Umbraco.Core
|
||||
cache &= specificAssemblies == null;
|
||||
|
||||
return ResolveTypesInternal(
|
||||
typeof (object), typeof (TAttribute),
|
||||
typeof(object), typeof(TAttribute),
|
||||
() => TypeFinder.FindClassesWithAttribute<TAttribute>(specificAssemblies ?? AssembliesToScan),
|
||||
cache);
|
||||
}
|
||||
@@ -694,13 +694,13 @@ namespace Umbraco.Core
|
||||
var name = ResolvedName(baseType, attributeType);
|
||||
|
||||
lock (_typesLock)
|
||||
using (_logger.TraceDuration<PluginManager>(
|
||||
"Resolving " + name,
|
||||
"Resolved " + name)) // cannot contain typesFound.Count as it's evaluated before the find
|
||||
{
|
||||
// resolve within a lock & timer
|
||||
return ResolveTypesInternalLocked(baseType, attributeType, finder, cache);
|
||||
}
|
||||
using (_logger.TraceDuration<PluginManager>(
|
||||
"Resolving " + name,
|
||||
"Resolved " + name)) // cannot contain typesFound.Count as it's evaluated before the find
|
||||
{
|
||||
// resolve within a lock & timer
|
||||
return ResolveTypesInternalLocked(baseType, attributeType, finder, cache);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolvedName(Type baseType, Type attributeType)
|
||||
@@ -836,7 +836,7 @@ namespace Umbraco.Core
|
||||
|
||||
public TypeListKey(Type baseType, Type attributeType)
|
||||
{
|
||||
BaseType = baseType ?? typeof (object);
|
||||
BaseType = baseType ?? typeof(object);
|
||||
AttributeType = attributeType;
|
||||
}
|
||||
|
||||
@@ -854,7 +854,7 @@ namespace Umbraco.Core
|
||||
|
||||
var hash = 5381;
|
||||
hash = ((hash << 5) + hash) ^ BaseType.GetHashCode();
|
||||
hash = ((hash << 5) + hash) ^ (AttributeType ?? typeof (TypeListKey)).GetHashCode();
|
||||
hash = ((hash << 5) + hash) ^ (AttributeType ?? typeof(TypeListKey)).GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -917,7 +917,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
// look for IParameterEditor (fast, IDiscoverable) then filter
|
||||
|
||||
var propertyEditor = typeof (PropertyEditor);
|
||||
var propertyEditor = typeof(PropertyEditor);
|
||||
|
||||
return mgr.ResolveTypes<IParameterEditor>()
|
||||
.Where(x => propertyEditor.IsAssignableFrom(x) && x != propertyEditor);
|
||||
@@ -932,8 +932,8 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public static IEnumerable<Type> ResolveParameterEditors(this PluginManager mgr)
|
||||
{
|
||||
var propertyEditor = typeof (PropertyEditor);
|
||||
var parameterEditor = typeof (ParameterEditor);
|
||||
var propertyEditor = typeof(PropertyEditor);
|
||||
var parameterEditor = typeof(ParameterEditor);
|
||||
|
||||
return mgr.ResolveTypes<IParameterEditor>()
|
||||
.Where(x => x != propertyEditor && x != parameterEditor);
|
||||
|
||||
@@ -178,29 +178,25 @@ namespace Umbraco.Core.PropertyEditors
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ConvertItemsToJsonIfDetected(IDictionary<string, object> result)
|
||||
protected void ConvertItemsToJsonIfDetected(IDictionary<string, object> result)
|
||||
{
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
// convert values that are Json to true Json objects that can be consumed by Angular
|
||||
|
||||
var keys = result.Keys.ToArray();
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
if (result[keys[i]] is string)
|
||||
if ((result[keys[i]] is string) == false) continue;
|
||||
|
||||
var asString = result[keys[i]].ToString();
|
||||
if (asString.DetectIsJson() == false) continue;
|
||||
|
||||
try
|
||||
{
|
||||
var asString = result[keys[i]].ToString();
|
||||
if (asString.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject(asString);
|
||||
result[keys[i]] = json;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//swallow this exception, we thought it was json but it really isn't so continue returning a string
|
||||
}
|
||||
}
|
||||
result[keys[i]] = JsonConvert.DeserializeObject(asString);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// swallow this exception, we thought it was Json but it really isn't so continue returning a string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -176,6 +176,12 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <returns></returns>
|
||||
internal Attempt<object> TryConvertValueToCrlType(object value)
|
||||
{
|
||||
var jv = value as JValue;
|
||||
if (jv != null)
|
||||
{
|
||||
value = value.ToString();
|
||||
}
|
||||
|
||||
//this is a custom check to avoid any errors, if it's a string and it's empty just make it null
|
||||
var s = value as string;
|
||||
if (s != null)
|
||||
@@ -391,4 +397,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
[DefaultPropertyValueConverter]
|
||||
[PropertyValueType(typeof(string))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class ColorPickerValueConverter : PropertyValueConverterBase
|
||||
public class ColorPickerValueConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
@@ -18,11 +19,60 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return false;
|
||||
}
|
||||
|
||||
public Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
{
|
||||
return UseLabel(propertyType) ? typeof(PickedColor) : typeof(string);
|
||||
}
|
||||
|
||||
public PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue)
|
||||
{
|
||||
return PropertyCacheLevel.Content;
|
||||
}
|
||||
|
||||
private bool UseLabel(PublishedPropertyType propertyType)
|
||||
{
|
||||
var preValues = ApplicationContext.Current.Services.DataTypeService.GetPreValuesCollectionByDataTypeId(propertyType.DataTypeId);
|
||||
PreValue preValue;
|
||||
return preValues.PreValuesAsDictionary.TryGetValue("useLabel", out preValue) && preValue.Value == "1";
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// make sure it's a string
|
||||
return source == null ? string.Empty : source.ToString();
|
||||
var useLabel = UseLabel(propertyType);
|
||||
|
||||
if (source == null) return useLabel ? null : string.Empty;
|
||||
|
||||
var ssource = source.ToString();
|
||||
if (ssource.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var jo = JsonConvert.DeserializeObject<JObject>(ssource);
|
||||
if (useLabel) return new PickedColor(jo["value"].ToString(), jo["label"].ToString());
|
||||
return jo["value"].ToString();
|
||||
}
|
||||
catch { /* not json finally */ }
|
||||
}
|
||||
|
||||
if (useLabel) return new PickedColor(ssource, ssource);
|
||||
return ssource;
|
||||
}
|
||||
|
||||
public class PickedColor
|
||||
{
|
||||
public PickedColor(string color, string label)
|
||||
{
|
||||
Color = color;
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public string Color { get; private set; }
|
||||
public string Label { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Color;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
|
||||
//TODO: Change all singleton access to use ctor injection in v8!!!
|
||||
//TODO: That would mean that property value converters would need to be request lifespan, hrm....
|
||||
bool isDebug = HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled;
|
||||
var gridConfig = UmbracoConfig.For.GridConfig(
|
||||
ApplicationContext.Current.ProfilingLogger.Logger,
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache,
|
||||
new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.AppPlugins)),
|
||||
new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.Config)),
|
||||
HttpContext.Current.IsDebuggingEnabled);
|
||||
new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins)),
|
||||
new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Config)),
|
||||
isDebug);
|
||||
|
||||
var sections = GetArray(obj, "sections");
|
||||
foreach (var section in sections.Cast<JObject>())
|
||||
@@ -112,4 +113,4 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias);
|
||||
}
|
||||
|
||||
private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" };
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// data is (both in database and xml):
|
||||
@@ -53,7 +55,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
// Fall back on normal behaviour
|
||||
if (values.Any() == false)
|
||||
{
|
||||
return sourceString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
return sourceString.Split(NewLineDelimiters, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
|
||||
@@ -116,5 +116,19 @@ namespace Umbraco.Core.Scoping
|
||||
Enlisted[key] = enlistedOfT;
|
||||
return enlistedOfT.Item;
|
||||
}
|
||||
|
||||
public T GetEnlisted<T>(string key)
|
||||
{
|
||||
var enlistedObjects = _enlisted;
|
||||
if (enlistedObjects == null) return default (T);
|
||||
|
||||
IEnlistedObject enlisted;
|
||||
if (enlistedObjects.TryGetValue(key, out enlisted) == false)
|
||||
return default (T);
|
||||
|
||||
var enlistedAs = enlisted as EnlistedObject<T>;
|
||||
if (enlistedAs == null) throw new InvalidOperationException("An item with the key exists, but with a different type.");
|
||||
return enlistedAs.Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
//TODO: In v8 we need to change this to use an int? nullable TKey instead, see notes against overridden TwoFactorSignInAsync
|
||||
public class BackOfficeSignInManager : SignInManager<BackOfficeIdentityUser, int>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
@@ -259,5 +260,67 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two factor verification step
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="code"></param>
|
||||
/// <param name="isPersistent"></param>
|
||||
/// <param name="rememberBrowser"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is implemented because we cannot override GetVerifiedUserIdAsync and instead we have to shadow it
|
||||
/// so due to this and because we are using an INT as the TKey and not an object, it can never be null. Adding to that
|
||||
/// the default(int) value returned by the base class is always a valid user (i.e. the admin) so we just have to duplicate
|
||||
/// all of this code to check for -1 instead.
|
||||
/// </remarks>
|
||||
public override async Task<SignInStatus> TwoFactorSignInAsync(string provider, string code, bool isPersistent, bool rememberBrowser)
|
||||
{
|
||||
var userId = await GetVerifiedUserIdAsync();
|
||||
if (userId == -1)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
var user = await UserManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
if (await UserManager.IsLockedOutAsync(user.Id))
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
}
|
||||
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, provider, code))
|
||||
{
|
||||
// When token is verified correctly, clear the access failed count used for lockout
|
||||
await UserManager.ResetAccessFailedCountAsync(user.Id);
|
||||
await SignInAsync(user, isPersistent, rememberBrowser);
|
||||
return SignInStatus.Success;
|
||||
}
|
||||
// If the token is incorrect, record the failure which also may cause the user to be locked out
|
||||
await UserManager.AccessFailedAsync(user.Id);
|
||||
return SignInStatus.Failure;
|
||||
}
|
||||
|
||||
/// <summary>Send a two factor code to a user</summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is implemented because we cannot override GetVerifiedUserIdAsync and instead we have to shadow it
|
||||
/// so due to this and because we are using an INT as the TKey and not an object, it can never be null. Adding to that
|
||||
/// the default(int) value returned by the base class is always a valid user (i.e. the admin) so we just have to duplicate
|
||||
/// all of this code to check for -1 instead.
|
||||
/// </remarks>
|
||||
public override async Task<bool> SendTwoFactorCodeAsync(string provider)
|
||||
{
|
||||
var userId = await GetVerifiedUserIdAsync();
|
||||
if (userId == -1)
|
||||
return false;
|
||||
|
||||
var token = await UserManager.GenerateTwoFactorTokenAsync(userId, provider);
|
||||
var identityResult = await UserManager.NotifyTwoFactorTokenAsync(userId, provider, token);
|
||||
return identityResult.Succeeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
return repository.CountPublished();
|
||||
return repository.CountPublished(contentTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -993,8 +993,7 @@ namespace Umbraco.Core.Services
|
||||
FROM umbracoNode
|
||||
JOIN cmsDocument ON umbracoNode.id=cmsDocument.nodeId AND cmsDocument.published=@0
|
||||
WHERE umbracoNode.trashed=@1 AND umbracoNode.id IN (@2)",
|
||||
true, false, ids);
|
||||
Console.WriteLine(sql.SQL);
|
||||
true, false, ids);
|
||||
var x = uow.Database.Fetch<int>(sql);
|
||||
return ids.Length == x.Count;
|
||||
}
|
||||
@@ -1345,6 +1344,40 @@ namespace Umbraco.Core.Services
|
||||
return content;
|
||||
}
|
||||
|
||||
public void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentBlueprintRepository(uow);
|
||||
|
||||
var contentTypeIdsA = contentTypeIds.ToArray();
|
||||
var query = new Query<IContent>();
|
||||
if (contentTypeIdsA.Length > 0)
|
||||
{
|
||||
query.Where(x => contentTypeIdsA.Contains(x.ContentTypeId));
|
||||
}
|
||||
var blueprints = repository.GetByQuery(query).Select(x =>
|
||||
{
|
||||
((Content) x).IsBlueprint = true;
|
||||
return x;
|
||||
}).ToArray();
|
||||
|
||||
foreach (var blueprint in blueprints)
|
||||
{
|
||||
repository.Delete(blueprint);
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(DeletedBlueprint, this, new DeleteEventArgs<IContent>(blueprints), "DeletedBlueprint");
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteBlueprintsOfType(int contentTypeId, int userId = 0)
|
||||
{
|
||||
DeleteBlueprintsOfTypes(new[] {contentTypeId}, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -2009,6 +2042,96 @@ namespace Umbraco.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
|
||||
/// to the ordering of node Ids passed in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using this method will ensure that the Published-state is maintained upon sorting
|
||||
/// so the cache is updated accordingly - as needed.
|
||||
/// </remarks>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
public bool Sort(int[] ids, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var shouldBePublished = new List<IContent>();
|
||||
var shouldBeSaved = new List<IContent>();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
|
||||
var items = ids.Select(x => allContent[x]);
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var asArray = items.ToArray();
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(asArray);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Commit();
|
||||
return false;
|
||||
}
|
||||
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
|
||||
var i = 0;
|
||||
foreach (var content in asArray)
|
||||
{
|
||||
//If the current sort order equals that of the content
|
||||
//we don't need to update it, so just increment the sort order
|
||||
//and continue.
|
||||
if (content.SortOrder == i)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
content.SortOrder = i;
|
||||
content.WriterId = userId;
|
||||
i++;
|
||||
|
||||
if (content.Published)
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
var published = _publishingStrategy.Publish(uow, content, userId).Success;
|
||||
shouldBePublished.Add(content);
|
||||
}
|
||||
else
|
||||
shouldBeSaved.Add(content);
|
||||
|
||||
repository.AddOrUpdate(content);
|
||||
//add or update a preview
|
||||
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
|
||||
}
|
||||
|
||||
foreach (var content in shouldBePublished)
|
||||
{
|
||||
//Create and Save ContentXml DTO
|
||||
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
|
||||
if (shouldBePublished.Any())
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
_publishingStrategy.PublishingFinalized(uow, shouldBePublished, false);
|
||||
}
|
||||
|
||||
Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<IContent> GetBlueprintsForContentTypes(params int[] documentTypeIds)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
@@ -2749,4 +2872,4 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ namespace Umbraco.Core.Services
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs);
|
||||
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs, "DeletedMediaTypeContainer");
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
@@ -920,7 +920,9 @@ namespace Umbraco.Core.Services
|
||||
var deletedContentTypes = new List<IContentType> { contentType };
|
||||
deletedContentTypes.AddRange(GetDescendants(contentType));
|
||||
|
||||
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
|
||||
var ids = deletedContentTypes.Select(x => x.Id).ToArray();
|
||||
_contentService.DeleteContentOfTypes(ids, userId);
|
||||
_contentService.DeleteBlueprintsOfTypes(ids);
|
||||
|
||||
repository.Delete(contentType);
|
||||
deleteEventArgs.DeletedEntities = deletedContentTypes.DistinctBy(x => x.Id);
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace Umbraco.Core.Services
|
||||
xml.Add(new XAttribute("writerID", content.WriterId));
|
||||
xml.Add(new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString(CultureInfo.InvariantCulture)));
|
||||
xml.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));
|
||||
xml.Add(new XAttribute("isPublished", content.Published));
|
||||
|
||||
if (deep)
|
||||
{
|
||||
|
||||
@@ -101,7 +101,9 @@ namespace Umbraco.Core.Services
|
||||
IContent GetBlueprintById(Guid id);
|
||||
void SaveBlueprint(IContent content, int userId = 0);
|
||||
void DeleteBlueprint(IContent content, int userId = 0);
|
||||
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
|
||||
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
|
||||
void DeleteBlueprintsOfType(int contentTypeId, int userId = 0);
|
||||
void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all XML entries found in the cmsContentXml table based on the given path
|
||||
@@ -642,7 +644,21 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
|
||||
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
|
||||
/// to the ordering of node Ids passed in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using this method will ensure that the Published-state is maintained upon sorting
|
||||
/// so the cache is updated accordingly - as needed.
|
||||
/// </remarks>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
bool Sort(int[] ids, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent of the current content as an <see cref="IContent"/> item.
|
||||
|
||||
@@ -106,8 +106,8 @@ namespace Umbraco.Core.Services
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
_id2Key[id] = new TypedId<Guid>(val.Value, umbracoObjectType); ;
|
||||
_key2Id[val.Value] = new TypedId<int>();
|
||||
_id2Key[id] = new TypedId<Guid>(val.Value, umbracoObjectType);
|
||||
_key2Id[val.Value] = new TypedId<int>(id, umbracoObjectType);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Services
|
||||
IQuery<IMember> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
|
||||
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter) || x.Email.Contains(filter));
|
||||
}
|
||||
|
||||
var repository = RepositoryFactory.CreateMemberRepository(uow);
|
||||
@@ -986,7 +986,11 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IMember entity, bool raiseEvents = true)
|
||||
{
|
||||
{
|
||||
//trimming username and email to make sure we have no trailing space
|
||||
entity.Username = entity.Username.Trim();
|
||||
entity.Email = entity.Email.Trim();
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(entity);
|
||||
|
||||
@@ -1748,9 +1748,10 @@ namespace Umbraco.Core.Services
|
||||
|
||||
internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false)
|
||||
{
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
{
|
||||
if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs<string>(packageFilePath, metaData), this))
|
||||
{
|
||||
var initEmpty = new InstallationSummary().InitEmpty();
|
||||
@@ -1762,7 +1763,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, false), this);
|
||||
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, metaData, false), this);
|
||||
}
|
||||
|
||||
return installationSummary;
|
||||
|
||||
@@ -228,9 +228,9 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IUser"/>
|
||||
/// Disables an <see cref="IUser"/>
|
||||
/// </summary>
|
||||
/// <param name="membershipUser"><see cref="IUser"/> to Delete</param>
|
||||
/// <param name="membershipUser"><see cref="IUser"/> to disable</param>
|
||||
public void Delete(IUser membershipUser)
|
||||
{
|
||||
//disable
|
||||
@@ -712,7 +712,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id">Id of the User to retrieve</param>
|
||||
/// <returns><see cref="IProfile"/></returns>
|
||||
public IProfile GetProfileById(int id)
|
||||
{
|
||||
{
|
||||
//This is called a TON. Go get the full user from cache which should already be IProfile
|
||||
var fullUser = GetUserById(id);
|
||||
var asProfile = fullUser as IProfile;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Strings
|
||||
{
|
||||
foreach (var node in _umbracoSettings.RequestHandler.CharCollection)
|
||||
{
|
||||
if(string.IsNullOrEmpty(node.Char) == false)
|
||||
if (string.IsNullOrEmpty(node.Char) == false)
|
||||
_urlReplaceCharacters[node.Char] = node.Replacement;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ namespace Umbraco.Core.Strings
|
||||
private void EnsureNotFrozen()
|
||||
{
|
||||
if (_frozen)
|
||||
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
|
||||
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,7 +176,7 @@ namespace Umbraco.Core.Strings
|
||||
}).WithConfig(CleanStringType.Alias, new Config
|
||||
{
|
||||
PreFilter = ApplyUrlReplaceCharacters,
|
||||
IsTerm = (c, leading) => leading
|
||||
IsTerm = (c, leading) => leading
|
||||
? char.IsLetter(c) // only letters
|
||||
: (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore
|
||||
StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase,
|
||||
@@ -215,12 +215,12 @@ namespace Umbraco.Core.Strings
|
||||
return new Config
|
||||
{
|
||||
PreFilter = PreFilter,
|
||||
PostFilter = PostFilter,
|
||||
PostFilter = PostFilter,
|
||||
IsTerm = IsTerm,
|
||||
StringType = StringType,
|
||||
BreakTermsOnUpper = BreakTermsOnUpper,
|
||||
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
|
||||
GreedyAcronyms = GreedyAcronyms,
|
||||
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
|
||||
GreedyAcronyms = GreedyAcronyms,
|
||||
Separator = Separator
|
||||
};
|
||||
}
|
||||
@@ -338,9 +338,9 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Gets the JavaScript code defining client-side short string services.
|
||||
/// </summary>
|
||||
public string GetShortStringServicesJavaScript(string controllerPath)
|
||||
{
|
||||
return string.Format(SssjsFormat,
|
||||
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
|
||||
{
|
||||
return string.Format(SssjsFormat,
|
||||
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -467,7 +467,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
/// <remarks>The string is cleaned in the context of the default culture.</remarks>
|
||||
@@ -480,7 +480,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string, using a specified separator.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
@@ -494,7 +494,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string in the context of a specified culture.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
@@ -507,7 +507,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string in the context of a specified culture, using a specified separator.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
@@ -554,7 +554,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
text = Utf8ToAsciiConverter.ToAsciiString(text);
|
||||
break;
|
||||
case CleanStringType.TryAscii:
|
||||
const char ESC = (char) 27;
|
||||
const char ESC = (char)27;
|
||||
var ctext = Utf8ToAsciiConverter.ToAsciiString(text, ESC);
|
||||
if (ctext.Contains(ESC) == false) text = ctext;
|
||||
break;
|
||||
@@ -568,8 +568,8 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
|
||||
// apply post-filter
|
||||
if (config.PostFilter != null)
|
||||
text = config.PostFilter(text);
|
||||
|
||||
text = config.PostFilter(text);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -839,7 +839,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
{
|
||||
term = term.Substring(i);
|
||||
term.CopyTo(0, output, opos, term.Length);
|
||||
opos += term.Length;
|
||||
opos += term.Length;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -914,21 +914,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// <returns>The filtered string.</returns>
|
||||
public virtual string ReplaceMany(string text, IDictionary<string, string> replacements)
|
||||
{
|
||||
// be safe
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException("text");
|
||||
}
|
||||
|
||||
if (replacements == null)
|
||||
{
|
||||
throw new ArgumentNullException("replacements");
|
||||
}
|
||||
|
||||
// Have done various tests, implementing my own "super fast" state machine to handle
|
||||
// replacement of many items, or via regexes, but on short strings and not too
|
||||
// many replacements (which prob. is going to be our case) nothing can beat this...
|
||||
// (at least with safe and checked code -- we don't want unsafe/unchecked here)
|
||||
foreach (KeyValuePair<string, string> item in replacements)
|
||||
{
|
||||
text = text.Replace(item.Key, item.Value);
|
||||
}
|
||||
|
||||
// Note that it will do chained-replacements ie replaced items can be replaced
|
||||
// in turn by another replacement (ie the order of replacements is important)
|
||||
|
||||
return replacements.Aggregate(text, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -940,15 +941,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// <returns>The filtered string.</returns>
|
||||
public virtual string ReplaceMany(string text, char[] chars, char replacement)
|
||||
{
|
||||
// be safe
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException("text");
|
||||
}
|
||||
|
||||
if (chars == null)
|
||||
{
|
||||
throw new ArgumentNullException("chars");
|
||||
}
|
||||
|
||||
// see note above
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
text = text.Replace(chars[i], replacement);
|
||||
}
|
||||
|
||||
return chars.Aggregate(text, (current, c) => current.Replace(c, replacement));
|
||||
return text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Web;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
@@ -46,8 +47,20 @@ namespace Umbraco.Core.Sync
|
||||
// settings: for unit tests only
|
||||
internal static void EnsureApplicationUrl(ApplicationContext appContext, HttpRequestBase request = null, IUmbracoSettingsSection settings = null)
|
||||
{
|
||||
bool newApplicationUrl = false;
|
||||
if (request != null)
|
||||
{
|
||||
var applicationUrl = GetApplicationUrlFromRequest(request);
|
||||
newApplicationUrl = !appContext._umbracoApplicationDomains.Contains(applicationUrl);
|
||||
if (newApplicationUrl)
|
||||
{
|
||||
appContext._umbracoApplicationDomains.Add(applicationUrl);
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), string.Format("New ApplicationUrl detected: {0}", applicationUrl));
|
||||
}
|
||||
}
|
||||
|
||||
// if initialized, return
|
||||
if (appContext._umbracoApplicationUrl != null) return;
|
||||
if (appContext._umbracoApplicationUrl != null && !newApplicationUrl) return;
|
||||
|
||||
var logger = appContext.ProfilingLogger.Logger;
|
||||
|
||||
@@ -132,6 +145,12 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
var logger = appContext.ProfilingLogger.Logger;
|
||||
|
||||
appContext._umbracoApplicationUrl = GetApplicationUrlFromRequest(request);
|
||||
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
|
||||
}
|
||||
|
||||
private static string GetApplicationUrlFromRequest(HttpRequestBase request)
|
||||
{
|
||||
// if (HTTP and SSL not required) or (HTTPS and SSL required),
|
||||
// use ports from request
|
||||
// otherwise,
|
||||
@@ -147,8 +166,7 @@ namespace Umbraco.Core.Sync
|
||||
var ssl = useSsl ? "s" : ""; // force, whatever the first request
|
||||
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
|
||||
|
||||
appContext._umbracoApplicationUrl = url.TrimEnd('/');
|
||||
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
|
||||
return url.TrimEnd('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -21,6 +20,38 @@ namespace Umbraco.Core
|
||||
{
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private static readonly object LocalFilteredAssemblyCacheLocker = new object();
|
||||
private static readonly List<string> NotifiedLoadExceptionAssemblies = new List<string>();
|
||||
private static string[] _assembliesAcceptingLoadExceptions;
|
||||
|
||||
private static string[] AssembliesAcceptingLoadExceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_assembliesAcceptingLoadExceptions != null)
|
||||
return _assembliesAcceptingLoadExceptions;
|
||||
|
||||
var s = ConfigurationManager.AppSettings["Umbraco.AssembliesAcceptingLoadExceptions"];
|
||||
return _assembliesAcceptingLoadExceptions = string.IsNullOrWhiteSpace(s)
|
||||
? new string[0]
|
||||
: s.Split(',').Select(x => x.Trim()).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AcceptsLoadExceptions(Assembly a)
|
||||
{
|
||||
if (AssembliesAcceptingLoadExceptions.Length == 0)
|
||||
return false;
|
||||
if (AssembliesAcceptingLoadExceptions.Length == 1 && AssembliesAcceptingLoadExceptions[0] == "*")
|
||||
return true;
|
||||
var name = a.GetName().Name; // simple name of the assembly
|
||||
return AssembliesAcceptingLoadExceptions.Any(pattern =>
|
||||
{
|
||||
if (pattern.Length > name.Length) return false; // pattern longer than name
|
||||
if (pattern.Length == name.Length) return pattern.InvariantEquals(name); // same length, must be identical
|
||||
if (pattern[pattern.Length] != '.') return false; // pattern is shorter than name, must end with dot
|
||||
return name.StartsWith(pattern); // and name must start with pattern
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
@@ -45,7 +76,7 @@ namespace Umbraco.Core
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null || HostingEnvironment.IsHosted;
|
||||
var isHosted = IOHelper.IsHosted;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -528,9 +559,22 @@ namespace Umbraco.Core
|
||||
AppendCouldNotLoad(sb, a, getAll);
|
||||
foreach (var loaderException in rex.LoaderExceptions.WhereNotNull())
|
||||
AppendLoaderException(sb, loaderException);
|
||||
|
||||
var ex = new ReflectionTypeLoadException(rex.Types, rex.LoaderExceptions, sb.ToString());
|
||||
|
||||
// rethrow with new message
|
||||
throw new ReflectionTypeLoadException(rex.Types, rex.LoaderExceptions, sb.ToString());
|
||||
// rethrow with new message, unless accepted
|
||||
if (AcceptsLoadExceptions(a) == false) throw ex;
|
||||
|
||||
// log a warning, and return what we can
|
||||
lock (NotifiedLoadExceptionAssemblies)
|
||||
{
|
||||
if (NotifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
|
||||
{
|
||||
NotifiedLoadExceptionAssemblies.Add(a.FullName);
|
||||
LogHelper.WarnWithException(typeof(TypeFinder), "Could not load all types from " + a.GetName().Name + ".", ex);
|
||||
}
|
||||
}
|
||||
return rex.Types.WhereNotNull().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
return Document;
|
||||
case UmbracoObjectTypes.DocumentBlueprint:
|
||||
return DocumentBluePrint;
|
||||
case UmbracoObjectTypes.Media:
|
||||
return Media;
|
||||
case UmbracoObjectTypes.Member:
|
||||
@@ -161,6 +163,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
case Document:
|
||||
return UmbracoObjectTypes.Document;
|
||||
case DocumentBluePrint:
|
||||
return UmbracoObjectTypes.DocumentBlueprint;
|
||||
case Media:
|
||||
return UmbracoObjectTypes.Media;
|
||||
case Member:
|
||||
|
||||
@@ -39,25 +39,21 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.6\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.5.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.3\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||
@@ -67,11 +63,9 @@
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Owin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
@@ -87,17 +81,16 @@
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\semver.1.1.2\lib\net45\Semver.dll</HintPath>
|
||||
@@ -109,11 +102,9 @@
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -366,6 +357,7 @@
|
||||
<Compile Include="HashGenerator.cs" />
|
||||
<Compile Include="IEmailSender.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
|
||||
<Compile Include="Models\EntityBase\EntityPath.cs" />
|
||||
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
|
||||
<Compile Include="Models\IUserControl.cs" />
|
||||
@@ -1539,6 +1531,7 @@
|
||||
<Compile Include="ReadLock.cs" />
|
||||
<Compile Include="TypeFinder.cs" />
|
||||
<Compile Include="TypeHelper.cs" />
|
||||
<Compile Include="Collections\CompositeTypeTypeKey.cs" />
|
||||
<Compile Include="Udi.cs" />
|
||||
<Compile Include="UdiDefinitionAttribute.cs" />
|
||||
<Compile Include="UdiEntityType.cs" />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.6" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.3" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net45" />
|
||||
<package id="Log4Net.Async" version="2.0.4" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
|
||||
@@ -3,43 +3,24 @@ using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using ILogger = Umbraco.Core.Logging.ILogger;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class BulkInsertBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
//Add(ExecutionValidator.FailOnError);
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] _initDbBytes = null;
|
||||
|
||||
[Setup]
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var logger = new DebugDiagnosticsLogger();
|
||||
@@ -51,8 +32,8 @@ namespace Umbraco.Tests.Benchmarks
|
||||
SetupSqlCe(path, logger);
|
||||
SetupSqlServer(logger);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void SetupSqlServer(ILogger logger)
|
||||
{
|
||||
@@ -75,7 +56,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
[lastNotifiedDate] [datetime] NOT NULL,
|
||||
[isActive] [bit] NOT NULL,
|
||||
[isMaster] [bit] NOT NULL,
|
||||
CONSTRAINT [PK_umbracoServer] PRIMARY KEY CLUSTERED
|
||||
CONSTRAINT [PK_umbracoServer] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
@@ -87,7 +68,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var dbName = string.Concat("Umb", Guid.NewGuid(), ".sdf");
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", path);
|
||||
var sqlCeConnectionString = $"Datasource=|DataDirectory|\\{dbName};Flush Interval=1;";
|
||||
|
||||
|
||||
_dbFile = Path.Combine(path, dbName);
|
||||
|
||||
//only create the db one time
|
||||
@@ -107,12 +88,12 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var creation = new DatabaseSchemaCreation(_dbSqlCe, logger, _sqlCeSyntax);
|
||||
creation.InitializeDatabaseSchema();
|
||||
}
|
||||
_initDbBytes = File.ReadAllBytes(_dbFile);
|
||||
_initDbBytes = File.ReadAllBytes(_dbFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllBytes(_dbFile, _initDbBytes);
|
||||
}
|
||||
}
|
||||
|
||||
//create the db
|
||||
_dbSqlCe = new UmbracoDatabase(
|
||||
@@ -138,7 +119,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
return data;
|
||||
}
|
||||
|
||||
[Cleanup]
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_dbSqlCe.Dispose();
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Collections;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class ConcurrentDictionaryBenchmarks
|
||||
{
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, bool> AssignableTypeCache = new ConcurrentDictionary<CompositeTypeTypeKey, bool>();
|
||||
|
||||
private static object input = new Bar();
|
||||
|
||||
private static Type source = typeof(Bar);
|
||||
|
||||
private static Type target = typeof(Foo);
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public bool GetCachedCanAssignFactory()
|
||||
{
|
||||
return AssignableTypeCache.GetOrAdd(new CompositeTypeTypeKey(source, target), k =>
|
||||
{
|
||||
var ksource = k.Type1;
|
||||
var ktarget = k.Type2;
|
||||
|
||||
return ktarget.IsAssignableFrom(ksource) && typeof(IConvertible).IsAssignableFrom(ksource);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public bool GetCachedCanAssignNoFactory()
|
||||
{
|
||||
// This method is 10% faster
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
bool canConvert;
|
||||
if (AssignableTypeCache.TryGetValue(key, out canConvert))
|
||||
{
|
||||
return canConvert;
|
||||
}
|
||||
|
||||
// "is" is faster than "IsAssignableFrom"
|
||||
if (input is IConvertible && target.IsAssignableFrom(source))
|
||||
{
|
||||
return AssignableTypeCache[key] = true;
|
||||
}
|
||||
|
||||
return AssignableTypeCache[key] = false;
|
||||
}
|
||||
|
||||
private class Foo : IConvertible
|
||||
{
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return TypeCode.Object;
|
||||
}
|
||||
|
||||
public bool ToBoolean(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte ToByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public char ToChar(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DateTime ToDateTime(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public decimal ToDecimal(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public double ToDouble(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public short ToInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int ToInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public long ToInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public sbyte ToSByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public float ToSingle(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object ToType(Type conversionType, IFormatProvider provider)
|
||||
{
|
||||
if (conversionType == typeof(Foo))
|
||||
{
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ushort ToUInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public uint ToUInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ulong ToUInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class Bar : Foo
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the benchmark to run with less warmup and a shorter iteration time than the standard benchmark.
|
||||
/// </summary>
|
||||
public class QuickRunConfigAttribute : Attribute, IConfigSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuickRunConfigAttribute"/> class.
|
||||
/// </summary>
|
||||
public QuickRunConfigAttribute()
|
||||
{
|
||||
Config = (ManualConfig) ManualConfig.CreateEmpty()
|
||||
.With(Job.Default.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(new TimeInterval(100, TimeUnit.Millisecond)) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the manual configuration.
|
||||
/// </summary>
|
||||
protected ManualConfig Config { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
IConfig IConfigSource.Config => Config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the benchmark to run with less warmup and a shorter iteration time than the standard benchmark,
|
||||
/// and include memory usage diagnosis.
|
||||
/// </summary>
|
||||
public class QuickRunWithMemoryDiagnoserConfigAttribute : QuickRunConfigAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuickRunWithMemoryDiagnoserConfigAttribute"/> class.
|
||||
/// </summary>
|
||||
public QuickRunWithMemoryDiagnoserConfigAttribute()
|
||||
{
|
||||
Config.Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
/// <summary>
|
||||
/// Want to check what is faster OfType or Cast when a enurable all has the same items
|
||||
/// </summary>
|
||||
[Config(typeof(Config))]
|
||||
[MemoryDiagnoser]
|
||||
public class LinqCastBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
|
||||
public LinqCastBenchmarks()
|
||||
{
|
||||
_array = new List<object>();
|
||||
|
||||
@@ -1,47 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Validators;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using ILogger = Umbraco.Core.Logging.ILogger;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[MemoryDiagnoser]
|
||||
public class ModelToSqlExpressionHelperBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
|
||||
public ModelToSqlExpressionHelperBenchmarks()
|
||||
{
|
||||
var contentMapper = new ContentMapper(_syntaxProvider);
|
||||
@@ -51,7 +23,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
mappingResolver.Setup(resolver => resolver.ResolveMapperByType(It.IsAny<Type>())).Returns(contentMapper);
|
||||
_mappingResolver = mappingResolver.Object;
|
||||
}
|
||||
|
||||
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlCeSyntaxProvider();
|
||||
private readonly CachedExpression _cachedExpression;
|
||||
private readonly MappingResolver _mappingResolver;
|
||||
@@ -62,18 +34,15 @@ namespace Umbraco.Tests.Benchmarks
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
var a = i;
|
||||
var b = i*10;
|
||||
var b = i * 10;
|
||||
Expression<Func<IContent, bool>> predicate = content =>
|
||||
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
|
||||
|
||||
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
|
||||
var result = modelToSqlExpressionHelper.Visit(predicate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Benchmark()]
|
||||
public void WithCachedExpression()
|
||||
{
|
||||
@@ -83,7 +52,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var b = i * 10;
|
||||
Expression<Func<IContent, bool>> predicate = content =>
|
||||
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
|
||||
|
||||
|
||||
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
|
||||
|
||||
//wrap it!
|
||||
@@ -92,6 +61,5 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var result = modelToSqlExpressionHelper.Visit(_cachedExpression);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var switcher = new BenchmarkSwitcher(new[]
|
||||
{
|
||||
typeof(BulkInsertBenchmarks),
|
||||
typeof(ModelToSqlExpressionHelperBenchmarks),
|
||||
typeof(XmlBenchmarks),
|
||||
typeof(LinqCastBenchmarks),
|
||||
//typeof(DeepCloneBenchmarks),
|
||||
typeof(XmlPublishedContentInitBenchmarks),
|
||||
|
||||
});
|
||||
switcher.Run(args);
|
||||
new BenchmarkSwitcher(typeof(Program).Assembly).Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class StringReplaceManyBenchmarks
|
||||
{
|
||||
/*
|
||||
|
||||
short text, short replacement:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |---------:|----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 236.0 ns | 40.92 ns | 2.312 ns | 1.00 | 0.00 | 0.0461 | 200 B |
|
||||
'String.ReplaceMany w/chars - For Loop' | 166.7 ns | 70.51 ns | 3.984 ns | 0.71 | 0.01 | 0.0420 | 180 B |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 606.5 ns | 342.94 ns | 19.377 ns | 2.57 | 0.07 | 0.0473 | 212 B |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 571.8 ns | 232.33 ns | 13.127 ns | 2.42 | 0.05 | 0.0458 | 212 B |
|
||||
|
||||
long text, short replacement:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |----------:|----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 5.771 us | 9.963 us | 0.5630 us | 1.00 | 0.00 | 1.6798 | 6.94 KB |
|
||||
'String.ReplaceMany w/chars - For Loop' | 4.962 us | 2.121 us | 0.1199 us | 0.87 | 0.08 | 1.6840 | 6.92 KB |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 14.514 us | 8.189 us | 0.4627 us | 2.53 | 0.22 | 1.6447 | 6.96 KB |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 15.445 us | 24.745 us | 1.3981 us | 2.69 | 0.30 | 1.5696 | 6.96 KB |
|
||||
|
||||
short text, long replacements dictionary:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 257.0 ns | 200.0 ns | 11.30 ns | 1.00 | 0.00 | 0.0452 | 200 B |
|
||||
'String.ReplaceMany w/chars - For Loop' | 182.4 ns | 221.0 ns | 12.49 ns | 0.71 | 0.05 | 0.0425 | 180 B |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 7,273.8 ns | 2,747.1 ns | 155.22 ns | 28.34 | 1.12 | 0.0714 | 464 B |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 6,981.0 ns | 5,500.7 ns | 310.80 ns | 27.20 | 1.38 | 0.0775 | 464 B |
|
||||
|
||||
long text, long replacements dictionary:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |-----------:|-----------:|-----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 4.868 us | 3.420 us | 0.1932 us | 1.00 | 0.00 | 1.6816 | 6.94 KB |
|
||||
'String.ReplaceMany w/chars - For Loop' | 4.958 us | 2.633 us | 0.1487 us | 1.02 | 0.04 | 1.6791 | 6.92 KB |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 181.309 us | 210.177 us | 11.8754 us | 37.29 | 2.32 | 5.3571 | 24.28 KB |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 174.567 us | 113.733 us | 6.4262 us | 35.90 | 1.57 | 5.8594 | 24.28 KB |
|
||||
|
||||
*/
|
||||
|
||||
// don't use constants
|
||||
// ReSharper disable ConvertToConstant.Local
|
||||
|
||||
// input text for ReplaceMany
|
||||
private static readonly string Text;
|
||||
|
||||
// replaced chars for ReplaceMany with chars
|
||||
private static readonly char[] ReplacedChars = { ',', '.', ':', '&', '#' };
|
||||
|
||||
// replacement char for ReplaceMany with chars
|
||||
private static readonly char ReplacementChar = '*';
|
||||
|
||||
// replacements for ReplaceMany with dictionary
|
||||
private static readonly IDictionary<string, string> Replacements;
|
||||
|
||||
// ReSharper restore ConvertToConstant.Local
|
||||
|
||||
static StringReplaceManyBenchmarks()
|
||||
{
|
||||
// pick what you want to benchmark
|
||||
|
||||
// short
|
||||
Text = "1,2.3:4&5#6";
|
||||
|
||||
// long
|
||||
//Text = "Sed ut perspiciatis unde omnis iste natus &error sit voluptatem accusantium doloremque l:audantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et &quasi architecto beatae vitae ::dicta sunt explicabo. Nemo enim ipsam volupta:tem quia voluptas sit aspernatur aut o&dit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciun&t. Neque porro quisquam est, qui dolorem: ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut e:nim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi co&&nsequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse: quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?";
|
||||
|
||||
// short
|
||||
Replacements = new Dictionary<string, string>
|
||||
{
|
||||
{ ",", "*" },
|
||||
{ ".", "*" },
|
||||
{ ":", "*" },
|
||||
{ "&", "*" },
|
||||
{ "#", "*" },
|
||||
};
|
||||
|
||||
// long
|
||||
//Replacements = new Dictionary<string, string>();
|
||||
//for (var i = 2; i < 100; i++)
|
||||
// Replacements[Convert.ToChar(i).ToString()] = "*";
|
||||
}
|
||||
|
||||
// this is what v7 originally did
|
||||
[Benchmark(Description = "String.ReplaceMany w/chars - Aggregate", Baseline = true)]
|
||||
public string ReplaceManyAggregate()
|
||||
{
|
||||
var result = Text;
|
||||
return ReplacedChars.Aggregate(result, (current, c) => current.Replace(c, ReplacementChar));
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String.ReplaceMany w/chars - For Loop")]
|
||||
public string ReplaceManyForLoop()
|
||||
{
|
||||
var result = Text;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
// ReSharper disable once ForCanBeConvertedToForeach
|
||||
for (var i = 0; i < ReplacedChars.Length; i++)
|
||||
{
|
||||
result = result.Replace(ReplacedChars[i], ReplacementChar);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// this is what v7 originally did
|
||||
[Benchmark(Description = "String.ReplaceMany w/dictionary - Aggregate")]
|
||||
public string ReplaceManyDictionaryAggregate()
|
||||
{
|
||||
return Replacements.Aggregate(Text, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String.ReplaceMany w/dictionary - For Each")]
|
||||
public string ReplaceManyDictionaryForEach()
|
||||
{
|
||||
var result = Text;
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var item in Replacements)
|
||||
{
|
||||
result = result.Replace(item.Key, item.Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class TryConvertToBenchmarks
|
||||
{
|
||||
private static readonly List<string> List = new List<string>() { "hello", "world", "awesome" };
|
||||
private static readonly string Date = "Saturday 10, November 2012";
|
||||
|
||||
[Benchmark(Description = "List<string> to IEnumerable<string>")]
|
||||
public IEnumerable<string> TryConvertToEnumerable()
|
||||
{
|
||||
return List.TryConvertTo<IEnumerable<string>>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "Int to Double")]
|
||||
public double TryConvertToDouble()
|
||||
{
|
||||
return 1.TryConvertTo<double>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "Float to Decimal")]
|
||||
public decimal TryConvertToDecimal()
|
||||
{
|
||||
return 1F.TryConvertTo<decimal>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String to Boolean")]
|
||||
public bool TryConvertToBoolean()
|
||||
{
|
||||
return "1".TryConvertTo<bool>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String to DateTime")]
|
||||
public DateTime TryConvertToDateTime()
|
||||
{
|
||||
return Date.TryConvertTo<DateTime>().Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Umbraco.Tests.Benchmarks</RootNamespace>
|
||||
<AssemblyName>Umbraco.Tests.Benchmarks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -38,84 +39,147 @@
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.10.12\lib\net46\BenchmarkDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.10.12\lib\net46\BenchmarkDotNet.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Diagnostics.Windows, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.12\lib\net46\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.DotNet.InternalAbstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.DotNet.InternalAbstractions.1.0.0\lib\net451\Microsoft.DotNet.InternalAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.DotNet.PlatformAbstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.DotNet.PlatformAbstractions.1.1.1\lib\net451\Microsoft.DotNet.PlatformAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Win32.Registry, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Win32.Registry.4.3.0\lib\net46\Microsoft.Win32.Registry.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.1.1309.919, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.FileVersionInfo, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.StackTrace, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net46\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net46\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encoding.CodePages, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XmlDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath.XDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConcurrentDictionaryBenchmarks.cs" />
|
||||
<Compile Include="Config\QuickRunConfigAttribute.cs" />
|
||||
<Compile Include="Config\QuickRunWithMemoryDiagnoserConfigAttribute.cs" />
|
||||
<Compile Include="LinqCastBenchmarks.cs" />
|
||||
<Compile Include="ModelToSqlExpressionHelperBenchmarks.cs" />
|
||||
<Compile Include="BulkInsertBenchmarks.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="StringReplaceManyBenchmarks.cs" />
|
||||
<Compile Include="TryConvertToBenchmarks.cs" />
|
||||
<Compile Include="XmlBenchmarks.cs" />
|
||||
<Compile Include="XmlPublishedContentInitBenchmarks.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
@@ -131,10 +195,6 @@
|
||||
<Name>Umbraco.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
|
||||
@@ -1,42 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class XmlBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
//Add(ExecutionValidator.FailOnError);
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
[Setup]
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var templateId = 0;
|
||||
var xmlText = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<!DOCTYPE root[
|
||||
<!DOCTYPE root[
|
||||
<!ELEMENT Home ANY>
|
||||
<!ATTLIST Home id ID #REQUIRED>
|
||||
<!ELEMENT CustomDocument ANY>
|
||||
@@ -49,7 +26,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
<umbracoNaviHide>1</umbracoNaviHide>
|
||||
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
|
||||
<content><![CDATA[<div>This is some content</div>]]></content>
|
||||
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
|
||||
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
|
||||
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
|
||||
<content><![CDATA[]]></content>
|
||||
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
|
||||
@@ -70,7 +47,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
_xml.LoadXml(xmlText);
|
||||
}
|
||||
|
||||
[Cleanup]
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_xml = null;
|
||||
@@ -90,7 +67,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
public void XmlWithNavigation()
|
||||
{
|
||||
var elt = _xml.DocumentElement;
|
||||
var id = NavigateElementRoute(elt, new[] {"home", "sub1", "sub2"});
|
||||
var id = NavigateElementRoute(elt, new[] { "home", "sub1", "sub2" });
|
||||
if (id <= 0) Console.WriteLine("ERR");
|
||||
}
|
||||
|
||||
@@ -120,4 +97,4 @@ namespace Umbraco.Tests.Benchmarks
|
||||
return found ? int.Parse(elt.GetAttribute("id")) : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,37 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class XmlPublishedContentInitBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
public XmlPublishedContentInitBenchmarks()
|
||||
{
|
||||
_xml10 = Build(10);
|
||||
@@ -281,7 +261,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var nodes = xmlNode.SelectNodes(dataXPath);
|
||||
|
||||
contentType = GetPublishedContentType(PublishedItemType.Content, docTypeAlias);
|
||||
|
||||
|
||||
var propertyNodes = new Dictionary<string, XmlNode>();
|
||||
if (nodes != null)
|
||||
foreach (XmlNode n in nodes)
|
||||
@@ -307,8 +287,8 @@ namespace Umbraco.Tests.Benchmarks
|
||||
|
||||
private static PublishedContentType GetPublishedContentType(PublishedItemType type, string alias)
|
||||
{
|
||||
return new PublishedContentType(alias, new string[] {},
|
||||
new List<PublishedPropertyType>(Enumerable.Range(0, 10).Select(x => new PublishedPropertyType("prop" + x, 0, "test", initConverters:false))));
|
||||
return new PublishedContentType(alias, new string[] { },
|
||||
new List<PublishedPropertyType>(Enumerable.Range(0, 10).Select(x => new PublishedPropertyType("prop" + x, 0, "test", initConverters: false))));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845dcd8080cc91" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
|
||||
</dependentAssembly>
|
||||
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
@@ -27,6 +30,10 @@
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
@@ -36,45 +43,25 @@
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
<assemblyIdentity name="BenchmarkDotNet.Core" publicKeyToken="aa0ca2f9092cefc4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.10.12.0" newVersion="0.10.12.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
|
||||
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
|
||||
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
</configuration>
|
||||
@@ -1,40 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BenchmarkDotNet" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Core" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet" version="0.10.12" targetFramework="net46" />
|
||||
<package id="BenchmarkDotNet.Core" version="0.10.12" targetFramework="net46" />
|
||||
<package id="BenchmarkDotNet.Diagnostics.Windows" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Toolchains.Roslyn" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Toolchains.Roslyn" version="0.10.12" targetFramework="net46" />
|
||||
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp" version="1.3.2" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net46" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net46" />
|
||||
<package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="1.0.41" targetFramework="net45" />
|
||||
<package id="Microsoft.DotNet.InternalAbstractions" version="1.0.0" targetFramework="net46" />
|
||||
<package id="Microsoft.DotNet.PlatformAbstractions" version="1.1.1" targetFramework="net46" />
|
||||
<package id="Microsoft.SqlServer.Compact" version="4.0.8854.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Win32.Registry" version="4.3.0" targetFramework="net46" />
|
||||
<package id="Moq" version="4.1.1309.0919" targetFramework="net45" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
<package id="System.Collections" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net45" />
|
||||
<package id="System.Collections.Immutable" version="1.2.0" targetFramework="net45" />
|
||||
<package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Diagnostics.Tools" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Dynamic.Runtime" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Globalization" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Linq" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Linq.Expressions" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Reflection" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Reflection.Metadata" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections.Immutable" version="1.3.1" targetFramework="net46" />
|
||||
<package id="System.Console" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Globalization" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net46" />
|
||||
<package id="System.Reflection.Primitives" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Runtime" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.Extensions" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.InteropServices" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.Numerics" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Text.Encoding" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.0.0" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks.Parallel" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.ValueTuple" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XmlSerializer" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XPath" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net46" />
|
||||
</packages>
|
||||
@@ -6,6 +6,10 @@ using System.Threading;
|
||||
using System.Web.UI.WebControls;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
@@ -155,16 +159,151 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual("Hello world", result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public virtual void CanConvertObjectToSameObject()
|
||||
{
|
||||
var obj = new MyTestObject();
|
||||
var result = obj.TryConvertTo<object>();
|
||||
|
||||
Assert.AreEqual(obj, result.Result);
|
||||
Assert.AreEqual(obj, result.Result);
|
||||
}
|
||||
|
||||
private CultureInfo savedCulture;
|
||||
|
||||
[Test]
|
||||
public void ConvertToIntegerTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = "100.001".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = 100.001m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToNullableDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToNullableDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type()
|
||||
{
|
||||
var valueEditor = new PropertyValueEditor
|
||||
{
|
||||
ValueType = PropertyEditorValueTypes.Decimal
|
||||
};
|
||||
|
||||
var result = valueEditor.TryConvertValueToCrlType(12.34d);
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(12.34d, result.Result);
|
||||
}
|
||||
|
||||
private CultureInfo _savedCulture;
|
||||
|
||||
/// <summary>
|
||||
/// Run once before each test in derived test fixtures.
|
||||
@@ -172,10 +311,13 @@ namespace Umbraco.Tests
|
||||
[SetUp]
|
||||
public void TestSetup()
|
||||
{
|
||||
savedCulture = Thread.CurrentThread.CurrentCulture;
|
||||
_savedCulture = Thread.CurrentThread.CurrentCulture;
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); // make sure the dates parse correctly
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = SettingsForTests.GetDefault();
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run once after each test in derived test fixtures.
|
||||
@@ -183,9 +325,9 @@ namespace Umbraco.Tests
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = savedCulture;
|
||||
return;
|
||||
}
|
||||
Thread.CurrentThread.CurrentCulture = _savedCulture;
|
||||
ShortStringHelperResolver.Reset();
|
||||
}
|
||||
|
||||
private class MyTestObject
|
||||
{
|
||||
@@ -195,4 +337,4 @@ namespace Umbraco.Tests
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +332,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var contentType = (IContentType)MockedContentTypes.CreateSimpleContentType2("test", "Test", propertyGroupName: "testGroup");
|
||||
|
||||
Assert.AreEqual(4, contentType.PropertyTypes.Count());
|
||||
|
||||
// remove all templates - since they are not saved, they would break the (wtf) mapping code
|
||||
contentType.AllowedTemplates = new ITemplate[0];
|
||||
|
||||
// there is NO mapping from display to contentType, but only from save
|
||||
// to contentType, so if we want to test, let's to it properly!
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
[TestCase("Alpha (10)", "Alpha (2)", +1)] // this is the real stuff
|
||||
[TestCase("Kilo", "Golf (2)", +1)]
|
||||
[TestCase("Kilo (1)", "Golf (2)", +1)]
|
||||
public void ComparerTest(string name1, string name2, int expected)
|
||||
[TestCase("", "", 0)]
|
||||
[TestCase(null, null, 0)]
|
||||
public void ComparerTest(string name1, string name2, int expected)
|
||||
{
|
||||
var comparer = new SimilarNodeName.Comparer();
|
||||
|
||||
@@ -76,7 +78,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
[TestCase(0, "Alpha", "Alpha (3)")]
|
||||
[TestCase(0, "Kilo (1)", "Kilo (1) (1)")] // though... we might consider "Kilo (2)"
|
||||
[TestCase(6, "Kilo (1)", "Kilo (1)")] // because of the id
|
||||
public void Test(int nodeId, string nodeName, string expected)
|
||||
[TestCase(0, "", " (1)")]
|
||||
[TestCase(0, null, " (1)")]
|
||||
public void Test(int nodeId, string nodeName, string expected)
|
||||
{
|
||||
var names = new[]
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropData_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
var index = 0;
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropFocalPoint_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.FocalPoint.Left, d.FocalPoint.Left);
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropDataSet_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.Src, d.Src);
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropDataSet_Methods_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.HasCrop("thumb"), d.HasCrop("thumb"));
|
||||
@@ -108,7 +108,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
public void CanConvertImageCropperDataSetSrcToString()
|
||||
{
|
||||
//cropperJson3 - has not crops
|
||||
var sourceObj = cropperJson3.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson3.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<string>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.AreEqual(destObj.Result, "/media/1005/img_0672.jpg");
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
public void CanConvertImageCropperDataSetJObject()
|
||||
{
|
||||
//cropperJson3 - has not crops
|
||||
var sourceObj = cropperJson3.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson3.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<JObject>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.AreEqual(sourceObj, destObj.Result.ToObject<ImageCropDataSet>());
|
||||
@@ -127,7 +127,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void CanConvertImageCropperDataSetJsonToString()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<string>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.IsTrue(destObj.Result.DetectIsJson());
|
||||
@@ -150,7 +150,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
var converter = new Umbraco.Web.PropertyEditors.ValueConverters.ImageCropperValueConverter(dataTypeService.Object);
|
||||
var result = converter.ConvertDataToSource(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion
|
||||
|
||||
var resultShouldMatch = val2.SerializeToCropDataSet();
|
||||
var resultShouldMatch = val2.DeserializeToCropDataSet();
|
||||
if (expected)
|
||||
{
|
||||
Assert.AreEqual(resultShouldMatch, result);
|
||||
@@ -220,7 +220,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetBaseCropUrlFromModelTest()
|
||||
{
|
||||
var cropDataSet = cropperJson1.SerializeToCropDataSet();
|
||||
var cropDataSet = cropperJson1.DeserializeToCropDataSet();
|
||||
var urlString = cropDataSet.GetCropUrl("thumb");
|
||||
Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.businesslogic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
@@ -99,7 +102,7 @@ namespace Umbraco.Tests.Scoping
|
||||
DoDeleteForContent += OnDoThingFail;
|
||||
DoForTestArgs += OnDoThingFail;
|
||||
DoForTestArgs2 += OnDoThingFail;
|
||||
|
||||
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
|
||||
var content1 = MockedContent.CreateBasicContent(contentType);
|
||||
@@ -114,10 +117,10 @@ namespace Umbraco.Tests.Scoping
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
|
||||
|
||||
//content1 will be filtered from the args
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(new[]{ content1 , content3}));
|
||||
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1));
|
||||
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1), "DoDeleteForContent");
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
|
||||
//this entire event will be filtered
|
||||
scope.Events.Dispatch(DoForTestArgs, this, new TestEventArgs(content1));
|
||||
@@ -141,15 +144,36 @@ namespace Umbraco.Tests.Scoping
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SupersededEvents2()
|
||||
{
|
||||
var contentService = Mock.Of<IContentService>();
|
||||
var content = Mock.Of<IContent>();
|
||||
var l1 = new List<IEventDefinition>
|
||||
{
|
||||
new EventDefinition<IContentService, PublishEventArgs<IContent>>(Test_UnPublished, contentService, new PublishEventArgs<IContent>(new [] { content }), "UnPublished"),
|
||||
new EventDefinition<IContentService, DeleteEventArgs<IContent>>(Test_Deleted, contentService, new DeleteEventArgs<IContent>(new [] { content }), "Deleted")
|
||||
};
|
||||
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
|
||||
foreach (var e in l1)
|
||||
l2.Add(e);
|
||||
|
||||
var l3 = ScopeEventDispatcherBase.FilterSupersededAndUpdateToLatestEntity(l2);
|
||||
|
||||
// see U4-10764
|
||||
Assert.AreEqual(2, l3.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will test that when we track events that before we Get the events we normalize all of the
|
||||
/// event entities to be the latest one (most current) found amongst the event so that there is
|
||||
/// event entities to be the latest one (most current) found amongst the event so that there is
|
||||
/// no 'stale' entities in any of the args
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void LatestEntities()
|
||||
{
|
||||
DoSaveForContent += OnDoThingFail;
|
||||
DoSaveForContent += OnDoThingFail;
|
||||
|
||||
var now = DateTime.Now;
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
@@ -165,7 +189,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
{
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
|
||||
@@ -173,7 +197,7 @@ namespace Umbraco.Tests.Scoping
|
||||
// events have been queued
|
||||
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
|
||||
Assert.AreEqual(3, events.Length);
|
||||
|
||||
|
||||
foreach (var t in events)
|
||||
{
|
||||
var args = (SaveEventArgs<IContent>)t.Args;
|
||||
@@ -212,7 +236,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
// events have been queued
|
||||
var events = scope.Events.GetEvents(EventDefinitionFilter.FirstIn).ToArray();
|
||||
Assert.AreEqual(1, events.Length);
|
||||
Assert.AreEqual(1, events.Length);
|
||||
Assert.AreEqual(content1, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First());
|
||||
Assert.IsTrue(object.ReferenceEquals(content1, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First()));
|
||||
Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First().UpdateDate);
|
||||
@@ -350,6 +374,9 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
|
||||
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Test_UnPublished;
|
||||
public static event TypedEventHandler<IContentService, DeleteEventArgs<IContent>> Test_Deleted;
|
||||
|
||||
public class TestEventArgs : CancellableObjectEventArgs
|
||||
{
|
||||
public TestEventArgs(object eventObject) : base(eventObject)
|
||||
|
||||
@@ -388,13 +388,12 @@ namespace Umbraco.Tests.TestHelpers
|
||||
return ctx;
|
||||
}
|
||||
|
||||
protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null)
|
||||
protected virtual FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null)
|
||||
{
|
||||
var factory = routeData != null
|
||||
? new FakeHttpContextFactory(url, routeData)
|
||||
: new FakeHttpContextFactory(url);
|
||||
|
||||
|
||||
//set the state helper
|
||||
StateHelper.HttpContext = factory.HttpContext;
|
||||
|
||||
|
||||
@@ -108,8 +108,9 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var mappers = PluginManager.Current.FindAndCreateInstances<IMapperConfiguration>(
|
||||
specificAssemblies: new[]
|
||||
{
|
||||
typeof(ContentModelMapper).Assembly,
|
||||
typeof(ApplicationRegistrar).Assembly
|
||||
typeof(ApplicationContext).Assembly, //Umbraco.Core
|
||||
typeof(ContentModelMapper).Assembly, //Umbraco.Web
|
||||
typeof(ApplicationRegistrar).Assembly //umbraco.businesslogic
|
||||
});
|
||||
foreach (var mapper in mappers)
|
||||
{
|
||||
@@ -124,7 +125,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
protected virtual void ResetPluginManager()
|
||||
{
|
||||
PluginManager.Current = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual CacheHelper CreateCacheHelper()
|
||||
{
|
||||
@@ -218,4 +219,4 @@ namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
protected CacheHelper CacheHelper { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TryConvertToTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var settings = SettingsForTests.GetDefault();
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ShortStringHelperResolver.Reset();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToIntegerTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = "100.001".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = 100.001m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,12 @@ namespace Umbraco.Tests
|
||||
[TestFixture]
|
||||
public class UdiTests : BaseUmbracoApplicationTest
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Udi.ResetUdiTypes();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringUdiCtorTest()
|
||||
{
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
@@ -231,7 +231,6 @@
|
||||
<Compile Include="Services\CachedDataTypeServiceTests.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedUserGroup.cs" />
|
||||
<Compile Include="TryConvertToTests.cs" />
|
||||
<Compile Include="UdiTests.cs" />
|
||||
<Compile Include="UmbracoExamine\RandomIdRAMDirectory.cs" />
|
||||
<Compile Include="UmbracoExamine\UmbracoContentIndexerTests.cs" />
|
||||
|
||||
@@ -20,8 +20,14 @@ using Umbraco.Web.Templates;
|
||||
namespace Umbraco.Tests.Web
|
||||
{
|
||||
[TestFixture]
|
||||
public class TemplateUtilitiesTests
|
||||
public class TemplateUtilitiesTests : BaseUmbracoApplicationTest
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Udi.ResetUdiTypes();
|
||||
}
|
||||
|
||||
[TestCase("", "")]
|
||||
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net45" />
|
||||
<package id="Log4Net.Async" version="2.0.4" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
|
||||
@@ -31,15 +31,17 @@
|
||||
display: block;
|
||||
padding: 4px;
|
||||
line-height: @baseLineHeight;
|
||||
border: 1px solid #ddd;
|
||||
border: 1px solid @gray-8;
|
||||
.border-radius(@baseBorderRadius);
|
||||
.box-shadow(0 1px 3px rgba(0,0,0,.055));
|
||||
.transition(all .2s ease-in-out);
|
||||
}
|
||||
// Add a hover/focus state for linked versions only
|
||||
a.thumbnail:hover,
|
||||
a.thumbnail:focus {
|
||||
border-color: @linkColor;
|
||||
// Add a hover/focus state for linked versions only.
|
||||
a.thumbnail:hover,
|
||||
a.thumbnail:focus,
|
||||
a div.thumbnail:hover,
|
||||
a div.thumbnail:focus {
|
||||
border-color: @turquoise;
|
||||
.box-shadow(0 1px 4px rgba(0,105,214,.25));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"cssnano": "^3.7.6",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-connect": "^5.0.0",
|
||||
"gulp-connect": "5.0.0",
|
||||
"gulp-less": "^3.1.0",
|
||||
"gulp-ngdocs": "^0.3.0",
|
||||
"gulp-open": "^2.0.0",
|
||||
|
||||
+4
-2
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.directives.directive:umbSections
|
||||
* @restrict E
|
||||
**/
|
||||
function sectionsDirective($timeout, $window, navigationService, treeService, sectionService, appState, eventsService, $location) {
|
||||
function sectionsDirective($timeout, $window, navigationService, treeService, sectionService, appState, eventsService, $location, historyService) {
|
||||
return {
|
||||
restrict: "E", // restrict to an element
|
||||
replace: true, // replace the html element with the template
|
||||
@@ -161,7 +161,9 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
$location.path(section.routePath);
|
||||
}
|
||||
else {
|
||||
$location.path(section.alias).search('');
|
||||
var lastAccessed = historyService.getLastAccessedItemForSection(section.alias);
|
||||
var path = lastAccessed != null ? lastAccessed.link : section.alias;
|
||||
$location.path(path).search('');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -185,6 +185,8 @@
|
||||
|
||||
$scope.page.buttonGroupState = "success";
|
||||
|
||||
}, function(err) {
|
||||
$scope.page.buttonGroupState = 'error';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,9 @@ angular.module("umbraco.directives")
|
||||
// element might still be there even after the modal has been hidden.
|
||||
scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
|
||||
tinyMceEditor.destroy()
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ angular.module("umbraco.directives")
|
||||
// this will greatly improve performance since there's potentially a lot of nodes being rendered = a LOT of watches!
|
||||
|
||||
template: '<li ng-class="{\'current\': (node == currentNode), \'has-children\': node.hasChildren}" on-right-click="altSelect(node, $event)">' +
|
||||
'<div ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" >' +
|
||||
'<div ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" ng-dblclick="load(node)" >' +
|
||||
//NOTE: This ins element is used to display the search icon if the node is a container/listview and the tree is currently in dialog
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded || node.metaData.isContainer, \'icon-navigation-down\': node.expanded && !node.metaData.isContainer}" ng-click="load(node)"> </ins>' +
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
itemMinWidth = scope.itemMinWidth;
|
||||
}
|
||||
|
||||
if (scope.itemMinWidth) {
|
||||
if (scope.itemMinHeight) {
|
||||
itemMinHeight = scope.itemMinHeight;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@
|
||||
|
||||
@param {string} icon (<code>binding</code>): The node icon.
|
||||
@param {string} name (<code>binding</code>): The node name.
|
||||
@param {boolean} published (<code>binding</code>): The node pusblished state.
|
||||
@param {boolean} published (<code>binding</code>): The node published state.
|
||||
@param {string} description (<code>binding</code>): A short description.
|
||||
@param {boolean} sortable (<code>binding</code>): Will add a move cursor on the node preview. Can used in combination with ui-sortable.
|
||||
@param {boolean} allowRemove (<code>binding</code>): Show/Hide the remove button.
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbPasswordToggle
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<strong>Added in Umbraco v. 7.7.4:</strong> Use this directive to render a password toggle.
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// comes from https://codepen.io/jakob-e/pen/eNBQaP
|
||||
// works fine with Angular 1.6.5 - alas not with 1.1.5 - binding issue
|
||||
|
||||
function PasswordToggleDirective($compile) {
|
||||
|
||||
var directive = {
|
||||
restrict: 'A',
|
||||
scope: {},
|
||||
link: function(scope, elem, attrs) {
|
||||
scope.tgl = function () { elem.attr("type", (elem.attr("type") === "text" ? "password" : "text")); }
|
||||
var lnk = angular.element("<a data-ng-click=\"tgl()\">Toggle</a>");
|
||||
$compile(lnk)(scope);
|
||||
elem.wrap("<div class=\"password-toggle\"/>").after(lnk);
|
||||
}
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbPasswordToggle', PasswordToggleDirective);
|
||||
|
||||
})();
|
||||
@@ -1,3 +1,114 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTable
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<strong>Added in Umbraco v. 7.4:</strong> Use this directive to render a data table.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.TableController as vm">
|
||||
|
||||
<umb-table
|
||||
ng-if="items"
|
||||
items="vm.items"
|
||||
item-properties="vm.options.includeProperties"
|
||||
allow-select-all="vm.allowSelectAll"
|
||||
on-select="vm.selectItem"
|
||||
on-click="vm.clickItem"
|
||||
on-select-all="vm.selectAll"
|
||||
on-selected-all="vm.isSelectedAll"
|
||||
on-sorting-direction="vm.isSortDirection"
|
||||
on-sort="vm.sort">
|
||||
</umb-table>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.items = [
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 1",
|
||||
"published": true,
|
||||
"description": "A short description of my node",
|
||||
"author": "Author 1"
|
||||
},
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 2",
|
||||
"published": true,
|
||||
"description": "A short description of my node",
|
||||
"author": "Author 2"
|
||||
}
|
||||
];
|
||||
|
||||
vm.options = {
|
||||
includeProperties: [
|
||||
{ alias: "description", header: "Description" },
|
||||
{ alias: "author", header: "Author" }
|
||||
]
|
||||
};
|
||||
|
||||
vm.selectItem = selectItem;
|
||||
vm.clickItem = clickItem;
|
||||
vm.selectAll = selectAll;
|
||||
vm.isSelectedAll = isSelectedAll;
|
||||
vm.isSortDirection = isSortDirection;
|
||||
vm.sort = sort;
|
||||
|
||||
function selectAll($event) {
|
||||
alert("select all");
|
||||
}
|
||||
|
||||
function isSelectedAll() {
|
||||
|
||||
}
|
||||
|
||||
function clickItem(item) {
|
||||
alert("click node");
|
||||
}
|
||||
|
||||
function selectItem(selectedItem, $index, $event) {
|
||||
alert("select node");
|
||||
}
|
||||
|
||||
function isSortDirection(col, direction) {
|
||||
|
||||
}
|
||||
|
||||
function sort(field, allow, isSystem) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.TableController", Controller);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
@param {string} icon (<code>binding</code>): The node icon.
|
||||
@param {string} name (<code>binding</code>): The node name.
|
||||
@param {string} published (<code>binding</code>): The node published state.
|
||||
@param {function} onSelect (<code>expression</code>): Callback function when the row is selected.
|
||||
@param {function} onClick (<code>expression</code>): Callback function when the "Name" column link is clicked.
|
||||
@param {function} onSelectAll (<code>expression</code>): Callback function when selecting all items.
|
||||
@param {function} onSelectedAll (<code>expression</code>): Callback function when all items are selected.
|
||||
@param {function} onSortingDirection (<code>expression</code>): Callback function when sorting direction is changed.
|
||||
@param {function} onSort (<code>expression</code>): Callback function when sorting items.
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
+6
-1
@@ -9,9 +9,14 @@ function noDirtyCheck() {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
elm.focus(function () {
|
||||
ctrl.$pristine = false;
|
||||
scope.$watch(function() {
|
||||
ctrl.$pristine = false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
value = value.replace("#", "");
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
|
||||
@@ -493,7 +493,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* @methodOf umbraco.resources.mediaResource
|
||||
*
|
||||
* @description
|
||||
* Empties the media recycle bin
|
||||
* Paginated search for media items starting on the supplied nodeId
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
@@ -506,7 +506,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* @param {string} query The search query
|
||||
* @param {int} pageNumber The page number
|
||||
* @param {int} pageSize The number of media items on a page
|
||||
* @param {int} searchFrom Id to search from
|
||||
* @param {int} searchFrom NodeId to search from (-1 for root)
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.assetsService
|
||||
*
|
||||
* @requires $q
|
||||
* @requires $q
|
||||
* @requires angularHelper
|
||||
*
|
||||
*
|
||||
* @description
|
||||
* Promise-based utillity service to lazy-load client-side dependencies inside angular controllers.
|
||||
*
|
||||
*
|
||||
* ##usage
|
||||
* To use, simply inject the assetsService into any controller that needs it, and make
|
||||
* sure the umbraco.services module is accesible - which it should be by default.
|
||||
@@ -18,7 +18,7 @@
|
||||
* //this code executes when the dependencies are done loading
|
||||
* });
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
*
|
||||
* You can also load individual files, which gives you greater control over what attibutes are passed to the file, as well as timeout
|
||||
*
|
||||
@@ -38,13 +38,14 @@
|
||||
* //loadcss cannot determine when the css is done loading, so this will trigger instantly
|
||||
* });
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
*/
|
||||
angular.module('umbraco.services')
|
||||
.factory('assetsService', function ($q, $log, angularHelper, umbRequestHelper, $rootScope, $http) {
|
||||
|
||||
var initAssetsLoaded = false;
|
||||
var appendRnd = function (url) {
|
||||
|
||||
function appendRnd (url) {
|
||||
//if we don't have a global umbraco obj yet, the app is bootstrapping
|
||||
if (!Umbraco.Sys.ServerVariables.application) {
|
||||
return url;
|
||||
@@ -77,7 +78,8 @@ angular.module('umbraco.services')
|
||||
return this.loadedAssets[path];
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
/**
|
||||
Internal method. This is called when the application is loading and the user is already authenticated, or once the user is authenticated.
|
||||
There's a few assets the need to be loaded for the application to function but these assets require authentication to load.
|
||||
*/
|
||||
@@ -108,10 +110,10 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Injects a file as a stylesheet into the document head
|
||||
*
|
||||
*
|
||||
* @param {String} path path to the css file to load
|
||||
* @param {Scope} scope optional scope to pass into the loader
|
||||
* @param {Object} keyvalue collection of attributes to pass to the stylesheet element
|
||||
* @param {Object} keyvalue collection of attributes to pass to the stylesheet element
|
||||
* @param {Number} timeout in milliseconds
|
||||
* @returns {Promise} Promise object which resolves when the file has loaded
|
||||
*/
|
||||
@@ -149,10 +151,10 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Injects a file as a javascript into the document
|
||||
*
|
||||
*
|
||||
* @param {String} path path to the js file to load
|
||||
* @param {Scope} scope optional scope to pass into the loader
|
||||
* @param {Object} keyvalue collection of attributes to pass to the script element
|
||||
* @param {Object} keyvalue collection of attributes to pass to the script element
|
||||
* @param {Number} timeout in milliseconds
|
||||
* @returns {Promise} Promise object which resolves when the file has loaded
|
||||
*/
|
||||
@@ -192,8 +194,8 @@ angular.module('umbraco.services')
|
||||
* @methodOf umbraco.services.assetsService
|
||||
*
|
||||
* @description
|
||||
* Injects a collection of files, this can be ONLY js files
|
||||
*
|
||||
* Injects a collection of css and js files
|
||||
*
|
||||
*
|
||||
* @param {Array} pathArray string array of paths to the files to load
|
||||
* @param {Scope} scope optional scope to pass into the loader
|
||||
@@ -206,61 +208,72 @@ angular.module('umbraco.services')
|
||||
throw "pathArray must be an array";
|
||||
}
|
||||
|
||||
// Check to see if there's anything to load, resolve promise if not
|
||||
var nonEmpty = _.reject(pathArray, function (item) {
|
||||
return item === undefined || item === "";
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//don't load anything if there's nothing to load
|
||||
if (nonEmpty.length > 0) {
|
||||
var promises = [];
|
||||
var assets = [];
|
||||
|
||||
//compile a list of promises
|
||||
//blocking
|
||||
_.each(nonEmpty, function (path) {
|
||||
|
||||
path = convertVirtualPath(path);
|
||||
|
||||
var asset = service._getAssetPromise(path);
|
||||
//if not previously loaded, add to list of promises
|
||||
if (asset.state !== "loaded") {
|
||||
if (asset.state === "new") {
|
||||
asset.state = "loading";
|
||||
assets.push(asset);
|
||||
}
|
||||
|
||||
//we need to always push to the promises collection to monitor correct
|
||||
//execution
|
||||
promises.push(asset.deferred.promise);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//gives a central monitoring of all assets to load
|
||||
promise = $q.all(promises);
|
||||
|
||||
_.each(assets, function (asset) {
|
||||
LazyLoad.js(appendRnd(asset.path), function () {
|
||||
asset.state = "loaded";
|
||||
if (!scope) {
|
||||
asset.deferred.resolve(true);
|
||||
}
|
||||
else {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
//return and resolve
|
||||
if (nonEmpty.length === 0) {
|
||||
var deferred = $q.defer();
|
||||
promise = deferred.promise;
|
||||
deferred.resolve(true);
|
||||
return promise;
|
||||
}
|
||||
|
||||
//compile a list of promises
|
||||
//blocking
|
||||
var promises = [];
|
||||
var assets = [];
|
||||
_.each(nonEmpty, function (path) {
|
||||
path = convertVirtualPath(path);
|
||||
var asset = service._getAssetPromise(path);
|
||||
//if not previously loaded, add to list of promises
|
||||
if (asset.state !== "loaded") {
|
||||
if (asset.state === "new") {
|
||||
asset.state = "loading";
|
||||
assets.push(asset);
|
||||
}
|
||||
|
||||
//we need to always push to the promises collection to monitor correct
|
||||
//execution
|
||||
promises.push(asset.deferred.promise);
|
||||
}
|
||||
});
|
||||
|
||||
//gives a central monitoring of all assets to load
|
||||
promise = $q.all(promises);
|
||||
|
||||
// Split into css and js asset arrays, and use LazyLoad on each array
|
||||
var cssAssets = _.filter(assets,
|
||||
function (asset) {
|
||||
return asset.path.match(/(\.css$|\.css\?)/ig);
|
||||
});
|
||||
var jsAssets = _.filter(assets,
|
||||
function (asset) {
|
||||
return asset.path.match(/(\.js$|\.js\?)/ig);
|
||||
});
|
||||
|
||||
function assetLoaded(asset) {
|
||||
asset.state = "loaded";
|
||||
if (!scope) {
|
||||
asset.deferred.resolve(true);
|
||||
return;
|
||||
}
|
||||
angularHelper.safeApply(scope,
|
||||
function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
if (cssAssets.length > 0) {
|
||||
var cssPaths = _.map(cssAssets, function (asset) { return appendRnd(asset.path) });
|
||||
LazyLoad.css(cssPaths, function() { _.each(cssAssets, assetLoaded); });
|
||||
}
|
||||
|
||||
if (jsAssets.length > 0) {
|
||||
var jsPaths = _.map(jsAssets, function (asset) { return appendRnd(asset.path) });
|
||||
LazyLoad.js(jsPaths, function () { _.each(jsAssets, assetLoaded); });
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,27 @@ angular.module('umbraco.services')
|
||||
*/
|
||||
getCurrent: function(){
|
||||
return nArray;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.historyService#getLastAccessedItemForSection
|
||||
* @methodOf umbraco.services.historyService
|
||||
*
|
||||
* @description
|
||||
* Method to return the item that was last accessed in the given section
|
||||
*
|
||||
* @param {string} sectionAlias Alias of the section to return the last accessed item for.
|
||||
*/
|
||||
getLastAccessedItemForSection: function (sectionAlias) {
|
||||
for (var i = 0, len = nArray.length; i < len; i++) {
|
||||
var item = nArray[i];
|
||||
if (item.link.indexOf(sectionAlias + "/") === 0) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -242,8 +242,8 @@
|
||||
var propGroups = _.find(genericTab.properties, function (item) {
|
||||
return item.alias === "_umb_membergroup";
|
||||
});
|
||||
saveModel.email = propEmail.value;
|
||||
saveModel.username = propLogin.value;
|
||||
saveModel.email = propEmail.value.trim();
|
||||
saveModel.username = propLogin.value.trim();
|
||||
|
||||
saveModel.password = this.formatChangePasswordModel(propPass.value);
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
$scope.isSearching = false;
|
||||
$scope.selectedResult = -1;
|
||||
|
||||
|
||||
$scope.navigateResults = function (ev) {
|
||||
//38: up 40: down, 13: enter
|
||||
|
||||
@@ -34,12 +33,14 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var group = undefined;
|
||||
var groupIndex = -1;
|
||||
var itemIndex = -1;
|
||||
$scope.selectedItem = undefined;
|
||||
|
||||
$scope.clearSearch = function () {
|
||||
$scope.searchTerm = null;
|
||||
};
|
||||
|
||||
function iterateResults(up) {
|
||||
//default group
|
||||
|
||||
@@ -17,7 +17,7 @@ angular.module("umbraco.install").factory('installerService', function($rootScop
|
||||
|
||||
//add to umbraco installer facts here
|
||||
var facts = ['Umbraco helped millions of people watch a man jump from the edge of space',
|
||||
'Over 420 000 websites are currently powered by Umbraco',
|
||||
'Over 440 000 websites are currently powered by Umbraco',
|
||||
"At least 2 people have named their cat 'Umbraco'",
|
||||
'On an average day, more than 1000 people download Umbraco',
|
||||
'<a target="_blank" href="https://umbraco.tv">umbraco.tv</a> is the premier source of Umbraco video tutorials to get you started',
|
||||
@@ -31,10 +31,10 @@ angular.module("umbraco.install").factory('installerService', function($rootScop
|
||||
"At least 4 people have the Umbraco logo tattooed on them",
|
||||
"'Umbraco' is the danish name for an allen key",
|
||||
"Umbraco has been around since 2005, that's a looong time in IT",
|
||||
"More than 550 people from all over the world meet each year in Denmark in June for our annual conference <a target='_blank' href='https://umbra.co/codegarden'>CodeGarden</a>",
|
||||
"More than 600 people from all over the world meet each year in Denmark in June for our annual conference <a target='_blank' href='https://umbra.co/codegarden'>CodeGarden</a>",
|
||||
"While you are installing Umbraco someone else on the other side of the planet is probably doing it too",
|
||||
"You can extend Umbraco without modifying the source code using either JavaScript or C#",
|
||||
"Umbraco was installed in more than 165 countries in 2015"
|
||||
"Umbraco has been installed in more than 198 countries"
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="email">Email</label>
|
||||
<div class="controls">
|
||||
<input type="email" id="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" val-email />
|
||||
<input type="email" id="email" name="email" placeholder="you@example.com" val-email required ng-model="installer.current.model.email" />
|
||||
<small class="inline-help">Your email will be used as your login</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
color: @gray-3;
|
||||
}
|
||||
|
||||
.umb-grid .umb-cell-rte textarea {
|
||||
.umb-grid .umb-cell-rte textarea.mceNoEditor {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
|
||||
.nested-content__item--active:not(.nested-content__item--single)
|
||||
{
|
||||
background: #f8f8f8;
|
||||
background: @gray-10;
|
||||
}
|
||||
|
||||
.nested-content__item.ui-sortable-placeholder
|
||||
{
|
||||
background: #f8f8f8;
|
||||
border: 1px dashed #d9d9d9;
|
||||
background: @gray-10;
|
||||
border-bottom: 1px dashed @purple-l3;
|
||||
visibility: visible !important;
|
||||
height: 55px;
|
||||
margin-top: -1px;
|
||||
@@ -56,7 +56,7 @@
|
||||
.nested-content__header-bar
|
||||
{
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px dashed #e0e0e0;
|
||||
border-bottom: 1px dashed @purple-l3;
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
@@ -113,8 +113,8 @@
|
||||
.nested-content__icon--active
|
||||
{
|
||||
color: white;
|
||||
background: #2e8aea;
|
||||
border-color: #2e8aea;
|
||||
background: @turquoise-d1;
|
||||
border-color: @turquoise-d1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
.nested-content__content
|
||||
{
|
||||
border-bottom: 1px dashed #e0e0e0;
|
||||
border-bottom: 1px dashed @purple-l3;
|
||||
}
|
||||
|
||||
.nested-content__content .umb-control-group {
|
||||
@@ -165,7 +165,7 @@
|
||||
clear: both;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
background: #f8f8f8;
|
||||
background: @gray-10;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
.umb-node-preview__content {
|
||||
flex: 1 1 auto;
|
||||
margin-right: 25px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-node-preview__name {
|
||||
@@ -50,6 +51,13 @@
|
||||
color: @gray-3;
|
||||
}
|
||||
|
||||
.umb-node-preview__name,
|
||||
.umb-node-preview__description {
|
||||
/*text-overflow: ellipsis;
|
||||
overflow: hidden;*/
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.umb-node-preview__actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
padding: 15px 10px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
border: 2px solid transparent;
|
||||
border: 1px solid @gray-8;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.umb-healthcheck-group:hover {
|
||||
border: 2px solid @turquoise;
|
||||
border: 1px solid @turquoise;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user