Compare commits

...

580 Commits

Author SHA1 Message Date
Sebastiaan Janssen a91669abc0 Fixes unit tests 2016-02-17 13:28:11 +01:00
Shannon 3b9db8a92f tries fixing test for appveyor 2016-02-17 12:25:40 +01:00
Sebastiaan Janssen 1bfc1229bd Merge pull request #1134 from umbraco/temp-738-U4-7996
Upgrade SQL CE to hopefully fix SQL CE data loss bug
2016-02-17 11:54:25 +01:00
Sebastiaan Janssen 3d6fd2d785 Updates to SQL CE 4.0.0.1 2016-02-17 11:44:33 +01:00
Shannon e56881abc6 adds unit tests for new ext methods 2016-02-17 11:21:15 +01:00
Shannon d32991c30a re-organizing some namespaces for tests 2016-02-17 10:59:48 +01:00
Shannon 8758f9649b checks for null before assigning culture 2016-02-17 10:57:20 +01:00
Shannon 6f0f1ab2c3 fixes wrong constant used 2016-02-17 10:22:37 +01:00
Shannon cd28240172 Moves strings to constants, adds ControllerContextExtensions to get the UmbracoContext from the hierarchy of ControllerContext's, changes RenderModelBinder to use this method to get the UmbracoContext, changes UmbracoViewPageOfTModel to use this method to get the UmbracoContext, adds RouteDataExtensions to get the UmbracoContext from routedata, adds extension methods on the HttpContext to get the UmbracoContext from it.
Conflicts:
	src/Umbraco.Web/Mvc/RenderModelBinder.cs
2016-02-17 10:22:22 +01:00
Shannon 7002291c41 adds tests for ShouldAuthenticateRequest for app configurations 2016-02-16 14:51:15 +01:00
Shannon 51bbf7ceb5 U4-7494 Installation Fails for 7.3.3 - Intermittent - Value cannot be null. Parameter name: sqlSyntax 2016-02-16 14:22:59 +01:00
Shannon 82297a6ff1 U4-7929 Label datatype strips leading zeros 2016-02-16 13:23:37 +01:00
Shannon cc5ac1a84c bumps version 2016-02-16 11:57:10 +01:00
Shannon 6373add383 U4-7922 Preview is not working 2016-02-16 11:53:54 +01:00
Shannon 180099b718 U4-7890 XSLT Macro's not working - "Cannot use this obsoleted overload when the current provider" 2016-02-16 11:52:16 +01:00
Shannon 65f15125e1 U4-7939 - fix routes cache 2016-02-16 11:48:09 +01:00
Shannon 856c345905 Merge branch '7.3.7' of https://github.com/umbraco/Umbraco-CMS into 7.3.7 2016-02-02 18:01:56 +01:00
Shannon b2cd5dfb85 adds null check to session id - might not exist in old cookies 2016-02-02 18:01:36 +01:00
Sebastiaan Janssen 462f7a59b5 Merge pull request #1078 from dawoe/U4-7872
Use product name in migration runner instead of Umbraco productname
2016-02-02 17:06:56 +01:00
Shannon 22689d24ec changes port 2016-02-02 17:05:21 +01:00
Shannon 4055afdf05 Merge branch '7.3.7' of https://github.com/umbraco/Umbraco-CMS into 7.3.7 2016-02-02 16:52:08 +01:00
Shannon a1c70a219a ensures correct sort order for content type queries + test 2016-02-02 16:51:57 +01:00
Sebastiaan Janssen 3151515855 U4-7072 Grid TinyMce with style_formats throws "Cannot assign to read only property 'name' 2016-02-02 16:09:02 +01:00
Shannon 25df9da715 bumps Version 2016-02-02 16:00:28 +01:00
Shannon 9c2f438476 fixes tests 2016-02-02 15:43:44 +01:00
Shannon 0de3be42cf U4-7869 Examine & SQL Azure - Timeouts - ensure the other reader is executed with retry. 2016-02-02 15:33:22 +01:00
Shannon 1545e0eed7 Merge branch '7.3.7' of https://github.com/umbraco/Umbraco-CMS into 7.3.7 2016-02-02 15:14:56 +01:00
Shannon 42a7ed6877 U4-7821 KeepUserLoggedIn with a long umbracoTimeOutInMinutes has logout issues 2016-02-02 15:14:47 +01:00
Sebastiaan Janssen 98b8aedc4d U4-7849 Unclear error message when applying public access 2016-02-02 15:13:57 +01:00
Shannon c7a2b54d1c Merge branch '7.3.7' of https://github.com/umbraco/Umbraco-CMS into 7.3.7 2016-02-02 12:13:03 +01:00
Shannon 6583ff4439 U4-7821 KeepUserLoggedIn with a long umbracoTimeOutInMinutes has logout issues 2016-02-02 12:12:51 +01:00
Sebastiaan Janssen 7b08b3e936 Merged branch 7.3.7 into 7.3.7 2016-02-02 11:55:40 +01:00
Sebastiaan Janssen bd2fc71dc5 U4-7276 When creating folders in the "Partials" view folder a YSOD appears (Umbraco 7.3 and 7.4) 2016-02-02 11:55:24 +01:00
Shannon 0af97f63e2 U4-7857 Flexible Load Balancing does not sync with the correct timeout threshold 2016-02-02 11:11:47 +01:00
Shannon 1db635f24c Updates DeepCloneableList to support behaviors, for the FullDataSetCachePolicy we only want to clone when writing to cache, not when reading, the cloning will then be done on individual items after filtering by the FullDataSetRepositoryCachePolicy 2016-02-02 01:32:36 +01:00
Shannon 6e27b3d6d4 Fixes up the FullDataSetRepositoryCachePolicy to handle individual items, updates and removes correctly, splits up it's logic so it's not overriding the DefaultRepositoryCachePolicy since that is just different. Adds tests. 2016-02-02 00:47:18 +01:00
Shannon 1dea0edcf1 re-includes the static cache for published property types, this cache is much more than a simple cache of content type infos, it is also the cache for associated converters which is required for all front-end rendering. Fixes the issue of not setting the xpath cache level corectly. 2016-02-01 22:50:38 +01:00
Shannon 1abab41955 Fixes perf issue with DeepCloneHelper - so we cache the actual property types instead of re-reflecting each time 2016-02-01 21:45:34 +01:00
Shannon d1be38be64 reverts profiler changes, we'll inlcude in 7.4 2016-01-28 18:37:56 +01:00
Shannon 8916c68a0c reverts profiler changes, we'll inlcude in 7.4 2016-01-28 18:35:29 +01:00
Shannon 6faa7e2fc9 dont' have RebuildOnAppStart set for dev purposes! 2016-01-28 18:31:47 +01:00
Shannon a6093f41bd Fixes installer login for user and adds notes 2016-01-28 18:02:22 +01:00
Stephan 107e66e4da Merge pull request #1071 from umbraco/temp-U4-7682
U4-7682 Add option to DatabaseServerMessengerOptions to force a Cold …
2016-01-28 14:33:02 +01:00
Shannon 256849f8a6 adds nicer profiling during startup for app event handlers. 2016-01-28 14:19:38 +01:00
Stephan c9c451be65 U4-7682 Minor review adjustments 2016-01-28 14:19:32 +01:00
Shannon 1fcea083e7 Ensures no profiling occurs when not in debug mode 2016-01-28 14:10:13 +01:00
Shannon 85d6ee5713 Merge branch '7.3.6' of https://github.com/umbraco/Umbraco-CMS into 7.3.6 2016-01-28 13:50:55 +01:00
Shannon ec81583741 Fixes case sensitive matching on alias in TemplateRepository 2016-01-28 13:50:45 +01:00
Sebastiaan Janssen 332da9bf2d Merge pull request #1070 from umbraco/temp-RepoCachePerf736
Temp repo cache perf736
2016-01-28 12:15:24 +01:00
Shannon a0036d925e U4-7682 Add option to DatabaseServerMessengerOptions to force a Cold Boot if there are too many instructions 2016-01-28 12:14:30 +01:00
Shannon 81a99d6f7d adds null check and ensures that SetInternalRedirectPublishedContent cannot be called with a null result 2016-01-28 10:19:51 +01:00
Shannon e912238574 Saw there was another place with the incorrect case for the column name AllowedId 2016-01-28 09:32:01 +01:00
Shannon 9a830e5de6 fixes tests 2016-01-27 19:44:36 +01:00
Shannon 7d9ba0e36e manually backports changes from 7.4 fixes 2016-01-27 19:42:06 +01:00
Shannon 6c5e09fd84 Ensures that the main content type repositories are returning the correct result from their GetAll methods. Fixes the FullDataSetRepositoryCachePolicy to ensure that any request with Ids actually returns the result of GetAll and then filters to ensure caching is correct. 2016-01-27 19:26:08 +01:00
Sebastiaan Janssen 2f8c43c689 Merge pull request #1057 from umbraco/temp-U4-7836
U4-7836 YSOD when upgrading Umbraco with error during AddUserDataClaims
2016-01-26 19:25:04 +01:00
Shannon 7a25cb52b2 updates the repository cache policies so that we aren't keeping everything in cache unnecessarily 2016-01-26 19:13:42 +01:00
Shannon 19bc97a7fd Removes the static (hack) cache for content types for creating published content 2016-01-26 18:56:29 +01:00
Shannon 72900ef3b3 U4-7813 Enable MiniProfiler to profiler during startup
Conflicts:
	src/Umbraco.Core/Umbraco.Core.csproj
2016-01-26 17:56:25 +01:00
Shannon 74ddd09c5d U4-7836 YSOD when upgrading Umbraco with error during AddUserDataClaims - this also ensures that no empty/null sections can be added to the user object since this is where the original exception was coming from. 2016-01-26 17:05:46 +01:00
Sebastiaan Janssen e461cb92da U4-7787 Shorthand use of ?altTemplate= doesn't work
#U4-7787 Fixed
2016-01-26 16:07:44 +01:00
Mads Rasmussen e91b53e66d back ported: https://github.com/Umbraco/Umbraco-CMS/commit/2d0f198f58071f5113d5c3437f10f2b85220c348 2016-01-25 11:09:20 +01:00
Shannon b5e8cb29dd ensure appctx and security isn't nulled on disposal (it's an application singleton it doesn't need to be nulled), creates new CreateContext method for creating standalone UmbracoContext instances. 2016-01-23 12:38:08 +01:00
Shannon 20dc4f5bc4 fixes merge issue/build 2016-01-23 12:27:40 +01:00
Shannon 2c399860ca Fixes DisposableTimer so that the profiled step is disposed - and thus tracked/timed properly! 2016-01-22 17:27:46 +01:00
Shannon 4dc4c36581 U4-7811 Content type repositories should use FullDataSetRepositoryCachePolicyFactory for performance
Conflicts:
	src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
	src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs
	src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaTypeRepository.cs
	src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs
2016-01-22 17:08:21 +01:00
Shannon fe774f557c Fixes ms value: U4-7810 DatabaseServerRegistrar should not execute as soon as a request is made, this slows down app start 2016-01-22 17:06:14 +01:00
Shannon 3ecb9d0f86 U4-7807 Domain, language, public access cache (GetAll) caches not working when there are no items 2016-01-22 17:05:27 +01:00
Shannon f78a425985 U4-7816 The IsolatedCache instance in the RepositoryFactory differs from the ApplicationContext singleton instance 2016-01-22 16:37:47 +01:00
Sebastiaan Janssen 9f365727e0 Bumps version 2016-01-20 14:10:31 +01:00
Sebastiaan Janssen 74d73cfe94 U4-7796 Get UrlRewritingNet from the official NuGet location
#U4-7796 Fixed
2016-01-20 13:57:35 +01:00
Sebastiaan Janssen 7fb9d430a9 changes default upload limit to 50 mb 2016-01-20 10:54:43 +01:00
Sebastiaan Janssen 7cd8ba13c0 U4-7781 Setting a user's start node causes YSOD
#U4-7781 Fixed
2016-01-20 10:45:40 +01:00
Sebastiaan Janssen 1888888650 Update ImageProcessor, this time also in the nuspec file 2016-01-19 11:07:17 +01:00
Sebastiaan Janssen 39b1357a2a Ensure correct assembly redirects for System.Web.WebPages.Razor and HtmlAgilityPack 2016-01-15 15:07:53 +01:00
Claus e1ee8a1437 Fix to ensure config array is copied and not referenced. 2016-01-15 10:00:05 +01:00
Claus 21ba88a34d Fixes: U4-6297 Add Settings to Grid Controls
Reusing the existing code for calling the dialog instead of having a separate method for this.
2016-01-15 09:43:01 +01:00
Shannon b5abbc7c30 Adds some null checks 2016-01-14 18:11:48 +01:00
Shannon 7958b5fcb1 U4-7740 Speed up the current user's culture lookup 2016-01-14 16:43:31 +01:00
Shannon 44b22503e1 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-01-14 16:36:13 +01:00
Shannon bfa12856db Fixes issue with DefaultRepositoryCachePolicy when creating new items - we were generating the cache key before actually calling the method to create the item therefore there was no id assigned yet (it would be zero). 2016-01-14 16:36:03 +01:00
Sebastiaan Janssen d9542f4ca5 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-01-14 15:06:39 +01:00
Sebastiaan Janssen f057976f78 U4-7735 Localization fallback doesn't seem to work.
#U4-7735 Fixed
2016-01-14 15:06:16 +01:00
Claus 151c28a20f Merge pull request #642 from AussieInSeattle/U4-6297
U4 6297
2016-01-14 14:35:54 +01:00
Claus d2c8268fc4 Merge pull request #1014 from kvakulo/fix-media-item-without-image
Fix the media picker not rendering when a media item has no image
2016-01-14 13:46:12 +01:00
Claus 13a9f40815 Fixes: U4-7728 Folder view in media section gives an exception
Ensuring umbracoFile property isn't accessed if this is called on a folder.
2016-01-14 09:40:40 +01:00
Claus 67f8141015 Merge branch 'bjarnef-dev-v7-mediapicker-only-images' into dev-v7 2016-01-14 08:56:34 +01:00
bjarnef 06a098215b Add media picker config to restrict the editors to only pick images 2016-01-14 00:36:53 +01:00
bjarnef 051b320904 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-13 23:16:10 +01:00
Shannon 5aab50ba3b Ensures fcnMode and file size maximums are set for the debug web config transform and also for the nuget transform. 2016-01-13 17:27:56 +01:00
Shannon 5b9cbae860 Fixes: U4-7712 fcnMode = Single by default 2016-01-13 17:17:39 +01:00
Claus 59759c4919 Merge pull request #1018 from umbraco/temp-U4-5982
U4-5982 Webpages unpublishing by themselves
2016-01-13 14:29:37 +01:00
Shannon 68ddea2776 refactors a bit of code from the PR, adds more translations to the other english file. 2016-01-13 12:33:57 +01:00
Shannon 8857b2db59 Merge branch 'JJCLane-UKFest-6322' into temp-U4-5982 2016-01-13 12:24:00 +01:00
Shannon fae5618865 Merge branch 'UKFest-6322' of https://github.com/JJCLane/Umbraco-CMS into JJCLane-UKFest-6322 2016-01-13 12:23:26 +01:00
Shannon 40dbcbd7d9 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-01-13 12:10:22 +01:00
Shannon 074d894271 Fixes: U4-7706 Property Type UniqueIds do not stay consistent during package installation 2016-01-13 12:10:04 +01:00
Mads Rasmussen eb6ae95039 Merge pull request #1015 from umbraco/temp-U4-7561
U4-7561 Backoffice Media Section should provide information on physic…
2016-01-13 10:40:54 +01:00
Shannon 5e461b0cec adds packaging test 2016-01-13 10:29:44 +01:00
Shannon d6a49f275f adds test that fails - need to fix it now 2016-01-13 10:29:26 +01:00
Sebastiaan Janssen 8e024fccff Don't hardcode the umbracoFile constant 2016-01-12 20:05:22 +01:00
Sebastiaan Janssen 43227d4510 Support for multiple properties spawning a url - adding more uploadfields to umbracoSettings.config (autoFillImageProperties) 2016-01-12 19:46:05 +01:00
Sebastiaan Janssen 79cc4cd2fa Change "umbracoFile" to the constant for this value 2016-01-12 18:16:55 +01:00
Sebastiaan Janssen ff83d2e1f4 U4-7561 Backoffice Media Section should provide information on physical location of files 2016-01-12 17:41:53 +01:00
Regin Larsen cb7df58fdd Fix the media picker not rendering when a media item has no image 2016-01-12 16:25:29 +01:00
Sebastiaan Janssen 5cc274a580 Merge pull request #1004 from umbraco/temp-U4-7681
U4-7681 Legacy CMSNode.Parent uses old SqlHelper API and doesn't keep…
2016-01-12 14:48:54 +01:00
Sebastiaan Janssen 6c5b5ee637 Merge branch 'Phosworks-U4-7312-2' into dev-v7 2016-01-12 14:20:40 +01:00
Sebastiaan Janssen 9bfac0fdcd Still create the thumbnails upon upload (for backwards compatibility) 2016-01-12 14:20:25 +01:00
Sebastiaan Janssen bd5823f0de Merge branch 'U4-7312-2' of https://github.com/Phosworks/Umbraco-CMS into Phosworks-U4-7312-2 2016-01-12 13:24:42 +01:00
Sebastiaan Janssen 70035632b6 Update ImageProcessor and UrlRewritingNet dependencies 2016-01-12 11:22:49 +01:00
Stephan 20f5560767 Merge pull request #1002 from umbraco/temp-U4-7558-2
U4-7558 Fix GetAll repository level caching for repositories that return a query result based on the result of GetAll
2016-01-11 15:14:00 +01:00
Shannon ecd024c462 U4-7681 Legacy CMSNode.Parent uses old SqlHelper API and doesn't keep a reference 2016-01-08 13:59:40 +01:00
Shannon ba91bf0b9c missing a file save 2016-01-07 19:33:55 +01:00
Shannon 2b13297c36 Changes method name to be shorter and makes internal instead of protected. 2016-01-07 19:27:59 +01:00
Shannon fb5faa3db7 Fixes tests, adds LanguageId to the interface 2016-01-07 18:59:59 +01:00
Shannon d7a142e724 Refactors DictionaryItem and DictionaryTranslation so that the attached ILanguage entity is not cached nor cloned. This will save on lots of memory and cloning cycles especially if there are quire a few dictioanry items. Unfortunatley to achieve this requires a not so pretty hack where we need to assign an internal callback to the model so it knows how to retrieve the language when it needs it. In v8, the ILanguage entity will not be attached at all. This also fixes a cache refresher issue for when a language is deleted -> all dictionary cache must be removed. This commit also changes a method name: ClearAllIsolatedCacheByRepositoryEntityType 2016-01-07 18:44:04 +01:00
Shannon 63785ae70f Adds cache policy tests 2016-01-07 17:54:55 +01:00
Shannon 68aa6ff093 Moves repository caching logic into new CachePolicies. 2016-01-07 16:31:20 +01:00
Shannon 3e985acef1 ensures that the public access cache refresher is called when a public access item is deleted. 2016-01-07 12:18:57 +01:00
Shannon 6d13d33cfd Changes PublicAccessRepository to use GetAllCacheAsCollection option and return a single result by ID based on the cache of GetAll 2016-01-07 12:03:32 +01:00
Shannon Deminick ced0a852b1 Merge pull request #1000 from bjarnef/dev-v7-U4-7648
Set focus on input by clicking label
2016-01-07 10:14:07 +01:00
bjarnef ba0da15f7f Set focus on input by clicking label 2016-01-07 01:04:55 +01:00
bjarnef 2875cd10f3 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-06 22:01:33 +01:00
Shannon b91661cf65 fixes issue with RepositoryBase - it would cache all entities with a single key even if there were ids specified which is wrong. Updates TemplateRepository to use a single GetAll query as its base source and it uses the GetAllCacheAsCollection option, also massively simplifies its GetDescendants methods, obsoletes some unused code, 2016-01-06 19:27:15 +01:00
Shannon 827f7a7bc8 Updates DictionaryRepository(s) to have custom GetAll caching options - to basically disable it since there could be tons of these and currently an IDictionaryItem is a massive entity (need to fix that) 2016-01-06 18:34:07 +01:00
Shannon ff829d49a3 Updates all cache refreshers to reference the IsolatedRuntimeCache where required, refactors how IsolatedRuntimeCache is exposed on the CacheHelper, ensures that IsolatedRuntimeCache is used in all repositories instead of the global RuntimeCache, changes all obsolete usages of CacheHelper to the non obsolete equivalent, obsoletes many of the cache keys, obsoletes a couple cache refreshers that aren't used anymore in 7.3, simplifies CacheHelper with regards to it's 'disabled' cache state. 2016-01-06 18:08:14 +01:00
Sebastiaan Janssen d2483159bc Fixes unit tests, not all packages will have the sort order in there 2016-01-06 15:59:23 +01:00
Sebastiaan Janssen 48ab3f580c Fixes the build 2016-01-06 15:21:45 +01:00
Claus c524d67a37 Fixes: U4-7553 Importing Document Type doesn't respect property sort order
Handling sortOrder property in both import/export.

(cherry picked from commit 378479b4c1)

# Conflicts:
#	src/Umbraco.Core/Services/PackagingService.cs
2016-01-06 14:56:31 +01:00
Shannon 4f40fff5ee Moves DeepCloneRuntimeCacheProvider to Cache namespace. Creates DeepCloneableList + tests. Updates RepositoryBase to use DeepCloneableList when GetAllCacheAsCollection is used (so that all entries that get cached are deep cloned into and out-of the cache). Adds test for DeepCloneRuntimeCacheProvider for dealing with this list type. 2016-01-06 14:17:51 +01:00
Shannon b04d0fc886 Adds Isolated cache to the CacheHelper, adds cache option: GetAllCacheAsCollection, changes the default repository cache to be an isolated cache (instead of part of the single main dictionary cache), adds the logic for the cache option GetAllCacheAsCollection to RepositoryBase, updates Language and Domain repositories to use GetAllCacheAsCollection, updates RepositoryFactory to be the one responsible for injecting a DeepCloneRuntimeCacheProvider and to use a single _noCache instance. 2016-01-06 13:48:03 +01:00
Shannon 4c3258812c normalize culture for test 2016-01-06 12:50:41 +01:00
Shannon bc98f5e8fc code cleanup.
Conflicts:
	src/Umbraco.Core/ObjectExtensions.cs
2016-01-06 12:49:18 +01:00
Shannon 6f2f6c088b Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-01-06 12:48:36 +01:00
Shannon da91923577 Changes ObjectExtensions NormalizeNumberDecimalSeparator to use normal Culture (not UI Culture) 2016-01-06 12:48:26 +01:00
Sebastiaan Janssen fbc46d8046 Merge pull request #989 from umbraco/temp-U4-7643
U4-7643 DatabaseServerMessenger.cs causes lucene indexes to rebuild o…
2016-01-06 12:43:36 +01:00
Shannon e8a0fae557 adds notes 2016-01-06 12:24:09 +01:00
Shannon Deminick e0baf45247 Merge pull request #992 from umbraco/temp-U4-5168
U4-5168 Media Items label says "Document Type" instead of  "Media Type"
2016-01-06 12:22:53 +01:00
Sebastiaan Janssen 43e983e27a Corrects spelling of localStorateDir to localStorageDir 2016-01-06 12:17:48 +01:00
Sebastiaan Janssen b882806847 Merge pull request #980 from umbraco/temp-U4-7614
U4-7614 Allow Examine's local temp storage to exist in the current Us…
2016-01-06 12:09:31 +01:00
Shannon 58c30cd7a6 removes erroneous reverse call 2016-01-06 12:00:50 +01:00
Shannon Deminick ae1b6d95b8 Merge pull request #990 from umbraco/temp-PVS-Studio
Temp pvs studio
2016-01-06 12:00:28 +01:00
Sebastiaan Janssen 403af78ba9 U4-5168 Media Items label says "Document Type" instead of "Media Type" 2016-01-06 11:22:15 +01:00
Sebastiaan Janssen 59fe690a88 Code sample No.10 2016-01-05 23:34:30 +01:00
Sebastiaan Janssen a15b005d95 Code sample No.6, No.7 2016-01-05 23:22:16 +01:00
Sebastiaan Janssen b94c396d4e Code sample No.5 2016-01-05 23:20:47 +01:00
Sebastiaan Janssen 8afc4f5ad1 Code sample No.3 2016-01-05 23:15:25 +01:00
Sebastiaan Janssen f68b2de9e3 Code sample No.2 2016-01-05 23:13:37 +01:00
Sebastiaan Janssen f4e29d90e0 Code sample No.1 2016-01-05 23:12:09 +01:00
Sebastiaan Janssen 5ad5e945c4 Merge pull request #813 from TimGeyssens/dev-v7
Fixes U4-7249 Insert Macro split button, when selecting a macro that …
2016-01-05 19:49:14 +01:00
Sebastiaan Janssen 4ef7b7735e Fixes U4-6510 again as merging PR apparently went wrong 2016-01-05 17:04:11 +01:00
Sebastiaan Janssen db538d95ba Bumps version 2016-01-05 16:11:59 +01:00
Sebastiaan Janssen cef7cd1ca7 Merge pull request #981 from umbraco/temp-U4-7583
U4-7583
2016-01-05 16:02:51 +01:00
Shannon 726416fe0c Fixes: U4-7624 Datepicker Sql server error
Since we are not saving the formatted value, don't try parsing the date with formatting config.
Added in explicit parsing format compatible with the one used when saving the value, just to ensure parsing is done the same way.
2016-01-05 15:47:42 +01:00
Shannon Deminick 1957d8bb3b Merge pull request #928 from kiasyn/patch-1
U4-7400 - Datepicker is not updating scope model value in time for 3r…
2016-01-05 15:19:31 +01:00
Shannon fab30d353a U4-7223 GetCropUrl outputs html entities in url when used in css 2016-01-05 14:54:02 +01:00
Shannon 75990b5961 U4-7643 DatabaseServerMessenger.cs causes lucene indexes to rebuild on app startup 2016-01-05 14:20:13 +01:00
Shannon 18900d0e25 Fixes: U4-6659 Examine: Specific doctype not being indexed 2016-01-05 12:38:13 +01:00
Shannon d08f4230c8 U4-7538 GetRemainingTimeoutSeconds is double setting the cookie in 7.4 2016-01-05 12:35:06 +01:00
Shannon 15d06557e9 U4-7605 Colons/Parens Unnecessarily Removed From Data Type Names 2016-01-05 11:42:02 +01:00
Shannon 8d2e708d1c Adds exception handling for the BackOfficeUserStore - this will occur if the external OAuth provider doesn't return the Email or Name correctly, then an exception is swallowed at the service level and the user is not actually created, but the BackOfficeUserStore could not detect this, so it's detecting this now. 2016-01-05 11:36:52 +01:00
Shannon 280573be28 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-01-05 11:35:35 +01:00
Shannon 415aaf3e2b U4-7477 xss char stripping on data type names is being too agressive 2016-01-05 11:35:24 +01:00
Sebastiaan Janssen 5081027482 Improve batch files: SETLOCAL makes sure we don't change the user's actual path, so no need to revert changes any more either 2016-01-05 11:33:10 +01:00
Wincent 96b24d7ee0 Removes dependency to System.IO.File 2015-12-31 12:01:35 +01:00
Shannon ac1785bc08 U4-7583 2015-12-28 16:20:48 +01:00
Shannon 1da1a20734 ensures the setting is enabled for the searcher too 2015-12-28 13:43:47 +01:00
Shannon c765ab9112 U4-7614 Allow Examine's local temp storage to exist in the current User's temp storage location - useful for Azure 2015-12-28 13:37:56 +01:00
Shannon Deminick 664aa3842d Merge pull request #979 from robertjf/dev-v7
fix for issue U4-7609/U4-7610 - IE related problems
2015-12-28 10:09:29 +01:00
Robert Foster fbee58e445 Added json mimetype Mapping to web.config.template to support things like manifest.json in certain browsers (e.g. IE). 2015-12-26 19:05:44 +11:00
Robert Foster a5e87dcedf Fix for IE not being able to install packages in Umbraco backoffice. 2015-12-26 18:57:24 +11:00
Wincent 53f9e104ec Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into U4-7312-2
Conflicts:
	src/Umbraco.Web/Editors/ImagesController.cs - Removed changes from upstream
2015-12-19 11:16:30 +01:00
Robert Foster ffe41fe060 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' 2015-12-18 22:45:46 +11:00
Shannon Deminick e89cc24d51 Merge pull request #958 from lars-erik/overridable-domain-repository
Can't log into youtrack. Simple changes to repositoryfactory and umbr…
2015-12-16 10:19:25 +01:00
Claus 61f3b2ae4a Added CultureInvariant to regex. 2015-12-16 09:53:15 +01:00
Claus a752c7ee4b Merge branch 'rasmusjp-U4-7462' into dev-v7 2015-12-16 09:52:36 +01:00
Lars-Erik Aabech a14f0021bd Can't log into youtrack. Simple changes to repositoryfactory and umbraco.web.ui assemblyinfo. 2015-12-16 09:50:17 +01:00
Claus 5eb5549448 Merge branch 'U4-7462' of git://github.com/rasmusjp/Umbraco-CMS into rasmusjp-U4-7462 2015-12-16 09:36:49 +01:00
Claus f5e9151ffd Localized some texts on the slider configuration. 2015-12-15 15:42:14 +01:00
bjarnef 5a9dd11a7c Change margin-top for triangle and re-order config properties 2015-12-15 15:42:14 +01:00
bjarnef 9e6123abd3 Modify properties and styling 2015-12-15 15:42:13 +01:00
bjarnef 6c3ef2aaa9 Add more config properties 2015-12-15 15:42:13 +01:00
bjarnef 95ae504c9b Change "reversed" property to boolean 2015-12-15 15:42:12 +01:00
bjarnef 88fadcf74e Add slider bootstrap-slider v5.2.6
Add newer version of script and add addtional properties.
2015-12-15 15:42:12 +01:00
Sebastiaan Janssen bb4994f9fc Merge pull request #935 from torerikk/dev-v7
Update Norwegian translations
2015-12-15 15:10:46 +01:00
Claus c334f94d72 Fixed a few comments. 2015-12-15 14:47:19 +01:00
Claus ddf525db40 Merge branch 'AffinityID-u4-7522' into dev-v7 2015-12-15 14:43:22 +01:00
Claus 9c7ef46222 Merge pull request #941 from bugsancho/dev-v7
U4-7508 - IsChildOfListView should be populated for Media items
2015-12-15 14:18:27 +01:00
Sebastiaan Janssen eacc7f7fb3 Whoops, was supposed to be en-US by default 2015-12-15 13:50:19 +01:00
Sebastiaan Janssen 80f597a7eb U4-7424 - Also update all other errors displayed in the frontend 2015-12-15 12:51:45 +01:00
Sebastiaan Janssen d069da8a4f Make LocalizedTextService fall back to en-GB if the key is not found in the current file 2015-12-15 12:51:03 +01:00
Sebastiaan Janssen 44ebd8d9ea Proper formatting of this file, only whitespace changes 2015-12-15 12:18:23 +01:00
Sebastiaan Janssen 2fd6dc3603 Merge branch 'engern-U4-7424' into dev-v7 2015-12-15 12:14:07 +01:00
Sebastiaan Janssen 0629b49112 Merge branch 'U4-7424' of https://github.com/engern/Umbraco-CMS into engern-U4-7424 2015-12-15 12:13:35 +01:00
Sebastiaan Janssen 4958c5a59a Merge branch 'jamescoxhead-U4-7503-Disable-X-AspNetMvc-Version-Header' into dev-v7 2015-12-15 11:21:23 +01:00
Sebastiaan Janssen 523501db8c Merge branch 'U4-7503-Disable-X-AspNetMvc-Version-Header' of https://github.com/jamescoxhead/Umbraco-CMS into jamescoxhead-U4-7503-Disable-X-AspNetMvc-Version-Header 2015-12-15 11:21:11 +01:00
Sebastiaan Janssen 23cd2b09ca Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-12-15 11:13:22 +01:00
Sebastiaan Janssen a1ff1d4543 Merge branch 'TimoPerplex-dev-v7' into dev-v7 2015-12-15 11:12:57 +01:00
Sebastiaan Janssen 1bf2a3b1bf Merge branch 'dev-v7' of https://github.com/TimoPerplex/Umbraco-CMS into TimoPerplex-dev-v7
Conflicts:
	src/Umbraco.Web/Editors/ImagesController.cs
2015-12-15 11:12:13 +01:00
Shannon 8598ab565c Fixes: U4-7536 Sign-out in back office will call all ASP.Net identity middleware sign out methods
publicises a few things too.
2015-12-15 10:34:11 +01:00
Rasmus John Pedersen a56936b6f9 Fixes bug with macro multiline parameters 2015-12-14 13:44:57 +01:00
Andrey Shchekin b3e21e0827 U4-7522 Removed unnecessary exception from DeepCloneHelper. 2015-12-10 14:33:52 +13:00
James Coxhead 739ff33ce1 Removed X-AspNet-Version and X-AspNetMvc-Version headers 2015-12-08 21:44:40 +00:00
James Coxhead f27a726a6e Disabled the X-AspNetMvc-Version header 2015-12-08 21:19:41 +00:00
Alexander Todorov aed906e682 U4-7508 - IsChildOfListView should be populated for Media items, similarly to Content items 2015-12-08 18:41:59 +02:00
Sebastiaan Janssen 220446afec Adds some more dependencies so we upgrade those properly when necessary 2015-12-08 14:24:52 +01:00
Sebastiaan Janssen a101367292 This would've stayed here for years and be irrelevant, we can link to twitter profiles in the docs on Our 2015-12-08 14:02:43 +01:00
Sebastiaan Janssen e90fedb835 Bumps version 2015-12-08 13:54:57 +01:00
Sebastiaan Janssen d5f9dfecc4 U4-7496 Backoffice dropdowns quit working in Chrome after update to v47.0.2526.73
#U4-7496 Fixed
2015-12-08 13:54:56 +01:00
Claus cbb84f79d1 Merge pull request #799 from esn303/patch-1
Major revamp with keys added and texts fixed everywhere
2015-12-08 11:40:42 +01:00
Sebastiaan Janssen a7377d0686 Merge pull request #939 from hartvig/dev-v7
Fixing a little typo as reported by Chris Houston
2015-12-07 11:49:28 +01:00
hartvig 68a4749917 Fixing a little typo 2015-12-07 11:11:02 +01:00
Sebastiaan Janssen 81763bf4d8 Merge pull request #938 from hartvig/dev-v7
Adding number of countries to the installer faq
2015-12-07 10:25:09 +01:00
hartvig 0e0bc9fbef Adding number of countries to the installer faq 2015-12-07 10:11:35 +01:00
Claus 964d9a9328 Closing break tag. 2015-12-06 17:55:20 +01:00
Wincent e0ee786271 Re-enables support for non media thumbnails 2015-12-04 09:31:39 +01:00
Wincent 2664a75c84 Removed generation of old thumbnails 2015-12-03 17:33:40 +01:00
Wincent 5d9bde807e Changes GetBigThumbnail to image processor in mediahelper.service.js and fileupload.controller.js
Changed ImageController.GetBigThumbnail to redirect
Changed thumbnail paths to include rnd equal to UpdateDate
2015-12-03 17:27:47 +01:00
Tor-Erik Klausen 0370f9a1c8 Update Norwegian translations
Adds missing translations and removes some old ones. Based on current
en.xml
2015-12-02 20:09:06 +01:00
Sebastiaan Janssen 64dac39bae Merge branch 'temp-U4-7220' into dev-v7 2015-12-01 10:35:38 +01:00
Sebastiaan Janssen 6040d149ec Merge branch 'dev-v7' into temp-U4-7220 2015-12-01 09:57:44 +01:00
Claus bfbc6595fb Fixed a few more split separators. 2015-11-30 19:29:23 +01:00
Claus 25d8fc7a13 Fixing split separator for thumbnailSizes in FileUploadPropertyValueEditor. 2015-11-30 19:18:57 +01:00
Claus e11b5c3fdb Fixes: U4-7220 Upgrading 4.9.0 to 7.3.0 fails due to missing UniqueID field on cmsPropertyType table
Migration happening in 6.0.2 failing due to use of a PropertyTypeDto type where we have added UniqueId in 7.3.0.
2015-11-30 18:13:51 +01:00
Shannon 87100feb3d Fixes: U4-7467 Umbraco 7.3.2 Clean install, OWIN error after database creation and bumps version 2015-11-27 21:23:24 +01:00
Shannon Deminick eae74b0e20 Merge pull request #931 from lars-erik/fix-u4-7329
Actually save the domain
2015-11-27 16:56:07 +01:00
Shannon 610efe552d Bumps version 2015-11-27 16:54:02 +01:00
Shannon c4860a490f Ensures that GetUserSecondsMiddleWare uses the SystemClock for UTC Now, ensures that it only extends the ticket when necessary and not everytime this middleware is called - the same logic that OWIN normally renews tickets with, this means the cookie is not written everytime this request is made. 2015-11-27 16:43:02 +01:00
Shannon 8e6bbc3df9 Ensures that written cookies are done so consistently based on the UmbracoBackOfficeCookieAuthOptions. Ensures that when a webforms page requests token renewal that the token is not always renewed for the request, it checks if the tokens expiry correctly and only renews when necessary so the cookie is not written each time. Fixes the ForceRenewalCookieAuthenticationHandler to only write a cookie if the request is for a request that is not normally auth'd (i.e. is a webforms form that exists outside the normal /umbraco path ... legacy). 2015-11-27 16:25:39 +01:00
Lars-Erik Aabech c16d0b77c2 Actually save the domain 2015-11-27 12:59:15 +01:00
Sebastiaan Janssen 2c4403f892 Fixes image that was missing from the build 2015-11-26 13:08:59 +01:00
Shannon fd66f08520 Fixes setting auth cookie during install, removes some try/catch/swallow with some error messaging, converts some String -> string and == false updates. 2015-11-26 13:07:22 +01:00
Shannon 8e50f4968f Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-11-26 12:02:17 +01:00
Shannon 9acbe09449 fixes the tmh dynamic local version, the bower version the build server runs has an issue! 2015-11-26 12:02:08 +01:00
Sebastiaan Janssen 4baaafd006 Also remove change password dashboard from nuget package 2015-11-26 11:57:37 +01:00
Shannon 3f7293304d removes password change dashboard from release 2015-11-26 11:55:42 +01:00
Shannon f62581bd38 reverts more of the caps lock 2015-11-26 11:39:49 +01:00
Shannon 9782e3711e Revert "Update bower.json with ngCapsLock"
This reverts commit f0e1460550.

Conflicts:
	src/Umbraco.Web.UI.Client/bower.json
2015-11-26 10:54:43 +01:00
Shannon 1f4ba9cfdc ignores file that shouldn't be there 2015-11-26 10:36:15 +01:00
Shannon ba4f0cc6a4 remove file that shouldn't be checked in 2015-11-26 10:35:28 +01:00
Shannon fc84821e8b fixes U4-6340 Partial view macro with parameters not working in RTE - to use a Model to post with the same Action name 2015-11-26 10:32:43 +01:00
Shannon Deminick 0fcf0b505a Merge pull request #922 from engern/U4-6340
Fixes U4-6340 : Partial view macro with parameters not working in RTE and Grid (backend)
2015-11-26 09:54:24 +01:00
Shannon d300146cf6 trips content/media names, makes sure that the content type editor when rendering template names html encodes the names. 2015-11-25 20:44:53 +01:00
Shannon c8482b9f59 Revert "Merge pull request #875 from Phosworks/U4-7312"
This reverts commit 14265fc964, reversing
changes made to 18c3345e47.

Conflicts:
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js
	src/Umbraco.Web/Editors/ImagesController.cs
2015-11-25 20:27:58 +01:00
Shannon b7795e19ef Changes bigthumbnail pr to not cache per second, just minute 2015-11-25 20:21:24 +01:00
Shannon c97617f5b5 Fixes: U4-7461 xss vulnerability in content type editor 2015-11-25 20:15:28 +01:00
bjarnef b2d4eccf7b Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-25 20:13:15 +01:00
Shannon Deminick 14265fc964 Merge pull request #875 from Phosworks/U4-7312
Changed web api GetBigThumbnail to image processor
2015-11-25 19:52:14 +01:00
Shannon 18c3345e47 Fixes U4-7459 XSRF protection bypass - ensures tokens are checked for the non-editor api controllers 2015-11-25 19:39:24 +01:00
Shannon 924a016ffe Fixes U4-7457 Server side request forgery (xsrf) in feedproxy.aspx 2015-11-25 18:05:57 +01:00
Claus a02b41e9d2 Merge pull request #927 from umbraco/temp-U4-7307
U4-7307 Windows Authentication prompts for Windows login after Umbrac…
2015-11-25 15:22:36 +01:00
Shannon 068c4a0b16 Fixes PR for U4-7362 Add message to login screen if Caps Lock is on 2015-11-25 11:22:12 +01:00
Shannon Deminick f7d28d769a Merge pull request #886 from bjarnef/dev-v7-U4-7362
Add message to login screen if Caps Lock is on
2015-11-25 11:01:47 +01:00
Claus 9a07e206d8 Merge pull request #874 from andydale1982/U4-7323_(#871)‏
U4 7323 (#871)‏
2015-11-25 10:51:41 +01:00
Shannon Deminick 0edb71f4aa Merge pull request #917 from bjarnef/dev-v7-move-umb-version-in-dialog
Move Umbraco version label to header in user dialog
2015-11-25 10:51:36 +01:00
Shannon Deminick b376207ef6 Merge pull request #868 from opelpanfan/UKFest-U4-7324
U4-7324 Member Picker search results doesn't show correct icons
2015-11-25 10:33:59 +01:00
kiasyn dbece874dd U4-7400 - Datepicker is not updating scope model value in time for 3rd party plugins
Force set scope model value when the datetime changes, rather than just on formsubmit. This means that 3rd party plugins (such as grids) can use this editor.
2015-11-25 10:25:00 +13:00
Shannon 6d0aa824ad U4-7307 Windows Authentication prompts for Windows login after Umbraco login 2015-11-24 16:31:18 +01:00
Claus 89afacf161 Merge pull request #915 from umbraco/temp-U4-7380
U4-7380 Backoffice timeouts after 7.3.1  upgrade
2015-11-24 11:35:01 +01:00
Claus 0fa6940bb6 Merge branch 'arknu-U4-6657-mediapicker' into dev-v7 2015-11-24 10:37:11 +01:00
Claus 1353b0a592 Reordering flex properties - recess module crashes with out of memory exception if they are in the other order. 2015-11-24 10:35:54 +01:00
Claus 617fec171f Merge branch 'U4-6657-mediapicker' of git://github.com/arknu/Umbraco-CMS into arknu-U4-6657-mediapicker 2015-11-24 10:33:04 +01:00
Claus 2c63866cb3 Merge pull request #909 from umbraco/U4-7270-1
Creates an IAsyncRenderMvcController which can be used instead of IRe…
2015-11-24 10:09:45 +01:00
Sebastiaan Janssen 18d3aa9ee2 Merge pull request #926 from kiasyn/patch-1
Remove unnecessary ToLowerInvariant call from PreviewMode
2015-11-23 22:17:07 +01:00
kiasyn f83c966e55 Remove unnecessary ToLowerInvariant call from PreviewMode
Text was being set lowercase and then injected with the preview badge markup. This meant that things such as script tags were being lowercased, breaking the javascript.
2015-11-24 10:02:14 +13:00
Tommy Enger de41a1f1ca Clean up the code
DRY
2015-11-23 16:29:09 +01:00
Tommy Enger c9f57c6ce3 Split Get and Post
Split Get and Post into 2 separate methods to maintain backwards
compability
2015-11-23 15:52:36 +01:00
engern 54ab26e2ed Simplifying thge code even further
Realized that we don't need to convert the exisitng dictionary to a new
dictionary.
2015-11-21 14:00:58 +01:00
engern 31dc1b2cdb Fixes U46340 2015-11-21 13:20:13 +01:00
engern 07c714fd11 Fixes U4-7424
Add the possibilty to change the error message when a macro partial view
fails to render.
2015-11-21 11:33:46 +01:00
Claus d4b9a711c6 Merge pull request #919 from umbraco/temp-U4-4641
Fixes: U4-4641 Feature Request:  template and code editors should have insert Section, Define section buttons
2015-11-20 13:41:50 +01:00
Claus 9521742254 Fixes to MultiNodePicker when using media. 2015-11-20 13:17:28 +01:00
Claus 9fee3f5873 Merge pull request #918 from umbraco/temp-U4-5764
Related to: U4-5764 - adding in Open button on content/media picker
2015-11-20 12:09:21 +01:00
Claus cb10578e19 Merge branch 'Nicholas-Westby-feature/U4-5764-node-picker-info' into temp-U4-5764 2015-11-20 11:52:25 +01:00
Claus cdc4435f2d Merge branch 'feature/U4-5764-node-picker-info' of git://github.com/Nicholas-Westby/Umbraco-CMS into Nicholas-Westby-feature/U4-5764-node-picker-info 2015-11-20 11:47:48 +01:00
bjarnef a885840b9f Move Umbraco version label to header in user dialog 2015-11-19 21:55:54 +01:00
bjarnef 62173cef58 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-19 21:12:24 +01:00
Shannon Deminick e5b0a4d98c Merge pull request #854 from Spijkerboer/UKFest-U4-7322
Uk fest u4 7322
2015-11-19 19:26:53 +01:00
Shannon Deminick 9479d63cba Merge pull request #899 from Acentrage/U4-7219
Fixes U4-7219
2015-11-19 19:24:24 +01:00
Shannon 4c544acb42 fixes links so that working with vdirs works too. 2015-11-19 19:21:55 +01:00
Shannon Deminick c7c5f481f1 Merge pull request #879 from danieland/U4-4794--nodebug
U4 4794  nodebug
2015-11-19 19:10:35 +01:00
Shannon 5e8e62cbf7 missing csproj save 2015-11-19 18:29:11 +01:00
Shannon 555b520a0c Cleans up the usages of auth cookies. OWIN is in charge of auth cookies but because we have Webforms, WebApi, MVC and OWIN, they all like to deal with cookies differently. OWIN should still be solely in charge of the auth cookies, so the auth extensions are cleaned up, the renewal now works by queuing the renewal and we have custom middleware detect if a force renewal has been queued and we renew the auth cookie there. Have obsoleted a few methods that should not be used that write auth tickets directly (this is purely for backwards compat with webforms). All of these changes now ensure that the auth cookie is renewed consistently between Webforms, WebApi, MVC and OWIN. Some changes also include ensuring that OWIN is used to sign out. 2015-11-19 18:12:21 +01:00
Simon Busborg 8053db32b6 code comments 2015-11-19 15:40:38 +01:00
Sebastiaan Janssen 3e2d59e526 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-11-19 14:43:45 +01:00
Sebastiaan Janssen 9d3e967c2a Ignore test that keeps crapping out on build server 2015-11-19 14:43:35 +01:00
Shannon 71ec09486d Reverts the 'fix' from U4-7118 since it is incorrect. Updates the sliding expiration of the cookie/ticket when the user is supposed to be always logged in to 30 minutes in case the timeout is actually set very low in config. 2015-11-19 14:17:06 +01:00
Claus 8dadc92aa8 Fixed migration causing issues when upgrading from a site pre-migrations-table to version 7.3.2. 2015-11-19 12:01:46 +01:00
Shannon f472f5d950 Ensures that OWIN signout method is called - this ensures that any auth middleware configured for the current user is called for sign out. Updates our cookie middleware provider to also ensure that our custom cookies are cleared when signing out with OWIN. 2015-11-19 11:57:24 +01:00
Simon Busborg 775a6f80ea Added comments to support the changes 2015-11-19 11:47:49 +01:00
Simon Busborg 5bf8b8ecba Used less function 'fade' instead of random color 2015-11-19 11:44:33 +01:00
Simon Busborg 397ef32665 Added hover & active state to input-label--small 2015-11-19 11:40:29 +01:00
Simon Busborg 2634e33f51 Used @fontSizeLarge variable to determine font-size for panel-dialog--header 2015-11-19 11:27:56 +01:00
Simon Busborg 6e27caa547 Added comments and notes 2015-11-19 11:11:09 +01:00
Simon Busborg 9c027dcdbc some ui love for the panel dialogs 2015-11-19 10:32:17 +01:00
bjarnef f3876b86dc Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-19 00:38:32 +01:00
Shannon Deminick 58c3dfac1c Merge pull request #913 from Nicholas-Westby/feature/u4-7425-forms-constant-comment
Fixed typo for "forms": http://issues.umbraco.org/issue/U4-7425
2015-11-19 00:34:54 +01:00
Nicholas-Westby dcf59d2b17 Fixed typo for "forms": http://issues.umbraco.org/issue/U4-7425 2015-11-18 14:29:10 -08:00
bjarnef 71099514cb Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-18 22:00:33 +01:00
Sebastiaan Janssen 887111318f Update install facts 2015-11-18 20:35:36 +01:00
Sebastiaan Janssen bf9755b27c Don't end response so people can actually hook into PostRequestHandlerExecute 2015-11-18 19:41:20 +01:00
Sebastiaan Janssen aca181b32e U4-7410 Version issue with MySql.Data after upgrade to 7.3.1.
#U4-7410 Fixed
2015-11-18 19:39:10 +01:00
Shannon Deminick 886347e763 Merge pull request #912 from lars-erik/fix-u4-7268
Support generic CultureInfo as language culture
2015-11-18 18:26:09 +01:00
Shannon Deminick 9fa606e065 Merge pull request #907 from umbraco/temp-U4-7414
U4-7414 Deleted tab's properties should become generic properties
2015-11-18 17:01:02 +01:00
Shannon e40ac44afd updates test to reflect the instructions to replicate the original issue U4-7414 2015-11-18 17:00:27 +01:00
Shannon 48603fb840 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-11-18 16:07:10 +01:00
Shannon f824439180 Merge branch 'UKFest-U4-4792' of https://github.com/opelpanfan/Umbraco-CMS into opelpanfan-UKFest-U4-4792
Conflicts:
	src/Umbraco.Core/Services/ContentService.cs
2015-11-18 16:07:01 +01:00
Shannon Deminick b3616c9f8c Merge pull request #911 from umbraco/temp-U4-4792
Fixes: U4-4792 Ancestors() on IContent throws "Object reference not set to an instance of an object."
2015-11-18 16:04:22 +01:00
Shannon 48383f2e7a updaes null check and ensures the path isn't pre-set in the withidentity overload 2015-11-18 16:04:01 +01:00
Shannon cb98385242 updates content/media service methods - null checks for parent IContent, dosn't use Parent() syntactic sugar methods, removes path creation in the WithIdentity methods. 2015-11-18 15:52:32 +01:00
Shannon 916bad82df Ensures that the RenderActionInvoker isn't doing anything special so that MVC takes care of everything regarding async vs non-async and any controller descriptor/action descriptor lookups and cache. Creates a RenderIndexActionSelectorAttribute - this is used to decorate the underlying RenderMvcController.Index action. MVC will call into this method to check if the MethodInfo is valid, we then do a quick comparison of types, if the current type is the same as the reflected type, this means that the Index action has been overridden or there is no custom controller... lets use it. If the types don't match we'll do a simple reflected lookup to check if the reflected controller type (current controller) has more than one index action, if so, it means that a custom controller is in play and it has a custom index action... so we won't use the base class action and then it's up to MVC to find any other matching Index action based on the current request parameters. Added some tests for this too. 2015-11-18 14:59:29 +01:00
Claus 29ec8cb2d3 Merge pull request #857 from gerwinbouwhuis/UKFest-U4-5581
Uk fest u4 5581
2015-11-18 14:32:52 +01:00
Lars-Erik Aabech 04900337c7 Support generic CultureInfo as language culture 2015-11-18 14:13:32 +01:00
Claus 1433685160 MediaService assigns Path when creating media objects. 2015-11-18 09:26:45 +01:00
Stephan c5994ed54a Fix previous commit 2015-11-17 17:25:01 +01:00
Shannon 9fd80d791a Creates an IAsyncRenderMvcController which can be used instead of IRenderMvcController if developers want access to an async Index action. 2015-11-17 17:05:00 +01:00
Stephan f5f9cb676c Fix CultureInfo leak in UmbracoApplicationBase too. 2015-11-17 16:54:24 +01:00
Claus 04e2d2370a Fixes: U4-4792 Ancestors() on IContent throws "Object reference not set to an instance of an object." 2015-11-17 16:49:01 +01:00
Stephan 8d00d931b0 U4-7414 Deleted tab's properties should become generic properties 2015-11-17 16:36:57 +01:00
Shannon Deminick 2998ad8cea Merge pull request #873 from AffinityID/u4-7352
U4-7352 Fixed exception logging in UmbracoDatabase.
2015-11-17 16:21:18 +01:00
Shannon Deminick 46c15ef28f Merge pull request #877 from cheeseytoastie/UKFest-7341
Ukfest 7341
2015-11-17 16:19:35 +01:00
Claus 2b369a57d8 Merge pull request #864 from andycyberian/UKFest-U4-6980
Uk fest u4 6980
2015-11-17 14:25:38 +01:00
Claus c37a6bb928 Merge pull request #870 from JJCLane/UKFest-U4-6094
Adds a check to include users in the send to translation list that ha…
2015-11-17 13:48:01 +01:00
Claus 6e53291877 Fixed up a few things. 2015-11-17 13:42:00 +01:00
Claus bb78f756c7 Merge branch 'Jeavon-U4-4641' into temp-U4-4641 2015-11-17 12:47:18 +01:00
Claus ffb0de4050 Merge branch 'U4-4641' of git://github.com/Jeavon/Umbraco-CMS into Jeavon-U4-4641 2015-11-17 12:46:24 +01:00
Claus 0fecad9867 Merge pull request #906 from umbraco/temp-U4-6515
Fixes: U4-6515 Media picker does not set $dirty
2015-11-17 11:51:58 +01:00
Claus 3045068d68 Fixes: U4-6515 Media picker does not set $dirty
Included fix for member picker.
2015-11-17 10:59:21 +01:00
Claus 37a6668313 Merge branch 'U4-6515' of git://github.com/deepak4u/Umbraco-CMS into deepak4u-U4-6515 2015-11-17 10:50:07 +01:00
Sebastiaan Janssen 36814d746f Merge pull request #905 from GertyEngrie/dev-v7
U4-7297 - fixes <hr/>-button in tinymce
2015-11-17 10:34:37 +01:00
Claus a72f6edb6b Merge pull request #846 from OptimisticCoder/UKFest-U4-6732
U4-6732 - Added message on back office, when JS is disabled.
2015-11-17 10:23:06 +01:00
Sebastiaan Janssen e01cbcd405 Fix failing upgrade due to old dll being in bin folder 2015-11-17 09:24:22 +01:00
Claus 012ed6cf16 Merge pull request #862 from dampee/u4-7314
U4-7314 Change name of "Textbox Multiple" to "TextArea"
2015-11-17 08:57:49 +01:00
Gerty Engrie eb3ff12916 U4-7297 - fixes <hr/>-button 2015-11-17 00:35:10 +01:00
Claus 1ebff69358 Merge pull request #904 from umbraco/temp-U4-7393
Fixes: U4-7393 Actions menu placed behind publish button on mobile phone
2015-11-16 16:02:00 +01:00
Claus 5435c44ea9 Using a lower z-index to fix the issue at hand. 2015-11-16 16:00:43 +01:00
Claus 76fa477c35 Merge branch 'U4-7393' of git://github.com/Acentrage/Umbraco-CMS into Acentrage-U4-7393 2015-11-16 15:55:04 +01:00
Claus 1f6f36d8c8 Updated unit test after adding in TaskTypeMapper. 2015-11-16 15:53:58 +01:00
Claus Jensen c46ac11125 Merge pull request #849 from mzajkowski/UKFest-U4-6282
U4-6282  Add note to Register Partial Macro
2015-11-16 15:37:47 +01:00
Claus 73d5a3f993 Merge branch 'opelpanfan-UKFest-U4-6511' into dev-v7 2015-11-16 15:31:29 +01:00
Claus Jensen 5a99a6903d Merge pull request #888 from umbraco/temp-U4-7353
Fixes: U4-7353 OAuth providers for the back office require more flexi…
2015-11-13 14:47:11 +01:00
Shannon Deminick 775639da41 Merge pull request #848 from Khinrot/UKFest-U4-5560
Fixing "U4-5560 White space issue in content tree"
2015-11-13 14:06:40 +01:00
Shannon Deminick 2375ede161 Merge pull request #867 from jbreuer/U4-4028
U4-4028 Don't load the full images, but server side resized.
2015-11-13 13:41:53 +01:00
Shannon Deminick fcd00599da Merge pull request #858 from tompipe/U4-1959
Fixes U4-1959
2015-11-13 13:40:26 +01:00
Shannon d3f5090150 Fixes up a couple of missing path updates and incorrect icon resolution and fixed another issue with webservice path reference 2015-11-13 13:38:30 +01:00
Shannon 6a7faf457b Merge branch 'dev-uk-U4-1117' of https://github.com/JeffreyPerplex/Umbraco-CMS into JeffreyPerplex-dev-uk-U4-1117 2015-11-13 11:35:29 +01:00
Shannon ec247d2b27 ensures the migration table's seed is higher than 1 (have put it to 100). 2015-11-13 11:31:59 +01:00
Shannon f32479bb10 bumps version 2015-11-13 11:26:31 +01:00
Shannon Deminick 371269436f Merge pull request #891 from umbraco/temp-U4-7128
Fixes: U4-7128 Send to Translation gives YSOD
2015-11-13 10:23:41 +01:00
Claus ef13e4112f Merge branch 'UKFest-U4-6511' of git://github.com/opelpanfan/Umbraco-CMS into opelpanfan-UKFest-U4-6511 2015-11-12 16:40:01 +01:00
Claus Jensen ce5b6861bb Merge pull request #855 from ryanmcdonough/UKFest-U4-5617
UKFest-U4-5617 RTE now respects CSS Directory AppSetting.
2015-11-12 16:35:27 +01:00
Acentrage eaf64d1814 Increased timeout from 200 to 1000 ms so you can actually type something and added support for manually submit with enter without waiting for the timer. 2015-11-12 15:33:49 +01:00
Acentrage 6bf1ecdb11 Fixes U4-7393
Safe to use both for mobile and desktop.
2015-11-12 15:17:27 +01:00
Claus Jensen fdd0ff2c23 Merge pull request #897 from umbraco/temp-U4-7070
Fixes: U4-7070 UX - Mediapicker autofocus when creating a folder
2015-11-12 15:14:19 +01:00
Claus bade8e42ba Fixes to media picker when creating new folders.
Changed to ngShow to ensure input field hides when blur event is hit.
Clearing and switching visibility of input field on successful submit.
Fixed up focus directive to use $timeout. The focus event can trigger before the element is rendered by angular so its safer to have a timeout ensure it is done at the end of the digest cycle - using $timeout instead of setTimeout ensures it is handled by angular at the right time.
2015-11-12 15:12:59 +01:00
Claus cfdf2768e6 Merge branch 'UKFest-U4-7070' of git://github.com/JJCLane/Umbraco-CMS into JJCLane-UKFest-U4-7070 2015-11-12 14:05:10 +01:00
Claus Jensen c3ca006f14 Merge pull request #896 from umbraco/temp-U4-3774
Fixes: U4-3774 Change password UX
2015-11-12 13:36:36 +01:00
Claus 6c47c8f792 Added danish translation. 2015-11-12 13:36:13 +01:00
Claus 63160e2e2d Removing the Change Password tab from Content section. 2015-11-12 13:31:03 +01:00
Claus edc58fe8a5 Merge branch 'dev-uk-U4-3774' of git://github.com/JeffreyPerplex/Umbraco-CMS into JeffreyPerplex-dev-uk-U4-3774 2015-11-12 11:23:36 +01:00
Claus Jensen 23632dc0c3 Merge pull request #856 from tompipe/U7-6928
Fixes U4-6928 - Persist Creator ID of member
2015-11-12 11:07:57 +01:00
Claus Jensen d739b9fb31 Merge pull request #894 from umbraco/temp-U4-6167
Fixes: U4-6167 MNTP: show path of selected node
2015-11-12 10:58:24 +01:00
Claus 2ae4ede258 Showing path when hovering nodes should be configurable on the content picker. 2015-11-12 10:55:00 +01:00
Claus cacd08b57c Merge branch 'tompipe-U4-6167' into temp-U4-6167 2015-11-11 17:21:51 +01:00
Claus 4eddfb4cf5 Merge branch 'U4-6167' of git://github.com/tompipe/Umbraco-CMS into tompipe-U4-6167 2015-11-11 17:13:40 +01:00
Claus f2b3d7c041 Removed commented out line. 2015-11-11 12:07:45 +01:00
Claus 5d97a94dcb Fixed to use alias instead of hardcoded id.
Added mapper for TaskType.
2015-11-11 12:02:12 +01:00
Claus de6e7dd28d Merge branch 'U4-7128' of git://github.com/tompipe/Umbraco-CMS into tompipe-U4-7128 2015-11-11 11:14:38 +01:00
Claus Jensen 420c029bf7 Merge pull request #859 from Khinrot/UKFest-U4-6426
Fixing "U4-6426 CTRL click should open in a new window"
2015-11-11 11:12:22 +01:00
Claus 61441dd436 Fixes: U4-7370 Upgrading from 7.3.1 to 7.4 fails
cherrypicked from 7.4.0 branch.
Added migration for 7.3.2, ensuring the identity on the table is correct. It failed due to rows initially being inserted with identity disabled and therefore the seed of the table was zero even when the table had data.
2015-11-10 12:15:44 +01:00
bjarnef 5c24867925 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-09 23:52:27 +01:00
Wincent 0409cbe613 Changed ImageController.GetBigThumbnail to redirect
Changed thumbnail paths to include rnd equal to UpdateDate
2015-11-09 21:41:25 +01:00
Shannon bbbea99ced removes redundant null check. 2015-11-09 10:56:07 +01:00
Shannon 3d213342bf Fixes: U4-7353 OAuth providers for the back office require more flexibility with Challenge Results 2015-11-09 10:42:15 +01:00
Sebastiaan Janssen 48fdb75d96 Improves clean scripts for Claus 2015-11-09 09:25:59 +01:00
Sebastiaan Janssen a97094458d U4-7356 <siteMap><providers> element can only be added once, when using nuget update-packge
U4-7356 Fixed
2015-11-09 09:25:58 +01:00
Nicholas-Westby f81353af0b Amended last commit for detailed node info (so it plays nice when picking media): http://issues.umbraco.org/issue/U4-5764
Also added node path to title of "Open" button (so it shows the full path on hover).
More consistent quoting (namely, using apostrophes rather than double quotes).
2015-11-08 17:16:17 -08:00
bjarnef f0e1460550 Update bower.json with ngCapsLock 2015-11-09 00:34:34 +01:00
bjarnef d15c09ad2a Localize "Caps Lock is on" 2015-11-09 00:06:16 +01:00
Nicholas-Westby 5813202892 Finished implementation of detailed node info (added breadcrumb to content dialog): http://issues.umbraco.org/issue/U4-5764
Also moved the breadcrumb into a directive since it was used in multiple places.
2015-11-07 23:51:07 -08:00
bjarnef 82f6b6a66d Add ngCapsLock 2015-11-07 23:53:35 +01:00
bjarnef eec6ee79aa Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-07 00:25:49 +01:00
Nicholas-Westby 5ed4f262cd Partial implementation of detailed node info (changed button text to "Open" and styled a bit): http://issues.umbraco.org/issue/U4-5764 2015-11-04 22:25:37 -08:00
Nicholas-Westby e5d7f6fd04 Partial implementation of detailed node info (show node in "view" is clicked): http://issues.umbraco.org/issue/U4-5764 2015-11-03 22:39:36 -08:00
Daniel a9ad0ae8eb removed the debug check 2015-11-02 23:34:33 +01:00
Daniel Andreasen 9cd64a9061 Merge pull request #2 from umbraco/dev-v7
merge from umbraco/
2015-11-02 22:41:44 +01:00
Steve Morgan 839c0d011b Added ConfigureAwait(false)
ConfigureAwait(false) is recommended on async calls?
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Credit: @dampeebe
2015-11-02 10:26:25 +00:00
Nicholas-Westby 15c9aadcdc Partial implementation of detailed node info: http://issues.umbraco.org/issue/U4-5764 2015-11-01 22:43:27 -08:00
Wincent 36a1c0a9e0 Changed web api GetBigThumbnail to image processor in mediahelper.service.js and fileupload.controller.js 2015-10-31 16:31:19 +01:00
Stephan 30f0c96052 Fix AsyncLock finalizer throwing exceptions 2015-10-31 12:47:04 +01:00
Stephan cfab30a1ef Fix thread CultureInfo issue breaking PetaPoco 2015-10-31 12:47:03 +01:00
Stephan 1dd0086eb5 Revert "strange/crazy peta poco fix for cultures"
This reverts commit 0d29e1438c.
2015-10-31 12:47:02 +01:00
andydale1982 a7f06ebc56 Typo Correction 2015-10-30 10:38:05 +00:00
Andrey Shchekin 9498bc4bfd U4-7352 Fixed exception logging in UmbracoDatabase. 2015-10-30 11:24:18 +13:00
Jeavon Leopold 38b13bf6ce Basic implementation for U4-4641 2015-10-29 17:18:40 +00:00
Jeavon Leopold c8cb5b26b0 Basic implementation for U4-4641 Feature Request: template and code editors should have insert Section, Define section buttons 2015-10-29 17:14:45 +00:00
andydale1982 5749f80a7f Added instructions to manually install node_modules. 2015-10-29 17:10:39 +00:00
Jordan Lane 5d9a935621 Adds a check to include users in the send to translation list that have the translate permission for current page
http://issues.umbraco.org/issue/U4-6094#
2015-10-29 16:50:00 +00:00
Tom Pipe 1ff4fe26dd Fixes YSOD after send to translation 2015-10-29 16:43:54 +00:00
Benas Brazdziunas bd69820028 Member Picker search results doesn't show correct icons 2015-10-29 16:29:33 +00:00
Jeroen Breuer 3c9953979a U4-4028 Don't load the full images, but server side resized. 2015-10-29 17:00:23 +01:00
andydale1982 2f6189ae24 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-29 15:55:49 +00:00
deepak4u 5ff329778d fix for issue u4-6515 2015-10-29 15:53:11 +00:00
Andy Rose befb2b4d2f U4-6980: Fixing merge issue 2015-10-29 15:32:03 +00:00
Andy Rose f4ae45d8f2 U4-6980: Adding supporting unit tests for changes to the template repository 2015-10-29 15:29:23 +00:00
Andy Rose 7b73ed1796 U4-6980: Adding supporting unit tests for changes to the template repository 2015-10-29 15:29:22 +00:00
Andy Rose 0eacbcb7cb U4-6980: Only assume a masterpage template if a MVC hasn't already been created 2015-10-29 15:29:20 +00:00
Jeffrey Schoemaker f871de61d5 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:28:12 +01:00
Jeffrey Schoemaker e02693e46b U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:27:33 +01:00
Jeffrey Schoemaker db62d14b1a U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:27:05 +01:00
Jeffrey Schoemaker c096ab9e54 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:26:31 +01:00
Jeffrey Schoemaker ada5a031b4 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:26:06 +01:00
Jeffrey Schoemaker 9c8b9f8bb4 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:25:41 +01:00
Jeffrey Schoemaker a4bd3abfbe U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:25:15 +01:00
Jeffrey Schoemaker a8a768a50f U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:24:41 +01:00
Jeffrey Schoemaker 62b99ffc59 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:24:16 +01:00
Jordan Lane 8e6bac534a Fix a bug where PublishStatusType would fallback to FailedContentInvalid (and break) if it was expired or trashed and add error message for FailedHasExpired
TODO: Add error message to other languages
2015-10-29 15:23:40 +00:00
Jeffrey Schoemaker 6b0c94948e U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:23:30 +01:00
Jeffrey Schoemaker 25f049e167 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:22:39 +01:00
Jeffrey Schoemaker f7979fa19d U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:22:05 +01:00
Jeffrey Schoemaker 6fd1784337 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:21:25 +01:00
Jordan Lane c5cf1fa6b2 Checks if content has expired or is awaiting release before publishing 2015-10-29 15:21:15 +00:00
Jordan Lane 1e4c9c2505 Set the publish status of new content version to saved if validation of publication fails e.g. a release date of the future or past unpublish date 2015-10-29 15:20:35 +00:00
Jeffrey Schoemaker a7bb8e0d00 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 16:20:17 +01:00
Jeffrey Schoemaker ed4a9f84f0 U4-1117 - Fixed any errors when renaming /umbraco to something else
We removed the ~/umbraco from the reserved path settings key. We could'nt find the location where the same setting is set in the web.config.
The variable is no longer needed as the "umbracoPath" value is automatically inserted into the reserved path setting.
2015-10-29 16:18:14 +01:00
Jordan Lane a6b56db2f5 Fixes an issue with the contentService.RePublishAll() where it wouldn't publish an old published version if the newest version of the content wasn't published i.e had a scheduled date set because this would create a new version with status not published 2015-10-29 15:16:44 +00:00
Sebastiaan Janssen bbe4a87784 U4-6171 Continuous Deployment from Visual Studio Online to Azure Websites not working as expected
#U4-6171 Fixed
2015-10-29 16:07:07 +01:00
Sebastiaan Janssen cbd5c295bd Merge pull request #728 from vnbaaij/dev-v7
Fix for #U4-6171 Continuous Deployment from Visual Studio Online to A…
2015-10-29 16:05:20 +01:00
Shannon 0d29e1438c strange/crazy peta poco fix for cultures 2015-10-29 15:24:06 +01:00
Jeffrey Schoemaker 4796827f02 U4-1117 - Fixed any errors when renaming /umbraco to something else 2015-10-29 15:05:24 +01:00
Andy Rose c6f7ece764 Merge branch 'UKFest-U4-6980' of https://github.com/andycyberian/Umbraco-CMS into UKFest-U4-6980 2015-10-29 14:00:46 +00:00
Andy Rose e86aaefaaf U4-6980: Only assume a masterpage template if a MVC hasn't already been created 2015-10-29 13:59:09 +00:00
Andy Rose 97e9cd4be0 U4-6980: Only assume a masterpage template if a MVC hasn't already been created 2015-10-29 13:54:12 +00:00
Asbjørn Riis-Knudsen 63af822bad U4-6657: Use flexbox for mediapicker search field and upload button to allow button to scale for different translations 2015-10-29 14:52:18 +01:00
Tom Pipe b65f653c91 Fixes U4-1959 2015-10-29 13:08:37 +00:00
Damiaan 3b404a2f76 U4-7314 Change name of "Textbox Multiple" to "Large textbox" or "Textarea" 2015-10-29 13:54:16 +01:00
Tom Pipe e9567e7adc Fixes U4-6928 - Persist Creator ID of member 2015-10-29 12:52:36 +00:00
gerwin.bouwhuis 697daab4d7 change :get the correct alternative recursive field 2015-10-29 13:50:30 +01:00
Alejandro Ocampo 6c29ad854c Fixing "U4-6426 CTRL click should open in a new window" 2015-10-29 12:48:40 +00:00
gerwin.bouwhuis 93d89535aa undo 2015-10-29 13:32:50 +01:00
gerwin.bouwhuis eb093ca4a6 change : find the correct alternative recursive field 2015-10-29 13:23:43 +01:00
ryanmcdonough 1040f234dc Update grid.rte.directive.js 2015-10-29 12:09:29 +00:00
Sebastiaan Janssen 5a1ace9362 Revert "Fixes tests failing due to missing path"
This reverts commit 0c402310d9.
2015-10-29 13:00:51 +01:00
ryanmcdonough 3f835fe19c RTE now respects CSS Directory AppSetting.
Fixes #U4-5617
2015-10-29 12:00:43 +00:00
Dennis Spijkerboer bf43ce3281 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into UKFest-U4-7322 2015-10-29 12:57:27 +01:00
Dennis Spijkerboer c37ba0dc8a Checked if the trimmed value starts and ends with brackets. If so, use the trimmed value. 2015-10-29 12:56:07 +01:00
Jeffrey Schoemaker 7b5ad9a5c6 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:44:30 +01:00
Steve Morgan f0afa701bc Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-29 11:38:03 +00:00
Jeffrey Schoemaker 71dc1110d8 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:38:00 +01:00
Jeffrey Schoemaker 4de4eb9cc8 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:34:05 +01:00
Jeffrey Schoemaker 308d5ba344 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:32:57 +01:00
Tom Pipe 74dac71e8a Fixes U4-6167 - Show path of selected node 2015-10-29 11:31:53 +00:00
Jeffrey Schoemaker 64518774c6 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:29:24 +01:00
Jeffrey Schoemaker f65b0df3e2 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:28:23 +01:00
Jeffrey Schoemaker 5cfe9e85f8 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:27:32 +01:00
Jeffrey Schoemaker 61044b6018 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:23:47 +01:00
Jeffrey Schoemaker 00fc5a5bb2 U4-3774 / U4-4752 - Added a change password form to the user dialog 2015-10-29 12:22:20 +01:00
Stephan da85e4eb28 fixes list view ancestor check fix 2015-10-29 12:20:10 +01:00
Alejandro Ocampo 3f23865e0a Fixing "U4-5560 White space issue in content tree" 2015-10-29 11:06:31 +00:00
Shannon fbc08d66f1 fixes list view ancestor check 2015-10-29 12:05:46 +01:00
Shannon 79f04bf939 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-29 11:57:07 +01:00
Shannon 9ab90595e2 Adds a filter to the interceptor to ignore errors for certain requests. 2015-10-29 11:56:23 +01:00
Marcin Zajkowski aac208c0e8 U4-6282 Add note to Register Partial Macro 2015-10-29 10:53:29 +00:00
Benas Brazdziunas f8e101ec13 U4-6511 make MNTP icon clickable 2015-10-29 10:43:04 +00:00
OptimisticCoder 23fcc1ac55 Added message on back office, when JS is disabled.
" JAVASCRIPT IS DISABLED. PLEASE ENABLE TO CONTINUE!"
2015-10-29 10:28:49 +00:00
Jordan Lane 6356531207 Focus new folder input automatically
http://issues.umbraco.org/issue/U4-7070
2015-10-29 10:22:34 +00:00
Sebastiaan Janssen 51b618826c Merge pull request #844 from ryanmcdonough/UKFest-U4-7151
Update database placeholder to backslash for instance name.
2015-10-29 11:16:56 +01:00
ryanmcdonough 04c28e5006 Update database placeholder to backslash for instance name. 2015-10-29 09:56:22 +00:00
andydale1982 e9ef9b9d75 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-29 09:54:19 +00:00
Sebastiaan Janssen c160ce98c1 Merge pull request #794 from mstodd/dev-v7
Setting UMB_CONTEXT with Domain "FALSE"
2015-10-29 10:19:28 +01:00
Sebastiaan Janssen c3a60ea0e0 Merge pull request #838 from ryanmcdonough/U4-7302
Login overlay now higher than bootstrap datepicker
2015-10-29 09:19:42 +01:00
Stephan 3408efdee4 Merge pull request #842 from umbraco/temp-U4-7285
U4-7285 Fix DistributedCache.ClearXxxCacheOnCurrentServer
2015-10-28 19:38:04 +01:00
Shannon 1f0dc7e65d Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-28 18:26:44 +01:00
Shannon f89083c772 bumped version 2015-10-28 18:26:34 +01:00
Sebastiaan Janssen 752065e540 Merge pull request #835 from umbraco/temp-U4-7032
U4-7032 7.3.0 Custom backoffice login provider requires simpler implementation extensibility
2015-10-28 18:25:10 +01:00
Sebastiaan Janssen 82e4e50584 Merge pull request #841 from umbraco/temp-U4-7231
U4-7231 TryConvertTo<T> of ObjectExtensions doesn't do null checks (c…
2015-10-28 17:09:30 +01:00
Sebastiaan Janssen 775e63148d Merge branch 'temp-U4-5963' into dev-v7 2015-10-28 17:02:51 +01:00
Sebastiaan Janssen 4259b02b8d Merge branch 'dev-v7' into temp-U4-5963
Conflicts:
	src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
2015-10-28 16:56:40 +01:00
Sebastiaan Janssen 0c402310d9 Fixes tests failing due to missing path 2015-10-28 16:07:54 +01:00
Stephan 8d92330ad6 Fix broken comments 2015-10-28 15:01:23 +01:00
Sebastiaan Janssen 44e76f741f Merge pull request #840 from umbraco/temp-U4-7021
Fixes: U4-7021 "Actions" dropdown not available to children in listvi…
2015-10-28 14:52:48 +01:00
Shannon ecbced5c62 Massively simplifies the RenderActionInvoker which will support the native MVC caching and both async and non async support. U4-7270 Async Index actions for controllers implementing IRenderMvcController do not render view correctly 2015-10-28 14:31:40 +01:00
Shannon e6773dafc1 Updates PR to only display the prop alias in the title attribute when in debug mode. U4-4794 Display the property alias for content properties & provide a link to the content type from the generic properties tab 2015-10-28 12:45:15 +01:00
Shannon Deminick 7b8b7ed170 Merge pull request #837 from digbyswift/dev-v7
U4-7270 - Addition of allowance for async/await Index actions
2015-10-28 12:33:32 +01:00
Shannon Deminick c0997e1b9f Merge pull request #817 from tobbbe/hooverpropforalias
Hoover a property in backend to get its alias
2015-10-28 12:31:20 +01:00
Shannon d4f862a44f Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-28 12:28:41 +01:00
Shannon 64c983eb07 Updates PR with fixes for code and implementation logic for the url list. 2015-10-28 12:28:29 +01:00
Shannon e25222162c Merge branch 'danieland-U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section' into dev-v7 2015-10-28 09:50:20 +01:00
Shannon e022687457 Merge branch 'U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section' of https://github.com/danieland/Umbraco-CMS into danieland-U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section 2015-10-28 09:49:55 +01:00
Shannon 84db2f4d85 U4-7285 Every server that reads a instruction from umbracoCacheInstruction will also write the same instruction to the database. Intentional ? 2015-10-27 19:24:56 +01:00
Shannon ef64409a9a U4-7231 TryConvertTo<T> of ObjectExtensions doesn't do null checks (causes handled errors on members after upgrade) 2015-10-27 18:29:46 +01:00
Shannon f0b68ac31e Fixes: U4-7021 "Actions" dropdown not available to children in listview nodes 2015-10-27 18:13:18 +01:00
Jeffrey Schoemaker dba7bcf60a Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-27 15:21:07 +01:00
Sebastiaan Janssen 6c80bd9eb9 U4-6385 Poor Handling of disallowedUploadFiles
#U4-6385 State: Review
2015-10-27 13:45:02 +01:00
TimoPerplex 43baba1733 Revert "Latest"
This reverts commit 95a9e4b5ff.
2015-10-27 13:10:25 +01:00
TimoPerplex 95a9e4b5ff Latest 2015-10-27 13:09:21 +01:00
TimoPerplex 9b0aa49d4d Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-27 13:08:32 +01:00
Sebastiaan Janssen c7b7bf1510 Merge pull request #839 from umbraco/temp-U4-7214
U4-7214 Culture is not supported. Parameter name: name en_us is an in…
2015-10-27 11:27:53 +01:00
Shannon d1805b1448 U4-7214 Culture is not supported. Parameter name: name en_us is an invalid culture identifier error selecting user with different language after upgrade to 7.3.0 2015-10-27 11:22:28 +01:00
ryanmcdonough 780937dae9 Login overlay now higher than bootstrap datepicker 2015-10-26 15:49:55 +00:00
Shannon 9b054eaa47 Adds native ability to be able to fallback to default password checking if specifying a custom IBackOfficeUserPasswordChecker 2015-10-26 14:51:19 +01:00
bjarnef 1584530615 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-25 18:40:45 +01:00
bjarnef 100ca5caa6 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-25 18:29:13 +01:00
Shannon Deminick badd9ae289 Merge pull request #833 from umbraco/temp-U4-7201
Fixes: U4-7201 Can only save once in some editors after upgrade to 7.3
2015-10-23 11:45:24 +02:00
Kieron McIntyre db6755a5bb Addition of allowance for async/await Index actions 2015-10-23 10:04:14 +01:00
Daniel 738815170c more nullchecks needed?
null check that we can access user
2015-10-23 00:21:42 +02:00
Daniel ef091e8c3a U4-7296
http://issues.umbraco.org/issue/U4-7296
2015-10-22 23:41:18 +02:00
Daniel 71b3810e9c Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-22 21:49:49 +02:00
Shannon Deminick a1e62dae5e Merge pull request #834 from Attackmonkey/Fix-U4-7257
Fixes issue where dictionary items are displayed in a random order
2015-10-22 18:43:23 +02:00
Shannon 96c087d00f adds a ctor to the BackOfficeUserManager to allow better inheritance so that all settings are initialized by default, changes init method to be protected so other devs can use it. Adds a new property for devs to use to more easily extend the logic to just validate the username/password. 2015-10-22 18:40:20 +02:00
Tim 0568bf51f0 Fixes issue where dictionary items are displayed in a random order (see issue U4-7257) 2015-10-22 17:17:29 +01:00
Shannon Deminick e3bade4d1a Merge pull request #816 from Jeavon/U4-7260
Fix for U4-7260
2015-10-22 18:08:23 +02:00
Shannon Deminick 633b0b0003 Merge pull request #830 from albinj/dev-v7
U4-7283 - Only Master/Single ServerRole should be removing old instru…
2015-10-22 18:06:53 +02:00
Shannon Deminick 82adf48699 Merge pull request #805 from umbraco/temp-7234
Fixes #7234
2015-10-22 18:06:14 +02:00
Shannon 63be12b9fe Merge branch 'dev-v7-U4-6967' of https://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-U4-6967
Conflicts:
	src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
2015-10-22 18:03:03 +02:00
Shannon 33f7ed5129 Fixes: U4-7223 GetCropUrl outputs html entities in url when used in css
Adding in HtmlHelper extensions for GetCropUrl.
2015-10-22 17:52:58 +02:00
Shannon 79583c571c Fixes: U4-7201 Can only save once in some editors after upgrade to 7.3 2015-10-22 15:40:12 +02:00
Shannon Deminick a7e2c0b4dc Merge pull request #804 from rasmusjp/feature/copy-content-dialog
Added recursive option to copy dialog
2015-10-22 10:38:07 +02:00
Shannon da48e1b392 Fixes: U4-6962 Public access in multiple levels is broken in 7.3
Ensured the backoffice UI will look at protection for the specific node only (no inheritance) when specifying public access.
Added non-recursive method to Access class.
Fixed bug causing the tree (child nodes) not to update correctly after changing public access on nodes.
2015-10-21 18:43:30 +02:00
albinj f535ece685 U4-7283 - Only Master/Single ServerRole should be removing old instructions from the database 2015-10-21 14:29:18 +01:00
Claus Jensen 04e46c7cd1 Merge pull request #815 from umbraco/temp-U4-7198
Fixes: U4-7198 Change default log4net config to include machine name …
2015-10-21 12:20:45 +02:00
Claus Jensen 1089aef00a Merge pull request #825 from umbraco/temp-U4-7217
Fixes: U4-7217 umbracoReservedUrls do not always resolve correctly.
2015-10-21 11:52:39 +02:00
bjarnef 0288d6ec89 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-20 22:28:50 +02:00
Shannon 8950d94b25 adds unit test showing deleting a property group does not delete the property types. 2015-10-20 14:51:08 +02:00
Shannon bb6299cc01 Fixes: U4-7217 umbracoReservedUrls do not always resolve correctly.
Verified that all tests in GlobalSettingsTests run correctly.
Removes the strange old legacy compare thing and replaces it with a more readable Linq solution that ensures that the strings compared are always consistent.
2015-10-20 09:48:58 +02:00
Shannon Deminick 2176f2a1c9 Merge pull request #802 from tmoxon/dev-v7
Null check to prevent object reference error with public properties on custom indexers
2015-10-19 18:05:33 +02:00
Shannon Deminick 6a351bede1 Merge pull request #823 from umbraco/tmp-6797
U4-6797 - clear domains cache when deleting content
2015-10-19 15:52:37 +02:00
Shannon Deminick efc1aae0ae Merge pull request #822 from umbraco/tmp-3642
U4-3642 - proper validation msg in hostnames dialog
2015-10-19 15:49:09 +02:00
Stephan df39e027fd U4-3642 - proper validation msg in hostnames dialog 2015-10-16 17:23:12 +02:00
Stephan 64f05e4c97 U4-6797 - clear domains cache when deleting content 2015-10-16 17:21:44 +02:00
Shannon 30bc89ba93 U4-7092 can't show avatar because in China all users can't access to some sites. - Fixes where and how the avatar gets loaded, we first check if it exist or that we can connect to the internet and then load it, removes the avatar loading from the user service.. not sure why it was even there. 2015-10-16 14:45:49 +02:00
Shannon 841c8d69fc removes unused avatar directive 2015-10-16 14:30:23 +02:00
Shannon aa780d2b8a updates the googlefontpicker to lazy load the required google font lib. 2015-10-16 14:09:54 +02:00
Shannon 59f15f1618 updates the canvas loader, ensures that there are no external dependencies and that paths are relative. 2015-10-16 14:09:27 +02:00
TOXIC\Tobbe b2f0a9f23d Hoover a property in backend to get its alias 2015-10-16 14:07:19 +02:00
Shannon 40cd07f3f4 removes wide setting from canvas designer since it does not exist. 2015-10-16 13:36:30 +02:00
Shannon 99e7f84f79 Moves EnableCanvasDesigner to HtmlHelperRenderExtensions because it's for rendering html, obsoletes the old ones and fixes up the canvasdesigner to use
the correct umbraco paths instead of hard coded absolute paths.
2015-10-16 13:36:10 +02:00
Stephan 3a5a32c65f U4-7255 - fix RefreshInstruction serialization 2015-10-16 12:28:14 +02:00
Shannon c2627f3a2a removes strange parse feed method, what the heck is this? it isn't used so its removed 2015-10-15 19:17:47 +02:00
Shannon 22b8d41aee U4-5963 There should be no external request dependencies - updates nonodes, removes the font references that is never used, replaces the open sans font-reference with the one that we already have locally and uses it. 2015-10-15 19:08:53 +02:00
Jeavon ee47ea2026 Fix for U4-7260 - Multi node tree picker with no selection can cause a error to display in the backoffice 2015-10-15 16:29:40 +01:00
Shannon 57622cef9a Fixes: U4-7198 Change default log4net config to include machine name in file name 2015-10-15 17:14:24 +02:00
Shannon 30ad3f5aa6 bumps version 2015-10-15 17:12:13 +02:00
Shannon 2c11f0be0f updates method to use the available request instance instead of using HttpContext.Current! no idea why it was using that. 2015-10-15 17:07:46 +02:00
Shannon c514ce8da3 Fixes: U4-7248 Can't update roles on public access, obsolete AddOrUpdateRule 2015-10-15 17:06:00 +02:00
Sebastiaan Janssen 65d421b619 Can_Update_Rule was wrong, it's not possible to "update" a rule, can only add or remove - added a test for removing 2015-10-14 11:32:55 +02:00
TimGeyssens 7eeb0c4966 Fixes U4-7249 Insert Macro split button, when selecting a macro that has parameters the dialog should immediately show those 2015-10-14 11:29:34 +02:00
Sebastiaan Janssen 62897f7064 Test was wrong, 2 rules were added and was expecting 1 to be returned, now that the code is fixed, this test needs to be corrected 2015-10-14 11:13:23 +02:00
Sebastiaan Janssen e0619edabb U4-6962 Public access in multiple levels is broken in 7.3
#U4-6962 Fixed
2015-10-14 10:19:39 +02:00
Sebastiaan Janssen 4142f47861 U4-6125 Installing MySQL Web Provider Breaks Page Publishing
#U4-6125 Fixed Due in version 7.3.1
2015-10-13 13:48:58 +02:00
Sebastiaan Janssen 7135f9a268 Removes message that is no longer correct 2015-10-13 13:12:28 +02:00
Niels Hartvig a75a58b719 Fixes #7234 2015-10-12 18:45:01 +02:00
Claus Jensen 7b969fc167 Merge pull request #790 from umbraco/U4-7075
Fixes: U4-7075 Enable Content and Media section by default for new ba…
2015-10-12 14:46:28 +02:00
Rasmus John Pedersen 78475b0686 Added recursive option to copy dialog 2015-10-09 20:25:51 +02:00
Shannon 4925d55e8f Fixes: U4-7197 open redirect vulnerability with ClientRedirect 2015-10-06 11:46:38 +02:00
Shannon 52d2306e17 Fixes: U4-7196 XSS vulnerability in BrowseRepository 2015-10-06 11:36:54 +02:00
Shannon 5e5207d4f3 Fixes: U4-7194 XSS issue with regexws page, U4-7195 XSS issue with editview.aspx 2015-10-06 10:56:16 +02:00
Sebastiaan Janssen 96d46c82fe U4-7193 NuGet install doesn't add all bindingRedirects
#U4-7193 Fixed Due in version 7.3.1
2015-10-06 08:58:19 +02:00
Per Ploug 86bf50db12 Merge pull request #803 from Tazer/dev-v7
Updated readme with working intro video , that is for umbraco v7
2015-10-05 14:28:08 +02:00
Patrik 14778422e6 Updated readme with working intro video , that is for umbraco v7 2015-10-05 14:22:57 +02:00
tmoxon 6a931273a6 The indexing api would break if an indexer was created with a public property defaulting to a null value. This would result in an object reference error in the admin system. Added null check and warning to the log. 2015-10-01 14:42:32 +01:00
Sebastiaan Janssen 5fab1ea436 U4-7164 Nuget Update-Package UmbracoCms fails if I have removed dashboard section
#U4-7164 Fixed Due in version 7.3.1
2015-10-01 08:52:40 +02:00
Daniel Andreasen 5310ce38fd Merge pull request #1 from umbraco/dev-v7
update original fork
2015-09-27 23:30:26 +02:00
Marc Stöcker 9a99ed655a Major revamp with keys added and texts fixed everywhere
Thanks to @merkledo and the others of the Stuttgart Umbraco Meetup, we pulled together all the bits and pieces for a single solid translation file. Even if not perfect it will still be better than everthing we had before and something we hopefully can keep current from now on.
2015-09-25 15:09:53 +02:00
Robert Foster e9d0aa87bd Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' 2015-09-21 20:32:43 +10:00
m_stodd 7abbfbcfcc Setting UMB_CONTEXT with Domain "FALSE"
Running Umbraco on localhost, Chrome does not handle received 'Set Cookie's with no domain.  "FALSE" works as noted here:  http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
2015-09-18 02:13:12 -05:00
Vincent Baaij a22b97643a Merge remote-tracking branch 'umbraco/dev-v7' into dev-v7 2015-09-14 21:53:33 +02:00
Claus 80be614731 Fixes: U4-7075 Enable Content and Media section by default for new backoffice users 2015-09-14 11:06:03 +02:00
Robert Foster 803ca677c1 Merge remote-tracking branch 'umbraco/dev-v7' into dev-v7 2015-09-10 02:07:34 +10:00
Vincent Baaij e25886180a Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-09-09 13:57:35 +02:00
Vincent Baaij d5a41d41e9 Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-08-18 09:14:11 +02:00
TimoPerplex 68ff77f5b6 This commit removes the hardcoded .jpg thumbnails
This commit removes the hardcoded .jpg thumbnails and uses the image
original extension to create the thumbnail.
Because we now use the original extension the image is no longer masked
as another (extension is .jpg but the file is actually a .png)

This fixes issues with Internet Explorer used in combination with the
no-sniff header.
Ref topic:
https://our.umbraco.org/forum/umbraco-7/using-umbraco-7/66788-adding-nosniff-header-breaks-png-images-in-internet-explorer
2015-07-24 16:27:26 +02:00
TimoPerplex 47e7469d65 Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-07-24 16:18:58 +02:00
Vincent Baaij 2e43a34812 Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-06-25 17:37:36 +02:00
Vincent Baaij 1b9afc961b Fix for #U4-6171 Continuous Deployment from Visual Studio Online to Azure Websites not working as expected 2015-06-25 17:35:15 +02:00
AussieInSeattle 2276584c90 Update for when first control has settings
Adding style for when first control has settings - it was previously overlapping the "cog" icon above it
2015-03-11 11:52:57 -07:00
AussieInSeattle 05a0846e89 Update grid.controller.js 2015-03-09 11:22:16 -07:00
AussieInSeattle b2947264e1 edit function for settings on a custom grid editor 2015-02-19 15:49:03 -08:00
AussieInSeattle 066927742e Update UI for settings for a custom grid editor 2015-02-19 15:47:11 -08:00
TimoPerplex 4616afced4 Merge pull request #1 from umbraco/dev-v7
Update to latest data
2015-01-19 09:05:18 +01:00
484 changed files with 14071 additions and 7356 deletions
+1
View File
@@ -131,3 +131,4 @@ src/*.boltdata/
src/umbraco.sln.ide/*
build/UmbracoCms.*/
src/.vs/
src/Umbraco.Web.UI/umbraco/js/install.loader.js
+2 -2
View File
@@ -7,9 +7,9 @@ The easiest way to get started is to run `build/build.bat` which will build both
If you're interested in making changes to Belle make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md). Note that you can always [download a nightly build](http://nightly.umbraco.org/umbraco%207.0.0/) so you don't have to build the code yourself.
## Watch a five minute introduction video ##
## Watch a introduction video ##
[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco)
[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
## Umbraco - the simple, flexible and friendly ASP.NET CMS ##
+2 -2
View File
@@ -175,8 +175,8 @@
<!-- Copy SQL CE -->
<ItemGroup>
<SQLCE4Files
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
Include="..\src\packages\SqlServerCE.4.0.0.1\**\*.*"
Exclude="..\src\packages\SqlServerCE.4.0.0.1\lib\**\*;..\src\packages\SqlServerCE.4.0.0.1\**\*.nu*"
/>
</ItemGroup>
+5 -9
View File
@@ -1,4 +1,6 @@
@ECHO OFF
SETLOCAL
SET release=%1
ECHO Installing Npm NuGet Package
@@ -11,12 +13,9 @@ ECHO Current folder: %CD%
for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
ECHO Temporarily adding Npm and Node to path
SET oldPath=%PATH%
path=%npmPath%;%nodePath%;%PATH%
ECHO %path%
ECHO Adding Npm and Node to path
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
PATH=%npmPath%;%nodePath%;%PATH%
SET buildFolder=%CD%
@@ -29,8 +28,5 @@ call npm install -g grunt-cli --quiet
call npm install -g bower --quiet
call grunt build --buildversion=%release%
ECHO Reset path to what it was before
path=%oldPath%
ECHO Move back to the build folder
CD %buildFolder%
+5 -6
View File
@@ -1,19 +1,19 @@
@ECHO OFF
SET oldPath=%PATH%
SETLOCAL
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
git.exe 2> NUL
if %ERRORLEVEL%==9009 GOTO :trydefaultpath
GOTO :EOF
:trydefaultpath
path=C:\Program Files (x86)\Git\cmd;%PATH%
path=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
git.exe 2> NUL
if %ERRORLEVEL%==9009 GOTO :showerror
GOTO :EOF
:showerror
path=%oldPath%
ECHO Git is not in your path and could not be found in C:\Program Files (x86)\Git\bin
ECHO Git is not in your path and could not be found in C:\Program Files (x86)\Git\cmd nor in C:\Program Files\Git\cmd
set /p install=" Do you want to install Git through Chocolatey [y/n]? " %=%
if %install%==y (
GOTO :installgit
@@ -29,5 +29,4 @@ GOTO :EOF
ECHO Installing Chocolatey first
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
ECHO Installing Git through Chocolatey
choco install git
path=C:\Program Files (x86)\Git\cmd;%path%
choco install git
+4 -4
View File
@@ -26,18 +26,19 @@
<dependency id="HtmlAgilityPack" version="[1.4.9, 2.0.0)" />
<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.7, 7.0.0)" />
<dependency id="MySql.Data" version="[6.9.8, 7.0.0)" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.3.0, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.4.0, 5.0.0)" />
<dependency id="ImageProcessor" version="[2.3.2, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.5.1, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
</dependencies>
</metadata>
<files>
@@ -72,7 +73,6 @@
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<!-- Added to be able to produce a symbols package -->
+12 -1
View File
@@ -1,6 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyUmbracoFilesToWebRootForDeploy" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
<ItemGroup>
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
</ItemGroup>
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="$(_PackageTempDir)\%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
<!-- This copies the files listed in `AddUmbracoFilesToOutput` to the webroot during NuGet install and should -->
<!-- not be altered to support automated builds, use `CopyUmbracoFilesToWebRootForDeploy` for that instead -->
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
@@ -47,4 +58,4 @@
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
</Project>
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<dashBoard xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<section alias="StartupSettingsDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupSettingsDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Welcome" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<control showOnce="true" addPanel="true" panelCaption="" xdt:Transform="InsertIfMissing">
@@ -20,7 +20,7 @@
</tab>
</section>
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Replace">
<control showOnce="true" addPanel="true" panelCaption="">
views/dashboard/developer/developerdashboardvideos.html
@@ -29,7 +29,7 @@
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<control>
views/dashboard/developer/examinemanagement.html
@@ -39,10 +39,10 @@
<control>
views/dashboard/developer/xmldataintegrityreport.html
</control>
</tab>
</tab>
</section>
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing" />
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="Replace">
@@ -52,7 +52,7 @@
</tab>
</section>
<section alias="StartupDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Get Started" xdt:Transform="Insert">
<access>
@@ -62,17 +62,10 @@
views/dashboard/default/startupdashboardintro.html
</control>
</tab>
<tab caption="Change password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Change Password" xdt:Transform="Insert">
<control showOnce="false" addPanel="false" panelCaption="">
views/dashboard/ChangePassword.html
</control>
</tab>
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Get Started" xdt:Transform="Insert">
<control showOnce="true" addPanel="true" panelCaption="">
-3
View File
@@ -10,9 +10,6 @@
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
+33 -7
View File
@@ -48,8 +48,13 @@
<system.web xdt:Transform="InsertIfMissing" />
<system.web>
<siteMap xdt:Transform="Remove" />
<siteMap xdt:Transform="InsertIfMissing">
<providers xdt:Transform="InsertIfMissing">
<remove name="MySqlSiteMapProvider" xdt:Transform="InsertIfMissing" />
</providers>
</siteMap>
<httpRuntime xdt:Transform="InsertIfMissing" />
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
<httpRuntime targetFramework="4.5" maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(targetFramework,fcnMode,maxRequestLength)" />
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
@@ -76,6 +81,10 @@
</compilation>
<compilation>
<assemblies>
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
</assemblies>
<assemblies>
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
@@ -131,6 +140,13 @@
<remove name="SpellChecker" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="SpellChecker" xdt:Locator="Match(name)" xdt:Transform="Remove" />
</handlers>
<security xdt:Transform="InsertIfMissing">
<requestFiltering xdt:Transform="InsertIfMissing">
<requestLimits maxAllowedContentLength="52428800" xdt:Transform="InsertIfMissing" />
</requestFiltering>
</security>
</system.webServer>
<system.codedom xdt:Transform="Remove" />
@@ -142,20 +158,26 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.WebPages.Razor')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Http')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.OAuth')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
</assemblyBinding>
</runtime>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
@@ -168,27 +190,31 @@
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
+12
View File
@@ -57,13 +57,25 @@ if ($project) {
if(Test-Path $umbracoBinFolder\ImageProcessor.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Infrastructure.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Infrastructure.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\MiniProfiler.dll) { Remove-Item $umbracoBinFolder\MiniProfiler.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\MySql.Data.dll) { Remove-Item $umbracoBinFolder\MySql.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\System.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.WebHost.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.WebHost.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Mvc.dll) { Remove-Item $umbracoBinFolder\System.Web.Mvc.dll -Force -Confirm:$false }
+3 -4
View File
@@ -45,9 +45,6 @@ del ..\src\Umbraco.Web.UI\UserControls\*.*
echo Removing masterpage files
del ..\src\Umbraco.Web.UI\masterpages\*.*
echo Removing view files
del ..\src\Umbraco.Web.UI\Views\*.*
echo Removing razor files
del ..\src\Umbraco.Web.UI\macroScripts\*.*
@@ -104,7 +101,9 @@ echo Removing user control files
FOR %%A IN (..\src\Umbraco.Web.UI\usercontrols\*.*) DO DEL %%A
echo Removing view files
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
ATTRIB +H ..\src\Umbraco.Web.UI\Views\Partials\Grid\*.cshtml /S
FOR %%A IN (..\src\Umbraco.Web.UI\Views\) DO DEL /Q /S *.cshtml -H
ATTRIB -H ..\src\Umbraco.Web.UI\Views\Partials\Grid\*.cshtml /S
echo Removing razor files
FOR %%A IN (..\src\Umbraco.Web.UI\macroScripts\*.*) DO DEL %%A
+6 -4
View File
@@ -54,9 +54,6 @@ del ..\src\Umbraco.Web.UI\UserControls\*.*
echo Removing masterpage files
del ..\src\Umbraco.Web.UI\masterpages\*.*
echo Removing view files
del ..\src\Umbraco.Web.UI\Views\*.*
echo Removing razor files
del ..\src\Umbraco.Web.UI\macroScripts\*.*
@@ -122,7 +119,9 @@ echo Removing user control files
FOR %%A IN (..\src\Umbraco.Web.UI\usercontrols\*.*) DO DEL %%A
echo Removing view files
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
ATTRIB +H ..\src\Umbraco.Web.UI\Views\Partials\Grid\*.cshtml /S
FOR %%A IN (..\src\Umbraco.Web.UI\Views\) DO DEL /Q /S *.cshtml -H
ATTRIB -H ..\src\Umbraco.Web.UI\Views\Partials\Grid\*.cshtml /S
echo Removing razor files
FOR %%A IN (..\src\Umbraco.Web.UI\macroScripts\*.*) DO DEL %%A
@@ -151,6 +150,9 @@ rmdir "..\src\Umbraco.Web.UI\usercontrols\umbracoContour\" /S /Q
echo Start with a clean web.config
copy ..\src\Umbraco.Web.UI\web.Template.config ..\src\Umbraco.Web.UI\web.config /Y
echo Start with a clean web.config
copy ..\src\Umbraco.Web.UI\web.Template.config ..\src\Umbraco.Web.UI\web.config /Y
echo "Umbraco install reverted to clean install"
pause
exit
+1 -1
View File
@@ -1,2 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.3.0
7.3.8
+8 -6
View File
@@ -47,13 +47,15 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll</HintPath>
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
</packages>
+3 -3
View File
@@ -2,7 +2,7 @@
using System.Resources;
[assembly: AssemblyCompany("Umbraco")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2015")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyInformationalVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.8")]
[assembly: AssemblyInformationalVersion("7.3.8")]
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Umbraco.Core
/// <summary>
/// A resolver to return all IAction objects
/// </summary>
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
public sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
{
/// <summary>
/// Constructor
+10 -3
View File
@@ -283,7 +283,12 @@ namespace Umbraco.Core
{
var configStatus = ConfigurationStatus;
var currentVersion = UmbracoVersion.GetSemanticVersion();
var ok = configStatus == currentVersion;
var ok =
//we are not configured if this is null
string.IsNullOrWhiteSpace(configStatus) == false
//they must match
&& configStatus == currentVersion;
if (ok)
{
@@ -308,8 +313,9 @@ namespace Umbraco.Core
return ok;
}
catch
catch (Exception ex)
{
LogHelper.Error<ApplicationContext>("Error determining if application is configured, returning false", ex);
return false;
}
@@ -400,7 +406,8 @@ namespace Umbraco.Core
//clear the cache
if (ApplicationCache != null)
{
ApplicationCache.ClearAllCache();
ApplicationCache.RuntimeCache.ClearAllCache();
ApplicationCache.IsolatedRuntimeCache.ClearAllCaches();
}
//reset all resolvers
ResolverCollection.ResetAll();
+28 -10
View File
@@ -1,5 +1,6 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -117,38 +118,55 @@ namespace Umbraco.Core
private class NamedSemaphoreReleaser : CriticalFinalizerObject, IDisposable
{
private readonly Semaphore _semaphore;
private GCHandle _handle;
internal NamedSemaphoreReleaser(Semaphore semaphore)
{
_semaphore = semaphore;
_handle = GCHandle.Alloc(_semaphore);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
GC.SuppressFinalize(this); // finalize will not run
}
private void Dispose(bool disposing)
{
// critical
_handle.Free();
_semaphore.Release();
_semaphore.Dispose();
}
// we WANT to release the semaphore because it's a system object
// ie a critical non-managed resource - so we inherit from CriticalFinalizerObject
// which means that the finalizer "should" run in all situations
// we WANT to release the semaphore because it's a system object, ie a critical
// non-managed resource - and if it is not released then noone else can acquire
// the lock - so we inherit from CriticalFinalizerObject which means that the
// finalizer "should" run in all situations - there is always a chance that it
// does not run and the semaphore remains "acquired" but then chances are the
// whole process (w3wp.exe...) is going down, at which point the semaphore will
// be destroyed by Windows.
// however... that can fail with System.ObjectDisposedException because the
// underlying handle was closed... because we cannot guarantee that the semaphore
// is not gone already... unless we get a GCHandle = GCHandle.Alloc(_semaphore);
// which should keep it around and then we free the handle?
// however, the semaphore is a managed object, and so when the finalizer runs it
// might have been finalized already, and then we get a, ObjectDisposedException
// in the finalizer - which is bad.
// so... I'm not sure this is safe really...
// in order to prevent this we do two things
// - use a GCHandler to ensure the semaphore is still there when the finalizer
// runs, so we can actually release it
// - wrap the finalizer code in a try...catch to make sure it never throws
~NamedSemaphoreReleaser()
{
Dispose(false);
try
{
Dispose(false);
}
catch
{
// we do NOT want the finalizer to throw - never ever
}
}
}
+29 -2
View File
@@ -1,8 +1,9 @@
using System;
using System.ComponentModel;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Constants storing cache keys used in caching
/// </summary>
@@ -12,52 +13,78 @@ namespace Umbraco.Core.Cache
public const string ApplicationsCacheKey = "ApplicationCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserTypeCacheKey = "UserTypeCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future - it is referenced but no cache is stored against this key")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string ContentItemCacheKey = "contentItem";
[UmbracoWillObsolete("This cache key is only used for the legacy 'library' caching, remove in v8")]
public const string MediaCacheKey = "UL_GetMedia";
public const string MacroXsltCacheKey = "macroXslt_";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string MacroCacheKey = "UmbracoMacroCache";
public const string MacroHtmlCacheKey = "macroHtml_";
public const string MacroControlCacheKey = "macroControl_";
public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_";
public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_";
[UmbracoWillObsolete("This cache key is only used for legacy 'library' member caching, remove in v8")]
public const string MemberLibraryCacheKey = "UL_GetMember";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
[UmbracoWillObsolete("This cache key is only used for legacy template business logic caching, remove in v8")]
public const string TemplateFrontEndCacheKey = "template";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserContextCacheKey = "UmbracoUserContext";
public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserCacheKey = "UmbracoUser";
public const string UserPermissionsCacheKey = "UmbracoUserPermissions";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string ContentTypeCacheKey = "UmbracoContentType";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string LanguageCacheKey = "UmbracoLanguageCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string DomainCacheKey = "UmbracoDomainList";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string StylesheetCacheKey = "UmbracoStylesheet";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
@@ -2,6 +2,7 @@
using Umbraco.Core.Events;
using Umbraco.Core.Sync;
using umbraco.interfaces;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
@@ -63,5 +64,15 @@ namespace Umbraco.Core.Cache
{
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById));
}
/// <summary>
/// Clears the cache for all repository entities of this type
/// </summary>
/// <typeparam name="TEntity"></typeparam>
internal void ClearAllIsolatedCacheByEntityType<TEntity>()
where TEntity : class, IAggregateRoot
{
ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.ClearCache<TEntity>();
}
}
}
@@ -2,20 +2,27 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Caching;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Persistence.Repositories
namespace Umbraco.Core.Cache
{
/// <summary>
/// Interface describing this cache provider as a wrapper for another
/// </summary>
internal interface IRuntimeCacheProviderWrapper
{
IRuntimeCacheProvider InnerProvider { get; }
}
/// <summary>
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
/// reset if the object is TracksChangesEntityBase
/// </summary>
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper
{
internal IRuntimeCacheProvider InnerProvider { get; private set; }
public IRuntimeCacheProvider InnerProvider { get; private set; }
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
{
@@ -0,0 +1,268 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// The default cache policy for retrieving a single entity
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
/// <remarks>
/// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
/// default policy with no expiry.
/// </remarks>
internal class DefaultRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
: base(cache)
{
if (options == null) throw new ArgumentNullException("options");
_options = options;
}
protected string GetCacheIdKey(object id)
{
if (id == null) throw new ArgumentNullException("id");
return string.Format("{0}{1}", GetCacheTypeKey(), id);
}
protected string GetCacheTypeKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
//set the disposal action
SetCacheAction(() =>
{
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
}
catch
{
//set the disposal action
SetCacheAction(() =>
{
//if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
Cache.ClearCacheItem(GetCacheIdKey(entity.Id));
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
throw;
}
}
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
}
finally
{
//set the disposal action
var cacheKey = GetCacheIdKey(entity.Id);
SetCacheAction(() =>
{
Cache.ClearCacheItem(cacheKey);
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
}
}
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
var cacheKey = GetCacheIdKey(id);
var fromCache = Cache.GetCacheItem<TEntity>(cacheKey);
if (fromCache != null)
return fromCache;
var entity = getFromRepo(id);
//set the disposal action
SetCacheAction(cacheKey, entity);
return entity;
}
public override TEntity Get(TId id)
{
var cacheKey = GetCacheIdKey(id);
return Cache.GetCacheItem<TEntity>(cacheKey);
}
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
var cacheKey = GetCacheIdKey(id);
var fromCache = Cache.GetCacheItem<TEntity>(cacheKey);
return fromCache != null || getFromRepo(id);
}
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
if (ids.Any())
{
var entities = ids.Select(Get).ToArray();
if (ids.Length.Equals(entities.Length) && entities.Any(x => x == null) == false)
return entities;
}
else
{
var allEntities = GetAllFromCache();
if (allEntities.Any())
{
if (_options.GetAllCacheValidateCount)
{
//Get count of all entities of current type (TEntity) to ensure cached result is correct
var totalCount = _options.PerformCount();
if (allEntities.Length == totalCount)
return allEntities;
}
else
{
return allEntities;
}
}
else if (_options.GetAllCacheAllowZeroCount)
{
//if the repository allows caching a zero count, then check the zero count cache
if (HasZeroCountCache())
{
//there is a zero count cache so return an empty list
return new TEntity[] {};
}
}
}
//we need to do the lookup from the repo
var entityCollection = getFromRepo(ids)
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
.ToArray();
//set the disposal action
SetCacheAction(ids, entityCollection);
return entityCollection;
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected bool HasZeroCountCache()
{
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
return (zeroCount != null && zeroCount.Any() == false);
}
/// <summary>
/// Performs the lookup for all entities of this type from the cache
/// </summary>
/// <returns></returns>
protected TEntity[] GetAllFromCache()
{
var allEntities = Cache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey())
.WhereNotNull()
.ToArray();
return allEntities.Any() ? allEntities : new TEntity[] {};
}
/// <summary>
/// Sets the action to execute on disposal for a single entity
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="entity"></param>
protected virtual void SetCacheAction(string cacheKey, TEntity entity)
{
if (entity == null) return;
SetCacheAction(() =>
{
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
Cache.InsertCacheItem(cacheKey, () => entity,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
});
}
/// <summary>
/// Sets the action to execute on disposal for an entity collection
/// </summary>
/// <param name="ids"></param>
/// <param name="entityCollection"></param>
protected virtual void SetCacheAction(TId[] ids, TEntity[] entityCollection)
{
SetCacheAction(() =>
{
//This option cannot execute if we are looking up specific Ids
if (ids.Any() == false && entityCollection.Length == 0 && _options.GetAllCacheAllowZeroCount)
{
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
// to signify that there is a zero count cache
//NOTE: Don't set expiry/sliding for a zero count
Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
}
else
{
//This is the default behavior, we'll individually cache each item so that if/when these items are resolved
// by id, they are returned from the already existing cache.
foreach (var entity in entityCollection.WhereNotNull())
{
var localCopy = entity;
//just to be safe, we cannot cache an item without an identity
if (localCopy.HasIdentity)
{
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
}
}
});
}
}
}
@@ -0,0 +1,27 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class DefaultRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
{
_runtimeCache = runtimeCache;
_options = options;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new DefaultRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _options);
}
}
}
@@ -0,0 +1,229 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// A caching policy that caches an entire dataset as a single collection
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly Func<TEntity, TId> _getEntityId;
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
private readonly bool _expires;
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
: base(cache)
{
_getEntityId = getEntityId;
_getAllFromRepo = getAllFromRepo;
_expires = expires;
}
private bool? _hasZeroCountCache;
protected string GetCacheTypeKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
}
catch
{
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
throw;
}
}
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
}
finally
{
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
}
}
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
{
//Force get all with cache
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
//we don't have anything in cache (this should never happen), just return from the repo
if (found == null) return getFromRepo(id);
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
if (entity == null) return null;
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
return (TEntity)entity.DeepClone();
}
public override TEntity Get(TId id)
{
//Force get all with cache
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
//we don't have anything in cache (this should never happen), just return null
if (found == null) return null;
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
if (entity == null) return null;
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
return (TEntity)entity.DeepClone();
}
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
{
//Force get all with cache
var found = GetAll(new TId[] {}, ids => _getAllFromRepo().WhereNotNull());
//we don't have anything in cache (this should never happen), just return from the repo
return found == null
? getFromRepo(id)
: found.Any(x => _getEntityId(x).Equals(id));
}
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
//process getting all including setting the cache callback
var result = PerformGetAll(getFromRepo);
//now that the base result has been calculated, they will all be cached.
// Now we can just filter by ids if they have been supplied
return (ids.Any()
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
: result)
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
.Select(x => (TEntity)x.DeepClone())
.ToArray();
}
private TEntity[] PerformGetAll(Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
var allEntities = GetAllFromCache();
if (allEntities.Any())
{
return allEntities;
}
//check the zero count cache
if (HasZeroCountCache())
{
//there is a zero count cache so return an empty list
return new TEntity[] { };
}
//we need to do the lookup from the repo
var entityCollection = getFromRepo(new TId[] {})
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
.ToArray();
//set the disposal action
SetCacheAction(entityCollection);
return entityCollection;
}
/// <summary>
/// For this type of caching policy, we don't cache individual items
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="entity"></param>
protected void SetCacheAction(string cacheKey, TEntity entity)
{
//No-op
}
/// <summary>
/// Sets the action to execute on disposal for an entity collection
/// </summary>
/// <param name="entityCollection"></param>
protected void SetCacheAction(TEntity[] entityCollection)
{
//set the disposal action
SetCacheAction(() =>
{
//We want to cache the result as a single collection
if (_expires)
{
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection),
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
else
{
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
}
});
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected bool HasZeroCountCache()
{
if (_hasZeroCountCache.HasValue)
return _hasZeroCountCache.Value;
_hasZeroCountCache = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey()) != null;
return _hasZeroCountCache.Value;
}
/// <summary>
/// This policy will cache the full data set as a single collection
/// </summary>
/// <returns></returns>
protected TEntity[] GetAllFromCache()
{
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
//This method will get called before checking for zero count cache, so we'll just set the flag here
_hasZeroCountCache = found != null;
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class FullDataSetRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly Func<TEntity, TId> _getEntityId;
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
private readonly bool _expires;
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
{
_runtimeCache = runtimeCache;
_getEntityId = getEntityId;
_getAllFromRepo = getAllFromRepo;
_expires = expires;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
internal interface IRepositoryCachePolicy<TEntity, TId> : IDisposable
where TEntity : class, IAggregateRoot
{
TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
TEntity Get(TId id);
bool Exists(TId id, Func<TId, bool> getFromRepo);
void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
void Remove(TEntity entity, Action<TEntity> persistMethod);
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
}
}
@@ -0,0 +1,9 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
internal interface IRepositoryCachePolicyFactory<TEntity, TId> where TEntity : class, IAggregateRoot
{
IRepositoryCachePolicy<TEntity, TId> CreatePolicy();
}
}
@@ -0,0 +1,91 @@
using System;
using System.Collections.Concurrent;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Used to get/create/manipulate isolated runtime cache
/// </summary>
/// <remarks>
/// This is useful for repository level caches to ensure that cache lookups by key are fast so
/// that the repository doesn't need to search through all keys on a global scale.
/// </remarks>
public class IsolatedRuntimeCache
{
internal Func<Type, IRuntimeCacheProvider> CacheFactory { get; set; }
/// <summary>
/// Constructor that allows specifying a factory for the type of runtime isolated cache to create
/// </summary>
/// <param name="cacheFactory"></param>
public IsolatedRuntimeCache(Func<Type, IRuntimeCacheProvider> cacheFactory)
{
CacheFactory = cacheFactory;
}
private readonly ConcurrentDictionary<Type, IRuntimeCacheProvider> _isolatedCache = new ConcurrentDictionary<Type, IRuntimeCacheProvider>();
/// <summary>
/// Returns an isolated runtime cache for a given type
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public IRuntimeCacheProvider GetOrCreateCache<T>()
{
return _isolatedCache.GetOrAdd(typeof(T), type => CacheFactory(type));
}
/// <summary>
/// Returns an isolated runtime cache for a given type
/// </summary>
/// <returns></returns>
public IRuntimeCacheProvider GetOrCreateCache(Type type)
{
return _isolatedCache.GetOrAdd(type, t => CacheFactory(t));
}
/// <summary>
/// Tries to get a cache by the type specified
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public Attempt<IRuntimeCacheProvider> GetCache<T>()
{
IRuntimeCacheProvider cache;
if (_isolatedCache.TryGetValue(typeof(T), out cache))
{
return Attempt.Succeed(cache);
}
return Attempt<IRuntimeCacheProvider>.Fail();
}
/// <summary>
/// Clears all values inside this isolated runtime cache
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public void ClearCache<T>()
{
IRuntimeCacheProvider cache;
if (_isolatedCache.TryGetValue(typeof(T), out cache))
{
cache.ClearAllCache();
}
}
/// <summary>
/// Clears all of the isolated caches
/// </summary>
public void ClearAllCaches()
{
foreach (var key in _isolatedCache.Keys)
{
IRuntimeCacheProvider cache;
if (_isolatedCache.TryRemove(key, out cache))
{
cache.ClearAllCache();
}
}
}
}
}
@@ -0,0 +1,27 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class OnlySingleItemsRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly RepositoryCachePolicyOptions _options;
public OnlySingleItemsRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
{
_runtimeCache = runtimeCache;
_options = options;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new SingleItemsOnlyRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _options);
}
}
}
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private Action _action;
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
{
if (cache == null) throw new ArgumentNullException("cache");
Cache = cache;
}
protected IRuntimeCacheProvider Cache { get; private set; }
/// <summary>
/// The disposal performs the caching
/// </summary>
protected override void DisposeResources()
{
if (_action != null)
{
_action();
}
}
/// <summary>
/// Sets the action to execute on disposal
/// </summary>
/// <param name="action"></param>
protected void SetCacheAction(Action action)
{
_action = action;
}
public abstract TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
public abstract TEntity Get(TId id);
public abstract bool Exists(TId id, Func<TId, bool> getFromRepo);
public abstract void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
public abstract void Remove(TEntity entity, Action<TEntity> persistMethod);
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
}
}
@@ -1,17 +1,34 @@
namespace Umbraco.Core.Persistence.Repositories
using System;
namespace Umbraco.Core.Cache
{
internal class RepositoryCacheOptions
internal class RepositoryCachePolicyOptions
{
/// <summary>
/// Constructor sets defaults
/// Ctor - sets GetAllCacheValidateCount = true
/// </summary>
public RepositoryCacheOptions()
public RepositoryCachePolicyOptions(Func<int> performCount)
{
PerformCount = performCount;
GetAllCacheValidateCount = true;
GetAllCacheAllowZeroCount = false;
GetAllCacheThresholdLimit = 100;
}
/// <summary>
/// Ctor - sets GetAllCacheValidateCount = false
/// </summary>
public RepositoryCachePolicyOptions()
{
PerformCount = null;
GetAllCacheValidateCount = false;
GetAllCacheAllowZeroCount = false;
}
/// <summary>
/// Callback required to get count for GetAllCacheValidateCount
/// </summary>
public Func<int> PerformCount { get; private set; }
/// <summary>
/// True/false as to validate the total item count when all items are returned from cache, the default is true but this
/// means that a db lookup will occur - though that lookup will probably be significantly less expensive than the normal
@@ -21,16 +38,11 @@ namespace Umbraco.Core.Persistence.Repositories
/// setting this to return false will improve performance of GetAll cache with no params but should only be used
/// for specific circumstances
/// </remarks>
public bool GetAllCacheValidateCount { get; set; }
public bool GetAllCacheValidateCount { get; private set; }
/// <summary>
/// True if the GetAll method will cache that there are zero results so that the db is not hit when there are no results found
/// </summary>
public bool GetAllCacheAllowZeroCount { get; set; }
/// <summary>
/// The threshold entity count for which the GetAll method will cache entities
/// </summary>
public int GetAllCacheThresholdLimit { get; set; }
}
}
@@ -0,0 +1,24 @@
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// A caching policy that ignores all caches for GetAll - it will only cache calls for individual items
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class SingleItemsOnlyRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options) : base(cache, options)
{
}
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
{
//no-op
}
}
}
+117 -223
View File
@@ -1,6 +1,8 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
@@ -11,20 +13,15 @@ using Umbraco.Core.Logging;
namespace Umbraco.Core
{
/// <summary>
/// Class that is exposed by the ApplicationContext for application wide caching purposes
/// </summary>
public class CacheHelper
{
private readonly bool _enableCache;
private readonly ICacheProvider _requestCache;
private readonly ICacheProvider _nullRequestCache = new NullCacheProvider();
private readonly ICacheProvider _staticCache;
private readonly ICacheProvider _nullStaticCache = new NullCacheProvider();
private readonly IRuntimeCacheProvider _httpCache;
private readonly IRuntimeCacheProvider _nullHttpCache = new NullCacheProvider();
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
/// <summary>
/// Creates a cache helper with disabled caches
/// </summary>
@@ -34,7 +31,7 @@ namespace Umbraco.Core
/// </remarks>
public static CacheHelper CreateDisabledCacheHelper()
{
return new CacheHelper(null, null, null, false);
return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache));
}
/// <summary>
@@ -44,7 +41,8 @@ namespace Umbraco.Core
: this(
new HttpRuntimeCacheProvider(HttpRuntime.Cache),
new StaticCacheProvider(),
new HttpRequestCacheProvider())
new HttpRequestCacheProvider(),
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
{
}
@@ -56,93 +54,75 @@ namespace Umbraco.Core
: this(
new HttpRuntimeCacheProvider(cache),
new StaticCacheProvider(),
new HttpRequestCacheProvider())
new HttpRequestCacheProvider(),
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
{
}
/// <summary>
/// Initializes a new instance based on the provided providers
/// </summary>
/// <param name="httpCacheProvider"></param>
/// <param name="staticCacheProvider"></param>
/// <param name="requestCacheProvider"></param>
[Obsolete("Use the constructor the specifies all dependencies")]
[EditorBrowsable(EditorBrowsableState.Never)]
public CacheHelper(
IRuntimeCacheProvider httpCacheProvider,
ICacheProvider staticCacheProvider,
ICacheProvider requestCacheProvider)
: this(httpCacheProvider, staticCacheProvider, requestCacheProvider, true)
: this(httpCacheProvider, staticCacheProvider, requestCacheProvider, new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
{
}
/// <summary>
/// Private ctor used for creating a disabled cache helper
/// </summary>
/// <param name="httpCacheProvider"></param>
/// <param name="staticCacheProvider"></param>
/// <param name="requestCacheProvider"></param>
/// <param name="enableCache"></param>
private CacheHelper(
/// <summary>
/// Initializes a new instance based on the provided providers
/// </summary>
/// <param name="httpCacheProvider"></param>
/// <param name="staticCacheProvider"></param>
/// <param name="requestCacheProvider"></param>
/// <param name="isolatedCacheManager"></param>
public CacheHelper(
IRuntimeCacheProvider httpCacheProvider,
ICacheProvider staticCacheProvider,
ICacheProvider requestCacheProvider,
bool enableCache)
ICacheProvider requestCacheProvider,
IsolatedRuntimeCache isolatedCacheManager)
{
if (enableCache)
{
_httpCache = httpCacheProvider;
_staticCache = staticCacheProvider;
_requestCache = requestCacheProvider;
}
else
{
_httpCache = null;
_staticCache = null;
_requestCache = null;
}
_enableCache = enableCache;
if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider");
if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider");
if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider");
if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager");
RuntimeCache = httpCacheProvider;
StaticCache = staticCacheProvider;
RequestCache = requestCacheProvider;
IsolatedRuntimeCache = isolatedCacheManager;
}
/// <summary>
/// Returns the current Request cache
/// </summary>
public ICacheProvider RequestCache
{
get { return _enableCache ? _requestCache : _nullRequestCache; }
}
/// <summary>
/// Returns the current Runtime cache
/// </summary>
public ICacheProvider StaticCache
{
get { return _enableCache ? _staticCache : _nullStaticCache; }
}
/// <summary>
/// Returns the current Runtime cache
/// </summary>
public IRuntimeCacheProvider RuntimeCache
{
get { return _enableCache ? _httpCache : _nullHttpCache; }
}
public ICacheProvider RequestCache { get; internal set; }
#region Legacy Runtime/Http Cache accessors
/// <summary>
/// Returns the current Runtime cache
/// </summary>
public ICacheProvider StaticCache { get; internal set; }
/// <summary>
/// Returns the current Runtime cache
/// </summary>
public IRuntimeCacheProvider RuntimeCache { get; internal set; }
/// <summary>
/// Returns the current Isolated Runtime cache manager
/// </summary>
public IsolatedRuntimeCache IsolatedRuntimeCache { get; internal set; }
#region Legacy Runtime/Http Cache accessors
/// <summary>
/// Clears the item in umbraco's runtime cache
/// </summary>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ClearAllCache()
{
if (_enableCache == false)
{
_nullHttpCache.ClearAllCache();
}
else
{
_httpCache.ClearAllCache();
}
RuntimeCache.ClearAllCache();
IsolatedRuntimeCache.ClearAllCaches();
}
/// <summary>
@@ -150,16 +130,10 @@ namespace Umbraco.Core
/// </summary>
/// <param name="key">Key</param>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ClearCacheItem(string key)
{
if (_enableCache == false)
{
_nullHttpCache.ClearCacheItem(key);
}
else
{
_httpCache.ClearCacheItem(key);
}
RuntimeCache.ClearCacheItem(key);
}
@@ -171,30 +145,17 @@ namespace Umbraco.Core
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
public void ClearCacheObjectTypes(string typeName)
{
if (_enableCache == false)
{
_nullHttpCache.ClearCacheObjectTypes(typeName);
}
else
{
_httpCache.ClearCacheObjectTypes(typeName);
}
RuntimeCache.ClearCacheObjectTypes(typeName);
}
/// <summary>
/// Clears all objects in the System.Web.Cache with the System.Type specified
/// </summary>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ClearCacheObjectTypes<T>()
{
if (_enableCache == false)
{
_nullHttpCache.ClearCacheObjectTypes<T>();
}
else
{
_httpCache.ClearCacheObjectTypes<T>();
}
RuntimeCache.ClearCacheObjectTypes<T>();
}
/// <summary>
@@ -202,16 +163,10 @@ namespace Umbraco.Core
/// </summary>
/// <param name="keyStartsWith">The start of the key</param>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ClearCacheByKeySearch(string keyStartsWith)
{
if (_enableCache == false)
{
_nullHttpCache.ClearCacheByKeySearch(keyStartsWith);
}
else
{
_httpCache.ClearCacheByKeySearch(keyStartsWith);
}
RuntimeCache.ClearCacheByKeySearch(keyStartsWith);
}
/// <summary>
@@ -219,29 +174,17 @@ namespace Umbraco.Core
/// </summary>
/// <param name="regexString"></param>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void ClearCacheByKeyExpression(string regexString)
{
if (_enableCache == false)
{
_nullHttpCache.ClearCacheByKeyExpression(regexString);
}
else
{
_httpCache.ClearCacheByKeyExpression(regexString);
}
RuntimeCache.ClearCacheByKeyExpression(regexString);
}
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
{
if (_enableCache == false)
{
return _nullHttpCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
}
else
{
return _httpCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
}
return RuntimeCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
}
/// <summary>
@@ -251,16 +194,10 @@ namespace Umbraco.Core
/// <param name="cacheKey"></param>
/// <returns></returns>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public TT GetCacheItem<TT>(string cacheKey)
{
if (_enableCache == false)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey);
}
else
{
return _httpCache.GetCacheItem<TT>(cacheKey);
}
return RuntimeCache.GetCacheItem<TT>(cacheKey);
}
/// <summary>
@@ -271,16 +208,11 @@ namespace Umbraco.Core
/// <param name="getCacheItem"></param>
/// <returns></returns>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
{
if (_enableCache == false)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem);
}
else
{
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem);
}
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem);
}
/// <summary>
@@ -292,17 +224,12 @@ namespace Umbraco.Core
/// <param name="getCacheItem"></param>
/// <returns></returns>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public TT GetCacheItem<TT>(string cacheKey,
TimeSpan timeout, Func<TT> getCacheItem)
{
if (_enableCache == false)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
}
else
{
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
}
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
}
/// <summary>
@@ -315,18 +242,13 @@ namespace Umbraco.Core
/// <param name="getCacheItem"></param>
/// <returns></returns>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public TT GetCacheItem<TT>(string cacheKey,
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
Func<TT> getCacheItem)
{
if (!_enableCache)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
}
else
{
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
}
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
}
/// <summary>
@@ -340,18 +262,13 @@ namespace Umbraco.Core
/// <param name="getCacheItem"></param>
/// <returns></returns>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public TT GetCacheItem<TT>(string cacheKey,
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
Func<TT> getCacheItem)
{
if (_enableCache == false)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
}
else
{
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
}
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
}
/// <summary>
@@ -373,20 +290,13 @@ namespace Umbraco.Core
TimeSpan timeout,
Func<TT> getCacheItem)
{
if (_enableCache == false)
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null);
}
else
{
var cache = _httpCache as HttpRuntimeCacheProvider;
if (cache != null)
{
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
}
/// <summary>
@@ -404,20 +314,13 @@ namespace Umbraco.Core
CacheDependency cacheDependency,
Func<TT> getCacheItem)
{
if (!_enableCache)
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
return _nullHttpCache.GetCacheItem<TT>(cacheKey, getCacheItem, null, false, priority, null, null);
}
else
{
var cache = _httpCache as HttpRuntimeCacheProvider;
if (cache != null)
{
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
}
/// <summary>
@@ -427,18 +330,14 @@ namespace Umbraco.Core
/// <param name="cacheKey"></param>
/// <param name="priority"></param>
/// <param name="getCacheItem"></param>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void InsertCacheItem<T>(string cacheKey,
CacheItemPriority priority,
Func<T> getCacheItem)
{
if (_enableCache == false)
{
_nullHttpCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
}
else
{
_httpCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
}
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
}
/// <summary>
@@ -449,19 +348,14 @@ namespace Umbraco.Core
/// <param name="priority"></param>
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
/// <param name="getCacheItem"></param>
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void InsertCacheItem<T>(string cacheKey,
CacheItemPriority priority,
TimeSpan timeout,
Func<T> getCacheItem)
{
if (_enableCache == false)
{
_nullHttpCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
}
else
{
_httpCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
}
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
}
/// <summary>
@@ -480,19 +374,12 @@ namespace Umbraco.Core
TimeSpan timeout,
Func<T> getCacheItem)
{
if (_enableCache == false)
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
_nullHttpCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null);
}
else
{
var cache = _httpCache as HttpRuntimeCacheProvider;
if (cache != null)
{
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
}
/// <summary>
@@ -513,22 +400,29 @@ namespace Umbraco.Core
TimeSpan? timeout,
Func<T> getCacheItem)
{
if (_enableCache == false)
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
_nullHttpCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null);
}
else
{
var cache = _httpCache as HttpRuntimeCacheProvider;
if (cache != null)
{
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
}
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
}
#endregion
}
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
{
HttpRuntimeCacheProvider cache;
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
if (wrapper != null)
{
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
}
else
{
cache = RuntimeCache as HttpRuntimeCacheProvider;
}
return cache;
}
}
}
@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Collections
{
/// <summary>
/// A List that can be deep cloned with deep cloned elements and can reset the collection's items dirty flags
/// </summary>
/// <typeparam name="T"></typeparam>
internal class DeepCloneableList<T> : List<T>, IDeepCloneable, IRememberBeingDirty
{
private readonly ListCloneBehavior _listCloneBehavior;
public DeepCloneableList(ListCloneBehavior listCloneBehavior)
{
_listCloneBehavior = listCloneBehavior;
}
public DeepCloneableList(IEnumerable<T> collection, ListCloneBehavior listCloneBehavior) : base(collection)
{
_listCloneBehavior = listCloneBehavior;
}
/// <summary>
/// Default behavior is CloneOnce
/// </summary>
/// <param name="collection"></param>
public DeepCloneableList(IEnumerable<T> collection)
: this(collection, ListCloneBehavior.CloneOnce)
{
}
/// <summary>
/// Creates a new list and adds each element as a deep cloned element if it is of type IDeepCloneable
/// </summary>
/// <returns></returns>
public object DeepClone()
{
switch (_listCloneBehavior)
{
case ListCloneBehavior.CloneOnce:
//we are cloning once, so create a new list in none mode
// and deep clone all items into it
var newList = new DeepCloneableList<T>(ListCloneBehavior.None);
foreach (var item in this)
{
var dc = item as IDeepCloneable;
if (dc != null)
{
newList.Add((T)dc.DeepClone());
}
else
{
newList.Add(item);
}
}
return newList;
case ListCloneBehavior.None:
//we are in none mode, so just return a new list with the same items
return new DeepCloneableList<T>(this, ListCloneBehavior.None);
case ListCloneBehavior.Always:
//always clone to new list
var newList2 = new DeepCloneableList<T>(ListCloneBehavior.Always);
foreach (var item in this)
{
var dc = item as IDeepCloneable;
if (dc != null)
{
newList2.Add((T)dc.DeepClone());
}
else
{
newList2.Add(item);
}
}
return newList2;
default:
throw new ArgumentOutOfRangeException();
}
}
public bool IsDirty()
{
return this.OfType<IRememberBeingDirty>().Any(x => x.IsDirty());
}
public bool WasDirty()
{
return this.OfType<IRememberBeingDirty>().Any(x => x.WasDirty());
}
/// <summary>
/// Always returns false, the list has no properties we need to report
/// </summary>
/// <param name="propName"></param>
/// <returns></returns>
public bool IsPropertyDirty(string propName)
{
return false;
}
/// <summary>
/// Always returns false, the list has no properties we need to report
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
public bool WasPropertyDirty(string propertyName)
{
return false;
}
public void ResetDirtyProperties()
{
foreach (var dc in this.OfType<IRememberBeingDirty>())
{
dc.ResetDirtyProperties();
}
}
public void ForgetPreviouslyDirtyProperties()
{
foreach (var dc in this.OfType<IRememberBeingDirty>())
{
dc.ForgetPreviouslyDirtyProperties();
}
}
public void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
{
foreach (var dc in this.OfType<IRememberBeingDirty>())
{
dc.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
}
}
}
@@ -0,0 +1,20 @@
namespace Umbraco.Core.Collections
{
internal enum ListCloneBehavior
{
/// <summary>
/// When set, DeepClone will clone the items one time and the result list behavior will be None
/// </summary>
CloneOnce,
/// <summary>
/// When set, DeepClone will not clone any items
/// </summary>
None,
/// <summary>
/// When set, DeepClone will always clone all items
/// </summary>
Always
}
}
+23 -120
View File
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Configuration
//make this volatile so that we can ensure thread safety with a double check lock
private static volatile string _reservedUrlsCache;
private static string _reservedPathsCache;
private static StartsWithContainer _reservedList = new StartsWithContainer();
private static HashSet<string> _reservedList = new HashSet<string>();
private static string _reservedPaths;
private static string _reservedUrls;
//ensure the built on (non-changeable) reserved paths are there at all times
@@ -767,38 +767,31 @@ namespace Umbraco.Core.Configuration
// store references to strings to determine changes
_reservedPathsCache = GlobalSettings.ReservedPaths;
_reservedUrlsCache = GlobalSettings.ReservedUrls;
string _root = SystemDirectories.Root.Trim().ToLower();
// add URLs and paths to a new list
StartsWithContainer _newReservedList = new StartsWithContainer();
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
var newReservedList = new HashSet<string>();
foreach (var reservedUrlTrimmed in _reservedUrlsCache
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim().ToLowerInvariant())
.Where(x => x.IsNullOrWhiteSpace() == false)
.Select(reservedUrl => IOHelper.ResolveUrl(reservedUrl).Trim().EnsureStartsWith("/"))
.Where(reservedUrlTrimmed => reservedUrlTrimmed.IsNullOrWhiteSpace() == false))
{
if (string.IsNullOrWhiteSpace(reservedUrl))
continue;
//resolves the url to support tilde chars
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl.Trim()).Trim().ToLower();
if (reservedUrlTrimmed.Length > 0)
_newReservedList.Add(reservedUrlTrimmed);
newReservedList.Add(reservedUrlTrimmed);
}
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
foreach (var reservedPathTrimmed in _reservedPathsCache
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim().ToLowerInvariant())
.Where(x => x.IsNullOrWhiteSpace() == false)
.Select(reservedPath => IOHelper.ResolveUrl(reservedPath).Trim().EnsureStartsWith("/").EnsureEndsWith("/"))
.Where(reservedPathTrimmed => reservedPathTrimmed.IsNullOrWhiteSpace() == false))
{
bool trimEnd = !reservedPath.EndsWith("/");
if (string.IsNullOrWhiteSpace(reservedPath))
continue;
//resolves the url to support tilde chars
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath.Trim()).Trim().ToLower();
if (reservedPathTrimmed.Length > 0)
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
newReservedList.Add(reservedPathTrimmed);
}
// use the new list from now on
_reservedList = _newReservedList;
_reservedList = newReservedList;
}
}
}
@@ -806,107 +799,17 @@ namespace Umbraco.Core.Configuration
//The url should be cleaned up before checking:
// * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/'
// * We shouldn't be comparing the query at all
var pathPart = url.Split('?')[0];
if (!pathPart.Contains(".") && !pathPart.EndsWith("/"))
var pathPart = url.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0].ToLowerInvariant();
if (pathPart.Contains(".") == false)
{
pathPart += "/";
pathPart = pathPart.EnsureEndsWith('/');
}
// return true if url starts with an element of the reserved list
return _reservedList.StartsWith(pathPart.ToLowerInvariant());
return _reservedList.Any(x => pathPart.InvariantStartsWith(x));
}
/// <summary>
/// Structure that checks in logarithmic time
/// if a given string starts with one of the added keys.
/// </summary>
private class StartsWithContainer
{
/// <summary>Internal sorted list of keys.</summary>
public SortedList<string, string> _list
= new SortedList<string, string>(StartsWithComparator.Instance);
/// <summary>
/// Adds the specified new key.
/// </summary>
/// <param name="newKey">The new key.</param>
public void Add(string newKey)
{
// if the list already contains an element that begins with newKey, return
if (String.IsNullOrEmpty(newKey) || StartsWith(newKey))
return;
// create a new collection, so the old one can still be accessed
SortedList<string, string> newList
= new SortedList<string, string>(_list.Count + 1, StartsWithComparator.Instance);
// add only keys that don't already start with newKey, others are unnecessary
foreach (string key in _list.Keys)
if (!key.StartsWith(newKey))
newList.Add(key, null);
// add the new key
newList.Add(newKey, null);
// update the list (thread safe, _list was never in incomplete state)
_list = newList;
}
/// <summary>
/// Checks if the given string starts with any of the added keys.
/// </summary>
/// <param name="target">The target.</param>
/// <returns>true if a key is found that matches the start of target</returns>
/// <remarks>
/// Runs in O(s*log(n)), with n the number of keys and s the length of target.
/// </remarks>
public bool StartsWith(string target)
{
return _list.ContainsKey(target);
}
/// <summary>Comparator that tests if a string starts with another.</summary>
/// <remarks>Not a real comparator, since it is not reflexive. (x==y does not imply y==x)</remarks>
private sealed class StartsWithComparator : IComparer<string>
{
/// <summary>Default string comparer.</summary>
private readonly static Comparer<string> _stringComparer = Comparer<string>.Default;
/// <summary>Gets an instance of the StartsWithComparator.</summary>
public static readonly StartsWithComparator Instance = new StartsWithComparator();
/// <summary>
/// Tests if whole begins with all characters of part.
/// </summary>
/// <param name="part">The part.</param>
/// <param name="whole">The whole.</param>
/// <returns>
/// Returns 0 if whole starts with part, otherwise performs standard string comparison.
/// </returns>
public int Compare(string part, string whole)
{
// let the default string comparer deal with null or when part is not smaller then whole
if (part == null || whole == null || part.Length >= whole.Length)
return _stringComparer.Compare(part, whole);
////ensure both have a / on the end
//part = part.EndsWith("/") ? part : part + "/";
//whole = whole.EndsWith("/") ? whole : whole + "/";
//if (part.Length >= whole.Length)
// return _stringComparer.Compare(part, whole);
// loop through all characters that part and whole have in common
int pos = 0;
bool match;
do
{
match = (part[pos] == whole[pos]);
} while (match && ++pos < part.Length);
// return result of last comparison
return match ? 0 : (part[pos] < whole[pos] ? -1 : 1);
}
}
}
}
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.3.0");
private static readonly Version Version = new Version("7.3.8");
/// <summary>
/// Gets the current version of Umbraco.
+1 -1
View File
@@ -43,7 +43,7 @@
public const string Users = "users";
/// <summary>
/// Application alias for the users section.
/// Application alias for the forms section.
/// </summary>
public const string Forms = "forms";
}
+1 -1
View File
@@ -206,7 +206,7 @@ namespace Umbraco.Core
/// </summary>
internal const string StandardPropertiesGroupName = "Membership";
internal static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
public static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
{
return new Dictionary<string, PropertyType>
{
@@ -310,13 +310,13 @@ namespace Umbraco.Core
public const string TextboxAlias = "Umbraco.Textbox";
/// <summary>
/// Guid for the Textbox multiple datatype.
/// Guid for the Textarea datatype.
/// </summary>
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string TextboxMultiple = "67DB8357-EF57-493E-91AC-936D305E0F2A";
/// <summary>
/// Alias for the Textbox multiple datatype.
/// Alias for the Textarea datatype.
/// </summary>
public const string TextboxMultipleAlias = "Umbraco.TextboxMultiple";
+12 -1
View File
@@ -1,4 +1,7 @@
namespace Umbraco.Core
using System;
using System.ComponentModel;
namespace Umbraco.Core
{
public static partial class Constants
{
@@ -7,6 +10,12 @@
/// </summary>
public static class Web
{
public const string UmbracoContextDataToken = "umbraco-context";
public const string UmbracoDataToken = "umbraco";
public const string PublishedDocumentRequestDataToken = "umbraco-doc-request";
public const string CustomRouteDataToken = "umbraco-custom-route";
public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
/// <summary>
/// The preview cookie name
/// </summary>
@@ -15,6 +24,8 @@
/// <summary>
/// The auth cookie name
/// </summary>
[Obsolete("DO NOT USE THIS, USE ISecuritySection.AuthCookieName, this will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string AuthCookieName = "UMB_UCONTEXT";
}
+20 -5
View File
@@ -136,7 +136,10 @@ namespace Umbraco.Core
{
try
{
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationInitialized", x.GetType())))
{
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
}
}
catch (Exception ex)
{
@@ -188,10 +191,16 @@ namespace Umbraco.Core
protected virtual CacheHelper CreateApplicationCache()
{
var cacheHelper = new CacheHelper(
new ObjectCacheRuntimeCacheProvider(),
//we need to have the dep clone runtime cache provider to ensure
//all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()),
new StaticCacheProvider(),
//we have no request based cache when not running in web-based context
new NullCacheProvider());
new NullCacheProvider(),
new IsolatedRuntimeCache(type =>
//we need to have the dep clone runtime cache provider to ensure
//all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())));
return cacheHelper;
}
@@ -293,7 +302,10 @@ namespace Umbraco.Core
{
try
{
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarting", x.GetType())))
{
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
}
}
catch (Exception ex)
{
@@ -344,7 +356,10 @@ namespace Umbraco.Core
{
try
{
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarted", x.GetType())))
{
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
}
}
catch (Exception ex)
{
+44 -21
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Web;
@@ -12,6 +13,12 @@ namespace Umbraco.Core
/// </summary>
public class DisposableTimer : DisposableObject
{
private readonly ILogger _logger;
private readonly LogType? _logType;
private readonly IProfiler _profiler;
private readonly Type _loggerType;
private readonly string _endMessage;
private readonly IDisposable _profilerStep;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private readonly Action<long> _callback;
@@ -25,25 +32,12 @@ namespace Umbraco.Core
if (logger == null) throw new ArgumentNullException("logger");
if (loggerType == null) throw new ArgumentNullException("loggerType");
_callback = x =>
{
if (profiler != null)
{
profiler.DisposeIfDisposable();
}
switch (logType)
{
case LogType.Debug:
logger.Debug(loggerType, () => endMessage + " (took " + x + "ms)");
break;
case LogType.Info:
logger.Info(loggerType, () => endMessage + " (took " + x + "ms)");
break;
default:
throw new ArgumentOutOfRangeException("logType");
}
};
_logger = logger;
_logType = logType;
_profiler = profiler;
_loggerType = loggerType;
_endMessage = endMessage;
switch (logType)
{
case LogType.Debug:
@@ -58,7 +52,7 @@ namespace Umbraco.Core
if (profiler != null)
{
profiler.Step(loggerType, startMessage);
_profilerStep = profiler.Step(loggerType, startMessage);
}
}
@@ -223,7 +217,36 @@ namespace Umbraco.Core
/// </summary>
protected override void DisposeResources()
{
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
if (_profiler != null)
{
_profiler.DisposeIfDisposable();
}
if (_profilerStep != null)
{
_profilerStep.Dispose();
}
if (_logType.HasValue && _endMessage.IsNullOrWhiteSpace() == false && _loggerType != null && _logger != null)
{
switch (_logType)
{
case LogType.Debug:
_logger.Debug(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
break;
case LogType.Info:
_logger.Info(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
break;
default:
throw new ArgumentOutOfRangeException("logType");
}
}
if (_callback != null)
{
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
}
}
}
+1 -1
View File
@@ -154,7 +154,7 @@ namespace Umbraco.Core.IO
{
get
{
return IOHelper.ReturnPath("umbracoWebservicesPath", "~/umbraco/webservices");
return IOHelper.ReturnPath("umbracoWebservicesPath", Umbraco.EnsureEndsWith("/") + "webservices");
}
}
+2 -2
View File
@@ -199,8 +199,8 @@ namespace Umbraco.Core.IO
using (var image = Image.FromStream(fs))
{
var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition)
? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)))
: string.Format("{0}_{1}.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition);
? string.Format("{0}_UMBRACOSYSTHUMBNAIL." + Extension, Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)))
: string.Format("{0}_{1}." + Extension, Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition);
var thumbnail = maxWidthHeight == -1
? ImageHelper.GenerateThumbnail(image, width, height, fileNameThumb, Extension, _fs)
+6 -2
View File
@@ -11,8 +11,12 @@ namespace Umbraco.Core.Macros
/// </summary>
internal class MacroTagParser
{
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO (?:.+?)?macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat =
new Regex(@"(<\?UMBRACO_MACRO (?:.+?)??macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Singleline);
/// <summary>
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Media.Exif
{
if (items.ContainsKey (key))
items.Remove (key);
if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) {
if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) {
items.Add (key, new WindowsByteString (key, value));
} else {
items.Add (key, new ExifAscii (key, value, parent.Encoding));
+37 -16
View File
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Media
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
}
}
public static string GetMimeType(this Image image)
@@ -79,22 +79,22 @@ namespace Umbraco.Core.Media
/// <param name="additionalThumbSizes"></param>
/// <returns></returns>
internal static IEnumerable<ResizedImage> GenerateMediaThumbnails(
IFileSystem fs,
string fileName,
string extension,
IFileSystem fs,
string fileName,
string extension,
Image originalImage,
IEnumerable<int> additionalThumbSizes)
{
var result = new List<ResizedImage>();
var allSizesDictionary = new Dictionary<int,string> {{100,"thumb"}, {500,"big-thumb"}};
var allSizesDictionary = new Dictionary<int, string> { { 100, "thumb" }, { 500, "big-thumb" } };
//combine the static dictionary with the additional sizes with only unique values
var allSizes = allSizesDictionary.Select(kv => kv.Key)
.Union(additionalThumbSizes.Where(x => x > 0).Distinct());
var sizesDictionary = allSizes.ToDictionary(s => s, s => allSizesDictionary.ContainsKey(s) ? allSizesDictionary[s]: "");
var sizesDictionary = allSizes.ToDictionary(s => s, s => allSizesDictionary.ContainsKey(s) ? allSizesDictionary[s] : "");
foreach (var s in sizesDictionary)
{
@@ -121,9 +121,9 @@ namespace Umbraco.Core.Media
/// <returns></returns>
private static ResizedImage Resize(IFileSystem fileSystem, string path, string extension, int maxWidthHeight, string fileNameAddition, Image originalImage)
{
var fileNameThumb = String.IsNullOrEmpty(fileNameAddition)
? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", path.Substring(0, path.LastIndexOf(".")))
: string.Format("{0}_{1}.jpg", path.Substring(0, path.LastIndexOf(".")), fileNameAddition);
var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition)
? string.Format("{0}_UMBRACOSYSTHUMBNAIL." + extension, path.Substring(0, path.LastIndexOf(".", StringComparison.Ordinal)))
: string.Format("{0}_{1}." + extension, path.Substring(0, path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition);
var thumb = GenerateThumbnail(
originalImage,
@@ -190,9 +190,9 @@ namespace Umbraco.Core.Media
//use best quality
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
}
g.SmoothingMode = SmoothingMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
@@ -202,10 +202,29 @@ namespace Umbraco.Core.Media
// Copy metadata
var imageEncoders = ImageCodecInfo.GetImageEncoders();
var codec = extension.ToLower() == "png" || extension.ToLower() == "gif"
? imageEncoders.Single(t => t.MimeType.Equals("image/png"))
: imageEncoders.Single(t => t.MimeType.Equals("image/jpeg"));
ImageCodecInfo codec;
switch (extension.ToLower())
{
case "png":
codec = imageEncoders.Single(t => t.MimeType.Equals("image/png"));
break;
case "gif":
codec = imageEncoders.Single(t => t.MimeType.Equals("image/gif"));
break;
case "tif":
case "tiff":
codec = imageEncoders.Single(t => t.MimeType.Equals("image/tiff"));
break;
case "bmp":
codec = imageEncoders.Single(t => t.MimeType.Equals("image/bmp"));
break;
// TODO: this is dirty, defaulting to jpg but the return value of this thing is used all over the
// place so left it here, but it needs to not set a codec if it doesn't know which one to pick
// Note: when fixing this: both .jpg and .jpeg should be handled as extensions
default:
codec = imageEncoders.Single(t => t.MimeType.Equals("image/jpeg"));
break;
}
// Set compresion ratio to 90%
var ep = new EncoderParameters();
@@ -213,12 +232,14 @@ namespace Umbraco.Core.Media
// Save the new image using the dimensions of the image
var predictableThumbnailName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", maxWidthHeight.ToString(CultureInfo.InvariantCulture));
var predictableThumbnailNameJpg = predictableThumbnailName.Substring(0, predictableThumbnailName.LastIndexOf(".", StringComparison.Ordinal)) + ".jpg";
using (var ms = new MemoryStream())
{
bp.Save(ms, codec, ep);
ms.Seek(0, 0);
fs.AddFile(predictableThumbnailName, ms);
fs.AddFile(predictableThumbnailNameJpg, ms);
}
// TODO: Remove this, this is ONLY here for backwards compatibility but it is essentially completely unusable see U4-5385
+1 -2
View File
@@ -560,8 +560,7 @@ namespace Umbraco.Core.Models
//Additional thumbnails configured as prevalues on the DataType
if (thumbnailSizes != null)
{
var sep = (thumbnailSizes.Contains("") == false && thumbnailSizes.Contains(",")) ? ',' : ';';
foreach (var thumb in thumbnailSizes.Split(sep))
foreach (var thumb in thumbnailSizes.Split(new[] { ";", "," }, StringSplitOptions.RemoveEmptyEntries))
{
int thumbSize;
if (thumb != "" && int.TryParse(thumb, out thumbSize))
+6
View File
@@ -53,6 +53,9 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or sets the alias of the default Template.
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
/// we should not store direct entity
/// </summary>
[IgnoreDataMember]
public ITemplate DefaultTemplate
@@ -79,6 +82,9 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or Sets a list of Templates which are allowed for the ContentType
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
/// we should not store direct entity
/// </summary>
[DataMember]
public IEnumerable<ITemplate> AllowedTemplates
@@ -533,6 +533,18 @@ namespace Umbraco.Core.Models
/// <param name="propertyGroupName">Name of the <see cref="PropertyGroup"/> to remove</param>
public void RemovePropertyGroup(string propertyGroupName)
{
// if no group exists with that name, do nothing
var group = PropertyGroups[propertyGroupName];
if (group == null) return;
// re-assign the group's properties to no group
foreach (var property in group.PropertyTypes)
{
property.PropertyGroupId = new Lazy<int>(() => 0);
_propertyTypes.Add(property);
}
// actually remove the group
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(PropertyGroupCollectionSelector);
}
+99 -55
View File
@@ -9,10 +9,30 @@ namespace Umbraco.Core.Models
{
public static class DeepCloneHelper
{
/// <summary>
/// Stores the metadata for the properties for a given type so we know how to create them
/// </summary>
private struct ClonePropertyInfo
{
public ClonePropertyInfo(PropertyInfo propertyInfo) : this()
{
if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
PropertyInfo = propertyInfo;
}
public PropertyInfo PropertyInfo { get; private set; }
public bool IsDeepCloneable { get; set; }
public Type GenericListType { get; set; }
public bool IsList
{
get { return GenericListType != null; }
}
}
/// <summary>
/// Used to avoid constant reflection (perf)
/// </summary>
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
private static readonly ConcurrentDictionary<Type, ClonePropertyInfo[]> PropCache = new ConcurrentDictionary<Type, ClonePropertyInfo[]>();
/// <summary>
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
@@ -30,75 +50,99 @@ namespace Umbraco.Core.Models
throw new InvalidOperationException("Both the input and output types must be the same");
}
//get the property metadata from cache so we only have to figure this out once per type
var refProperties = PropCache.GetOrAdd(inputType, type =>
inputType.GetProperties()
.Where(x =>
//is not attributed with the ignore clone attribute
x.GetCustomAttribute<DoNotCloneAttribute>() == null
.Select<PropertyInfo, ClonePropertyInfo?>(propertyInfo =>
{
if (
//is not attributed with the ignore clone attribute
propertyInfo.GetCustomAttribute<DoNotCloneAttribute>() != null
//reference type but not string
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|| propertyInfo.PropertyType.IsValueType || propertyInfo.PropertyType == typeof (string)
//settable
&& x.CanWrite
|| propertyInfo.CanWrite == false
//non-indexed
&& x.GetIndexParameters().Any() == false)
|| propertyInfo.GetIndexParameters().Any())
{
return null;
}
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
{
return new ClonePropertyInfo(propertyInfo) { IsDeepCloneable = true };
}
if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
{
if (propertyInfo.PropertyType.IsGenericType
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
}
if (propertyInfo.PropertyType.IsArray
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
{
//if its an array, we'll create a list to work with first and then convert to array later
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
return new ClonePropertyInfo(propertyInfo) { GenericListType = typeof(List<object>) };
}
//skip instead of trying to create instance of abstract or interface
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
{
return null;
}
//its a custom IEnumerable, we'll try to create it
try
{
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
//if it's an IList we can work with it, otherwise we cannot
var newList = custom as IList;
if (newList == null)
{
return null;
}
return new ClonePropertyInfo(propertyInfo) {GenericListType = propertyInfo.PropertyType};
}
catch (Exception)
{
//could not create this type so we'll skip it
return null;
}
}
return new ClonePropertyInfo(propertyInfo);
})
.Where(x => x.HasValue)
.Select(x => x.Value)
.ToArray());
foreach (var propertyInfo in refProperties)
foreach (var clonePropertyInfo in refProperties)
{
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
if (clonePropertyInfo.IsDeepCloneable)
{
//this ref property is also deep cloneable so clone it
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
var result = (IDeepCloneable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
if (result != null)
{
//set the cloned value to the property
propertyInfo.SetValue(output, result.DeepClone(), null);
clonePropertyInfo.PropertyInfo.SetValue(output, result.DeepClone(), null);
}
}
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
else if (clonePropertyInfo.IsList)
{
IList newList;
if (propertyInfo.PropertyType.IsGenericType
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
newList = (IList)Activator.CreateInstance(genericType);
}
else if (propertyInfo.PropertyType.IsArray
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
{
//if its an array, we'll create a list to work with first and then convert to array later
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
newList = new List<object>();
}
else
{
//its a custom IEnumerable, we'll try to create it
try
{
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
//if it's an IList we can work with it, otherwise we cannot
newList = custom as IList;
if (newList == null)
{
continue;
}
}
catch (Exception)
{
//could not create this type so we'll skip it
continue;
}
}
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
var enumerable = (IEnumerable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
if (enumerable == null) continue;
var newList = (IList)Activator.CreateInstance(clonePropertyInfo.GenericListType);
var isUsableType = true;
//now clone each item
@@ -130,21 +174,21 @@ namespace Umbraco.Core.Models
continue;
}
if (propertyInfo.PropertyType.IsArray)
if (clonePropertyInfo.PropertyInfo.PropertyType.IsArray)
{
//need to convert to array
var arr = (object[])Activator.CreateInstance(propertyInfo.PropertyType, newList.Count);
var arr = (object[])Activator.CreateInstance(clonePropertyInfo.PropertyInfo.PropertyType, newList.Count);
for (int i = 0; i < newList.Count; i++)
{
arr[i] = newList[i];
}
//set the cloned collection
propertyInfo.SetValue(output, arr, null);
clonePropertyInfo.PropertyInfo.SetValue(output, arr, null);
}
else
{
//set the cloned collection
propertyInfo.SetValue(output, newList, null);
clonePropertyInfo.PropertyInfo.SetValue(output, newList, null);
}
}
+12 -1
View File
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class DictionaryItem : Entity, IDictionaryItem
{
public Func<int, ILanguage> GetLanguage { get; set; }
private Guid? _parentId;
private string _itemKey;
private IEnumerable<IDictionaryTranslation> _translations;
@@ -78,7 +79,17 @@ namespace Umbraco.Core.Models
{
SetPropertyValueAndDetectChanges(o =>
{
_translations = value;
var asArray = value.ToArray();
//ensure the language callback is set on each translation
if (GetLanguage != null)
{
foreach (var translation in asArray.OfType<DictionaryTranslation>())
{
translation.GetLanguage = GetLanguage;
}
}
_translations = asArray;
return _translations;
}, _translations, TranslationsSelector,
//Custom comparer for enumerable
@@ -13,13 +13,18 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class DictionaryTranslation : Entity, IDictionaryTranslation
{
internal Func<int, ILanguage> GetLanguage { get; set; }
private ILanguage _language;
private string _value;
//note: this will be memberwise cloned
private int _languageId;
public DictionaryTranslation(ILanguage language, string value)
{
if (language == null) throw new ArgumentNullException("language");
_language = language;
_languageId = _language.Id;
_value = value;
}
@@ -27,6 +32,20 @@ namespace Umbraco.Core.Models
{
if (language == null) throw new ArgumentNullException("language");
_language = language;
_languageId = _language.Id;
_value = value;
Key = uniqueId;
}
internal DictionaryTranslation(int languageId, string value)
{
_languageId = languageId;
_value = value;
}
internal DictionaryTranslation(int languageId, string value, Guid uniqueId)
{
_languageId = languageId;
_value = value;
Key = uniqueId;
}
@@ -37,20 +56,43 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets or sets the <see cref="Language"/> for the translation
/// </summary>
/// <remarks>
/// Marked as DoNotClone - TODO: this member shouldn't really exist here in the first place, the DictionaryItem
/// class will have a deep hierarchy of objects which all get deep cloned which we don't want. This should have simply
/// just referenced a language ID not the actual language object. In v8 we need to fix this.
/// We're going to have to do the same hacky stuff we had to do with the Template/File contents so that this is returned
/// on a callback.
/// </remarks>
[DataMember]
[DoNotClone]
public ILanguage Language
{
get { return _language; }
get
{
if (_language != null)
return _language;
// else, must lazy-load
if (GetLanguage != null && _languageId > 0)
_language = GetLanguage(_languageId);
return _language;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_language = value;
_languageId = _language == null ? -1 : _language.Id;
return _language;
}, _language, LanguageSelector);
}
}
public int LanguageId
{
get { return _languageId; }
}
/// <summary>
/// Gets or sets the translated text
/// </summary>
@@ -68,5 +110,23 @@ namespace Umbraco.Core.Models
}
}
public override object DeepClone()
{
var clone = (DictionaryTranslation)base.DeepClone();
// clear fields that were memberwise-cloned and that we don't want to clone
clone._language = null;
// turn off change tracking
clone.DisableChangeTracking();
// this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
// re-enable tracking
clone.EnableChangeTracking();
return clone;
}
}
}
@@ -12,6 +12,8 @@ namespace Umbraco.Core.Models
[DataMember]
ILanguage Language { get; set; }
int LanguageId { get; }
/// <summary>
/// Gets or sets the translated text
/// </summary>
@@ -4,6 +4,7 @@ using AutoMapper;
using Umbraco.Core.Models.Mapping;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
namespace Umbraco.Core.Models.Identity
{
@@ -24,6 +25,18 @@ namespace Umbraco.Core.Models.Identity
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
.ForMember(user => user.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts))
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
config.CreateMap<BackOfficeIdentityUser, UserData>()
.ConstructUsing((BackOfficeIdentityUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id'
.ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
.ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
.ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => new[] { user.UserTypeAlias }))
.ForMember(detail => detail.StartContentNode, opt => opt.MapFrom(user => user.StartContentId))
.ForMember(detail => detail.StartMediaNode, opt => opt.MapFrom(user => user.StartMediaId))
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture))
.ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
}
private string GetPasswordHash(string storedPass)
+1 -1
View File
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
public CultureInfo CultureInfo
{
get { return CultureInfo.CreateSpecificCulture(IsoCode); }
get { return CultureInfo.GetCultureInfo(IsoCode); }
}
}
}
+6 -6
View File
@@ -280,7 +280,7 @@ namespace Umbraco.Core.Models
//This is the default value if the prop is not found
true);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsApproved].Value == null) return true;
var tryConvert = Properties[Constants.Conventions.Member.IsApproved].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -313,7 +313,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, "IsLockedOut", false);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsLockedOut].Value == null) return false;
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -346,7 +346,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, "LastLoginDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLoginDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -379,7 +379,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, "LastPasswordChangeDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -412,7 +412,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, "LastLockoutDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLockoutDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -446,7 +446,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, "FailedPasswordAttempts", 0);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value == null) return default(int);
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value.TryConvertTo<int>();
if (tryConvert.Success)
{
@@ -230,13 +230,13 @@ namespace Umbraco.Core.Models.PublishedContent
{
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
_xpathCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
}
else
{
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
_xpathCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
}
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Models.Rdbms
internal class MigrationDto
{
[Column("id")]
[PrimaryKeyColumn(AutoIncrement = true)]
[PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 100)]
public int Id { get; set; }
[Column("name")]
@@ -2,6 +2,7 @@
using System.Globalization;
using System.Linq;
using System.Threading;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
+11 -16
View File
@@ -1,15 +1,10 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Xml;
namespace Umbraco.Core
@@ -51,7 +46,7 @@ namespace Umbraco.Core
public static Attempt<T> TryConvertTo<T>(this object input)
{
var result = TryConvertTo(input, typeof(T));
if (!result.Success)
if (result.Success == false)
{
//just try a straight up conversion
try
@@ -64,7 +59,7 @@ namespace Umbraco.Core
return Attempt<T>.Fail(e);
}
}
return !result.Success ? Attempt<T>.Fail() : Attempt<T>.Succeed((T)result.Result);
return result.Success == false ? Attempt<T>.Fail() : Attempt<T>.Succeed((T)result.Result);
}
/// <summary>
@@ -117,7 +112,7 @@ namespace Umbraco.Core
}
// we've already dealed with nullables, so any other generic types need to fall through
if (!destinationType.IsGenericType)
if (destinationType.IsGenericType == false)
{
if (input is string)
{
@@ -335,11 +330,11 @@ namespace Umbraco.Core
return null; // we can't decide...
}
private readonly static char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','};
private static readonly char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','};
private static string NormalizeNumberDecimalSeparator(string s)
{
var normalized = System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator[0];
var normalized = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized);
}
@@ -442,7 +437,7 @@ namespace Umbraco.Core
{
var props = TypeDescriptor.GetProperties(o);
var d = new Dictionary<string, TVal>();
foreach (var prop in props.Cast<PropertyDescriptor>().Where(x => !ignoreProperties.Contains(x.Name)))
foreach (var prop in props.Cast<PropertyDescriptor>().Where(x => ignoreProperties.Contains(x.Name) == false))
{
var val = prop.GetValue(o);
if (val != null)
@@ -478,13 +473,13 @@ namespace Umbraco.Core
var items = (from object enumItem in enumerable let value = GetEnumPropertyDebugString(enumItem, levels) where value != null select value).Take(10).ToList();
return items.Count() > 0
return items.Any()
? "{{ {0} }}".InvariantFormat(String.Join(", ", items))
: null;
}
var props = obj.GetType().GetProperties();
if ((props.Count() == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2)
if ((props.Length == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2)
{
try
{
@@ -500,12 +495,12 @@ namespace Umbraco.Core
if (levels > -1)
{
var items =
from propertyInfo in props
(from propertyInfo in props
let value = GetPropertyDebugString(propertyInfo, obj, levels)
where value != null
select "{0}={1}".InvariantFormat(propertyInfo.Name, value);
select "{0}={1}".InvariantFormat(propertyInfo.Name, value)).ToArray();
return items.Count() > 0
return items.Any()
? "[{0}]:{{ {1} }}".InvariantFormat(obj.GetType().Name, String.Join(", ", items))
: null;
}
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Persistence.Factories
{
var text = new LanguageTextDto
{
LanguageId = translation.Language.Id,
LanguageId = translation.LanguageId,
UniqueId = translation.Key,
Value = translation.Value
};
@@ -7,20 +7,19 @@ namespace Umbraco.Core.Persistence.Factories
internal class DictionaryTranslationFactory
{
private readonly Guid _uniqueId;
private ILanguage _language;
public DictionaryTranslationFactory(Guid uniqueId, ILanguage language)
public DictionaryTranslationFactory(Guid uniqueId)
{
_uniqueId = uniqueId;
_language = language;
}
#region Implementation of IEntityFactory<DictionaryTranslation,LanguageTextDto>
public IDictionaryTranslation BuildEntity(LanguageTextDto dto)
{
var item = new DictionaryTranslation(_language, dto.Value, _uniqueId)
var item = new DictionaryTranslation(dto.LanguageId, dto.Value, _uniqueId)
{Id = dto.PrimaryKey};
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
item.ResetDirtyProperties(false);
@@ -31,7 +30,7 @@ namespace Umbraco.Core.Persistence.Factories
{
var text = new LanguageTextDto
{
LanguageId = entity.Language.Id,
LanguageId = entity.LanguageId,
UniqueId = _uniqueId,
Value = entity.Value
};
@@ -129,11 +129,7 @@ namespace Umbraco.Core.Persistence.Factories
Name = propertyType.Name,
SortOrder = propertyType.SortOrder,
ValidationRegExp = propertyType.ValidationRegExp,
UniqueId = propertyType.HasIdentity
? propertyType.Key == Guid.Empty
? Guid.NewGuid()
: propertyType.Key
: Guid.NewGuid()
UniqueId = propertyType.Key == Guid.Empty ? Guid.NewGuid() : propertyType.Key
};
if (tabId != default(int))
@@ -0,0 +1,38 @@
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Mappers
{
/// <summary>
/// Represents a <see cref="TaskType"/> to DTO mapper used to translate the properties of the public api
/// implementation to that of the database's DTO as sql: [tableName].[columnName].
/// </summary>
[MapperFor(typeof(TaskType))]
public sealed class TaskTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
public TaskTypeMapper()
{
BuildMap();
}
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<TaskType, TaskTypeDto>(src => src.Id, dto => dto.Id);
CacheMap<TaskType, TaskTypeDto>(src => src.Alias, dto => dto.Alias);
}
#endregion
}
}
@@ -108,7 +108,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -21, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,-21", SortOrder = 0, UniqueId = new Guid("BF7C7CBC-952F-4518-97A2-69E9C7B33842"), Text = "Recycle Bin", NodeObjectType = new Guid(Constants.ObjectTypes.MediaRecycleBin), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -92, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-92", SortOrder = 35, UniqueId = new Guid("f0bc4bfb-b499-40d6-ba86-058885a5178c"), Text = "Label", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -90, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-90", SortOrder = 34, UniqueId = new Guid("84c6b441-31df-4ffe-b67e-67d5bc3ae65a"), Text = "Upload", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -89, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-89", SortOrder = 33, UniqueId = new Guid("c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3"), Text = "Textbox multiple", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -89, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-89", SortOrder = 33, UniqueId = new Guid("c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3"), Text = "Textarea", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -88, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-88", SortOrder = 32, UniqueId = new Guid("0cc0eba1-9960-42c9-bf9b-60e150b429ae"), Text = "Textstring", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -87, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-87", SortOrder = 4, UniqueId = new Guid("ca90c950-0aff-4e72-b976-a30b1ac57dad"), Text = "Richtext editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -51, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-51", SortOrder = 2, UniqueId = new Guid("2e6d3631-066e-44b8-aec4-96f09099b2b5"), Text = "Numeric", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
@@ -289,7 +289,7 @@ namespace Umbraco.Core.Persistence.Migrations
//NOTE: We CANNOT do this as part of the transaction!!! This is because when upgrading to 7.3, we cannot
// create the migrations table and then add data to it in the same transaction without issuing things like GO
// commands and since we need to support all Dbs, we need to just do this after the fact.
var exists = _migrationEntryService.FindEntry(GlobalSettings.UmbracoMigrationName, _targetVersion);
var exists = _migrationEntryService.FindEntry(_productName, _targetVersion);
if (exists == null)
{
_migrationEntryService.CreateEntry(_productName, _targetVersion);
@@ -0,0 +1,38 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeOne
{
/// <summary>
/// This fixes the storage of user languages from the old format like en_us to en-US
/// </summary>
[Migration("7.3.1", 0, GlobalSettings.UmbracoMigrationName)]
public class UpdateUserLanguagesToIsoCode : MigrationBase
{
public UpdateUserLanguagesToIsoCode(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
var userData = Context.Database.Fetch<UserDto>(new Sql().Select("*").From<UserDto>(SqlSyntax));
foreach (var user in userData.Where(x => x.UserLanguage.Contains("_")))
{
var languageParts = user.UserLanguage.Split('_');
if (languageParts.Length == 2)
{
Update.Table("umbracoUser")
.Set(new {userLanguage = languageParts[0] + "-" + languageParts[1].ToUpperInvariant()})
.Where(new {id = user.Id});
}
}
}
public override void Down()
{
}
}
}
@@ -0,0 +1,50 @@
using System.Collections.Generic;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeTwo
{
/// <summary>
/// This reinserts all migrations in the migrations table to account for initial rows inserted
/// on creation without identity enabled.
/// </summary>
[Migration("7.3.2", 0, GlobalSettings.UmbracoMigrationName)]
public class EnsureMigrationsTableIdentityIsCorrect : MigrationBase
{
public EnsureMigrationsTableIdentityIsCorrect(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
// Due to the delayed execution of migrations, we have to wrap this code in Execute.Code to ensure the previous
// migration steps (esp. creating the migrations table) have completed before trying to fetch migrations from
// this table.
List<MigrationDto> migrations = null;
Execute.Code(db =>
{
migrations = Context.Database.Fetch<MigrationDto>(new Sql().Select("*").From<MigrationDto>(SqlSyntax));
return string.Empty;
});
Delete.FromTable("umbracoMigration").AllRows();
Execute.Code(database =>
{
if (migrations != null)
{
foreach (var migration in migrations)
{
database.Insert("umbracoMigration", "id", true,
new {name = migration.Name, createDate = migration.CreateDate, version = migration.Version});
}
}
return string.Empty;
});
}
public override void Down()
{
}
}
}
@@ -28,37 +28,38 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
{
if (database != null)
{
//Fetch all PropertyTypes that belongs to a PropertyTypeGroup
//Fetch all PropertyTypes that belongs to a PropertyTypeGroup
//NOTE: We are writing the full query because we've added a column to the PropertyTypeDto in later versions so one of the columns
// won't exist yet
var propertyTypes = database.Fetch<PropertyTypeDto>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
//NOTE: We're using dynamic to avoid having this migration fail due to the UniqueId column added in 7.3 (this column is not added
// in the table yet and will make the mapping of done by Fetch fail when the actual type is used here).
var propertyTypes = database.Fetch<dynamic>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
foreach (var propertyType in propertyTypes)
{
//Get the PropertyTypeGroup that the current PropertyType references
var parentPropertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyTypeGroupId);
var parentPropertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.propertyTypeGroupId);
if (parentPropertyTypeGroup != null)
{
//If the ContentType is the same on the PropertyType and the PropertyTypeGroup the group is valid and we skip to the next
if (parentPropertyTypeGroup.ContentTypeNodeId == propertyType.ContentTypeId) continue;
if (parentPropertyTypeGroup.ContentTypeNodeId == propertyType.contentTypeId) continue;
//Check if the 'new' PropertyTypeGroup has already been created
var existingPropertyTypeGroup =
propertyGroups.FirstOrDefault(
x =>
x.ParentGroupId == parentPropertyTypeGroup.Id && x.Text == parentPropertyTypeGroup.Text &&
x.ContentTypeNodeId == propertyType.ContentTypeId);
x.ContentTypeNodeId == propertyType.contentTypeId);
//This should ensure that we don't create duplicate groups for a single ContentType
if (existingPropertyTypeGroup == null)
{
//Create a new PropertyTypeGroup that references the parent group that the PropertyType was referencing pre-6.0.1
var propertyGroup = new PropertyTypeGroupDto
{
ContentTypeNodeId = propertyType.ContentTypeId,
ContentTypeNodeId = propertyType.contentTypeId,
ParentGroupId = parentPropertyTypeGroup.Id,
Text = parentPropertyTypeGroup.Text,
SortOrder = parentPropertyTypeGroup.SortOrder
@@ -69,19 +70,18 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
propertyGroup.Id = id;
propertyGroups.Add(propertyGroup);
//Update the reference to the new PropertyTypeGroup on the current PropertyType
propertyType.PropertyTypeGroupId = id;
database.Update(propertyType);
propertyType.propertyTypeGroupId = id;
database.Update("cmsPropertyType", "id", propertyType);
}
else
{
//Update the reference to the existing PropertyTypeGroup on the current PropertyType
propertyType.PropertyTypeGroupId = existingPropertyTypeGroup.Id;
database.Update(propertyType);
//Update the reference to the existing PropertyTypeGroup on the current PropertyType
propertyType.propertyTypeGroupId = existingPropertyTypeGroup.Id;
database.Update("cmsPropertyType", "id", propertyType);
}
}
}
}
return string.Empty;
}
}
+1 -1
View File
@@ -834,7 +834,7 @@ namespace Umbraco.Core.Persistence
var pd = PocoData.ForType(typeof(T));
try
{
r = cmd.ExecuteReader();
r = cmd.ExecuteReaderWithRetry();
OnExecutedCommand(cmd);
}
catch (Exception x)
@@ -18,8 +18,11 @@ namespace Umbraco.Core.Persistence.Relators
// Is this the same DictionaryItem as the current one we're processing
if (Current != null && Current.Id == a.Id)
{
// Yes, just add this User2AppDto to the current item's collection
Current.User2AppDtos.Add(p);
if (p.AppAlias.IsNullOrWhiteSpace() == false)
{
// Yes, just add this User2AppDto to the current item's collection
Current.User2AppDtos.Add(p);
}
// Return null to indicate we're not done with this User yet
return null;
@@ -35,7 +38,7 @@ namespace Umbraco.Core.Persistence.Relators
Current = a;
Current.User2AppDtos = new List<User2AppDto>();
//this can be null since we are doing a left join
if (p.AppAlias != null)
if (p.AppAlias.IsNullOrWhiteSpace() == false)
{
Current.User2AppDtos.Add(p);
}
@@ -155,8 +155,8 @@ namespace Umbraco.Core.Persistence.Repositories
"DELETE FROM cmsContentVersion WHERE ContentId = @Id",
"DELETE FROM cmsContentXml WHERE nodeId = @Id",
"DELETE FROM cmsContent WHERE nodeId = @Id",
"DELETE FROM umbracoNode WHERE id = @Id",
"DELETE FROM umbracoAccess WHERE nodeId = @Id"
"DELETE FROM umbracoAccess WHERE nodeId = @Id",
"DELETE FROM umbracoNode WHERE id = @Id"
};
return list;
}
@@ -234,8 +234,15 @@ namespace Umbraco.Core.Persistence.Repositories
var processed = 0;
do
{
var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending);
//NOTE: This is an important call, we cannot simply make a call to:
// GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending);
// because that method is used to query 'latest' content items where in this case we don't necessarily
// want latest content items because a pulished content item might not actually be the latest.
// see: http://issues.umbraco.org/issue/U4-6322 & http://issues.umbraco.org/issue/U4-5982
var descendants = GetPagedResultsByQuery<DocumentDto, Content>(query, pageIndex, pageSize, out total,
new Tuple<string, string>("cmsDocument", "nodeId"),
ProcessQuery, "Path", Direction.Ascending);
var xmlItems = (from descendant in descendants
let xml = serializer(descendant)
select new ContentXmlDto { NodeId = descendant.Id, Xml = xml.ToDataString() }).ToArray();
@@ -728,7 +735,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="content"></param>
/// <param name="xml"></param>
public void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml)
{
{
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IContent>(content, xml));
}
@@ -826,11 +833,11 @@ namespace Umbraco.Core.Persistence.Repositories
var contentTypes = _contentTypeRepository.GetAll(dtos.Select(x => x.ContentVersionDto.ContentDto.ContentTypeId).ToArray())
.ToArray();
var ids = dtos
.Where(dto => dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
.Select(x => x.TemplateId.Value).ToArray();
//NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types
var templates = ids.Length == 0 ? Enumerable.Empty<ITemplate>() : _templateRepository.GetAll(ids).ToArray();
@@ -972,4 +979,4 @@ namespace Umbraco.Core.Persistence.Repositories
_contentXmlRepository.Dispose();
}
}
}
}
@@ -30,12 +30,9 @@ namespace Umbraco.Core.Persistence.Repositories
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
_guidRepo = new GuidReadOnlyContentTypeBaseRepository(this, work, cache, logger, sqlSyntax);
{
}
private readonly GuidReadOnlyContentTypeBaseRepository _guidRepo;
/// <summary>
/// Returns the content type ids that match the query
/// </summary>
@@ -454,6 +451,7 @@ AND umbracoNode.id <> @id",
propType.DataTypeDefinitionId = dto.DataTypeId;
propType.Description = dto.Description;
propType.Id = dto.Id;
propType.Key = dto.UniqueId;
propType.Name = dto.Name;
propType.Mandatory = dto.Mandatory;
propType.SortOrder = dto.SortOrder;
@@ -564,14 +562,13 @@ AND umbracoNode.id <> @id",
}
}
public static IEnumerable<IMediaType> GetMediaTypes<TRepo, TId>(
TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
public static IEnumerable<IMediaType> GetMediaTypes<TRepo>(
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository)
where TRepo : IReadRepository<TId, TEntity>
where TId: struct
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<TId, IEnumerable<TId>> allParentMediaTypeIds;
var mediaTypes = MapMediaTypes(mediaTypeIds, db, sqlSyntax, out allParentMediaTypeIds)
IDictionary<int, List<int>> allParentMediaTypeIds;
var mediaTypes = MapMediaTypes(db, sqlSyntax, out allParentMediaTypeIds)
.ToArray();
MapContentTypeChildren(mediaTypes, db, sqlSyntax, contentTypeRepository, allParentMediaTypeIds);
@@ -579,16 +576,15 @@ AND umbracoNode.id <> @id",
return mediaTypes;
}
public static IEnumerable<IContentType> GetContentTypes<TRepo, TId>(
TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
public static IEnumerable<IContentType> GetContentTypes<TRepo>(
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository,
ITemplateRepository templateRepository)
where TRepo : IReadRepository<TId, TEntity>
where TId : struct
where TRepo : IReadRepository<int, TEntity>
{
IDictionary<TId, IEnumerable<AssociatedTemplate>> allAssociatedTemplates;
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds;
var contentTypes = MapContentTypes(contentTypeIds, db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
IDictionary<int, List<AssociatedTemplate>> allAssociatedTemplates;
IDictionary<int, List<int>> allParentContentTypeIds;
var contentTypes = MapContentTypes(db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
.ToArray();
if (contentTypes.Any())
@@ -603,12 +599,11 @@ AND umbracoNode.id <> @id",
return contentTypes;
}
internal static void MapContentTypeChildren<TRepo, TId>(IContentTypeComposition[] contentTypes,
internal static void MapContentTypeChildren<TRepo>(IContentTypeComposition[] contentTypes,
Database db, ISqlSyntaxProvider sqlSyntax,
TRepo contentTypeRepository,
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds)
where TRepo : IReadRepository<TId, TEntity>
where TId : struct
IDictionary<int, List<int>> allParentContentTypeIds)
where TRepo : IReadRepository<int, TEntity>
{
//NOTE: SQL call #2
@@ -630,20 +625,17 @@ AND umbracoNode.id <> @id",
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
if (allParentIdsAsArray.Any())
{
var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
foreach (var contentType in contentTypes)
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
{
var entityId = contentType.Id;
var parentContentTypes = allParentContentTypes.Where(x =>
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var parentEntityId = typeof(TId) == typeof(int) ? x.Id : (object)x.Key;
var parentEntityId = x.Id;
return allParentContentTypeIds[(TId)entityId].Contains((TId)parentEntityId);
return allParentContentTypeIds[entityId].Contains(parentEntityId);
});
foreach (var parentContentType in parentContentTypes)
{
@@ -661,13 +653,12 @@ AND umbracoNode.id <> @id",
}
internal static void MapContentTypeTemplates<TRepo, TId>(IContentType[] contentTypes,
internal static void MapContentTypeTemplates<TRepo>(IContentType[] contentTypes,
Database db,
TRepo contentTypeRepository,
ITemplateRepository templateRepository,
IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates)
where TRepo : IReadRepository<TId, TEntity>
where TId: struct
IDictionary<int, List<AssociatedTemplate>> associatedTemplates)
where TRepo : IReadRepository<int, TEntity>
{
if (associatedTemplates == null || associatedTemplates.Any() == false) return;
@@ -684,11 +675,9 @@ AND umbracoNode.id <> @id",
foreach (var contentType in contentTypes)
{
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
var associatedTemplateIds = associatedTemplates[(TId)entityId].Select(x => x.TemplateId)
var entityId = contentType.Id;
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
.Distinct()
.ToArray();
@@ -700,19 +689,14 @@ AND umbracoNode.id <> @id",
}
internal static IEnumerable<IMediaType> MapMediaTypes<TId>(TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<TId, IEnumerable<TId>> parentMediaTypeIds)
where TId : struct
internal static IEnumerable<IMediaType> MapMediaTypes(Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<int>> parentMediaTypeIds)
{
Mandate.That(mediaTypeIds.Any(), () => new InvalidOperationException("must be at least one content type id specified"));
Mandate.ParameterNotNull(db, "db");
//ensure they are unique
mediaTypeIds = mediaTypeIds.Distinct().ToArray();
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
@@ -734,27 +718,10 @@ AND umbracoNode.id <> @id",
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
if (mediaTypeIds.Any())
{
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
// work for the time being.
if (typeof(TId) == typeof(int))
{
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
}
else if (typeof(TId) == typeof(Guid))
{
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
}
}
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
if ((mediaTypeIds.Length - 1) > 2000)
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType), contentTypeIds = mediaTypeIds });
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType) });
if (result.Any() == false)
{
@@ -762,91 +729,114 @@ AND umbracoNode.id <> @id",
return Enumerable.Empty<IMediaType>();
}
parentMediaTypeIds = new Dictionary<TId, IEnumerable<TId>>();
parentMediaTypeIds = new Dictionary<int, List<int>>();
var mappedMediaTypes = new List<IMediaType>();
foreach (var contentTypeId in mediaTypeIds)
//loop through each result and fill in our required values, each row will contain different requried data than the rest.
// it is much quicker to iterate each result and populate instead of looking up the values over and over in the result like
// we used to do.
var queue = new Queue<dynamic>(result);
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
//the current content type id that we're working with
var ct = queue.Dequeue();
var currentCtId = contentTypeId;
//first we want to get the main content type data this is 1 : 1 with umbraco node data
var ct = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof (TId) == typeof (int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
.DistinctBy(x => (int)x.ctId)
.FirstOrDefault();
if (ct == null)
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
continue;
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
currAllowedContentTypes.Add(ctSort);
}
}
var contentTypeDto = new ContentTypeDto
//always ensure there's a list for this content type
if (parentMediaTypeIds.ContainsKey(ct.ctId) == false)
parentMediaTypeIds[ct.ctId] = new List<int>();
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
Alias = ct.ctAlias,
AllowAtRoot = ct.ctAllowAtRoot,
Description = ct.ctDesc,
Icon = ct.ctIcon,
IsContainer = ct.ctIsContainer,
NodeId = ct.ctId,
PrimaryKey = ct.ctPk,
Thumbnail = ct.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = ct.nCreateDate,
Level = (short)ct.nLevel,
NodeId = ct.ctId,
NodeObjectType = ct.nObjectType,
ParentId = ct.nParentId,
Path = ct.nPath,
SortOrder = ct.nSortOrder,
Text = ct.nName,
Trashed = ct.nTrashed,
UniqueId = ct.nUniqueId,
UserId = ct.nUser
}
};
var associatedParentIds = parentMediaTypeIds[ct.ctId];
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
//now create the media type object
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var mediaType = CreateForMapping(ct, currAllowedContentTypes);
mappedMediaTypes.Add(mediaType);
var factory = new MediaTypeFactory(new Guid(Constants.ObjectTypes.MediaType));
var mediaType = factory.BuildEntity(contentTypeDto);
//map the allowed content types
//map the child content type ids
MapCommonContentTypeObjects(mediaType, currentCtId, result, parentMediaTypeIds);
mappedMediaTypes.Add(mediaType);
//Here we need to reset the current variables, we're now collecting data for a different content type
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedMediaTypes;
}
internal static IEnumerable<IContentType> MapContentTypes<TId>(TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates,
out IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
where TId : struct
private static IMediaType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes)
{
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
var contentTypeDto = new ContentTypeDto
{
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
};
//now create the content type object
var factory = new MediaTypeFactory(new Guid(Constants.ObjectTypes.MediaType));
var mediaType = factory.BuildEntity(contentTypeDto);
//map the allowed content types
mediaType.AllowedContentTypes = currAllowedContentTypes;
return mediaType;
}
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
out IDictionary<int, List<int>> parentContentTypeIds)
{
Mandate.ParameterNotNull(db, "db");
//ensure they are unique
contentTypeIds = contentTypeIds.Distinct().ToArray();
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
@@ -877,28 +867,10 @@ AND umbracoNode.id <> @id",
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
) ParentTypes
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
if (contentTypeIds.Any())
{
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
// work for the time being.
if (typeof(TId) == typeof(int))
{
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
}
else if (typeof(TId) == typeof(Guid))
{
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
}
}
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
if ((contentTypeIds.Length - 1) > 2000)
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), contentTypeIds = contentTypeIds });
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
ORDER BY ctId";
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
if (result.Any() == false)
{
@@ -907,121 +879,141 @@ AND umbracoNode.id <> @id",
return Enumerable.Empty<IContentType>();
}
parentContentTypeIds = new Dictionary<TId, IEnumerable<TId>>();
associatedTemplates = new Dictionary<TId, IEnumerable<AssociatedTemplate>>();
parentContentTypeIds = new Dictionary<int, List<int>>();
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
var mappedContentTypes = new List<IContentType>();
foreach (var contentTypeId in contentTypeIds)
var queue = new Queue<dynamic>(result);
var currDefaultTemplate = -1;
var currAllowedContentTypes = new List<ContentTypeSort>();
while (queue.Count > 0)
{
//the current content type id that we're working with
var ct = queue.Dequeue();
var currentCtId = contentTypeId;
//first we want to get the main content type data this is 1 : 1 with umbraco node data
var ct = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
.DistinctBy(x => (int)x.ctId)
.FirstOrDefault();
if (ct == null)
//check for default templates
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
int? templateId = ct.dtTemplateId;
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && templateId.HasValue)
{
continue;
currDefaultTemplate = templateId.Value;
}
//get the unique list of associated templates
var defaultTemplates = result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
//use a tuple so that distinct checks both values (in some rare cases the dtIsDefault will not compute as bool?, so we force it with Convert.ToBoolean)
.Select(x => new Tuple<bool?, int?>(Convert.ToBoolean(x.dtIsDefault), x.dtTemplateId))
.Where(x => x.Item1.HasValue && x.Item2.HasValue)
.Distinct()
.OrderByDescending(x => x.Item1.Value)
.ToArray();
//if there isn't one set to default explicitly, we'll pick the first one
var defaultTemplate = defaultTemplates.FirstOrDefault(x => x.Item1.Value)
?? defaultTemplates.FirstOrDefault();
//always ensure there's a list for this content type
if (associatedTemplates.ContainsKey(ct.ctId) == false)
associatedTemplates[ct.ctId] = new List<AssociatedTemplate>();
var dtDto = new DocumentTypeDto
//check for associated templates and assign to the outgoing collection
if (ct.tId != null)
{
//create the content type dto
ContentTypeDto = new ContentTypeDto
var associatedTemplate = new AssociatedTemplate(ct.tId, ct.tAlias, ct.tText);
var associatedList = associatedTemplates[ct.ctId];
if (associatedList.Contains(associatedTemplate) == false)
associatedList.Add(associatedTemplate);
}
//check for allowed content types
int? allowedCtId = ct.ctaAllowedId;
int? allowedCtSort = ct.ctaSortOrder;
string allowedCtAlias = ct.ctaAlias;
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
{
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
if (currAllowedContentTypes.Contains(ctSort) == false)
{
Alias = ct.ctAlias,
AllowAtRoot = ct.ctAllowAtRoot,
Description = ct.ctDesc,
Icon = ct.ctIcon,
IsContainer = ct.ctIsContainer,
NodeId = ct.ctId,
PrimaryKey = ct.ctPk,
Thumbnail = ct.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = ct.nCreateDate,
Level = (short)ct.nLevel,
NodeId = ct.ctId,
NodeObjectType = ct.nObjectType,
ParentId = ct.nParentId,
Path = ct.nPath,
SortOrder = ct.nSortOrder,
Text = ct.nName,
Trashed = ct.nTrashed,
UniqueId = ct.nUniqueId,
UserId = ct.nUser
}
},
ContentTypeNodeId = ct.ctId,
IsDefault = defaultTemplate != null,
TemplateNodeId = defaultTemplate != null ? defaultTemplate.Item2.Value : 0,
};
currAllowedContentTypes.Add(ctSort);
}
}
// We will map a subset of the associated template - alias, id, name
//always ensure there's a list for this content type
if (parentContentTypeIds.ContainsKey(ct.ctId) == false)
parentContentTypeIds[ct.ctId] = new List<int>();
associatedTemplates.Add(currentCtId, result
.Where(x =>
{
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
// how it is for now.
return (typeof(TId) == typeof(int))
? x.ctId == currentCtId
: x.nUniqueId == currentCtId;
})
.Where(x => x.tId != null)
.Select(x => new AssociatedTemplate(x.tId, x.tAlias, x.tText))
.Distinct()
.ToArray());
//check for parent ids and assign to the outgoing collection
int? parentId = ct.chtParentId;
if (parentId.HasValue)
{
var associatedParentIds = parentContentTypeIds[ct.ctId];
//now create the content type object
if (associatedParentIds.Contains(parentId.Value) == false)
associatedParentIds.Add(parentId.Value);
}
var factory = new ContentTypeFactory(new Guid(Constants.ObjectTypes.DocumentType));
var contentType = factory.BuildEntity(dtDto);
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
{
//it's the last in the queue or the content type is changing (moving to the next one)
var contentType = CreateForMapping(ct, currAllowedContentTypes, currDefaultTemplate);
mappedContentTypes.Add(contentType);
//map the allowed content types
//map the child content type ids
MapCommonContentTypeObjects(contentType, currentCtId, result, parentContentTypeIds);
mappedContentTypes.Add(contentType);
//Here we need to reset the current variables, we're now collecting data for a different content type
currDefaultTemplate = -1;
currAllowedContentTypes = new List<ContentTypeSort>();
}
}
return mappedContentTypes;
}
private static IContentType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes, int currDefaultTemplate)
{
// * set the default template to the first one if a default isn't found
// * create the DTO object
// * create the content type object
// * map the allowed content types
// * add to the outgoing list
var dtDto = new DocumentTypeDto
{
//create the content type dto
ContentTypeDto = new ContentTypeDto
{
Alias = currCt.ctAlias,
AllowAtRoot = currCt.ctAllowAtRoot,
Description = currCt.ctDesc,
Icon = currCt.ctIcon,
IsContainer = currCt.ctIsContainer,
NodeId = currCt.ctId,
PrimaryKey = currCt.ctPk,
Thumbnail = currCt.ctThumb,
//map the underlying node dto
NodeDto = new NodeDto
{
CreateDate = currCt.nCreateDate,
Level = (short)currCt.nLevel,
NodeId = currCt.ctId,
NodeObjectType = currCt.nObjectType,
ParentId = currCt.nParentId,
Path = currCt.nPath,
SortOrder = currCt.nSortOrder,
Text = currCt.nName,
Trashed = currCt.nTrashed,
UniqueId = currCt.nUniqueId,
UserId = currCt.nUser
}
},
ContentTypeNodeId = currCt.ctId,
IsDefault = currDefaultTemplate != -1,
TemplateNodeId = currDefaultTemplate != -1 ? currDefaultTemplate : 0,
};
//now create the content type object
var factory = new ContentTypeFactory(new Guid(Constants.ObjectTypes.DocumentType));
var contentType = factory.BuildEntity(dtDto);
// NOTE
// that was done by the factory but makes little sense, moved here, so
// now we have to reset dirty props again (as the factory does it) and yet,
// we are not managing allowed templates... the whole thing is weird.
((ContentType)contentType).DefaultTemplateId = dtDto.TemplateNodeId;
contentType.ResetDirtyProperties(false);
//map the allowed content types
contentType.AllowedContentTypes = currAllowedContentTypes;
return contentType;
}
private static void MapCommonContentTypeObjects<T, TId>(T contentType, TId currentCtId, List<dynamic> result, IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
where T : IContentTypeBase
where TId : struct
@@ -1196,71 +1188,20 @@ AND umbracoNode.id <> @id",
}
/// <summary>
/// Inner repository to support the GUID lookups and keep the caching consistent
/// </summary>
internal class GuidReadOnlyContentTypeBaseRepository : PetaPocoRepositoryBase<Guid, TEntity>
{
private readonly ContentTypeBaseRepository<TEntity> _parentRepo;
public GuidReadOnlyContentTypeBaseRepository(
ContentTypeBaseRepository<TEntity> parentRepo,
IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
_parentRepo = parentRepo;
}
protected override TEntity PerformGet(Guid id)
{
return _parentRepo.PerformGet(id);
}
protected override IEnumerable<TEntity> PerformGetAll(params Guid[] ids)
{
return _parentRepo.PerformGetAll(ids);
}
protected override Sql GetBaseQuery(bool isCount)
{
return _parentRepo.GetBaseQuery(isCount);
}
protected override string GetBaseWhereClause()
{
return "umbracoNode.uniqueID = @Id";
}
#region No implementation required
protected override IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query)
{
throw new NotImplementedException();
}
protected override IEnumerable<string> GetDeleteClauses()
{
throw new NotImplementedException();
}
protected override Guid NodeObjectTypeId
{
get { throw new NotImplementedException(); }
}
protected override void PersistNewItem(TEntity entity)
{
throw new NotImplementedException();
}
protected override void PersistUpdatedItem(TEntity entity)
{
throw new NotImplementedException();
}
#endregion
}
protected abstract TEntity PerformGet(Guid id);
protected abstract TEntity PerformGet(string alias);
protected abstract IEnumerable<TEntity> PerformGetAll(params Guid[] ids);
protected abstract bool PerformExists(Guid id);
/// <summary>
/// Gets an Entity by alias
/// </summary>
/// <param name="alias"></param>
/// <returns></returns>
public TEntity Get(string alias)
{
return PerformGet(alias);
}
/// <summary>
/// Gets an Entity by Id
@@ -1269,7 +1210,7 @@ AND umbracoNode.id <> @id",
/// <returns></returns>
public TEntity Get(Guid id)
{
return _guidRepo.Get(id);
return PerformGet(id);
}
/// <summary>
@@ -1277,9 +1218,12 @@ AND umbracoNode.id <> @id",
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public IEnumerable<TEntity> GetAll(params Guid[] ids)
/// <remarks>
/// Ensure explicit implementation, we don't want to have any accidental calls to this since it is essentially the same signature as the main GetAll when there are no parameters
/// </remarks>
IEnumerable<TEntity> IReadRepository<Guid, TEntity>.GetAll(params Guid[] ids)
{
return _guidRepo.GetAll(ids);
return PerformGetAll(ids);
}
/// <summary>
@@ -1289,7 +1233,7 @@ AND umbracoNode.id <> @id",
/// <returns></returns>
public bool Exists(Guid id)
{
return _guidRepo.Exists(id);
return PerformExists(id);
}
}
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -27,46 +28,54 @@ namespace Umbraco.Core.Persistence.Repositories
_templateRepository = templateRepository;
}
#region Overrides of RepositoryBase<int,IContentType>
private FullDataSetRepositoryCachePolicyFactory<IContentType, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IContentType, int> CachePolicyFactory
{
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(),
//allow this cache to expire
expires:true));
}
}
protected override IContentType PerformGet(int id)
{
var contentTypes = ContentTypeQueryMapper.GetContentTypes(
new[] {id}, Database, SqlSyntax, this, _templateRepository);
var contentType = contentTypes.SingleOrDefault();
return contentType;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<IContentType> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
}
else
{
var sql = new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository);
}
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContentType>(sqlClause, query);
var sql = translator.Translate()
.OrderBy<NodeDto>(x => x.Text);
var sql = translator.Translate();
var dtos = Database.Fetch<DocumentTypeDto, ContentTypeDto, NodeDto>(sql);
return dtos.Any()
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
: Enumerable.Empty<IContentType>();
return
//This returns a lookup from the GetAll cached looup
(dtos.Any()
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
: Enumerable.Empty<IContentType>())
//order the result by name
.OrderBy(x => x.Name);
}
#endregion
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
/// </summary>
@@ -244,25 +253,33 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IContentType PerformGet(Guid id)
{
var contentTypes = ContentTypeQueryMapper.GetContentTypes(
new[] { id }, Database, SqlSyntax, this, _templateRepository);
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Key == id);
}
var contentType = contentTypes.SingleOrDefault();
return contentType;
protected override IContentType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
protected override IEnumerable<IContentType> PerformGetAll(params Guid[] ids)
{
//use the underlying GetAll which will force cache all content types
if (ids.Any())
{
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
return GetAll().Where(x => ids.Contains(x.Key));
}
else
{
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
return GetAll();
}
}
protected override bool PerformExists(Guid id)
{
return GetAll().FirstOrDefault(x => x.Key == id) != null;
}
}
}
@@ -24,17 +24,15 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase<int, IDataTypeDefinition>, IDataTypeDefinitionRepository
{
private readonly CacheHelper _cacheHelper;
private readonly IContentTypeRepository _contentTypeRepository;
private readonly DataTypePreValueRepository _preValRepository;
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax,
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax,
IContentTypeRepository contentTypeRepository)
: base(work, cache, logger, sqlSyntax)
{
_cacheHelper = cacheHelper;
_contentTypeRepository = contentTypeRepository;
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax);
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax);
}
#region Overrides of RepositoryBase<int,DataTypeDefinition>
@@ -231,7 +229,7 @@ AND umbracoNode.id <> @id",
//NOTE: This is a special case, we need to clear the custom cache for pre-values here so they are not stale if devs
// are querying for them in the Saved event (before the distributed call cache is clearing it)
_cacheHelper.RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id));
RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id));
entity.ResetDirtyProperties();
}
@@ -270,7 +268,7 @@ AND umbracoNode.id <> @id",
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
{
var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
var cached = RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
if (cached != null && cached.Any())
{
//return from the cache, ensure it's a cloned result
@@ -289,7 +287,7 @@ AND umbracoNode.id <> @id",
{
//We need to see if we can find the cached PreValueCollection based on the cache key above
var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeyExpression<PreValueCollection>(GetCacheKeyRegex(preValueId));
var cached = RuntimeCache.GetCacheItemsByKeyExpression<PreValueCollection>(GetCacheKeyRegex(preValueId));
if (cached != null && cached.Any())
{
//return from the cache
@@ -408,7 +406,7 @@ AND umbracoNode.id <> @id",
+ string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray());
//store into cache
_cacheHelper.RuntimeCache.InsertCacheItem(key, () => collection,
RuntimeCache.InsertCacheItem(key, () => collection,
//30 mins
new TimeSpan(0, 0, 30),
//sliding is true
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -19,30 +20,40 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class DictionaryRepository : PetaPocoRepositoryBase<int, IDictionaryItem>, IDictionaryRepository
{
private readonly ILanguageRepository _languageRepository;
public DictionaryRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider syntax, ILanguageRepository languageRepository)
public DictionaryRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider syntax)
: base(work, cache, logger, syntax)
{
_languageRepository = languageRepository;
}
{
}
private IRepositoryCachePolicyFactory<IDictionaryItem, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IDictionaryItem, int> CachePolicyFactory
{
get
{
//custom cache policy which will not cache any results for GetAll
return _cachePolicyFactory ?? (_cachePolicyFactory = new OnlySingleItemsRepositoryCachePolicyFactory<IDictionaryItem, int>(
RuntimeCache,
new RepositoryCachePolicyOptions
{
//allow zero to be cached
GetAllCacheAllowZeroCount = true
}));
}
}
#region Overrides of RepositoryBase<int,DictionaryItem>
protected override IDictionaryItem PerformGet(int id)
{
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new {Id = id})
.Where(GetBaseWhereClause(), new { Id = id })
.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
var dto = Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql).FirstOrDefault();
if (dto == null)
return null;
//This will be cached
var allLanguages = _languageRepository.GetAll().ToArray();
var entity = ConvertFromDto(dto, allLanguages);
var entity = ConvertFromDto(dto);
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -56,14 +67,11 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false).Where("cmsDictionary.pk > 0");
if (ids.Any())
{
sql.Where("cmsDictionary.pk in (@ids)", new { ids = ids });
sql.Where("cmsDictionary.pk in (@ids)", new { ids = ids });
}
//This will be cached
var allLanguages = _languageRepository.GetAll().ToArray();
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
.Select(dto => ConvertFromDto(dto, allLanguages));
.Select(dto => ConvertFromDto(dto));
}
protected override IEnumerable<IDictionaryItem> PerformGetByQuery(IQuery<IDictionaryItem> query)
@@ -72,12 +80,9 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator<IDictionaryItem>(sqlClause, query);
var sql = translator.Translate();
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
//This will be cached
var allLanguages = _languageRepository.GetAll().ToArray();
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
.Select(x => ConvertFromDto(x, allLanguages));
.Select(x => ConvertFromDto(x));
}
#endregion
@@ -87,7 +92,7 @@ namespace Umbraco.Core.Persistence.Repositories
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
if(isCount)
if (isCount)
{
sql.Select("COUNT(*)")
.From<DictionaryDto>(SqlSyntax);
@@ -123,26 +128,28 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistNewItem(IDictionaryItem entity)
{
((DictionaryItem)entity).AddingEntity();
var dictionaryItem = ((DictionaryItem) entity);
foreach (var translation in entity.Translations)
dictionaryItem.AddingEntity();
foreach (var translation in dictionaryItem.Translations)
translation.Value = translation.Value.ToValidXmlString();
var factory = new DictionaryItemFactory();
var dto = factory.BuildDto(entity);
var dto = factory.BuildDto(dictionaryItem);
var id = Convert.ToInt32(Database.Insert(dto));
entity.Id = id;
dictionaryItem.Id = id;
var translationFactory = new DictionaryTranslationFactory(entity.Key, null);
foreach (var translation in entity.Translations)
var translationFactory = new DictionaryTranslationFactory(dictionaryItem.Key);
foreach (var translation in dictionaryItem.Translations)
{
var textDto = translationFactory.BuildDto(translation);
translation.Id = Convert.ToInt32(Database.Insert(textDto));
translation.Key = entity.Key;
translation.Key = dictionaryItem.Key;
}
entity.ResetDirtyProperties();
dictionaryItem.ResetDirtyProperties();
}
protected override void PersistUpdatedItem(IDictionaryItem entity)
@@ -157,11 +164,11 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(dto);
var translationFactory = new DictionaryTranslationFactory(entity.Key, null);
var translationFactory = new DictionaryTranslationFactory(entity.Key);
foreach (var translation in entity.Translations)
{
var textDto = translationFactory.BuildDto(translation);
if(translation.HasIdentity)
if (translation.HasIdentity)
{
Database.Update(textDto);
}
@@ -183,7 +190,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
RecursiveDelete(entity.Key);
Database.Delete<LanguageTextDto>("WHERE UniqueId = @Id", new { Id = entity.Key});
Database.Delete<LanguageTextDto>("WHERE UniqueId = @Id", new { Id = entity.Key });
Database.Delete<DictionaryDto>("WHERE id = @Id", new { Id = entity.Key });
//Clear the cache entries that exist by uniqueid/item key
@@ -193,7 +200,7 @@ namespace Umbraco.Core.Persistence.Repositories
private void RecursiveDelete(Guid parentId)
{
var list = Database.Fetch<DictionaryDto>("WHERE parent = @ParentId", new {ParentId = parentId});
var list = Database.Fetch<DictionaryDto>("WHERE parent = @ParentId", new { ParentId = parentId });
foreach (var dto in list)
{
RecursiveDelete(dto.UniqueId);
@@ -209,20 +216,18 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
protected IDictionaryItem ConvertFromDto(DictionaryDto dto, ILanguage[] allLanguages)
protected IDictionaryItem ConvertFromDto(DictionaryDto dto)
{
var factory = new DictionaryItemFactory();
var entity = factory.BuildEntity(dto);
var list = new List<IDictionaryTranslation>();
foreach (var textDto in dto.LanguageTextDtos)
{
//Assuming this is cached!
var language = allLanguages.FirstOrDefault(x => x.Id == textDto.LanguageId);
if (language == null)
{
if (textDto.LanguageId <= 0)
continue;
var translationFactory = new DictionaryTranslationFactory(dto.UniqueId, language);
var translationFactory = new DictionaryTranslationFactory(dto.UniqueId);
list.Add(translationFactory.BuildEntity(textDto));
}
entity.Translations = list;
@@ -234,7 +239,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
using (var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, UnitOfWork, RepositoryCache, Logger, SqlSyntax))
{
return uniqueIdRepo.Get(uniqueId);
return uniqueIdRepo.Get(uniqueId);
}
}
@@ -242,10 +247,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
using (var keyRepo = new DictionaryByKeyRepository(this, UnitOfWork, RepositoryCache, Logger, SqlSyntax))
{
return keyRepo.Get(key);
return keyRepo.Get(key);
}
}
private IEnumerable<IDictionaryItem> GetRootDictionaryItems()
{
var query = Query<IDictionaryItem>.Builder.Where(x => x.ParentId == null);
@@ -254,9 +259,6 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<IDictionaryItem> GetDictionaryItemDescendants(Guid? parentId)
{
//This will be cached
var allLanguages = _languageRepository.GetAll().ToArray();
//This methods will look up children at each level, since we do not store a path for dictionary (ATM), we need to do a recursive
// lookup to get descendants. Currently this is the most efficient way to do it
@@ -275,7 +277,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
.Select(x => ConvertFromDto(x, allLanguages));
.Select(x => ConvertFromDto(x));
});
};
@@ -284,7 +286,7 @@ namespace Umbraco.Core.Persistence.Repositories
: getItemsFromParents(new[] { parentId.Value });
return childItems.SelectRecursive(items => getItemsFromParents(items.Select(x => x.Key).ToArray())).SelectMany(items => items);
}
private class DictionaryByUniqueIdRepository : SimpleGetRepository<Guid, IDictionaryItem, DictionaryDto>
@@ -314,20 +316,34 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IDictionaryItem ConvertToEntity(DictionaryDto dto)
{
//This will be cached
var allLanguages = _dictionaryRepository._languageRepository.GetAll().ToArray();
return _dictionaryRepository.ConvertFromDto(dto, allLanguages);
return _dictionaryRepository.ConvertFromDto(dto);
}
protected override object GetBaseWhereClauseArguments(Guid id)
{
return new {Id = id};
return new { Id = id };
}
protected override string GetWhereInClauseForGetAll()
{
return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("id") + " in (@ids)";
}
private IRepositoryCachePolicyFactory<IDictionaryItem, Guid> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IDictionaryItem, Guid> CachePolicyFactory
{
get
{
//custom cache policy which will not cache any results for GetAll
return _cachePolicyFactory ?? (_cachePolicyFactory = new OnlySingleItemsRepositoryCachePolicyFactory<IDictionaryItem, Guid>(
RuntimeCache,
new RepositoryCachePolicyOptions
{
//allow zero to be cached
GetAllCacheAllowZeroCount = true
}));
}
}
}
private class DictionaryByKeyRepository : SimpleGetRepository<string, IDictionaryItem, DictionaryDto>
@@ -357,9 +373,7 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IDictionaryItem ConvertToEntity(DictionaryDto dto)
{
//This will be cached
var allLanguages = _dictionaryRepository._languageRepository.GetAll().ToArray();
return _dictionaryRepository.ConvertFromDto(dto, allLanguages);
return _dictionaryRepository.ConvertFromDto(dto);
}
protected override object GetBaseWhereClauseArguments(string id)
@@ -371,17 +385,24 @@ namespace Umbraco.Core.Persistence.Repositories
{
return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("key") + " in (@ids)";
}
private IRepositoryCachePolicyFactory<IDictionaryItem, string> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IDictionaryItem, string> CachePolicyFactory
{
get
{
//custom cache policy which will not cache any results for GetAll
return _cachePolicyFactory ?? (_cachePolicyFactory = new OnlySingleItemsRepositoryCachePolicyFactory<IDictionaryItem, string>(
RuntimeCache,
new RepositoryCachePolicyOptions
{
//allow zero to be cached
GetAllCacheAllowZeroCount = true
}));
}
}
}
/// <summary>
/// Dispose disposable properties
/// </summary>
/// <remarks>
/// Ensure the unit of work is disposed
/// </remarks>
protected override void DisposeResources()
{
_languageRepository.Dispose();
}
}
}
@@ -18,25 +18,20 @@ namespace Umbraco.Core.Persistence.Repositories
internal class DomainRepository : PetaPocoRepositoryBase<int, IDomain>, IDomainRepository
{
private readonly RepositoryCacheOptions _cacheOptions;
public DomainRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
//Custom cache options for better performance
_cacheOptions = new RepositoryCacheOptions
{
GetAllCacheAllowZeroCount = true,
GetAllCacheValidateCount = false
};
{
}
/// <summary>
/// Returns the repository cache options
/// </summary>
protected override RepositoryCacheOptions RepositoryCacheOptions
private FullDataSetRepositoryCachePolicyFactory<IDomain, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IDomain, int> CachePolicyFactory
{
get { return _cacheOptions; }
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
}
}
protected override IDomain PerformGet(int id)
@@ -0,0 +1,11 @@
using System;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentTypeCompositionRepository<TEntity> : IRepositoryQueryable<int, TEntity>, IReadRepository<Guid, TEntity>
where TEntity : IContentTypeComposition
{
TEntity Get(string alias);
}
}
@@ -5,7 +5,7 @@ using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentTypeRepository : IRepositoryQueryable<int, IContentType>, IReadRepository<Guid, IContentType>
public interface IContentTypeRepository : IContentTypeCompositionRepository<IContentType>
{
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IMediaTypeRepository : IRepositoryQueryable<int, IMediaType>, IReadRepository<Guid, IMediaType>
public interface IMediaTypeRepository : IContentTypeCompositionRepository<IMediaType>
{
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IMemberTypeRepository : IRepositoryQueryable<int, IMemberType>, IReadRepository<Guid, IMemberType>
public interface IMemberTypeRepository : IContentTypeCompositionRepository<IMemberType>
{
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
@@ -22,6 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
TemplateNode GetTemplateNode(string alias);
/// <summary>
@@ -31,6 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="alias"></param>
/// <returns></returns>
[Obsolete("Use GetDescendants instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias);
/// <summary>
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -20,23 +21,18 @@ namespace Umbraco.Core.Persistence.Repositories
{
public LanguageRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
//Custom cache options for better performance
_cacheOptions = new RepositoryCacheOptions
{
GetAllCacheAllowZeroCount = true,
GetAllCacheValidateCount = false
};
{
}
private readonly RepositoryCacheOptions _cacheOptions;
/// <summary>
/// Returns the repository cache options
/// </summary>
protected override RepositoryCacheOptions RepositoryCacheOptions
private FullDataSetRepositoryCachePolicyFactory<ILanguage, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<ILanguage, int> CachePolicyFactory
{
get { return _cacheOptions; }
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
}
}
#region Overrides of RepositoryBase<int,Language>
@@ -159,13 +155,13 @@ namespace Umbraco.Core.Persistence.Repositories
public ILanguage GetByCultureName(string cultureName)
{
//use the underlying GetAll which will force cache all domains
//use the underlying GetAll which will force cache all languages
return GetAll().FirstOrDefault(x => x.CultureName.InvariantEquals(cultureName));
}
public ILanguage GetByIsoCode(string isoCode)
{
//use the underlying GetAll which will force cache all domains
//use the underlying GetAll which will force cache all languages
return GetAll().FirstOrDefault(x => x.IsoCode.InvariantEquals(isoCode));
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -24,46 +25,54 @@ namespace Umbraco.Core.Persistence.Repositories
{
}
#region Overrides of RepositoryBase<int,IMedia>
private FullDataSetRepositoryCachePolicyFactory<IMediaType, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IMediaType, int> CachePolicyFactory
{
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(),
//allow this cache to expire
expires: true));
}
}
protected override IMediaType PerformGet(int id)
{
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
new[] { id }, Database, SqlSyntax, this);
var contentType = contentTypes.SingleOrDefault();
return contentType;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
}
else
{
var sql = new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
//NOTE: This logic should never be executed according to our cache policy
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this)
.Where(x => ids.Contains(x.Id));
}
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this);
}
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
var sql = translator.Translate()
.OrderBy<NodeDto>(x => x.Text);
var sql = translator.Translate();
var dtos = Database.Fetch<ContentTypeDto, NodeDto>(sql);
return dtos.Any()
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
: Enumerable.Empty<IMediaType>();
return
//This returns a lookup from the GetAll cached looup
(dtos.Any()
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
: Enumerable.Empty<IMediaType>())
//order the result by name
.OrderBy(x => x.Name);
}
#endregion
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
@@ -168,25 +177,33 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IMediaType PerformGet(Guid id)
{
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
new[] { id }, Database, SqlSyntax, this);
var contentType = contentTypes.SingleOrDefault();
return contentType;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Key == id);
}
protected override IEnumerable<IMediaType> PerformGetAll(params Guid[] ids)
{
//use the underlying GetAll which will force cache all content types
if (ids.Any())
{
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
return GetAll().Where(x => ids.Contains(x.Key));
}
else
{
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
var allIds = Database.Fetch<int>(sql).ToArray();
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
return GetAll();
}
}
protected override bool PerformExists(Guid id)
{
return GetAll().FirstOrDefault(x => x.Key == id) != null;
}
protected override IMediaType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
}
}
@@ -20,13 +20,9 @@ namespace Umbraco.Core.Persistence.Repositories
internal class MemberGroupRepository : PetaPocoRepositoryBase<int, IMemberGroup>, IMemberGroupRepository
{
private readonly CacheHelper _cacheHelper;
public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, CacheHelper cacheHelper)
public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_cacheHelper = cacheHelper;
}
private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory();
@@ -135,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories
public IMemberGroup GetByName(string name)
{
return _cacheHelper.RuntimeCache.GetCacheItem<IMemberGroup>(
return RuntimeCache.GetCacheItem<IMemberGroup>(
string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name),
() =>
{
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using log4net;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models;
@@ -26,25 +27,23 @@ namespace Umbraco.Core.Persistence.Repositories
{
}
#region Overrides of RepositoryBase<int, IMemberType>
private FullDataSetRepositoryCachePolicyFactory<IMemberType, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<IMemberType, int> CachePolicyFactory
{
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(),
//allow this cache to expire
expires: true));
}
}
protected override IMemberType PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.OrderByDescending<NodeDto>(x => x.NodeId);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
new PropertyTypePropertyGroupRelator().Map, sql);
if (dtos == null || dtos.Any() == false)
return null;
var factory = new MemberTypeReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
return member;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
@@ -52,10 +51,11 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false);
if (ids.Any())
{
//NOTE: This logic should never be executed according to our cache policy
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
sql.Where(statement);
}
sql.OrderByDescending<NodeDto>(x => x.NodeId);
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Persistence.Repositories
var subquery = translator.Translate();
var sql = GetBaseQuery(false)
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
.OrderBy<NodeDto>(x => x.SortOrder);
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
@@ -79,11 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
return BuildFromDtos(dtos);
}
#endregion
#region Overrides of PetaPocoRepositoryBase<int, IMemberType>
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
@@ -157,11 +153,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
get { return new Guid(Constants.ObjectTypes.MemberType); }
}
#endregion
#region Unit of Work Implementation
protected override void PersistNewItem(IMemberType entity)
{
ValidateAlias(entity);
@@ -238,8 +230,7 @@ namespace Umbraco.Core.Persistence.Repositories
entity.ResetDirtyProperties();
}
#endregion
/// <summary>
/// Override so we can specify explicit db type's on any property types that are built-in.
@@ -262,38 +253,33 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IMemberType PerformGet(Guid id)
{
var sql = GetBaseQuery(false);
sql.Where("umbracoNode.uniqueID = @Id", new { Id = id });
sql.OrderByDescending<NodeDto>(x => x.NodeId);
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
new PropertyTypePropertyGroupRelator().Map, sql);
if (dtos == null || dtos.Any() == false)
return null;
var factory = new MemberTypeReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
return member;
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Key == id);
}
protected override IEnumerable<IMemberType> PerformGetAll(params Guid[] ids)
{
var sql = GetBaseQuery(false);
//use the underlying GetAll which will force cache all content types
if (ids.Any())
{
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.uniqueID='{0}'", x)));
sql.Where(statement);
return GetAll().Where(x => ids.Contains(x.Key));
}
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
else
{
return GetAll();
}
}
var dtos =
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
new PropertyTypePropertyGroupRelator().Map, sql);
protected override bool PerformExists(Guid id)
{
return GetAll().FirstOrDefault(x => x.Key == id) != null;
}
return BuildFromDtos(dtos);
protected override IMemberType PerformGet(string alias)
{
//use the underlying GetAll which will force cache all content types
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
/// <summary>
@@ -26,13 +26,14 @@ namespace Umbraco.Core.Persistence.Repositories
where TEntity : class, IAggregateRoot
{
private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly CacheHelper _cache;
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly ISqlSyntaxProvider _sqlSyntax;
internal PermissionRepository(IDatabaseUnitOfWork unitOfWork, CacheHelper cache, ISqlSyntaxProvider sqlSyntax)
{
_unitOfWork = unitOfWork;
_cache = cache;
//Make this repository use an isolated cache
_runtimeCache = cache.IsolatedRuntimeCache.GetOrCreateCache<EntityPermission>();
_sqlSyntax = sqlSyntax;
}
@@ -45,7 +46,7 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<EntityPermission> GetUserPermissionsForEntities(int userId, params int[] entityIds)
{
var entityIdKey = string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture)));
return _cache.RuntimeCache.GetCacheItem<IEnumerable<EntityPermission>>(
return _runtimeCache.GetCacheItem<IEnumerable<EntityPermission>>(
string.Format("{0}{1}{2}", CacheKeys.UserPermissionsCacheKey, userId, entityIdKey),
() =>
{
@@ -17,33 +17,24 @@ namespace Umbraco.Core.Persistence.Repositories
{
public PublicAccessRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
_options = new RepositoryCacheOptions
{
//We want to ensure that a zero count gets cached, even if there is nothing in the db we don't want it to lookup nothing each time
GetAllCacheAllowZeroCount = true,
//Set to 1000 just to ensure that all of them are cached, The GetAll on this repository gets called *A lot*, we want max performance
GetAllCacheThresholdLimit = 1000,
//Override to false so that a Count check against the db is NOT performed when doing a GetAll without params, we just want to
// return the raw cache without validation. The GetAll on this repository gets called *A lot*, we want max performance
GetAllCacheValidateCount = false
};
{
}
private readonly RepositoryCacheOptions _options;
private FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<PublicAccessEntry, Guid> CachePolicyFactory
{
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
}
}
protected override PublicAccessEntry PerformGet(Guid id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var taskDto = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql).FirstOrDefault();
if (taskDto == null)
return null;
var factory = new PublicAccessEntryFactory();
var entity = factory.BuildEntity(taskDto);
return entity;
//return from GetAll - this will be cached as a collection
return GetAll().FirstOrDefault(x => x.Key == id);
}
protected override IEnumerable<PublicAccessEntry> PerformGetAll(params Guid[] ids)
@@ -102,15 +93,6 @@ namespace Umbraco.Core.Persistence.Repositories
get { throw new NotImplementedException(); }
}
/// <summary>
/// Returns the repository cache options
/// </summary>
protected override RepositoryCacheOptions RepositoryCacheOptions
{
get { return _options; }
}
protected override void PersistNewItem(PublicAccessEntry entity)
{
entity.AddingEntity();
@@ -1,7 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Collections;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
@@ -22,11 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (logger == null) throw new ArgumentNullException("logger");
Logger = logger;
_work = work;
//IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying
// runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks
// changes entities are reset.
_cache = new CacheHelper(new DeepCloneRuntimeCacheProvider(cache.RuntimeCache), cache.StaticCache, cache.RequestCache);
_cache = cache;
}
/// <summary>
@@ -84,9 +82,41 @@ namespace Umbraco.Core.Persistence.Repositories
{
}
private readonly RepositoryCacheOptions _cacheOptions = new RepositoryCacheOptions();
#region IRepository<TEntity> Members
protected virtual TId GetEntityId(TEntity entity)
{
return (TId)(object)entity.Id;
}
/// <summary>
/// The runtime cache used for this repo by default is the isolated cache for this type
/// </summary>
protected override IRuntimeCacheProvider RuntimeCache
{
get { return RepositoryCache.IsolatedRuntimeCache.GetOrCreateCache<TEntity>(); }
}
private IRepositoryCachePolicyFactory<TEntity, TId> _cachePolicyFactory;
/// <summary>
/// Returns the Cache Policy for the repository
/// </summary>
/// <remarks>
/// The Cache Policy determines how each entity or entity collection is cached
/// </remarks>
protected virtual IRepositoryCachePolicyFactory<TEntity, TId> CachePolicyFactory
{
get
{
return _cachePolicyFactory ?? (_cachePolicyFactory = new DefaultRepositoryCachePolicyFactory<TEntity, TId>(
RuntimeCache,
new RepositoryCachePolicyOptions(() =>
{
//Get count of all entities of current type (TEntity) to ensure cached result is correct
var query = Query<TEntity>.Builder.Where(x => x.Id != 0);
return PerformCount(query);
})));
}
}
/// <summary>
/// Adds or Updates an entity of type TEntity
@@ -119,23 +149,16 @@ namespace Umbraco.Core.Persistence.Repositories
protected abstract TEntity PerformGet(TId id);
/// <summary>
/// Gets an entity by the passed in Id utilizing the repository's runtime cache
/// Gets an entity by the passed in Id utilizing the repository's cache policy
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public TEntity Get(TId id)
{
var cacheKey = GetCacheIdKey<TEntity>(id);
var fromCache = RuntimeCache.GetCacheItem<TEntity>(cacheKey);
if (fromCache != null) return fromCache;
var entity = PerformGet(id);
if (entity == null) return null;
RuntimeCache.InsertCacheItem(cacheKey, () => entity);
return entity;
using (var p = CachePolicyFactory.CreatePolicy())
{
return p.Get(id, PerformGet);
}
}
protected abstract IEnumerable<TEntity> PerformGetAll(params TId[] ids);
@@ -158,88 +181,13 @@ namespace Umbraco.Core.Persistence.Repositories
throw new InvalidOperationException("Cannot perform a query with more than 2000 parameters");
}
if (ids.Any())
using (var p = CachePolicyFactory.CreatePolicy())
{
var entities = ids.Select(x => RuntimeCache.GetCacheItem<TEntity>(GetCacheIdKey<TEntity>(x))).ToArray();
if (ids.Count().Equals(entities.Count()) && entities.Any(x => x == null) == false)
return entities;
}
else
{
var allEntities = RuntimeCache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey<TEntity>())
.WhereNotNull()
.ToArray();
if (allEntities.Any())
{
if (RepositoryCacheOptions.GetAllCacheValidateCount)
{
//Get count of all entities of current type (TEntity) to ensure cached result is correct
var query = Query<TEntity>.Builder.Where(x => x.Id != 0);
int totalCount = PerformCount(query);
if (allEntities.Count() == totalCount)
return allEntities;
}
else
{
return allEntities;
}
}
else if (RepositoryCacheOptions.GetAllCacheAllowZeroCount)
{
//if the repository allows caching a zero count, then check the zero count cache
var zeroCount = RuntimeCache.GetCacheItem<TEntity[]>(GetCacheTypeKey<TEntity>());
if (zeroCount != null && zeroCount.Any() == false)
{
//there is a zero count cache so return an empty list
return Enumerable.Empty<TEntity>();
}
}
}
var entityCollection = PerformGetAll(ids)
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
.ToArray();
//We need to put a threshold here! IF there's an insane amount of items
// coming back here we don't want to chuck it all into memory, this added cache here
// is more for convenience when paging stuff temporarily
if (entityCollection.Length > RepositoryCacheOptions.GetAllCacheThresholdLimit)
return entityCollection;
if (entityCollection.Length == 0 && RepositoryCacheOptions.GetAllCacheAllowZeroCount)
{
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
// to signify that there is a zero count cache
RuntimeCache.InsertCacheItem(GetCacheTypeKey<TEntity>(), () => new TEntity[] {});
}
foreach (var entity in entityCollection)
{
if (entity != null)
{
var localCopy = entity;
RuntimeCache.InsertCacheItem(GetCacheIdKey<TEntity>(entity.Id), () => localCopy);
}
}
return entityCollection;
var result = p.GetAll(ids, PerformGetAll);
return result;
}
}
/// <summary>
/// Returns the repository cache options
/// </summary>
protected virtual RepositoryCacheOptions RepositoryCacheOptions
{
get { return _cacheOptions; }
}
protected abstract IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query);
/// <summary>
/// Gets a list of entities by the passed in query
@@ -261,12 +209,10 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public bool Exists(TId id)
{
var fromCache = RuntimeCache.GetCacheItem<TEntity>(GetCacheIdKey<TEntity>(id));
if (fromCache != null)
using (var p = CachePolicyFactory.CreatePolicy())
{
return true;
return p.Exists(id, PerformExists);
}
return PerformExists(id);
}
protected abstract int PerformCount(IQuery<TEntity> query);
@@ -279,34 +225,19 @@ namespace Umbraco.Core.Persistence.Repositories
{
return PerformCount(query);
}
#endregion
#region IUnitOfWorkRepository Members
/// <summary>
/// Unit of work method that tells the repository to persist the new entity
/// </summary>
/// <param name="entity"></param>
public virtual void PersistNewItem(IEntity entity)
{
try
{
PersistNewItem((TEntity)entity);
RuntimeCache.InsertCacheItem(GetCacheIdKey<TEntity>(entity.Id), () => entity);
//If there's a GetAll zero count cache, ensure it is cleared
RuntimeCache.ClearCacheItem(GetCacheTypeKey<TEntity>());
}
catch (Exception)
{
//if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
RuntimeCache.ClearCacheItem(GetCacheIdKey<TEntity>(entity.Id));
//If there's a GetAll zero count cache, ensure it is cleared
RuntimeCache.ClearCacheItem(GetCacheTypeKey<TEntity>());
throw;
}
var casted = (TEntity)entity;
using (var p = CachePolicyFactory.CreatePolicy())
{
p.CreateOrUpdate(casted, PersistNewItem);
}
}
/// <summary>
@@ -315,23 +246,12 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entity"></param>
public virtual void PersistUpdatedItem(IEntity entity)
{
try
{
PersistUpdatedItem((TEntity)entity);
RuntimeCache.InsertCacheItem(GetCacheIdKey<TEntity>(entity.Id), () => entity);
//If there's a GetAll zero count cache, ensure it is cleared
RuntimeCache.ClearCacheItem(GetCacheTypeKey<TEntity>());
}
catch (Exception)
{
//if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
RuntimeCache.ClearCacheItem(GetCacheIdKey<TEntity>(entity.Id));
//If there's a GetAll zero count cache, ensure it is cleared
RuntimeCache.ClearCacheItem(GetCacheTypeKey<TEntity>());
throw;
}
var casted = (TEntity)entity;
using (var p = CachePolicyFactory.CreatePolicy())
{
p.CreateOrUpdate(casted, PersistUpdatedItem);
}
}
/// <summary>
@@ -340,21 +260,19 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entity"></param>
public virtual void PersistDeletedItem(IEntity entity)
{
PersistDeletedItem((TEntity)entity);
RuntimeCache.ClearCacheItem(GetCacheIdKey<TEntity>(entity.Id));
//If there's a GetAll zero count cache, ensure it is cleared
RuntimeCache.ClearCacheItem(GetCacheTypeKey<TEntity>());
var casted = (TEntity)entity;
using (var p = CachePolicyFactory.CreatePolicy())
{
p.Remove(casted, PersistDeletedItem);
}
}
#endregion
#region Abstract IUnitOfWorkRepository Methods
protected abstract void PersistNewItem(TEntity item);
protected abstract void PersistUpdatedItem(TEntity item);
protected abstract void PersistDeletedItem(TEntity item);
#endregion
/// <summary>
/// Dispose disposable properties
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -32,7 +33,6 @@ namespace Umbraco.Core.Persistence.Repositories
private readonly ITemplatesSection _templateConfig;
private readonly ViewHelper _viewHelper;
private readonly MasterPageHelper _masterPageHelper;
private readonly RepositoryCacheOptions _cacheOptions;
internal TemplateRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem, ITemplatesSection templateConfig)
: base(work, cache, logger, sqlSyntax)
@@ -41,41 +41,27 @@ namespace Umbraco.Core.Persistence.Repositories
_viewsFileSystem = viewFileSystem;
_templateConfig = templateConfig;
_viewHelper = new ViewHelper(_viewsFileSystem);
_masterPageHelper = new MasterPageHelper(_masterpagesFileSystem);
_cacheOptions = new RepositoryCacheOptions
{
//Allow a zero count cache entry because GetAll() gets used quite a lot and we want to ensure
// if there are no templates, that it doesn't keep going to the db.
GetAllCacheAllowZeroCount = true,
//GetAll gets called a lot, we want to ensure that all templates are in the cache, default is 100 which
// would normally be fine but we'll increase it in case people have a ton of templates.
GetAllCacheThresholdLimit = 500
};
_masterPageHelper = new MasterPageHelper(_masterpagesFileSystem);
}
/// <summary>
/// Returns the repository cache options
/// </summary>
protected override RepositoryCacheOptions RepositoryCacheOptions
private FullDataSetRepositoryCachePolicyFactory<ITemplate, int> _cachePolicyFactory;
protected override IRepositoryCachePolicyFactory<ITemplate, int> CachePolicyFactory
{
get { return _cacheOptions; }
get
{
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
}
}
#region Overrides of RepositoryBase<int,ITemplate>
protected override ITemplate PerformGet(int id)
{
var sql = GetBaseQuery(false).Where<TemplateDto>(x => x.NodeId == id);
var result = Database.Fetch<TemplateDto, NodeDto>(sql).FirstOrDefault();
if (result == null) return null;
//look up the simple template definitions that have a master template assigned, this is used
// later to populate the template item's properties
var childIds = GetAxisDefinitions(result).ToArray();
return MapFromDto(result, childIds);
//use the underlying GetAll which will force cache all templates
return base.GetAll().FirstOrDefault(x => x.Id == id);
}
protected override IEnumerable<ITemplate> PerformGetAll(params int[] ids)
@@ -479,126 +465,102 @@ namespace Umbraco.Core.Persistence.Repositories
public ITemplate Get(string alias)
{
var sql = GetBaseQuery(false).Where<TemplateDto>(x => x.Alias == alias);
var dto = Database.Fetch<TemplateDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
return MapFromDto(dto, GetAxisDefinitions(dto).ToArray());
return GetAll(alias).FirstOrDefault();
}
public IEnumerable<ITemplate> GetAll(params string[] aliases)
{
var sql = GetBaseQuery(false);
//We must call the base (normal) GetAll method
// which is cached. This is a specialized method and unfortunatley with the params[] it
// overlaps with the normal GetAll method.
if (aliases.Any() == false) return base.GetAll();
if (aliases.Any())
{
sql.Where("cmsTemplate.alias IN (@aliases)", new {aliases = aliases});
}
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
//return from base.GetAll, this is all cached
return base.GetAll().Where(x => aliases.InvariantContains(x.Alias));
}
public IEnumerable<ITemplate> GetChildren(int masterTemplateId)
{
var sql = GetBaseQuery(false);
if (masterTemplateId <= 0)
{
sql.Where<NodeDto>(x => x.ParentId <= 0);
}
else
{
sql.Where<NodeDto>(x => x.ParentId == masterTemplateId);
}
//return from base.GetAll, this is all cached
var all = base.GetAll().ToArray();
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
if (masterTemplateId <= 0) return all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace());
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
var parent = all.FirstOrDefault(x => x.Id == masterTemplateId);
if (parent == null) return Enumerable.Empty<ITemplate>();
var children = all.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias));
return children;
}
public IEnumerable<ITemplate> GetChildren(string alias)
{
var sql = GetBaseQuery(false);
if (alias.IsNullOrWhiteSpace())
{
sql.Where<NodeDto>(x => x.ParentId <= 0);
}
else
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var parent = Database.ExecuteScalar<int?>(new Sql().Select("nodeId").From<TemplateDto>(SqlSyntax).Where<TemplateDto>(dto => dto.Alias == alias));
if (parent.HasValue == false) return Enumerable.Empty<ITemplate>();
sql.Where<NodeDto>(x => x.ParentId == parent.Value);
}
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
//return from base.GetAll, this is all cached
return base.GetAll().Where(x => alias.IsNullOrWhiteSpace()
? x.MasterTemplateAlias.IsNullOrWhiteSpace()
: x.MasterTemplateAlias.InvariantEquals(alias));
}
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
{
var sql = GetBaseQuery(false);
//return from base.GetAll, this is all cached
var all = base.GetAll().ToArray();
var descendants = new List<ITemplate>();
if (masterTemplateId > 0)
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var path = Database.ExecuteScalar<string>(
new Sql().Select(SqlSyntax.GetQuotedColumnName("path"))
.From<TemplateDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<TemplateDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(dto => dto.NodeId == masterTemplateId));
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new { query = path + ",%" });
var parent = all.FirstOrDefault(x => x.Id == masterTemplateId);
if (parent == null) return Enumerable.Empty<ITemplate>();
//recursively add all children with a level
AddChildren(all, descendants, parent.Alias);
}
else
{
descendants.AddRange(all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace()));
foreach (var parent in descendants)
{
//recursively add all children with a level
AddChildren(all, descendants, parent.Alias);
}
}
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
//return the list - it will be naturally ordered by level
return descendants;
}
public IEnumerable<ITemplate> GetDescendants(string alias)
{
var sql = GetBaseQuery(false);
var all = base.GetAll().ToArray();
var descendants = new List<ITemplate>();
if (alias.IsNullOrWhiteSpace() == false)
{
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
// in a single query, now we have to lookup the path to acheive the same thing
var path = Database.ExecuteScalar<string>(
"SELECT umbracoNode.path FROM cmsTemplate INNER JOIN umbracoNode ON cmsTemplate.nodeId = umbracoNode.id WHERE cmsTemplate.alias = @alias", new { alias = alias });
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new {query = path + ",%" });
var parent = all.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
if (parent == null) return Enumerable.Empty<ITemplate>();
//recursively add all children
AddChildren(all, descendants, parent.Alias);
}
else
{
descendants.AddRange(all.Where(x => x.MasterTemplateAlias.IsNullOrWhiteSpace()));
foreach (var parent in descendants)
{
//recursively add all children with a level
AddChildren(all, descendants, parent.Alias);
}
}
//return the list - it will be naturally ordered by level
return descendants;
}
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
var axisDefos = GetAxisDefinitions(dtos).ToArray();
return dtos.Select(x => MapFromDto(x, axisDefos));
private void AddChildren(ITemplate[] all, List<ITemplate> descendants, string masterAlias)
{
var c = all.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray();
descendants.AddRange(c);
if (c.Any() == false) return;
//recurse through all children
foreach (var child in c)
{
AddChildren(all, descendants, child.Alias);
}
}
/// <summary>
@@ -610,9 +572,9 @@ namespace Umbraco.Core.Persistence.Repositories
public TemplateNode GetTemplateNode(string alias)
{
//first get all template objects
var allTemplates = GetAll().ToArray();
var allTemplates = base.GetAll().ToArray();
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias == alias);
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias.InvariantEquals(alias));
if (selfTemplate == null)
{
return null;
@@ -621,11 +583,11 @@ namespace Umbraco.Core.Persistence.Repositories
var top = selfTemplate;
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
{
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
top = allTemplates.Single(x => x.Alias.InvariantEquals(top.MasterTemplateAlias));
}
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(top.Alias));
//This now creates the hierarchy recursively
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
@@ -633,10 +595,11 @@ namespace Umbraco.Core.Persistence.Repositories
return FindTemplateInTree(topNode, alias);
}
[Obsolete("Only used by obsolete code")]
private static TemplateNode WalkTree(TemplateNode current, string alias)
{
//now walk the tree to find the node
if (current.Template.Alias == alias)
if (current.Template.Alias.InvariantEquals(alias))
{
return current;
}
@@ -682,14 +645,16 @@ namespace Umbraco.Core.Persistence.Repositories
public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template)
{
var engine = _templateConfig.DefaultRenderingEngine;
if (template.Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(template.Content))
var viewHelper = new ViewHelper(_viewsFileSystem);
if (viewHelper.ViewExists(template) == false)
{
//there is a design but its definitely a webforms design
return RenderingEngine.WebForms;
if (template.Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(template.Content))
{
//there is a design but its definitely a webforms design and we haven't got a MVC view already for it
return RenderingEngine.WebForms;
}
}
var viewHelper = new ViewHelper(_viewsFileSystem);
var masterPageHelper = new MasterPageHelper(_masterpagesFileSystem);
switch (engine)
@@ -766,7 +731,7 @@ namespace Umbraco.Core.Persistence.Repositories
//get this node's children
var local = childTemplate;
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
var kids = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(local.Alias));
//recurse
child.Children = CreateChildren(child, kids, allTemplates);
@@ -796,7 +761,7 @@ namespace Umbraco.Core.Persistence.Repositories
private bool AliasAlreadExists(ITemplate template)
{
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias == template.Alias && x.NodeId != template.Id);
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias.InvariantEquals(template.Alias) && x.NodeId != template.Id);
var count = Database.ExecuteScalar<int>(sql);
return count > 0;
}
@@ -1,5 +1,6 @@
using Umbraco.Core.Configuration;
using System;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -18,6 +19,7 @@ namespace Umbraco.Core.Persistence
private readonly ILogger _logger;
private readonly ISqlSyntaxProvider _sqlSyntax;
private readonly CacheHelper _cacheHelper;
private readonly CacheHelper _noCache;
private readonly IUmbracoSettingsSection _settings;
#region Ctors
@@ -29,7 +31,28 @@ namespace Umbraco.Core.Persistence
//if (sqlSyntax == null) throw new ArgumentNullException("sqlSyntax");
if (settings == null) throw new ArgumentNullException("settings");
_cacheHelper = cacheHelper;
_cacheHelper = cacheHelper;
//IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying
// runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks
// changes entities are reset.
if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false)
{
var origRuntimeCache = cacheHelper.RuntimeCache;
_cacheHelper.RuntimeCache = new DeepCloneRuntimeCacheProvider(origRuntimeCache);
}
//If the factory for isolated cache doesn't return DeepCloneRuntimeCacheProvider, then ensure it does
if (_cacheHelper.IsolatedRuntimeCache.CacheFactory.Method.ReturnType != typeof (DeepCloneRuntimeCacheProvider))
{
var origFactory = cacheHelper.IsolatedRuntimeCache.CacheFactory;
_cacheHelper.IsolatedRuntimeCache.CacheFactory = type =>
{
var cache = origFactory(type);
return new DeepCloneRuntimeCacheProvider(cache);
};
}
_noCache = CacheHelper.CreateDisabledCacheHelper();
_logger = logger;
_sqlSyntax = sqlSyntax;
_settings = settings;
@@ -53,6 +76,7 @@ namespace Umbraco.Core.Persistence
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_cacheHelper = cacheHelper;
_noCache = CacheHelper.CreateDisabledCacheHelper();
}
[Obsolete("Use the ctor specifying all dependencies instead")]
@@ -80,15 +104,15 @@ namespace Umbraco.Core.Persistence
public virtual ITaskRepository CreateTaskRepository(IDatabaseUnitOfWork uow)
{
return new TaskRepository(uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
return new TaskRepository(uow,
_noCache, //never cache
_logger, _sqlSyntax);
}
public virtual IAuditRepository CreateAuditRepository(IDatabaseUnitOfWork uow)
{
return new AuditRepository(uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
_noCache, //never cache
_logger, _sqlSyntax);
}
@@ -128,7 +152,6 @@ namespace Umbraco.Core.Persistence
{
return new DataTypeDefinitionRepository(
uow,
_cacheHelper,
_cacheHelper,
_logger, _sqlSyntax,
CreateContentTypeRepository(uow));
@@ -140,8 +163,7 @@ namespace Umbraco.Core.Persistence
uow,
_cacheHelper,
_logger,
_sqlSyntax,
CreateLanguageRepository(uow));
_sqlSyntax);
}
public virtual ILanguageRepository CreateLanguageRepository(IDatabaseUnitOfWork uow)
@@ -175,7 +197,7 @@ namespace Umbraco.Core.Persistence
{
return new RelationRepository(
uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
_noCache, //never cache
_logger, _sqlSyntax,
CreateRelationTypeRepository(uow));
}
@@ -184,7 +206,7 @@ namespace Umbraco.Core.Persistence
{
return new RelationTypeRepository(
uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
_noCache, //never cache
_logger, _sqlSyntax);
}
@@ -222,7 +244,7 @@ namespace Umbraco.Core.Persistence
{
return new MigrationEntryRepository(
uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
_noCache, //never cache
_logger, _sqlSyntax);
}
@@ -283,8 +305,7 @@ namespace Umbraco.Core.Persistence
{
return new MemberGroupRepository(uow,
_cacheHelper,
_logger, _sqlSyntax,
_cacheHelper);
_logger, _sqlSyntax);
}
public virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow)
@@ -292,15 +313,15 @@ namespace Umbraco.Core.Persistence
return new EntityRepository(uow);
}
public IDomainRepository CreateDomainRepository(IDatabaseUnitOfWork uow)
public virtual IDomainRepository CreateDomainRepository(IDatabaseUnitOfWork uow)
{
return new DomainRepository(uow, _cacheHelper, _logger, _sqlSyntax);
}
public ITaskTypeRepository CreateTaskTypeRepository(IDatabaseUnitOfWork uow)
{
return new TaskTypeRepository(uow,
CacheHelper.CreateDisabledCacheHelper(), //never cache
return new TaskTypeRepository(uow,
_noCache, //never cache
_logger, _sqlSyntax);
}
}
@@ -117,7 +117,7 @@ namespace Umbraco.Core.Persistence
public override void OnException(Exception x)
{
_logger.Info<UmbracoDatabase>(x.StackTrace);
_logger.Error<UmbracoDatabase>("Database exception occurred", x);
base.OnException(x);
}
@@ -2,6 +2,7 @@ using System;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Maps a property source value to a data object.
/// </summary>
// todo: drop IPropertyEditorValueConverter support (when?).
@@ -0,0 +1,28 @@
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
/// <summary>
/// We need this property converter so that we always force the value of a label to be a string
/// </summary>
/// <remarks>
/// Without a property converter defined for the label type, the value will be converted with
/// the `ConvertUsingDarkMagic` method which will try to parse the value into it's correct type, but this
/// can cause issues if the string is detected as a number and then strips leading zeros.
/// Example: http://issues.umbraco.org/issue/U4-7929
/// </remarks>
[DefaultPropertyValueConverter]
[PropertyValueType(typeof (string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class LabelValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
return source == null ? string.Empty : source.ToString();
}
}
}
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -15,7 +16,6 @@ using Microsoft.Owin;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
using Microsoft.Owin;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Security
@@ -157,9 +157,6 @@ namespace Umbraco.Core.Security
return new HttpContextWrapper(http).GetCurrentIdentity(authenticateRequestIfNotFound);
}
/// <summary>
/// This clears the forms authentication cookie
/// </summary>
public static void UmbracoLogout(this HttpContextBase http)
{
if (http == null) throw new ArgumentNullException("http");
@@ -170,6 +167,8 @@ namespace Umbraco.Core.Security
/// This clears the forms authentication cookie for webapi since cookies are handled differently
/// </summary>
/// <param name="response"></param>
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static void UmbracoLogoutWebApi(this HttpResponseMessage response)
{
if (response == null) throw new ArgumentNullException("response");
@@ -195,11 +194,8 @@ namespace Umbraco.Core.Security
response.Headers.AddCookies(new[] { authCookie, prevCookie, extLoginCookie });
}
/// <summary>
/// This adds the forms authentication cookie for webapi since cookies are handled differently
/// </summary>
/// <param name="response"></param>
/// <param name="user"></param>
[Obsolete("Use WebSecurity.SetPrincipalForRequest")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
{
if (response == null) throw new ArgumentNullException("response");
@@ -250,26 +246,29 @@ namespace Umbraco.Core.Security
if (http == null) throw new ArgumentNullException("http");
new HttpContextWrapper(http).UmbracoLogout();
}
/// <summary>
/// Renews the Umbraco authentication ticket
/// This will force ticket renewal in the OWIN pipeline
/// </summary>
/// <param name="http"></param>
/// <returns></returns>
public static bool RenewUmbracoAuthTicket(this HttpContextBase http)
{
if (http == null) throw new ArgumentNullException("http");
return RenewAuthTicket(http,
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName,
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain,
//Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
1440);
http.Items["umbraco-force-auth"] = true;
return true;
}
/// <summary>
/// This will force ticket renewal in the OWIN pipeline
/// </summary>
/// <param name="http"></param>
/// <returns></returns>
internal static bool RenewUmbracoAuthTicket(this HttpContext http)
{
if (http == null) throw new ArgumentNullException("http");
return new HttpContextWrapper(http).RenewUmbracoAuthTicket();
http.Items["umbraco-force-auth"] = true;
return true;
}
/// <summary>
@@ -358,7 +357,9 @@ namespace Umbraco.Core.Security
{
//TODO: Do we need to do more here?? need to make sure that the forms cookie is gone, but is that
// taken care of in our custom middleware somehow?
ctx.Authentication.SignOut();
ctx.Authentication.SignOut(
Core.Constants.Security.BackOfficeAuthenticationType,
Core.Constants.Security.BackOfficeExternalAuthenticationType);
return null;
}
}
@@ -390,8 +391,7 @@ namespace Umbraco.Core.Security
//ensure there's def an expired cookie
http.Response.Cookies.Add(new HttpCookie(c) { Expires = DateTime.Now.AddYears(-1) });
}
}
}
}
private static FormsAuthenticationTicket GetAuthTicket(this HttpContextBase http, string cookieName)
@@ -432,51 +432,6 @@ namespace Umbraco.Core.Security
return FormsAuthentication.Decrypt(formsCookie);
}
/// <summary>
/// Renews the forms authentication ticket & cookie
/// </summary>
/// <param name="http"></param>
/// <param name="cookieName"></param>
/// <param name="cookieDomain"></param>
/// <param name="minutesPersisted"></param>
/// <returns>true if there was a ticket to renew otherwise false if there was no ticket</returns>
private static bool RenewAuthTicket(this HttpContextBase http, string cookieName, string cookieDomain, int minutesPersisted)
{
if (http == null) throw new ArgumentNullException("http");
//get the ticket
var ticket = GetAuthTicket(http, cookieName);
//renew the ticket
var renewed = FormsAuthentication.RenewTicketIfOld(ticket);
if (renewed == null)
{
return false;
}
//get the request cookie to get it's expiry date,
//NOTE: this will never be null becaues we already do this
// check in teh GetAuthTicket.
var formsCookie = http.Request.Cookies[cookieName];
//encrypt it
var hash = FormsAuthentication.Encrypt(renewed);
//write it to the response
var cookie = new HttpCookie(cookieName, hash)
{
Expires = DateTime.Now.AddMinutes(minutesPersisted),
Domain = cookieDomain
};
if (GlobalSettings.UseSSL)
cookie.Secure = true;
//ensure http only, this should only be able to be accessed via the server
cookie.HttpOnly = true;
//rewrite the cooke
http.Response.Cookies.Set(cookie);
return true;
}
/// <summary>
/// Creates a custom FormsAuthentication ticket with the data specified
/// </summary>
@@ -9,6 +9,12 @@ namespace Umbraco.Core.Security
{
public class BackOfficeClaimsIdentityFactory : ClaimsIdentityFactory<BackOfficeIdentityUser, int>
{
public BackOfficeClaimsIdentityFactory()
{
SecurityStampClaimType = Constants.Security.SessionIdClaimType;
UserNameClaimType = ClaimTypes.Name;
}
/// <summary>
/// Create a ClaimsIdentity from a user
/// </summary>
@@ -20,7 +26,7 @@ namespace Umbraco.Core.Security
var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity,
//set a new session id
new UserData(Guid.NewGuid().ToString("N"))
new UserData
{
Id = user.Id,
Username = user.UserName,
@@ -29,7 +35,8 @@ namespace Umbraco.Core.Security
Culture = user.Culture,
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
StartContentNode = user.StartContentId,
StartMediaNode = user.StartMediaId
StartMediaNode = user.StartMediaId,
SessionId = user.SecurityStamp
});
return umbracoIdentity;

Some files were not shown because too many files have changed in this diff Show More