Compare commits

...

142 Commits

Author SHA1 Message Date
Claus 527f98189a Merge pull request #2423 from umbraco/temp-u4-10897
temp U4-10897
2018-02-01 13:29:45 +01:00
Sebastiaan Janssen 78c289a559 Merge pull request #2425 from umbraco/mittonp-dev-v7
Mittonp dev v7
2018-02-01 08:59:35 +01:00
Sebastiaan Jansssen 646abb3aea Merge branch 'dev-v7' of https://github.com/mittonp/Umbraco-CMS into mittonp-dev-v7
# Conflicts:
#	src/Umbraco.Web.UI/umbraco/config/lang/da.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/es.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/fr.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/nl.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/pl.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/ru.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/zh.xml
2018-02-01 08:57:47 +01:00
Sebastiaan Janssen 2af59471a2 Merge pull request #973 from mattbrailsford/dev-v7-insertmacrofix
Updated insert macro dialog to prevent closing on enter key
2018-02-01 08:28:59 +01:00
Sebastiaan Janssen 090f89e5b6 Merge pull request #2223 from kgiszewski/fix/U4-6309
U4-6309: Fix black bars that appear on a RTE image resize
2018-01-31 10:43:29 +01:00
Stephan 4870afd2d3 U4-10897 - change enlisting priorities 2018-01-30 14:27:58 +01:00
Stephan 80257b6684 Revert "U4-10897 - change enlisting priorities"
This reverts commit 8f3a0b6919.
2018-01-30 14:26:59 +01:00
Stephan 8f3a0b6919 U4-10897 - change enlisting priorities 2018-01-30 14:25:43 +01:00
Stephan 9fd2f34343 U4-10897 - defer Examine indexing until scope is all done 2018-01-30 13:53:37 +01:00
Stephan e774717346 U4-10897 - expose enlisted mutable Xml in events 2018-01-30 13:14:01 +01:00
Sebastiaan Jansssen 7cd540c37e Remove additional premature uses of C#7 features 2018-01-29 14:35:30 +01:00
Sebastiaan Jansssen 83595ecaf5 Don't rely on C# 7 features 2018-01-29 14:06:25 +01:00
Stephan f2819f61e5 Merge pull request #2417 from umbraco/temp-u4-10846
U4-10846 - fix member group cache
2018-01-25 11:06:17 +01:00
Sebastiaan Janssen 2107e9d9e3 Merge pull request #2420 from PerplexDaniel/patch-1
Fix NullReferenceException when HttpContext is not available
2018-01-25 10:18:32 +01:00
Daniël Knippers c623b448ba Fix NullReferenceException when HttpContext is null
This method will throw a NullReferenceException in contexts without an HttpContext, like is the case in background threads. As HttpContext is only used to set an isDebug flag, it seems more sensible to not throw in cases without an HttpContext, but simply set isDebug to false instead. If this is not acceptable behavior, could we perhaps look at something other than HttpContext.Current.IsDebuggingEnabled to decide whether isDebug should be set?
2018-01-25 08:56:46 +01:00
Sebastiaan Janssen 8bb49f57e8 Merge pull request #2419 from umbraco/redmorello-U4-10864_close_back_office_search_results
Redmorello u4 10864 close back office search results
2018-01-24 17:47:44 +01:00
Sebastiaan Jansssen da0b1c2f23 Merge branch 'U4-10864_close_back_office_search_results' of https://github.com/redmorello/Umbraco-CMS into redmorello-U4-10864_close_back_office_search_results
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/components/application/umb-navigation.html
2018-01-24 17:43:19 +01:00
Sebastiaan Jansssen a288fc62eb Workaround: keep the cache we used to have but clear all cache for membergroups when a member group changes 2018-01-24 17:26:21 +01:00
Sebastiaan Jansssen 82e50ccd3a Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2018-01-24 16:13:31 +01:00
Sebastiaan Jansssen 15b0dc9f29 Merge branch 'dev-v7.8' of https://github.com/kristoffer-tvera/Umbraco-CMS into kristoffer-tvera-dev-v7.8 2018-01-24 16:12:06 +01:00
Sebastiaan Janssen 8057d09fc2 Merge pull request #2416 from PeteDuncanson/patch-1
Prevent Pinterest messing with media in the back office
2018-01-24 15:53:40 +01:00
Sebastiaan Jansssen 8877100bf0 Merge branch 'dev-v7' into temp-u4-10846 2018-01-24 15:50:08 +01:00
Stephan 41c96e6e26 Merge pull request #2398 from leekelleher/issue/U4-10756
Proposed patch for U4-10756 - Guid TypedContent performance
2018-01-24 15:27:43 +01:00
Sebastiaan Jansssen abdd117264 Fixes bug in MB 3.0.9 2018-01-24 15:26:40 +01:00
Sebastiaan Jansssen 6272dac698 Use string.Format instead of interpolation 2018-01-24 14:34:21 +01:00
Sebastiaan Jansssen 7a4b5fa796 Bump version to 7.7.10 2018-01-24 14:34:03 +01:00
Sebastiaan Jansssen c962132ee0 Update to ModelsBuilder 3.0.9 2018-01-24 14:33:32 +01:00
leekelleher 0780979469 Eagerly populating the Guid lookup
as per @Shazwazza's comment: https://github.com/umbraco/Umbraco-CMS/pull/2398#issuecomment-358752346

Tested against 12,000 nodes (in the XML cache), profiling showed it took 55ms.
2018-01-24 11:53:52 +00:00
leekelleher a42e568fdf Initialized the ConcurrentDictionary statically
as per @JimBobSquarePants's comment: https://github.com/umbraco/Umbraco-CMS/pull/2398#discussion_r162799543
2018-01-24 11:51:53 +00:00
Robert e62661cc6a Merge pull request #2397 from leekelleher/issue/U4-10845
U4-10845 MNTP value-converter - trashed content causes database lookups
2018-01-24 12:48:29 +01:00
leekelleher 6841b2ac61 Amended the lookup dictionary setter,
as per @JimBobSquarePants's comment: https://github.com/umbraco/Umbraco-CMS/pull/2398#discussion_r162522998
2018-01-24 10:29:23 +00:00
leekelleher f7f4276485 Removed the need for the UseLegacyXmlSchema check
The enhancement in PR #2367 removed the `"@isDoc"` check,
which was the main difference between the legacy and current XML schema.

Reducing the XPath to `"//*[@key=$guid]"` will perform the same for both types of schema.
_(and saves on a couple of allocations)_
2018-01-24 10:29:23 +00:00
leekelleher bb9e23ca3e Proposed patch for U4-10756 - Guid TypedContent performance
This is a proposal for a temporary workaround to issue U4-10756.

It uses a local static ConcurrentDictionary to store a lookup of Guid/int values.
If the Guid isn't in the lookup, then the traditional XPath is used, which would add the resulting node ID (int) to the lookup.
If the lookup contains the Guid, then the returned int value will be used to perform a more efficient retrieval.

<http://issues.umbraco.org/issue/U4-10756>
2018-01-24 10:29:23 +00:00
Sebastiaan Janssen 7d5d69e2e3 Merge pull request #2418 from abjerner/patch-36
Nested Content should use the new turquoise/purple colors as the rest of the backoffice
2018-01-23 22:02:16 +01:00
Anders Bjerner ee75158dd0 Nested Content should use the new turquoise/purple colors as the rest of the backoffice 2018-01-23 21:55:15 +01:00
Stephan c022397d86 U4-10846 - fix member group cache 2018-01-23 20:54:47 +01:00
Shannon d104525a50 Updates core to use latest CDF version 2018-01-23 11:15:37 -07:00
Sebastiaan Janssen b0a64aa4b5 Merge pull request #2384 from umbraco/temp-u4-10822
U4-10822 - refactor view models binding error handling
2018-01-23 16:24:08 +01:00
Pete Duncanson ca86385269 Prevent Pinterest messing with media in the back office
Fixes: http://issues.umbraco.org/issue/U4-10865
2018-01-23 15:10:09 +00:00
Claus ef4322a9b3 Merge pull request #2414 from umbraco/temp-u4-10844
U4-10844 - delete blueprints with content types
2018-01-23 15:15:15 +01:00
Sebastiaan Janssen 4ab1c51327 Merge pull request #2392 from umbraco/temp-u4-10829
U4-10829 - fix tree controller
2018-01-23 14:13:39 +01:00
Stephan e007a37c36 U4-10844 - delete blueprints with content types 2018-01-23 13:41:36 +01:00
Sebastiaan Janssen 2f67008987 Merge pull request #2407 from abjerner/patch-34
Removed unnecessary &nbsp;
2018-01-23 09:42:30 +01:00
Sebastiaan Janssen 1672e284c5 Merge pull request #2406 from abjerner/patch-33
Minor casing change
2018-01-23 09:41:46 +01:00
Ian Houghton 60ce36a7f2 U4-10864 add button when search returns no results, to clear the search 2018-01-22 22:03:35 +00:00
Anders Bjerner 72e2cacc87 Removed unnecessary &nbsp; 2018-01-22 18:16:42 +01:00
Anders Bjerner 4285102422 Minor casing change 2018-01-22 18:08:37 +01:00
Mads Rasmussen abbcf0e26b Merge pull request #2358 from abjerner/patch-28
Triggers the save button to momentarily show an error icon
2018-01-22 14:55:10 +01:00
Sebastiaan Janssen 347b25472f Merge pull request #2403 from JimBobSquarePants/housekeeping-gitattributes
Add default gitattributes and cleanup editorconfig
2018-01-22 14:38:40 +01:00
Mads Rasmussen b745948dc6 Merge pull request #2361 from bjarnef/dev-v7-U4-10791
U4-10791 - Fix collapsed columns listview settings
2018-01-22 13:48:58 +01:00
Mads Rasmussen 8007c8869f Merge pull request #2401 from umbraco/temp-U4-10835
U4-10835 Adds context menu items to the User tree
2018-01-22 13:25:59 +01:00
Stephan b51a328ead Merge pull request #2402 from JimBobSquarePants/perf-tryconvertto
Performance - 8x Faster TryConvertTo
2018-01-22 13:22:22 +01:00
James Jackson-South f3b8f2eb5f Add default gitattributes and cleanup editorconfig 2018-01-22 21:44:08 +11:00
James Jackson-South de4628f450 Add perf explanation 2018-01-22 20:58:15 +11:00
James Jackson-South b0a64655b4 Fastest dictionary lookups 2018-01-22 16:43:02 +11:00
Stephan 48d88ec8fa Deal fix FIXME 2018-01-21 10:29:06 +01:00
Stephan 7ca151a3fa Use concurrent dictionaries 2018-01-21 10:18:13 +01:00
Stephan 363c8fab2c Cleanup 2018-01-21 10:03:17 +01:00
Stephan 8d4fd9d1cf Merge branch 'perf-tryconvertto' of https://github.com/JimBobSquarePants/Umbraco-CMS into perf-tryconvertto 2018-01-21 10:01:12 +01:00
James Jackson-South 24071eb3b1 Faster TryConvertTo 2018-01-20 14:54:52 +11:00
James Jackson-South 62ffbe7cf0 Cleanup benchmarks and add TryCOnvertTo 2018-01-20 13:00:10 +11:00
Warren Buckley f2d6b47e47 Update labels for context menu items to be just 'Create' & 'Invite' to keep the same consistency throughout the UI as other context menu items do not include the verb 2018-01-19 14:24:57 +00:00
Warren Buckley f3541908c7 Update Users tree context menu to include two new items that navigate directly to an Angular Location/Path which loads the Invite or Create User views as needed 2018-01-19 14:07:23 +00:00
Sebastiaan Jansssen 4e57e1cc18 Nicer variable name, thank to Lee Kelleher! 2018-01-19 12:50:45 +01:00
Sebastiaan Jansssen 410afffaa9 Optimizing use of newlines array 2018-01-19 12:42:04 +01:00
Claus 936e94789d adding to tinyMceConfig.Release.config. 2018-01-19 12:21:57 +01:00
Claus 468a56e5de Merge branch 'karltynan-dev-v7' into dev-v7 2018-01-19 11:11:53 +01:00
Claus 468ec8824a Merge branch 'dev-v7' of git://github.com/karltynan/Umbraco-CMS into karltynan-dev-v7 2018-01-19 11:11:13 +01:00
Sebastiaan Jansssen cad913b7a1 U4-10857 Update to ClientDependency 1.9.5 2018-01-19 08:26:34 +01:00
Sebastiaan Jansssen 382103d99d Bump version to 7.7.9 2018-01-19 08:26:33 +01:00
Sebastiaan Janssen cbb6b9bca0 Merge pull request #2310 from matthew-darby/U4-10495
U4-10495 - Install and customize buttons disabled
2018-01-18 18:38:37 +01:00
Sebastiaan Janssen a1b90a50cd Merge pull request #2343 from soreng/patch-5
Fix for U4-10733
2018-01-18 18:28:34 +01:00
Sebastiaan Janssen 9ea5855073 Merge pull request #2360 from janvanhelvoort/U4-10785
U4-10785 - Filtering of Grid Editors
2018-01-18 18:20:11 +01:00
Sebastiaan Janssen 4a37433042 Merge pull request #2372 from bjarnef/dev-v7-U4-10809
Fix checkmark tree icon, when custom font icon is used for tree icon
2018-01-18 18:00:53 +01:00
Sebastiaan Janssen 91469812d3 Merge pull request #2383 from MMasey/U4-10727
U4 10727 - If nodes with an empty name exist, it's not possible to empty recycle bin
2018-01-18 17:54:40 +01:00
Sebastiaan Janssen 68a8eb7f3f Merge pull request #2375 from redmorello/U4-10762
U4-10762 Fix issue with empty name when registering new members from …
2018-01-18 17:40:05 +01:00
Sebastiaan Janssen 2e7baabb94 Merge pull request #2394 from umbraco/temp-u4-10813
U4-10813 - fix error with groups having a large number of permissions
2018-01-18 17:27:11 +01:00
Sebastiaan Janssen 57745fe71d Merge pull request #2396 from leekelleher/issue/U4-10842
U4-10842 LegacyMediaPickerPropertyConverter null-reference check
2018-01-18 17:17:45 +01:00
Sebastiaan Janssen de6f9236e7 Merge pull request #2399 from leekelleher/issue/U4-8712
U4-8712 MultipleTextstring value newline delimiter changes
2018-01-18 17:13:46 +01:00
Sebastiaan Janssen a00c59e8b5 Merge pull request #2393 from umbraco/temp-u4-10079
U4-10079 - remove default template
2018-01-18 16:54:22 +01:00
Stephan 05c2da807f U4-10079 - fix test 2018-01-18 15:58:51 +01:00
leekelleher 0fd8ca43d6 U4-8712 MultipleTextstring value newline delimiter changes
PR #2185 goes towards resolving this, but doesn't handle the impromptu switch between the `\r\n` and `\n` newline delimiters when republishing a content node.

Using an explicit array of newline chars will resolve this, e.g. `Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)`

<http://issues.umbraco.org/issue/U4-8712>
2018-01-18 12:18:51 +00:00
leekelleher 87f09b2ee6 U4-10845 MultiNodeTreePickerPropertyConverter - trashed content causes database lookups
If the first ID in the MNTP value is a trashed content node, then the `ConvertSourceToObject` method would
check if the ID is a media or member node, both of these incur a database call.

This can cause a detrimental performance impact on the website.

This patch uses the `startNode.type` prevalue to detect the node type, (e.g. Content, Media or Member).
The prevalue is cached in a private `ConcurrentDictionary` and refreshed using the `DataTypeCacheRefresher` event.
> _Following the same caching-pattern as the Slider, Tags and MediaPicker value-converters._

<http://issues.umbraco.org/issue/U4-10845>
2018-01-18 10:49:18 +00:00
leekelleher e466878925 U4-10842 LegacyMediaPickerPropertyConverter ConvertDataToSource null-reference check
If a selected media node has been trashed on the source environment,
when Deploy comes to transfer the node ID, because it can't transfer the media dependency,
the node ID value is set to `null`.

This causes an issue for the `LegacyMediaPickerPropertyConverter`
and `ConvertDataToSource` throws a null-reference exception.

This patch adds in a null-reference check for the `source` value.

<http://issues.umbraco.org/issue/U4-10842>
2018-01-18 10:04:55 +00:00
Mikulas Tomanka 319acc199e Merge pull request #2391 from matthew-darby/U4-10825
U4-10825 Search member by email in member section
2018-01-17 14:18:43 +01:00
Stephan 2a982f21a7 U4-10813 - fix error with groups having a large number of permissions 2018-01-17 13:07:03 +01:00
Stephan 3ff455f11d U4-10079 - remove default template 2018-01-17 11:36:08 +01:00
Stephan 41ad1bf27b U4-10829 - fix tree controller 2018-01-17 10:47:35 +01:00
Matt Darby f49d939a2d U4-10825 Search member by email in member section 2018-01-16 23:06:15 +08:00
Shannon 7e1e83b493 Fixes PackageInstaller event args to make sure the package metadata is passed through 2018-01-16 19:18:08 +11:00
Sebastiaan Janssen 23be0134e7 Merge pull request #1605 from jobf/dev-v7
fix U4-8792 override overflow
2018-01-13 17:57:49 +01:00
Sebastiaan Janssen 355fb64d8b Merge pull request #1573 from drbldgtl/dev-v7-U4-6415
Renamed SerializeToCropDataSet to DeserializeToCropDataSet
2018-01-13 17:33:44 +01:00
Stephan 42959a1db5 U4-10822 - fix breaking change 2018-01-12 13:51:06 +01:00
Kristoffer Tverå a1cd22208b Extra check before assigning value to currentColor
In version 7.7.7 with the latest version of LeBlender (1.0.9.2), colorpickers will throw a javascript error in console. Applying this small check will resolve that issue.
ref: https://our.umbraco.org/forum/contributing-to-umbraco-cms/88890-color-picker-cannot-read-property-hasownproperty-of-null
2018-01-12 10:45:59 +01:00
Mads Rasmussen c3116d5df7 remove moment resolution for bower.json 2018-01-12 08:52:13 +01:00
Shannon Deminick b0b874212e Merge pull request #2381 from umbraco/temp-U4-10803
U4-10803: remove dependency on angular-moment
2018-01-12 14:43:06 +11:00
Shannon 19086ab3a1 Merge remote-tracking branch 'origin/dev-v7.8' into temp-U4-10803
# Conflicts:
#	src/Umbraco.Web.UI.Client/bower.json
2018-01-12 14:32:54 +11:00
Shannon Deminick 069594c3ac Merge pull request #2380 from umbraco/U4-10815
U4-10815 Make DisposableObjectSlim
2018-01-12 12:43:47 +11:00
Stephan 0bc4c7e2aa U4-10822 - refactor view models binding error handling 2018-01-11 16:42:20 +01:00
Stephan 7f12cff3bd Minor build cleanup 2018-01-11 16:25:18 +01:00
Robert e26cbccfe0 Reverted DisposableObject.cs to its original state 2018-01-11 13:22:23 +01:00
Robert fa058f348d Forgot to removed TODO 2018-01-11 11:02:05 +01:00
Mads Rasmussen 62d9a1a132 Merge pull request #2379 from umbraco/mzajkowski-U4-4902
U4-4902 Enable 'discard changes' alert throughout the UI
2018-01-11 10:59:22 +01:00
Robert 9284269428 TODO's for DisposableObject and DisposableObjectSlim done 2018-01-11 10:53:45 +01:00
Mads Rasmussen f8c4481eb1 Merge branch 'dev-v7' into mzajkowski-U4-4902 2018-01-11 10:28:28 +01:00
Mike 9f6e6e4701 Add tests to SimilarNodeNameTests to check for null and "" values. 2018-01-10 20:58:10 +00:00
Mike 34ba3f3351 Merge remote-tracking branch 'upstream/dev-v7' into U4-10727 2018-01-10 20:48:28 +00:00
Mike dcfb8b94d8 Refactor SimilarNodeName to account for null nodeName values. 2018-01-10 20:44:30 +00:00
Mads Rasmussen 0876004d9a U4-10803: remove dependency on angular-moment 2018-01-10 16:00:32 +01:00
Ilham Boulghallat 700b71f9fb Merge pull request #2377 from abjerner/patch-32
A few fixes for the Danish translation
2018-01-10 15:14:27 +01:00
Robert bba58ea0c0 Replaced all usages of DisposableObject with DisposableObjectSlim 2018-01-10 13:48:55 +01:00
Robert d0d4885812 Created slim version of DisposableObject and fixed some code indentation
DisposableObjectSlim has no finalizer
2018-01-10 13:36:53 +01:00
Robert 3642ff72a4 Removed console.log 2018-01-10 10:03:26 +01:00
Robert 6e830c1171 Wrapping the watch in the elm.focus
Seems to bring the watch calls way down.
2018-01-10 10:03:02 +01:00
Robert ab523baf4f Changed no-dirty-check directive to use scope.$watch to change $pristine to false 2018-01-10 09:24:42 +01:00
Claus 2dec03f441 Merge pull request #2374 from umbraco/temp-U4-10810
U4-10810 Update CDF to support storing TEMP files in environment %tem…
2018-01-10 09:04:58 +01:00
Claus 9ada0d9c97 reverting committed iis settings. 2018-01-10 09:03:35 +01:00
Shannon df553140e8 Updates to latest 1.9.4 of CDF and updates Nuspec 2018-01-10 12:25:24 +11:00
Anders Bjerner 0b898f2e32 A few fixes for the Danish translation 2018-01-09 22:54:48 +01:00
Ian Houghton f5f3676a56 U4-10762 Fix issue with empty name when registering new members from snippet 2018-01-09 15:51:32 +00:00
Shannon bc828fc6f3 U4-10810 Update CDF to support storing TEMP files in environment %temp% location 2018-01-09 13:52:52 +11:00
Mike dc7b83ca6c Add initial test fix for SimilarNodeName when a node has no name. 2018-01-08 17:30:11 +00:00
Robert 8188e4ff55 Merge branch 'U4-4902' of git://github.com/mzajkowski/Umbraco-CMS into mzajkowski-U4-4902 2018-01-08 15:39:29 +01:00
Bjarne Fyrstenborg fcf9dcd803 Fix checkmark tree icon, when custom font icon is used for tree icon, e.g. in UCommerce 2018-01-08 14:40:31 +01:00
Sebastiaan Jansssen 3556043b55 Update to latest modelsbuilder 2018-01-08 12:44:29 +01:00
Bjarne Fyrstenborg fef9e3fde0 Ensure placeholder is same height as original rows 2017-12-29 22:49:06 +01:00
Bjarne Fyrstenborg e849d2d0d0 Add required ng-model to ui-sortable 2017-12-29 22:48:14 +01:00
Bjarne Fyrstenborg 9a6123579f Fix collapsed columns in row when sorting 2017-12-29 22:47:29 +01:00
Jan van Helvoort 591a881283 Filtering of Grid Editors
If there are more than 15 items, 5 rows of 3, then show the filter.
2017-12-24 15:48:16 +01:00
Anders Bjerner 1554d52ea9 Triggers the save button to momentarily show an error icon 2017-12-20 21:51:59 +01:00
Søren Gregersen 50335723b0 Fix for U4-10733 2017-12-06 10:09:40 +01:00
Karl Tynan 58697eaa04 Merge pull request #1 from karltynan/karltynan-patch-1
Added small to allowed TinyMCE valid elements
2017-11-21 15:20:06 +00:00
Karl Tynan ce58ad91b5 Added `small` to allowed TinyMCE valid elements
We use ``small`` a lot in the RTE, and ``small`` is now considered a really useful tag in HTML5. I would like to see this in the default valid elements list for people to use out-of-the box.
2017-11-21 15:18:42 +00:00
Marcin Zajkowski e14aba3875 More no-dirty-checks and code polishment 2017-11-07 23:21:50 +01:00
Matt Darby 77162e4b51 Move val-email attribute before required attribute 2017-11-07 19:17:42 +07:00
Marcin Zajkowski 0df7767f4a Added no-dirty-check to search fields in all dialogs 2017-11-02 17:32:20 +01:00
Kevin Giszewski 6c172702be Fix for U4-6309 2017-09-27 11:32:36 -04:00
jf 7566546fd7 fix U4-8792 override overflow 2016-11-03 17:32:24 +00:00
Shane Marsden 59b8b397b7 Renamed SerializeToCropDataSet to DeserializeToCropDataSet 2016-11-03 11:33:00 +00:00
Mitton 7c72e70967 Added grid editor names for localization. 2016-05-05 05:42:33 +02:00
Mitton 75b74a6687 Enabled localization of grid editor names 2016-05-05 05:12:33 +02:00
mattbrailsford 7dcb4435d8 Updated insert macro dialog to prevent closing on enter key 2015-12-22 11:18:32 +00:00
424 changed files with 4949 additions and 11306 deletions
+11 -5
View File
@@ -1,10 +1,16 @@
root=true
# editorconfig.org
# top-most EditorConfig file
root = true
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.{cs,cshtml,csx,vb,vbx,vbhtml,fs,fsx,txt,ps1,sql}]
indent_size = 4
# Trim trailing whitespace, limited support.
# https://github.com/editorconfig/editorconfig/wiki/Property-research:-Trim-trailing-spaces
trim_trailing_whitespace = true
+49
View File
@@ -0,0 +1,49 @@
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
*.jpg binary
*.png binary
*.gif binary
*.cs text=auto diff=csharp
*.vb text=auto
*.c text=auto
*.cpp text=auto
*.cxx text=auto
*.h text=auto
*.hxx text=auto
*.py text=auto
*.rb text=auto
*.java text=auto
*.html text=auto
*.htm text=auto
*.css text=auto
*.scss text=auto
*.sass text=auto
*.less text=auto
*.js text=auto
*.lisp text=auto
*.clj text=auto
*.sql text=auto
*.php text=auto
*.lua text=auto
*.m text=auto
*.asm text=auto
*.erl text=auto
*.fs text=auto
*.fsx text=auto
*.hs text=auto
*.csproj text=auto merge=union
*.vbproj text=auto merge=union
*.fsproj text=auto merge=union
*.dbproj text=auto merge=union
*.sln text=auto eol=crlf merge=union
+1 -2
View File
@@ -139,5 +139,4 @@ src/PrecompiledWeb/*
build.out/
build.tmp/
build/Modules/*/temp/
/src/.idea/*
build/Modules/*/temp/
@@ -239,18 +239,18 @@ function Prepare-Tests
# data
Write-Host "Copy data files"
if( -Not (Test-Path -Path "$tmp\tests\Packaging" ) )
if (-Not (Test-Path -Path "$tmp\tests\Packaging" ) )
{
Write-Host "Create packaging directory"
New-Item -ItemType directory -Path "$tmp\tests\Packaging"
mkdir "$tmp\tests\Packaging" > $null
}
Copy-Files "$src\Umbraco.Tests\Packaging\Packages" "*" "$tmp\tests\Packaging\Packages"
# required for package install tests
if( -Not (Test-Path -Path "$tmp\tests\bin" ) )
if (-Not (Test-Path -Path "$tmp\tests\bin" ) )
{
Write-Host "Create bin directory"
New-Item -ItemType directory -Path "$tmp\tests\bin"
mkdir "$tmp\tests\bin" > $null
}
}
+2 -1
View File
@@ -27,8 +27,9 @@
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.9.9, 7.0.0)" />
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
<dependency id="ClientDependency" version="[1.9.6, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
+1 -2
View File
@@ -17,7 +17,7 @@
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.8, 4.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.10, 4.0.0)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
</dependencies>
@@ -32,7 +32,6 @@
<file src="$BuildTmp$\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
<file src="$BuildTmp$\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
+3 -3
View File
@@ -79,14 +79,14 @@
<add sortOrder="1" alias="dataTypes" application="developer"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes(sortOrder)" />
<add initialize="true" sortOrder="2" alias="macros" application="developer" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MacroTreeController, umbraco"
<add application="developer" alias="macros" title="Macros" type="umbraco.loadMacros, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
<add application="developer" alias="relationTypes" title="Relation Types" type="umbraco.loadRelationTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
<add initialize="true" sortOrder="5" alias="xslt" application="developer" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.XsltTreeController, umbraco"
<add application="developer" alias="xslt" title="XSLT Files" type="umbraco.loadXslt, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.8.0")]
[assembly: AssemblyInformationalVersion("7.8.0-beta005")]
[assembly: AssemblyFileVersion("7.7.10")]
[assembly: AssemblyInformationalVersion("7.7.10")]
-47
View File
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Configuration;
using System.Threading;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
@@ -355,52 +354,6 @@ namespace Umbraco.Core
}
}
/// <summary>
/// Gets the Current Version of the Umbraco Site before an upgrade
/// by using the last/most recent Umbraco Migration that has been run
/// </summary>
/// <returns>A SemVersion of the latest Umbraco DB Migration run</returns>
/// <remarks>
/// NOTE: This existed in the InstallHelper previously but should really be here so it can be re-used if necessary
/// </remarks>
internal SemVersion CurrentVersion()
{
//Set a default version of 0.0.0
var version = new SemVersion(0);
//If we have a db context available, if we don't then we are not installed anyways
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.CanConnect)
version = DatabaseContext.ValidateDatabaseSchema().DetermineInstalledVersionByMigrations(Services.MigrationEntryService);
if (version != new SemVersion(0))
return version;
// If we aren't able to get a result from the umbracoMigrations table then use the version in web.config, if it's available
if (string.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus))
return version;
var configuredVersion = GlobalSettings.ConfigurationStatus;
string currentComment = null;
var current = configuredVersion.Split('-');
if (current.Length > 1)
currentComment = current[1];
Version currentVersion;
if (Version.TryParse(current[0], out currentVersion))
{
version = new SemVersion(
currentVersion.Major,
currentVersion.Minor,
currentVersion.Build,
string.IsNullOrWhiteSpace(currentComment) ? null : currentComment,
currentVersion.Revision > 0 ? currentVersion.Revision.ToString() : null);
}
return version;
}
private void AssertIsNotReady()
{
if (this.IsReady)
@@ -0,0 +1,61 @@
using System;
namespace Umbraco.Core.Collections
{
/// <summary>
/// Represents a composite key of (Type, Type) for fast dictionaries.
/// </summary>
internal struct CompositeTypeTypeKey : IEquatable<CompositeTypeTypeKey>
{
/// <summary>
/// Initializes a new instance of the <see cref="CompositeTypeTypeKey"/> struct.
/// </summary>
public CompositeTypeTypeKey(Type type1, Type type2) : this()
{
Type1 = type1;
Type2 = type2;
}
/// <summary>
/// Gets the first type.
/// </summary>
public Type Type1 { get; private set; }
/// <summary>
/// Gets the second type.
/// </summary>
public Type Type2 { get; private set; }
/// <inheritdoc/>
public bool Equals(CompositeTypeTypeKey other)
{
return Type1 == other.Type1 && Type2 == other.Type2;
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
var other = obj is CompositeTypeTypeKey ? (CompositeTypeTypeKey)obj : default(CompositeTypeTypeKey);
return Type1 == other.Type1 && Type2 == other.Type2;
}
public static bool operator ==(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
{
return key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
}
public static bool operator !=(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
{
return key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
return (Type1.GetHashCode() * 397) ^ Type2.GetHashCode();
}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Collections
{
/// <summary>
/// Represents a list of types.
/// </summary>
/// <remarks>Types in the list are, or derive from, or implement, the base type.</remarks>
/// <typeparam name="TBase">The base type.</typeparam>
internal class TypeList<TBase>
{
private readonly List<Type> _list = new List<Type>();
/// <summary>
/// Adds a type to the list.
/// </summary>
/// <typeparam name="T">The type to add.</typeparam>
public void Add<T>()
where T : TBase
{
_list.Add(typeof(T));
}
/// <summary>
/// Determines whether a type is in the list.
/// </summary>
public bool Contains(Type type)
{
return _list.Contains(type);
}
}
}
@@ -1,18 +0,0 @@
using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class BackOfficeElement : UmbracoConfigurationElement, IBackOfficeSection
{
[ConfigurationProperty("tours")]
internal TourConfigElement Tours
{
get { return (TourConfigElement)this["tours"]; }
}
ITourSection IBackOfficeSection.Tours
{
get { return Tours; }
}
}
}
@@ -1,7 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IBackOfficeSection
{
ITourSection Tours { get; }
}
}
@@ -1,7 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface ITourSection
{
bool EnableTours { get; }
}
}
@@ -5,8 +5,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IUmbracoSettingsSection : IUmbracoConfigurationSection
{
IBackOfficeSection BackOffice { get; }
IContentSection Content { get; }
ISecuritySection Security { get; }
@@ -1,17 +0,0 @@
using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class TourConfigElement : UmbracoConfigurationElement, ITourSection
{
//disabled by default so that upgraders don't get it enabled by default
//TODO: we probably just want to disable the initial one from automatically loading ?
[ConfigurationProperty("enable", DefaultValue = false)]
public bool EnableTours
{
get { return (bool)this["enable"]; }
}
//TODO: We could have additional filters, etc... defined here
}
}
@@ -8,12 +8,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
public class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
{
[ConfigurationProperty("backOffice")]
internal BackOfficeElement BackOffice
{
get { return (BackOfficeElement)this["backOffice"]; }
}
[ConfigurationProperty("content")]
internal ContentElement Content
{
@@ -155,11 +149,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return Templates; }
}
IBackOfficeSection IUmbracoSettingsSection.BackOffice
{
get { return BackOffice; }
}
IDeveloperSection IUmbracoSettingsSection.Developer
{
get { return Developer; }
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.8.0");
private static readonly Version Version = new Version("7.7.10");
/// <summary>
/// Gets the current version of Umbraco.
@@ -73,11 +73,6 @@
/// </summary>
public const string Media = "media";
/// <summary>
/// alias for the macro tree.
/// </summary>
public const string Macros = "macros";
/// <summary>
/// alias for the datatype tree.
/// </summary>
+34 -34
View File
@@ -21,9 +21,9 @@ namespace Umbraco.Core
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
{
if (truncateTo == DateTruncate.Year)
return new DateTime(dt.Year, 0, 0);
return new DateTime(dt.Year, 1, 1);
if (truncateTo == DateTruncate.Month)
return new DateTime(dt.Year, dt.Month, 0);
return new DateTime(dt.Year, dt.Month, 1);
if (truncateTo == DateTruncate.Day)
return new DateTime(dt.Year, dt.Month, dt.Day);
if (truncateTo == DateTruncate.Hour)
@@ -41,43 +41,43 @@ namespace Umbraco.Core
Hour,
Minute,
Second
}
}
/// <summary>
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
/// date time is before the time, calculate onto next day)
/// </summary>
/// <param name="fromDateTime">Date to start from</param>
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
/// <returns></returns>
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
{
// Ensure time provided is 4 digits long
if (scheduledTime.Length == 3)
{
scheduledTime = "0" + scheduledTime;
}
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
DateTime scheduledDateTime;
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
{
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
}
else
{
var nextDay = fromDateTime.AddDays(1);
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
}
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
}
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
{
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
/// <returns></returns>
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
{
// Ensure time provided is 4 digits long
if (scheduledTime.Length == 3)
{
scheduledTime = "0" + scheduledTime;
}
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
DateTime scheduledDateTime;
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
{
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
}
else
{
var nextDay = fromDateTime.AddDays(1);
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
}
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
}
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
{
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Events
@@ -7,18 +8,27 @@ namespace Umbraco.Core.Events
public class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
{
private readonly MetaData _packageMetaData;
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the overload specifying packageMetaData instead")]
public ImportPackageEventArgs(TEntity eventObject, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
}
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: base(new[] { eventObject })
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
if (packageMetaData == null) throw new ArgumentNullException("packageMetaData");
_packageMetaData = packageMetaData;
}
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: this(eventObject, packageMetaData, true)
{
}
public MetaData PackageMetaData
{
get { return _packageMetaData; }
+2 -2
View File
@@ -26,13 +26,13 @@ namespace Umbraco.Core
var ipAddress = httpContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ipAddress))
return httpContext.Request.UserHostAddress;
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
var addresses = ipAddress.Split(',');
if (addresses.Length != 0)
return addresses[0];
return httpContext.Request.UserHostAddress;
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
}
catch (System.Exception ex)
{
+6 -36
View File
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Umbraco.Core.Logging;
namespace Umbraco.Core.IO
@@ -108,7 +107,7 @@ namespace Umbraco.Core.IO
try
{
WithRetry(() => Directory.Delete(fullPath, recursive));
Directory.Delete(fullPath, recursive);
}
catch (DirectoryNotFoundException ex)
{
@@ -226,8 +225,8 @@ namespace Umbraco.Core.IO
return;
try
{
WithRetry(() => File.Delete(fullPath));
{
File.Delete(fullPath);
}
catch (FileNotFoundException ex)
{
@@ -379,7 +378,7 @@ namespace Umbraco.Core.IO
{
if (overrideIfExists == false)
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
WithRetry(() => File.Delete(fullPath));
File.Delete(fullPath);
}
var directory = Path.GetDirectoryName(fullPath);
@@ -387,9 +386,9 @@ namespace Umbraco.Core.IO
Directory.CreateDirectory(directory); // ensure it exists
if (copy)
WithRetry(() => File.Copy(physicalPath, fullPath));
File.Copy(physicalPath, fullPath);
else
WithRetry(() => File.Move(physicalPath, fullPath));
File.Move(physicalPath, fullPath);
}
#region Helper Methods
@@ -418,35 +417,6 @@ namespace Umbraco.Core.IO
return path;
}
protected void WithRetry(Action action)
{
// 10 times 100ms is 1s
const int count = 10;
const int pausems = 100;
for (var i = 0;; i++)
{
try
{
action();
break; // done
}
catch (IOException e)
{
// if it's not *exactly* IOException then it could be
// some inherited exception such as FileNotFoundException,
// and then we don't want to retry
if (e.GetType() != typeof(IOException)) throw;
// if we have tried enough, throw, else swallow
// the exception and retry after a pause
if (i == count) throw;
}
Thread.Sleep(pausems);
}
}
#endregion
}
}
+1 -13
View File
@@ -2,30 +2,18 @@
namespace Umbraco.Core.Models
{
public sealed class AuditItem : Entity, IAuditItem
public sealed class AuditItem : Entity, IAggregateRoot
{
/// <summary>
/// Constructor for creating an item to be created
/// </summary>
/// <param name="objectId"></param>
/// <param name="comment"></param>
/// <param name="type"></param>
/// <param name="userId"></param>
public AuditItem(int objectId, string comment, AuditType type, int userId)
{
DisableChangeTracking();
Id = objectId;
Comment = comment;
AuditType = type;
UserId = userId;
EnableChangeTracking();
}
public string Comment { get; private set; }
public AuditType AuditType { get; private set; }
public int UserId { get; private set; }
}
}
+4 -2
View File
@@ -95,8 +95,10 @@ namespace Umbraco.Core.Models
get { return _allowedTemplates; }
set
{
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
Ps.Value.TemplateComparer);
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector, Ps.Value.TemplateComparer);
if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false)
DefaultTemplateId = 0;
}
}
-12
View File
@@ -1,12 +0,0 @@
using System;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
public interface IAuditItem : IAggregateRoot
{
string Comment { get; }
AuditType AuditType { get; }
int UserId { get; }
}
}
@@ -40,6 +40,19 @@ namespace Umbraco.Core.Models.Identity
identityUser.EnableChangeTracking();
});
config.CreateMap<BackOfficeIdentityUser, UserData>()
.ConstructUsing((BackOfficeIdentityUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id'
.ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
.ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Roles.Select(x => x.RoleId).ToArray()))
.ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
.ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.CalculatedContentStartNodeIds))
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
.ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.CalculatedMediaStartNodeIds))
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture))
.ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
}
private string GetPasswordHash(string storedPass)
+1 -6
View File
@@ -69,11 +69,6 @@ namespace Umbraco.Core.Models.Membership
/// <summary>
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>
string Avatar { get; set; }
/// <summary>
/// A Json blob stored for recording tour data for a user
/// </summary>
string TourData { get; set; }
string Avatar { get; set; }
}
}
+1 -13
View File
@@ -99,7 +99,6 @@ namespace Umbraco.Core.Models.Membership
private string _name;
private string _securityStamp;
private string _avatar;
private string _tourData;
private int _sessionTimeout;
private int[] _startContentIds;
private int[] _startMediaIds;
@@ -133,7 +132,6 @@ namespace Umbraco.Core.Models.Membership
public readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.SecurityStamp);
public readonly PropertyInfo AvatarSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Avatar);
public readonly PropertyInfo TourDataSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.TourData);
public readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartContentIds);
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartMediaIds);
@@ -466,18 +464,8 @@ namespace Umbraco.Core.Models.Membership
{
get { return _avatar; }
set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); }
}
}
/// <summary>
/// A Json blob stored for recording tour data for a user
/// </summary>
[DataMember]
public string TourData
{
get { return _tourData; }
set { SetPropertyValueAndDetectChanges(value, ref _tourData, Ps.Value.TourDataSelector); }
}
/// <summary>
/// Gets or sets the session timeout.
/// </summary>
@@ -27,10 +27,5 @@ namespace Umbraco.Core.Models.Rdbms
[NullSetting(NullSetting = NullSettings.NotNull)]
[Length(500)]
public string OriginIdentity { get; set; }
[Column("instructionCount")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = 1)]
public int InstructionCount { get; set; }
}
}
@@ -24,5 +24,4 @@ namespace Umbraco.Core.Models.Rdbms
[ResultColumn]
public NodeDto NodeDto { get; set; }
}
}
+1 -1
View File
@@ -32,6 +32,6 @@ namespace Umbraco.Core.Models.Rdbms
[Column("logComment")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(4000)]
public string Comment { get; set; }
public string Comment { get; set; }
}
}
-29
View File
@@ -1,29 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("cmsMedia")]
[PrimaryKey("versionId", autoIncrement = false)]
[ExplicitColumns]
internal class MediaDto
{
[Column("nodeId")]
[ForeignKey(typeof(ContentDto), Column = "nodeId")]
[ForeignKey(typeof(NodeDto))]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsMedia", ForColumns = "nodeId, versionId, mediaPath")]
public int NodeId { get; set; }
[Column("versionId")]
[PrimaryKeyColumn(AutoIncrement = false)]
public Guid VersionId { get; set; }
[Column("mediaPath")]
[NullSetting(NullSetting = NullSettings.Null)]
public string MediaPath { get; set; }
[ResultColumn]
public ContentVersionDto ContentVersionDto { get; set; }
}
}
@@ -27,7 +27,6 @@ namespace Umbraco.Core.Models.Rdbms
[ForeignKey(typeof(PropertyTypeGroupDto))]
public int? PropertyTypeGroupId { get; set; }
[Index(IndexTypes.NonClustered, Name = "IX_cmsPropertyTypeAlias")]
[Column("Alias")]
public string Alias { get; set; }
+3 -11
View File
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models.Rdbms
{
UserGroupDtos = new List<UserGroupDto>();
UserStartNodeDtos = new HashSet<UserStartNodeDto>();
}
}
[Column("id")]
[PrimaryKeyColumn(Name = "PK_user")]
@@ -40,7 +40,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("userPassword")]
[Length(500)]
public string Password { get; set; }
/// <summary>
/// This will represent a JSON structure of how the password has been created (i.e hash algorithm, iterations)
/// </summary>
@@ -95,7 +95,7 @@ namespace Umbraco.Core.Models.Rdbms
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
/// <summary>
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>
@@ -103,14 +103,6 @@ namespace Umbraco.Core.Models.Rdbms
[NullSetting(NullSetting = NullSettings.Null)]
[Length(500)]
public string Avatar { get; set; }
/// <summary>
/// A Json blob stored for recording tour data for a user
/// </summary>
[Column("tourData")]
[NullSetting(NullSetting = NullSettings.Null)]
[SpecialDbType(SpecialDbTypes.NTEXT)]
public string TourData { get; set; }
[ResultColumn]
public List<UserGroupDto> UserGroupDtos { get; set; }
@@ -1,52 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUserLogin")]
[PrimaryKey("sessionId", autoIncrement = false)]
[ExplicitColumns]
internal class UserLoginDto
{
[Column("sessionId")]
[PrimaryKeyColumn(AutoIncrement = false)]
public Guid SessionId { get; set; }
[Column("userId")]
[ForeignKey(typeof(UserDto), Name = "FK_umbracoUserLogin_umbracoUser_id")]
public int UserId { get; set; }
/// <summary>
/// Tracks when the session is created
/// </summary>
[Column("loggedInUtc")]
[NullSetting(NullSetting = NullSettings.NotNull)]
public DateTime LoggedInUtc { get; set; }
/// <summary>
/// Updated every time a user's session is validated
/// </summary>
/// <remarks>
/// This allows us to guess if a session is timed out if a user doesn't actively log out
/// and also allows us to trim the data in the table
/// </remarks>
[Column("lastValidatedUtc")]
[NullSetting(NullSetting = NullSettings.NotNull)]
public DateTime LastValidatedUtc { get; set; }
/// <summary>
/// Tracks when the session is removed when the user's account is logged out
/// </summary>
[Column("loggedOutUtc")]
[NullSetting(NullSetting = NullSettings.Null)]
public DateTime? LoggedOutUtc { get; set; }
/// <summary>
/// Logs the IP address of the session if available
/// </summary>
[Column("ipAddress")]
[NullSetting(NullSetting = NullSettings.Null)]
public string IpAddress { get; set; }
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[Obsolete("Table no longer exists as of 7.7 - retained only to support migrations from previous versions")]
[Obsolete("Table no longer exists as of 7.6 - retained only to support migrations from previous versions")]
[TableName("umbracoUserType")]
[PrimaryKey("id")]
[ExplicitColumns]
@@ -192,7 +192,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DocumentBlueprint, typeof(IContent))]
[FriendlyName("DocumentBlueprint")]
[UmbracoUdiType(Constants.UdiEntityType.DocumentBlueprint)]
[UmbracoUdiType(Constants.UdiEntityType.DocumentBluePrint)]
DocumentBlueprint,
/// <summary>
+2 -1
View File
@@ -30,11 +30,12 @@ namespace Umbraco.Core.Models
/// Tries to lookup the user's gravatar to see if the endpoint can be reached, if so it returns the valid URL
/// </summary>
/// <param name="user"></param>
/// <param name="userService"></param>
/// <param name="staticCache"></param>
/// <returns>
/// A list of 5 different sized avatar URLs
/// </returns>
internal static string[] GetUserAvatarUrls(this IUser user, ICacheProvider staticCache)
internal static string[] GetCurrentUserAvatarUrls(this IUser user, IUserService userService, ICacheProvider staticCache)
{
//check if the user has explicitly removed all avatars including a gravatar, this will be possible and the value will be "none"
if (user.Avatar == "none")
File diff suppressed because it is too large Load Diff
@@ -394,7 +394,7 @@ namespace Umbraco.Core.ObjectResolution
/// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances
/// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd
/// </summary>
internal virtual void ResetCollections()
internal void ResetCollections()
{
using (new WriteLock(_lock))
{
+38 -28
View File
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.IO.Compression;
using ICSharpCode.SharpZipLib.Zip;
namespace Umbraco.Core.Packaging
{
@@ -14,17 +14,17 @@ namespace Umbraco.Core.Packaging
bool fileFound = false;
string foundDir = null;
ReadZipfileEntries(packageFilePath, entry =>
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = Path.GetFileName(entry.Name);
if (string.IsNullOrEmpty(fileName) == false && fileName.Equals(fileToRead, StringComparison.CurrentCultureIgnoreCase))
if (string.IsNullOrEmpty(fileName) == false &&
fileName.Equals(fileToRead, StringComparison.CurrentCultureIgnoreCase))
{
foundDir = entry.Name.Substring(0, entry.Name.Length - fileName.Length);
fileFound = true;
using (var entryStream = entry.Open())
using (var reader = new StreamReader(entryStream))
using (var reader = new StreamReader(stream))
{
retVal = reader.ReadToEnd();
return false;
@@ -77,7 +77,7 @@ namespace Umbraco.Core.Packaging
var d = sourceDestination.ToDictionary(k => k.Key.ToLower(), v => v.Value);
ReadZipfileEntries(packageFilePath, entry =>
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower();
if (fileName == string.Empty) { return true; }
@@ -86,9 +86,8 @@ namespace Umbraco.Core.Packaging
if (string.IsNullOrEmpty(fileName) == false && d.TryGetValue(fileName, out destination))
{
using (var streamWriter = File.Open(destination, FileMode.Create))
using (var entryStream = entry.Open())
{
entryStream.CopyTo(streamWriter);
stream.CopyTo(streamWriter);
}
d.Remove(fileName);
@@ -107,7 +106,7 @@ namespace Umbraco.Core.Packaging
{
var retVal = expectedFiles.ToList();
ReadZipfileEntries(packageFilePath, zipEntry =>
ReadZipfileEntries(packageFilePath, (zipEntry, stream) =>
{
string fileName = Path.GetFileName(zipEntry.Name);
@@ -126,7 +125,7 @@ namespace Umbraco.Core.Packaging
var dictionary = new Dictionary<string, List<string>>();
ReadZipfileEntries(packageFilePath, entry =>
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower();
@@ -149,42 +148,53 @@ namespace Umbraco.Core.Packaging
{
CheckPackageExists(packageFilePath);
var files = new HashSet<string>(filesToGet.Select(f => f.ToLowerInvariant()));
var files = new HashSet<string>(filesToGet.Select(f => f.ToLower()));
using (var fs = File.OpenRead(packageFilePath))
using (var zipArchive = new ZipArchive(fs))
using (var fs = File.OpenRead(packageFilePath))
{
foreach (var zipEntry in zipArchive.Entries)
using (var zipInputStream = new ZipInputStream(fs))
{
if (zipEntry.Name.IsNullOrWhiteSpace() && zipEntry.FullName.EndsWith("/")) continue;
if (files.Contains(zipEntry.Name.ToLowerInvariant()))
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.GetNextEntry()) != null)
{
using (var memStream = new MemoryStream())
using (var entryStream = zipEntry.Open())
if (zipEntry.IsDirectory) continue;
if (files.Contains(zipEntry.Name))
{
entryStream.CopyTo(memStream);
memStream.Close();
yield return memStream.ToArray();
using (var memStream = new MemoryStream())
{
zipInputStream.CopyTo(memStream);
yield return memStream.ToArray();
memStream.Close();
}
}
}
zipInputStream.Close();
}
fs.Close();
}
}
private void ReadZipfileEntries(string packageFilePath, Func<ZipArchiveEntry, bool> entryFunc, bool skipsDirectories = true)
private void ReadZipfileEntries(string packageFilePath, Func<ZipEntry, ZipInputStream, bool> entryFunc, bool skipsDirectories = true)
{
CheckPackageExists(packageFilePath);
using (var fs = File.OpenRead(packageFilePath))
using (var zipArchive = new ZipArchive(fs))
{
foreach (var zipEntry in zipArchive.Entries)
using (var zipInputStream = new ZipInputStream(fs))
{
if (zipEntry.Name.IsNullOrWhiteSpace() && zipEntry.FullName.EndsWith("/") && skipsDirectories)
continue;
if (entryFunc(zipEntry) == false) break;
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.GetNextEntry()) != null)
{
if (zipEntry.IsDirectory && skipsDirectories) continue;
if (entryFunc(zipEntry, zipInputStream) == false) break;
}
zipInputStream.Close();
}
fs.Close();
}
}
}
@@ -98,18 +98,18 @@ namespace Umbraco.Core.Persistence.Factories
{
//NOTE Currently doesn't add Alias (legacy that eventually will go away)
var documentDto = new DocumentDto
{
Newest = true,
NodeId = entity.Id,
Published = entity.Published,
Text = entity.Name,
UpdateDate = entity.UpdateDate,
WriterUserId = entity.WriterId,
VersionId = entity.Version,
ExpiresDate = null,
ReleaseDate = null,
ContentVersionDto = BuildContentVersionDto(entity)
};
{
Newest = true,
NodeId = entity.Id,
Published = entity.Published,
Text = entity.Name,
UpdateDate = entity.UpdateDate,
WriterUserId = entity.WriterId,
VersionId = entity.Version,
ExpiresDate = null,
ReleaseDate = null,
ContentVersionDto = BuildContentVersionDto(entity)
};
if (entity.Template != null && entity.Template.Id > 0)
documentDto.TemplateId = entity.Template.Id;
@@ -5,7 +5,6 @@ using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Factories
{
internal class MacroFactory
{
public IMacro BuildEntity(MacroDto dto)
@@ -1,6 +1,5 @@
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
@@ -10,17 +9,20 @@ namespace Umbraco.Core.Persistence.Factories
{
private readonly IMediaType _contentType;
private readonly Guid _nodeObjectTypeId;
private readonly int _id;
private int _primaryKey;
public MediaFactory(IMediaType contentType, Guid nodeObjectTypeId)
public MediaFactory(IMediaType contentType, Guid nodeObjectTypeId, int id)
{
_contentType = contentType;
_nodeObjectTypeId = nodeObjectTypeId;
_id = id;
}
public MediaFactory(Guid nodeObjectTypeId)
public MediaFactory(Guid nodeObjectTypeId, int id)
{
_nodeObjectTypeId = nodeObjectTypeId;
_id = id;
}
#region Implementation of IEntityFactory<IMedia,ContentVersionDto>
@@ -62,27 +64,15 @@ namespace Umbraco.Core.Persistence.Factories
return BuildEntity(dto, _contentType);
}
public MediaDto BuildDto(IMedia entity)
public ContentVersionDto BuildDto(IMedia entity)
{
var versionDto = new ContentVersionDto
{
NodeId = entity.Id,
VersionDate = entity.UpdateDate,
VersionId = entity.Version,
ContentDto = BuildContentDto(entity)
};
//Extract the media path for storage
string mediaPath;
TryMatch(entity.GetValue<string>("umbracoFile"), out mediaPath);
var dto = new MediaDto()
{
NodeId = entity.Id,
ContentVersionDto = versionDto,
MediaPath = mediaPath,
VersionId = entity.Version
};
var dto = new ContentVersionDto
{
NodeId = entity.Id,
VersionDate = entity.UpdateDate,
VersionId = entity.Version,
ContentDto = BuildContentDto(entity)
};
return dto;
}
@@ -129,30 +119,5 @@ namespace Umbraco.Core.Persistence.Factories
return nodeDto;
}
private static readonly Regex MediaPathPattern = new Regex(@"(/media/.+?)(?:['""]|$)", RegexOptions.Compiled);
/// <summary>
/// Try getting a media path out of the string being stored for media
/// </summary>
/// <param name="text"></param>
/// <param name="mediaPath"></param>
/// <returns></returns>
internal static bool TryMatch(string text, out string mediaPath)
{
mediaPath = null;
if (string.IsNullOrWhiteSpace(text))
return false;
var match = MediaPathPattern.Match(text);
if (match.Success == false || match.Groups.Count != 2)
return false;
var url = match.Groups[1].Value;
mediaPath = url;
return true;
}
}
}
@@ -36,7 +36,6 @@ namespace Umbraco.Core.Persistence.Factories
user.Avatar = dto.Avatar;
user.EmailConfirmedDate = dto.EmailConfirmedDate;
user.InvitedDate = dto.InvitedDate;
user.TourData = dto.TourData;
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -70,8 +69,7 @@ namespace Umbraco.Core.Persistence.Factories
UpdateDate = entity.UpdateDate,
Avatar = entity.Avatar,
EmailConfirmedDate = entity.EmailConfirmedDate,
InvitedDate = entity.InvitedDate,
TourData = entity.TourData
InvitedDate = entity.InvitedDate
};
foreach (var startNodeId in entity.StartContentIds)
@@ -1,47 +0,0 @@
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Mappers
{
[MapperFor(typeof(AuditItem))]
[MapperFor(typeof(IAuditItem))]
public sealed class AuditMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
public AuditMapper(ISqlSyntaxProvider sqlSyntax) : base(sqlSyntax)
{
}
//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 AuditMapper()
{
BuildMap();
}
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if (PropertyInfoCache.IsEmpty)
{
CacheMap<AuditItem, LogDto>(src => src.Id, dto => dto.NodeId);
CacheMap<AuditItem, LogDto>(src => src.CreateDate, dto => dto.Datestamp);
CacheMap<AuditItem, LogDto>(src => src.UserId, dto => dto.UserId);
CacheMap<AuditItem, LogDto>(src => src.AuditType, dto => dto.Header);
CacheMap<AuditItem, LogDto>(src => src.Comment, dto => dto.Comment);
}
}
#endregion
}
}
@@ -43,28 +43,27 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
{3, typeof (ContentDto)},
{4, typeof (ContentVersionDto)},
{5, typeof (DocumentDto)},
{6, typeof (MediaDto)},
{7, typeof (ContentTypeTemplateDto)},
{8, typeof (DataTypeDto)},
{9, typeof (DataTypePreValueDto)},
{10, typeof (DictionaryDto)},
{11, typeof (LanguageDto)},
{12, typeof (LanguageTextDto)},
{13, typeof (DomainDto)},
{14, typeof (LogDto)},
{15, typeof (MacroDto)},
{16, typeof (MacroPropertyDto)},
{17, typeof (MemberTypeDto)},
{18, typeof (MemberDto)},
{19, typeof (Member2MemberGroupDto)},
{20, typeof (ContentXmlDto)},
{21, typeof (PreviewXmlDto)},
{22, typeof (PropertyTypeGroupDto)},
{23, typeof (PropertyTypeDto)},
{24, typeof (PropertyDataDto)},
{25, typeof (RelationTypeDto)},
{26, typeof (RelationDto)},
{6, typeof (ContentTypeTemplateDto)},
{7, typeof (DataTypeDto)},
{8, typeof (DataTypePreValueDto)},
{9, typeof (DictionaryDto)},
{10, typeof (LanguageDto)},
{11, typeof (LanguageTextDto)},
{12, typeof (DomainDto)},
{13, typeof (LogDto)},
{14, typeof (MacroDto)},
{15, typeof (MacroPropertyDto)},
{16, typeof (MemberTypeDto)},
{17, typeof (MemberDto)},
{18, typeof (Member2MemberGroupDto)},
{19, typeof (ContentXmlDto)},
{20, typeof (PreviewXmlDto)},
{21, typeof (PropertyTypeGroupDto)},
{22, typeof (PropertyTypeDto)},
{23, typeof (PropertyDataDto)},
{24, typeof (RelationTypeDto)},
{25, typeof (RelationDto)},
{28, typeof (TagDto)},
{29, typeof (TagRelationshipDto)},
@@ -92,7 +91,6 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
{52, typeof (UserGroup2NodePermissionDto) },
{53, typeof (UserGroup2AppDto) },
{54, typeof (UserStartNodeDto) },
{55, typeof (UserLoginDto)}
};
#endregion
@@ -148,12 +148,6 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
return new Version(7, 6, 0);
}
//if the error is for cmsMedia it must be the previous version to 7.8 since that is when it is added
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("cmsMedia"))))
{
return new Version(7, 7, 0);
}
return UmbracoVersion.Current;
}
@@ -1,101 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.8.0", 1, Constants.System.UmbracoMigrationName)]
public class AddCmsMediaTable : MigrationBase
{
public AddCmsMediaTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("cmsMedia") == false)
{
Create.Table<MediaDto>();
MigrateMediaPaths();
}
}
private void MigrateMediaPaths()
{
Execute.Code(database =>
{
//Due to how much data there can be and that this query will result in executing an Index Scan on the cmsPropertyData PK
//which will literally iterate over every row in there (assume there's 1,000,000 and you can see why this will perform
//horribly) ultimately we need to fix this: http://issues.umbraco.org/issue/U4-10286
//so in the meantime I've found an ugly query to work around this Index Scan issue which is to use a sub-query of Ids.
//Doing this results in the same Index Scan taking place but it only visits the explicit rows that are provided, not every row
//in the cmsPropertyData table. This results in a tremendously faster query when there is tons of data.
//The will return any media property in nvarchar or ntext that is an umbracoFile that is not null.
//This will give us the least amount of data returned to work with.
var sql = @"SELECT cmsPropertyData.dataNvarchar, cmsPropertyData.dataNtext, umbracoNode.id, cmsContentVersion.VersionId
FROM cmsPropertyData
INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid
INNER JOIN umbracoNode ON umbracoNode.id = cmsPropertyData.contentNodeId
INNER JOIN cmsContentVersion ON cmsContentVersion.ContentId = umbracoNode.id
WHERE cmsPropertyType.Alias = (@alias)
AND umbracoNode.id IN (SELECT umbracoNode.id
FROM umbracoNode
INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id
INNER JOIN cmsContentType ON cmsContentType.nodeId = cmsContent.contentType
INNER JOIN cmsPropertyType ON cmsPropertyType.contentTypeId = cmsContentType.nodeId
WHERE cmsPropertyType.Alias = (@alias) AND umbracoNode.nodeObjectType = (@nodeObjectType))
AND (cmsPropertyData.dataNvarchar IS NOT NULL OR cmsPropertyData.dataNtext IS NOT NULL)";
var paths = new List<MediaDto>();
//using QUERY = a db cursor, we won't load this all into memory first, just row by row
foreach (var row in database.Query<dynamic>(sql, new {alias = "umbracoFile", nodeObjectType = Constants.ObjectTypes.Media}))
{
var id = (int) row.id;
var versionId = (Guid)row.VersionId;
string mediaPath = null;
//if there's values in dataNvarchar then ensure there's a media path match and extract it
if (row.dataNvarchar != null && MediaFactory.TryMatch((string) row.dataNvarchar, out mediaPath))
{
paths.Add(new MediaDto
{
MediaPath = mediaPath,
NodeId = id,
VersionId = versionId
});
}
//if there's values in dataNtext then ensure there's a media path match and extract it
else if (row.dataNtext != null && MediaFactory.TryMatch((string) row.dataNtext, out mediaPath))
{
paths.Add(new MediaDto
{
MediaPath = mediaPath,
NodeId = id,
VersionId = versionId
});
}
}
//now we need to insert paths for each item
database.BulkInsertRecords(paths, SqlSyntax);
return null;
});
}
public override void Down()
{
}
}
}
@@ -1,48 +0,0 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.8.0", 0, Constants.System.UmbracoMigrationName)]
public class AddIndexToPropertyTypeAliasColumn : MigrationBase
{
public AddIndexToPropertyTypeAliasColumn(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{ }
public override void Up()
{
Execute.Code(database =>
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsPropertyTypeAlias")) == false)
{
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
//we can apply the index
localContext.Create.Index("IX_cmsPropertyTypeAlias").OnTable("cmsPropertyType")
.OnColumn("Alias")
.Ascending()
.WithOptions()
.NonClustered();
return localContext.GetSql();
}
return null;
});
}
public override void Down()
{
Delete.Index("IX_cmsPropertyTypeAlias").OnTable("cmsPropertyType");
}
}
}
@@ -1,32 +0,0 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.8.0", 2, Constants.System.UmbracoMigrationName)]
public class AddInstructionCountColumn : MigrationBase
{
public AddInstructionCountColumn(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
//Don't exeucte if the column is already there
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoCacheInstruction") && x.ColumnName.InvariantEquals("instructionCount")) == false)
Create.Column("instructionCount")
.OnTable("umbracoCacheInstruction")
.AsInt32()
.WithDefaultValue(1)
.NotNullable();
}
public override void Down()
{
}
}
}
@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.8.0", 1, Constants.System.UmbracoMigrationName)]
public class AddTourDataUserColumn : MigrationBase
{
public AddTourDataUserColumn(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
//Don't exeucte if the column is already there
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("tourData")) == false)
{
var textType = SqlSyntax.GetSpecialDbType(SpecialDbTypes.NTEXT);
Create.Column("tourData").OnTable("umbracoUser").AsCustom(textType).Nullable();
}
}
public override void Down()
{
}
}
}
@@ -1,29 +0,0 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.8.0", 4, Constants.System.UmbracoMigrationName)]
public class AddUserLoginTable : MigrationBase
{
public AddUserLoginTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("umbracoUserLogin") == false)
{
Create.Table<UserLoginDto>();
}
}
public override void Down()
{
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Data;
using System.Data.SqlClient;
using Umbraco.Core.Persistence.FaultHandling;
namespace Umbraco.Core.Persistence
@@ -1,12 +1,16 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlServerCe;
using System.Linq;
using System.Text.RegularExpressions;
using MySql.Data.MySqlClient;
using StackExchange.Profiling.Data;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence
@@ -38,12 +38,8 @@ namespace Umbraco.Core.Persistence
_tableDefinition = DefinitionFactory.GetTableDefinition(sqlSyntaxProvider, pd.type);
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.type);
//Only return real columns, do not include columns that are result columns
_readerColumns = pd.Columns
.Where(x => x.Value.ResultColumn == false)
.Select(x => x.Value)
.ToArray();
_readerColumns = pd.Columns.Select(x => x.Value).ToArray();
_sqlSyntaxProvider = sqlSyntaxProvider;
_enumerator = dataSource.GetEnumerator();
_columnDefinitions = _tableDefinition.Columns.ToArray();
@@ -1,113 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
internal class AuditRepository : PetaPocoRepositoryBase<int, IAuditItem>, IAuditRepository
internal class AuditRepository : PetaPocoRepositoryBase<int, AuditItem>, IAuditRepository
{
public AuditRepository(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{
}
/// <summary>
/// Return the audit items as paged result
/// </summary>
/// <param name="query">
/// The query coming from the service
/// </param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection"></param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// A user supplied custom filter
/// </param>
/// <returns></returns>
public IEnumerable<IAuditItem> GetPagedResultsByQuery(IQuery<IAuditItem> query, long pageIndex, int pageSize,
out long totalRecords, Direction orderDirection,
AuditType[] auditTypeFilter,
IQuery<IAuditItem> customFilter)
protected override void PersistNewItem(AuditItem entity)
{
if (auditTypeFilter == null) auditTypeFilter = new AuditType[0];
var sql = GetBaseQuery(false);
if (query == null) query = new Query<IAuditItem>();
var translatorIds = new SqlTranslator<IAuditItem>(sql, query);
var translatedQuery = translatorIds.Translate();
var customFilterWheres = customFilter != null ? customFilter.GetWhereClauses().ToArray() : null;
var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0;
if (hasCustomFilter)
{
var filterSql = new Sql();
var first = true;
foreach (var filterClaus in customFilterWheres)
{
if (first == false)
{
filterSql.Append(" AND ");
}
filterSql.Append(string.Format("({0})", filterClaus.Item1), filterClaus.Item2);
first = false;
}
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql);
}
if (auditTypeFilter.Length > 0)
{
var filterSql = new Sql();
var first = true;
foreach (var filterClaus in auditTypeFilter)
{
if (first == false || hasCustomFilter)
{
filterSql.Append(" AND ");
}
filterSql.Append("(logHeader = @logHeader)", new {logHeader = filterClaus.ToString() });
first = false;
}
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql);
}
if (orderDirection == Direction.Descending)
translatedQuery.OrderByDescending("Datestamp");
else
translatedQuery.OrderBy("Datestamp");
// Get page of results and total count
var pagedResult = Database.Page<LogDto>(pageIndex + 1, pageSize, translatedQuery);
totalRecords = pagedResult.TotalItems;
var pages = pagedResult.Items.Select(
dto => new AuditItem(dto.Id, dto.Comment, Enum<AuditType>.Parse(dto.Header), dto.UserId)).ToArray();
//Mapping the DateStamp
for (int i = 0; i < pages.Length; i++)
{
pages[i].CreateDate = pagedResult.Items[i].Datestamp;
}
return pages;
throw new NotImplementedException();
}
protected override void PersistUpdatedItem(IAuditItem entity)
#region Not Implemented - not needed
protected override void PersistUpdatedItem(AuditItem entity)
{
Database.Insert(new LogDto
{
@@ -119,40 +35,26 @@ namespace Umbraco.Core.Persistence.Repositories
});
}
protected override AuditItem PerformGet(int id)
{
throw new NotImplementedException();
}
protected override IEnumerable<AuditItem> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
protected override IEnumerable<AuditItem> PerformGetByQuery(IQuery<AuditItem> query)
{
throw new NotImplementedException();
}
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql()
.Select(isCount ? "COUNT(*)" : "umbracoLog.id, umbracoLog.userId, umbracoLog.NodeId, umbracoLog.Datestamp, umbracoLog.logHeader, umbracoLog.logComment, umbracoUser.userName, umbracoUser.avatar as userAvatar")
.From<LogDto>(SqlSyntax);
if (isCount == false)
{
sql = sql.LeftJoin<UserDto>(SqlSyntax).On<UserDto, LogDto>(SqlSyntax, dto => dto.Id, dto => dto.UserId);
}
return sql;
}
#region Not Implemented - not needed currently
protected override void PersistNewItem(IAuditItem entity)
{
throw new NotImplementedException();
}
protected override IAuditItem PerformGet(int id)
{
throw new NotImplementedException();
}
protected override IEnumerable<IAuditItem> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
protected override IEnumerable<IAuditItem> PerformGetByQuery(IQuery<IAuditItem> query)
{
throw new NotImplementedException();
}
protected override string GetBaseWhereClause()
{
throw new NotImplementedException();
@@ -169,33 +71,6 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql)
{
Sql filteredSql;
// Apply filter
if (filterSql != null)
{
var sqlFilter = " WHERE " + filterSql.SQL.TrimStart("AND ");
//NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql
// instance a couple of times to get the parameter order correct, for some reason the first
// time the arguments don't show up correctly but the SQL argument parameter names are actually updated
// accordingly - so we re-create it again. In v8 we don't need to do this and it's already taken care of.
filteredSql = new Sql(sql.SQL, sql.Arguments);
var args = filteredSql.Arguments.Concat(filterSql.Arguments).ToArray();
filteredSql = new Sql(
string.Format("{0} {1}", filteredSql.SQL, sqlFilter),
args);
filteredSql = new Sql(filteredSql.SQL, args);
}
else
{
//copy to var so that the original isn't changed
filteredSql = new Sql(sql.SQL, sql.Arguments);
}
return filteredSql;
}
}
}
@@ -901,7 +901,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
public void AddOrUpdatePermissions(ContentPermissionSet permission)
{
_permissionRepository.AddOrUpdate(permission);
}
}
/// <summary>
/// Used to remove the content xml for a content item
@@ -1075,8 +1075,8 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
}
#endregion
}
#endregion
#endregion
protected override string GetDatabaseFieldNameForOrderBy(string orderBy)
{
//Some custom ones
@@ -1,37 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using Umbraco.Core.Auditing;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IAuditRepository : IRepository<int, IAuditItem>
public interface IAuditRepository : IRepository<int, AuditItem>
{
/// <summary>
/// Return the audit items as paged result
/// </summary>
/// <param name="query">
/// The query coming from the service
/// </param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection"></param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// A user supplied custom filter
/// </param>
/// <returns></returns>
IEnumerable<IAuditItem> GetPagedResultsByQuery(
IQuery<IAuditItem> query,
long pageIndex, int pageSize, out long totalRecords,
Direction orderDirection,
AuditType[] auditTypeFilter,
IQuery<IAuditItem> customFilter);
}
}
@@ -9,8 +9,6 @@ namespace Umbraco.Core.Persistence.Repositories
{
public interface IMediaRepository : IRepositoryVersionable<int, IMedia>, IRecycleBinRepository<IMedia>, IReadRepository<Guid, IMedia>, IDeleteMediaFilesRepository
{
IMedia GetMediaByPath(string mediaPath);
/// <summary>
/// Used to add/update published xml for the media item
/// </summary>
@@ -91,12 +91,7 @@ namespace Umbraco.Core.Persistence.Repositories
IProfile GetProfile(string username);
IProfile GetProfile(int id);
IDictionary<UserState, int> GetUserStates();
Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true);
bool ValidateLoginSession(int userId, Guid sessionId);
int ClearLoginSessions(int userId);
int ClearLoginSessions(TimeSpan timespan);
void ClearLoginSession(Guid sessionId);
IDictionary<UserState, int> GetUserStates();
}
}
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text;
using System.Xml.Linq;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -87,7 +87,7 @@ namespace Umbraco.Core.Persistence.Repositories
#region Overrides of PetaPocoRepositoryBase<int,IMedia>
private Sql GetBaseQuery(BaseQueryType queryType, bool includeFilePaths)
protected override Sql GetBaseQuery(BaseQueryType queryType)
{
var sql = new Sql();
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsContentVersion.contentId" : "*"))
@@ -95,26 +95,14 @@ namespace Umbraco.Core.Persistence.Repositories
.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (includeFilePaths)
{
sql.InnerJoin<MediaDto>(SqlSyntax)
.On<MediaDto, ContentVersionDto>(SqlSyntax, left => left.VersionId, right => right.VersionId);
}
//TODO: IF we want to enable querying on content type information this will need to be joined
//.InnerJoin<ContentTypeDto>(SqlSyntax)
//.On<ContentDto, ContentTypeDto>(SqlSyntax, left => left.ContentTypeId, right => right.NodeId, SqlSyntax);
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId, SqlSyntax)
//TODO: IF we want to enable querying on content type information this will need to be joined
//.InnerJoin<ContentTypeDto>(SqlSyntax)
//.On<ContentDto, ContentTypeDto>(SqlSyntax, left => left.ContentTypeId, right => right.NodeId, SqlSyntax);
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
return sql;
}
protected override Sql GetBaseQuery(BaseQueryType queryType)
{
return GetBaseQuery(queryType, false);
}
protected override Sql GetBaseQuery(bool isCount)
{
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
@@ -140,7 +128,6 @@ namespace Umbraco.Core.Persistence.Repositories
"DELETE FROM cmsDocument WHERE nodeId = @Id",
"DELETE FROM cmsPropertyData WHERE contentNodeId = @Id",
"DELETE FROM cmsPreviewXml WHERE nodeId = @Id",
"DELETE FROM cmsMedia WHERE nodeId = @Id",
"DELETE FROM cmsContentVersion WHERE ContentId = @Id",
"DELETE FROM cmsContentXml WHERE nodeId = @Id",
"DELETE FROM cmsContent WHERE nodeId = @Id",
@@ -380,7 +367,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
var factory = new MediaFactory(NodeObjectTypeId);
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
var dto = factory.BuildDto(entity);
//NOTE Should the logic below have some kind of fallback for empty parent ids ?
@@ -393,7 +380,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sortOrder = maxSortOrder + 1;
//Create the (base) node data - umbracoNode
var nodeDto = dto.ContentVersionDto.ContentDto.NodeDto;
var nodeDto = dto.ContentDto.NodeDto;
nodeDto.Path = parent.Path;
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
nodeDto.SortOrder = sortOrder;
@@ -428,21 +415,15 @@ namespace Umbraco.Core.Persistence.Repositories
entity.Level = level;
//Create the Content specific data - cmsContent
var contentDto = dto.ContentVersionDto.ContentDto;
var contentDto = dto.ContentDto;
contentDto.NodeId = nodeDto.NodeId;
Database.Insert(contentDto);
//Create the first version - cmsContentVersion
//Assumes a new Version guid and Version date (modified date) has been set
var contentVersionDto = dto.ContentVersionDto;
contentVersionDto.NodeId = nodeDto.NodeId;
Database.Insert(contentVersionDto);
//Create the Media specific data for this version - cmsMedia
//Assumes a new Version guid has been generated
dto.NodeId = nodeDto.NodeId;
Database.Insert(dto);
//Create the PropertyData for this version - cmsPropertyData
var propertyFactory = new PropertyFactory(entity.ContentType.CompositionPropertyTypes.ToArray(), entity.Version, entity.Id);
var propertyDataDtos = propertyFactory.BuildDto(entity.Properties);
@@ -490,14 +471,14 @@ namespace Umbraco.Core.Persistence.Repositories
entity.SortOrder = maxSortOrder + 1;
}
var factory = new MediaFactory(NodeObjectTypeId);
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
//Look up Content entry to get Primary for updating the DTO
var contentDto = Database.First<ContentDto>("WHERE nodeId = @Id", new { Id = entity.Id });
var contentDto = Database.SingleOrDefault<ContentDto>("WHERE nodeId = @Id", new { Id = entity.Id });
factory.SetPrimaryKey(contentDto.PrimaryKey);
var dto = factory.BuildDto(entity);
//Updates the (base) node data - umbracoNode
var nodeDto = dto.ContentVersionDto.ContentDto.NodeDto;
var nodeDto = dto.ContentDto.NodeDto;
nodeDto.ValidatePathWithException();
var o = Database.Update(nodeDto);
@@ -505,18 +486,15 @@ namespace Umbraco.Core.Persistence.Repositories
if (contentDto.ContentTypeId != entity.ContentTypeId)
{
//Create the Content specific data - cmsContent
var newContentDto = dto.ContentVersionDto.ContentDto;
var newContentDto = dto.ContentDto;
Database.Update(newContentDto);
}
//In order to update the ContentVersion we need to retrieve its primary key id
var contentVerDto = Database.First<ContentVersionDto>("WHERE VersionId = @Version", new { Version = entity.Version });
dto.ContentVersionDto.Id = contentVerDto.Id;
var contentVerDto = Database.SingleOrDefault<ContentVersionDto>("WHERE VersionId = @Version", new { Version = entity.Version });
dto.Id = contentVerDto.Id;
//Updates the current version - cmsContentVersion
//Assumes a Version guid exists and Version date (modified date) has been set/updated
Database.Update(dto.ContentVersionDto);
//now update the media entry
Database.Update(dto);
//Create the PropertyData for this version - cmsPropertyData
@@ -661,39 +639,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
}
#endregion
/// <summary>
/// Gets an <see cref="IMedia"/> object from the path stored in the for the media item.
/// </summary>
/// <param name="mediaPath">Path of the media item to retrieve (for example: /media/1024/koala_403x328.jpg)</param>
/// <returns><see cref="IMedia"/></returns>
public IMedia GetMediaByPath(string mediaPath)
{
var umbracoFileValue = mediaPath;
const string pattern = ".*[_][0-9]+[x][0-9]+[.].*";
var isResized = Regex.IsMatch(mediaPath, pattern);
// If the image has been resized we strip the "_403x328" of the original "/media/1024/koala_403x328.jpg" url.
if (isResized)
{
var underscoreIndex = mediaPath.LastIndexOf('_');
var dotIndex = mediaPath.LastIndexOf('.');
umbracoFileValue = string.Concat(mediaPath.Substring(0, underscoreIndex), mediaPath.Substring(dotIndex));
}
var sql = GetBaseQuery(BaseQueryType.FullSingle, true);
sql.Where<MediaDto>(mediaDto => mediaDto.MediaPath == umbracoFileValue, SqlSyntax);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, sql);
return content;
}
#endregion
/// <summary>
/// Gets paged media results
@@ -757,8 +703,8 @@ namespace Umbraco.Core.Persistence.Repositories
if (EnsureUniqueNaming == false)
return nodeName;
var names = Database.Fetch<SimilarNodeName>("SELECT id, text AS name FROM umbracoNode WHERE nodeObjectType=@objectType AND parentId=@parentId",
new { objectType = NodeObjectTypeId, parentId });
var names = Database.Fetch<SimilarNodeName>("SELECT id, text AS name FROM umbracoNode WHERE nodeObjectType=@objectType AND parentId=@parentId",
new { objectType = NodeObjectTypeId, parentId });
return SimilarNodeName.GetUniqueName(names, id, nodeName);
}
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories
public IMemberGroup GetByName(string name)
{
return IsolatedCache.GetCacheItem<IMemberGroup>(
string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name),
string.Format("{0}.{1}", typeof(IMemberGroup).FullName, name),
() =>
{
var qry = new Query<IMemberGroup>().Where(group => group.Name.Equals(name));
@@ -140,7 +140,7 @@ namespace Umbraco.Core.Persistence.Repositories
return result.FirstOrDefault();
},
//cache for 5 mins since that is the default in the RuntimeCacheProvider
TimeSpan.FromMinutes(5),
TimeSpan.FromMinutes(5),
//sliding is true
true);
}
@@ -337,4 +337,4 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal static event TypedEventHandler<IMemberGroupRepository, SaveEventArgs<IMemberGroup>> SavedMemberGroup;
}
}
}
@@ -1,9 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -48,16 +53,15 @@ namespace Umbraco.Core.Persistence.Repositories
@"DELETE FROM umbracoRedirectUrl WHERE umbracoRedirectUrl.id IN(
SELECT TB1.id FROM umbracoRedirectUrl as TB1
INNER JOIN umbracoNode as TB2 ON TB1.contentKey = TB2.uniqueId
WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
FormatDeleteStatement("umbracoUserStartNode", "startNode"),
FormatUpdateStatement("umbracoUserGroup", "startContentId"),
FormatUpdateStatement("umbracoUserGroup", "startMediaId"),
FormatUpdateStatement("umbracoUserGroup", "startMediaId"),
FormatDeleteStatement("umbracoRelation", "parentId"),
FormatDeleteStatement("umbracoRelation", "childId"),
FormatDeleteStatement("cmsTagRelationship", "nodeId"),
FormatDeleteStatement("umbracoDomains", "domainRootStructureID"),
FormatDeleteStatement("cmsDocument", "nodeId"),
FormatDeleteStatement("cmsMedia", "nodeId"),
FormatDeleteStatement("cmsPropertyData", "contentNodeId"),
FormatDeleteStatement("cmsPreviewXml", "nodeId"),
FormatDeleteStatement("cmsContentVersion", "ContentId"),
@@ -4,6 +4,7 @@ using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Scoping;
@@ -20,6 +20,12 @@ namespace Umbraco.Core.Persistence.Repositories
var name = Name;
// cater for instances where node has no name.
if(string.IsNullOrWhiteSpace(name))
{
return _numPos;
}
if (name[name.Length - 1] != ')')
return _numPos = -1;
@@ -106,7 +112,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
return uniqueing || string.IsNullOrWhiteSpace(nodeName) ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
}
}
}
@@ -6,7 +6,6 @@ using System.Linq.Expressions;
using System.Text;
using System.Web.Security;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
@@ -188,8 +187,8 @@ UNION
SELECT '5CountOfInvited' AS colName, COUNT(id) AS num FROM umbracoUser WHERE lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL
ORDER BY colName";
var result = Database.Fetch<dynamic>(sql);
var result = Database.Fetch<dynamic>(sql);
return new Dictionary<UserState, int>
{
{UserState.All, (int)result[0].num},
@@ -200,83 +199,6 @@ ORDER BY colName";
};
}
public Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true)
{
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
//and also business logic models for these objects but that's just so overkill for what we are doing
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
var now = DateTime.UtcNow;
var dto = new UserLoginDto
{
UserId = userId,
IpAddress = requestingIpAddress,
LoggedInUtc = now,
LastValidatedUtc = now,
LoggedOutUtc = null,
SessionId = Guid.NewGuid()
};
Database.Insert(dto);
if (cleanStaleSessions)
{
ClearLoginSessions(TimeSpan.FromDays(15));
}
return dto.SessionId;
}
public bool ValidateLoginSession(int userId, Guid sessionId)
{
var found = Database.FirstOrDefault<UserLoginDto>("WHERE sessionId=@sessionId", new {sessionId = sessionId});
if (found == null || found.UserId != userId || found.LoggedOutUtc.HasValue)
return false;
//now detect if there's been a timeout
if (DateTime.UtcNow - found.LastValidatedUtc > TimeSpan.FromMinutes(GlobalSettings.TimeOutInMinutes))
{
//timeout detected, update the record
ClearLoginSession(sessionId);
return false;
}
//update the validate date
found.LastValidatedUtc = DateTime.UtcNow;
Database.Update(found);
return true;
}
public int ClearLoginSessions(int userId)
{
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
//and also business logic models for these objects but that's just so overkill for what we are doing
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
var count = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUserLogin WHERE userId=@userId", new { userId = userId });
Database.Execute("DELETE FROM umbracoUserLogin WHERE userId=@userId", new {userId = userId});
return count;
}
public int ClearLoginSessions(TimeSpan timespan)
{
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
//and also business logic models for these objects but that's just so overkill for what we are doing
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
var fromDate = DateTime.UtcNow - timespan;
var count = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate });
Database.Execute("DELETE FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate });
return count;
}
public void ClearLoginSession(Guid sessionId)
{
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
//and also business logic models for these objects but that's just so overkill for what we are doing
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
Database.Execute("UPDATE umbracoUserLogin SET loggedOutUtc=@now WHERE sessionId=@sessionId",
new { now = DateTime.UtcNow, sessionId = sessionId });
}
protected override IEnumerable<IUser> PerformGetAll(params int[] ids)
{
var sql = GetQueryWithGroups();
@@ -479,8 +401,7 @@ ORDER BY colName";
{"updateDate", "UpdateDate"},
{"avatar", "Avatar"},
{"emailConfirmedDate", "EmailConfirmedDate"},
{"invitedDate", "InvitedDate"},
{"tourData", "TourData"}
{"invitedDate", "InvitedDate"}
};
//create list of properties that have changed
@@ -913,6 +834,14 @@ ORDER BY colName";
{
return dtos.Select(UserFactory.BuildEntity);
}
//private IEnumerable<IUserGroup> ConvertFromDtos(IEnumerable<UserGroupDto> dtos)
//{
// return dtos.Select(dto =>
// {
// var userGroupFactory = new UserGroupFactory();
// return userGroupFactory.BuildEntity(dto);
// });
//}
}
}
+5 -5
View File
@@ -1,8 +1,10 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Umbraco.Core")]
@@ -10,8 +12,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("Umbraco CMS")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -48,8 +50,6 @@ using System.Runtime.InteropServices;
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
[assembly: InternalsVisibleTo("Umbraco.Headless")]
//allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
@@ -40,12 +40,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
//TODO: Change all singleton access to use ctor injection in v8!!!
//TODO: That would mean that property value converters would need to be request lifespan, hrm....
bool isDebug = HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled;
var gridConfig = UmbracoConfig.For.GridConfig(
ApplicationContext.Current.ProfilingLogger.Logger,
ApplicationContext.Current.ApplicationCache.RuntimeCache,
new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins)),
new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Config)),
HttpContext.Current.IsDebuggingEnabled);
isDebug);
var sections = GetArray(obj, "sections");
foreach (var section in sections.Cast<JObject>())
@@ -112,4 +113,4 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
}
}
}
}
@@ -18,6 +18,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias);
}
private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" };
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
// data is (both in database and xml):
@@ -53,7 +55,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
// Fall back on normal behaviour
if (values.Any() == false)
{
return sourceString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
return sourceString.Split(NewLineDelimiters, StringSplitOptions.None);
}
return values.ToArray();
+14
View File
@@ -116,5 +116,19 @@ namespace Umbraco.Core.Scoping
Enlisted[key] = enlistedOfT;
return enlistedOfT.Item;
}
public T GetEnlisted<T>(string key)
{
var enlistedObjects = _enlisted;
if (enlistedObjects == null) return default (T);
IEnlistedObject enlisted;
if (enlistedObjects.TryGetValue(key, out enlisted) == false)
return default (T);
var enlistedAs = enlisted as EnlistedObject<T>;
if (enlistedAs == null) throw new InvalidOperationException("An item with the key exists, but with a different type.");
return enlistedAs.Item;
}
}
}
@@ -11,14 +11,12 @@ using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Security;
using Microsoft.AspNet.Identity;
using AutoMapper;
using Microsoft.Owin;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Logging;
using IUser = Umbraco.Core.Models.Membership.IUser;
namespace Umbraco.Core.Security
{
@@ -243,11 +241,8 @@ namespace Umbraco.Core.Security
/// <param name="userdata"></param>
public static FormsAuthenticationTicket CreateUmbracoAuthTicket(this HttpContextBase http, UserData userdata)
{
//ONLY used by BasePage.doLogin!
if (http == null) throw new ArgumentNullException("http");
if (userdata == null) throw new ArgumentNullException("userdata");
if (userdata == null) throw new ArgumentNullException("userdata");
var userDataString = JsonConvert.SerializeObject(userdata);
return CreateAuthTicketAndCookie(
http,
@@ -259,7 +254,14 @@ namespace Umbraco.Core.Security
1440,
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName,
UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain);
}
}
internal static FormsAuthenticationTicket CreateUmbracoAuthTicket(this HttpContext http, UserData userdata)
{
if (http == null) throw new ArgumentNullException("http");
if (userdata == null) throw new ArgumentNullException("userdata");
return new HttpContextWrapper(http).CreateUmbracoAuthTicket(userdata);
}
/// <summary>
/// returns the number of seconds the user has until their auth session times out
@@ -329,23 +331,7 @@ namespace Umbraco.Core.Security
/// <param name="http"></param>
/// <param name="cookieName"></param>
private static void Logout(this HttpContextBase http, string cookieName)
{
//We need to clear the sessionId from the database. This is legacy code to do any logging out and shouldn't really be used at all but in any case
//we need to make sure the session is cleared. Due to the legacy nature of this it means we need to use singletons
if (http.User != null)
{
var claimsIdentity = http.User.Identity as ClaimsIdentity;
if (claimsIdentity != null)
{
var sessionId = claimsIdentity.FindFirstValue(Constants.Security.SessionIdClaimType);
Guid guidSession;
if (sessionId.IsNullOrWhiteSpace() == false && Guid.TryParse(sessionId, out guidSession))
{
ApplicationContext.Current.Services.UserService.ClearLoginSession(guidSession);
}
}
}
{
if (http == null) throw new ArgumentNullException("http");
//clear the preview cookie and external login
var cookies = new[] { cookieName, Constants.Web.PreviewCookieName, Constants.Security.BackOfficeExternalCookieName };
@@ -2,29 +2,16 @@
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.Identity;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Services;
namespace Umbraco.Core.Security
{
public class BackOfficeClaimsIdentityFactory<T> : ClaimsIdentityFactory<T, int>
where T: BackOfficeIdentityUser
{
private readonly ApplicationContext _appCtx;
[Obsolete("Use the overload specifying all dependencies instead")]
public BackOfficeClaimsIdentityFactory()
:this(ApplicationContext.Current)
{
}
public BackOfficeClaimsIdentityFactory(ApplicationContext appCtx)
{
if (appCtx == null) throw new ArgumentNullException("appCtx");
_appCtx = appCtx;
SecurityStampClaimType = Constants.Security.SessionIdClaimType;
UserNameClaimType = ClaimTypes.Name;
}
@@ -37,9 +24,9 @@ namespace Umbraco.Core.Security
public override async Task<ClaimsIdentity> CreateAsync(UserManager<T, int> manager, T user, string authenticationType)
{
var baseIdentity = await base.CreateAsync(manager, user, authenticationType);
var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity,
//NOTE - there is no session id assigned here, this is just creating the identity, a session id will be generated when the cookie is written
//set a new session id
new UserData
{
Id = user.Id,
@@ -50,22 +37,15 @@ namespace Umbraco.Core.Security
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
StartContentNodes = user.CalculatedContentStartNodeIds,
StartMediaNodes = user.CalculatedMediaStartNodeIds,
SecurityStamp = user.SecurityStamp
SessionId = user.SecurityStamp
});
return umbracoIdentity;
}
}
}
public class BackOfficeClaimsIdentityFactory : BackOfficeClaimsIdentityFactory<BackOfficeIdentityUser>
{
[Obsolete("Use the overload specifying all dependencies instead")]
public BackOfficeClaimsIdentityFactory()
{
}
{
public BackOfficeClaimsIdentityFactory(ApplicationContext appCtx) : base(appCtx)
{
}
}
}
@@ -1,83 +1,21 @@
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Globalization;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Identity;
namespace Umbraco.Core.Security
{
public class BackOfficeCookieAuthenticationProvider : CookieAuthenticationProvider
{
private readonly ApplicationContext _appCtx;
[Obsolete("Use the ctor specifying all dependencies")]
[EditorBrowsable(EditorBrowsableState.Never)]
public BackOfficeCookieAuthenticationProvider()
: this(ApplicationContext.Current)
{
}
public BackOfficeCookieAuthenticationProvider(ApplicationContext appCtx)
{
if (appCtx == null) throw new ArgumentNullException("appCtx");
_appCtx = appCtx;
}
private static readonly SemVersion MinUmbracoVersionSupportingLoginSessions = new SemVersion(7, 8);
public override void ResponseSignIn(CookieResponseSignInContext context)
{
var backOfficeIdentity = context.Identity as UmbracoBackOfficeIdentity;
if (backOfficeIdentity != null)
{
//generate a session id and assign it
//create a session token - if we are configured and not in an upgrade state then use the db, otherwise just generate one
//NOTE - special check because when we are upgrading to 7.8 we cannot create a session since the db isn't ready and we'll get exceptions
var canAcquireSession = _appCtx.IsUpgrading == false || _appCtx.CurrentVersion() >= MinUmbracoVersionSupportingLoginSessions;
var session = canAcquireSession
? _appCtx.Services.UserService.CreateLoginSession((int)backOfficeIdentity.Id, context.OwinContext.GetCurrentRequestIpAddress())
: Guid.NewGuid();
backOfficeIdentity.UserData.SessionId = session.ToString();
}
base.ResponseSignIn(context);
}
public override void ResponseSignOut(CookieResponseSignOutContext context)
{
//Clear the user's session on sign out
if (context != null && context.OwinContext != null && context.OwinContext.Authentication != null
&& context.OwinContext.Authentication.User != null && context.OwinContext.Authentication.User.Identity != null)
{
var claimsIdentity = context.OwinContext.Authentication.User.Identity as ClaimsIdentity;
var sessionId = claimsIdentity.FindFirstValue(Constants.Security.SessionIdClaimType);
Guid guidSession;
if (sessionId.IsNullOrWhiteSpace() == false && Guid.TryParse(sessionId, out guidSession))
{
_appCtx.Services.UserService.ClearLoginSession(guidSession);
}
}
base.ResponseSignOut(context);
//Make sure the definitely all of these cookies are cleared when signing out with cookies
context.Response.Cookies.Append(SessionIdValidator.CookieName, "", new CookieOptions
{
Expires = DateTime.Now.AddYears(-1),
Path = "/"
});
context.Response.Cookies.Append(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "", new CookieOptions
{
Expires = DateTime.Now.AddYears(-1),
@@ -96,45 +34,21 @@ namespace Umbraco.Core.Security
}
/// <summary>
/// Ensures that the culture is set correctly for the current back office user and that the user's session token is valid
/// Ensures that the culture is set correctly for the current back office user
/// </summary>
/// <param name="context"/>
/// <returns/>
public override async Task ValidateIdentity(CookieValidateIdentityContext context)
{
EnsureCulture(context);
await EnsureValidSessionId(context);
await base.ValidateIdentity(context);
}
/// <summary>
/// Ensures that the user has a valid session id
/// </summary>
/// <remarks>
/// So that we are not overloading the database this throttles it's check to every minute
/// </remarks>
protected virtual async Task EnsureValidSessionId(CookieValidateIdentityContext context)
{
if (_appCtx.IsConfigured && _appCtx.IsUpgrading == false)
await SessionIdValidator.ValidateSessionAsync(TimeSpan.FromMinutes(1), context);
}
private void EnsureCulture(CookieValidateIdentityContext context)
public override Task ValidateIdentity(CookieValidateIdentityContext context)
{
var umbIdentity = context.Identity as UmbracoBackOfficeIdentity;
if (umbIdentity != null && umbIdentity.IsAuthenticated)
{
Thread.CurrentThread.CurrentCulture =
Thread.CurrentThread.CurrentUICulture =
UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s));
new CultureInfo(umbIdentity.Culture);
}
}
/// <summary>
/// Used so that we aren't creating a new CultureInfo object for every single request
/// </summary>
private static readonly ConcurrentDictionary<string, CultureInfo> UserCultures = new ConcurrentDictionary<string, CultureInfo>();
return base.ValidateIdentity(context);
}
}
}
@@ -223,9 +223,6 @@ namespace Umbraco.Core.Security
user.AccessFailedCount = 0;
await UserManager.UpdateAsync(user);
//set the current request's principal to the identity just signed in!
_request.User = new ClaimsPrincipal(userIdentity);
_logger.WriteCore(TraceEventType.Information, 0,
string.Format(
"Login attempt succeeded for username {0} from IP address {1}",
@@ -152,6 +152,7 @@ namespace Umbraco.Core.Security
//NOTE: This method is mostly here for backwards compat
base.InitUserManager(manager, membershipProvider, options.DataProtectionProvider, contentSectionConfig);
}
}
/// <summary>
@@ -168,7 +169,7 @@ namespace Umbraco.Core.Security
#region What we support do not currently
//TODO: We could support this - but a user claims will mostly just be what is in the auth cookie
//NOTE: Not sure if we really want/need to ever support this
public override bool SupportsUserClaim
{
get { return false; }
@@ -270,22 +271,6 @@ namespace Umbraco.Core.Security
//manager.SmsService = new SmsService();
}
/// <summary>
/// Used to validate a user's session
/// </summary>
/// <param name="userId"></param>
/// <param name="sessionId"></param>
/// <returns></returns>
public virtual async Task<bool> ValidateSessionIdAsync(int userId, string sessionId)
{
var userSessionStore = Store as IUserSessionStore<BackOfficeIdentityUser, int>;
//if this is not set, for backwards compat (which would be super rare), we'll just approve it
if (userSessionStore == null)
return true;
return await userSessionStore.ValidateSessionIdAsync(userId, sessionId);
}
/// <summary>
/// This will determine which password hasher to use based on what is defined in config
/// </summary>
@@ -689,5 +674,4 @@ namespace Umbraco.Core.Security
return httpContext.GetCurrentRequestIpAddress();
}
}
}
@@ -26,13 +26,12 @@ namespace Umbraco.Core.Security
IUserRoleStore<BackOfficeIdentityUser, int>,
IUserSecurityStampStore<BackOfficeIdentityUser, int>,
IUserLockoutStore<BackOfficeIdentityUser, int>,
IUserTwoFactorStore<BackOfficeIdentityUser, int>,
IUserSessionStore<BackOfficeIdentityUser, int>
IUserTwoFactorStore<BackOfficeIdentityUser, int>
//TODO: This would require additional columns/tables for now people will need to implement this on their own
//IUserPhoneNumberStore<BackOfficeIdentityUser, int>,
//TODO: To do this we need to implement IQueryable - we'll have an IQuerable implementation soon with the UmbracoLinqPadDriver implementation
//IQueryableUserStore<BackOfficeIdentityUser, int>
//TODO: This would require additional columns/tables for now people will need to implement this on their own
//IUserPhoneNumberStore<BackOfficeIdentityUser, int>,
//TODO: To do this we need to implement IQueryable - we'll have an IQuerable implementation soon with the UmbracoLinqPadDriver implementation
//IQueryableUserStore<BackOfficeIdentityUser, int>
{
private readonly IUserService _userService;
private readonly IEntityService _entityService;
@@ -754,15 +753,6 @@ namespace Umbraco.Core.Security
if (_disposed)
throw new ObjectDisposedException(GetType().Name);
}
public Task<bool> ValidateSessionIdAsync(int userId, string sessionId)
{
Guid guidSessionId;
if (Guid.TryParse(sessionId, out guidSessionId))
{
return Task.FromResult(_userService.ValidateLoginSession(userId, guidSessionId));
}
return Task.FromResult(false);
}
}
}
@@ -1,17 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
namespace Umbraco.Core.Security
{
/// <summary>
/// An IUserStore interface part to implement if the store supports validating user session Ids
/// </summary>
/// <typeparam name="TUser"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface IUserSessionStore<TUser, in TKey> : IUserStore<TUser, TKey>, IDisposable
where TUser : class, IUser<TKey>
{
Task<bool> ValidateSessionIdAsync(int userId, string sessionId);
}
}
@@ -1,5 +1,4 @@
using System;
using System.Web;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Umbraco.Core.Models.Identity;
@@ -8,37 +7,6 @@ namespace Umbraco.Core.Security
{
public static class OwinExtensions
{
public static string GetCurrentRequestIpAddress(this IOwinContext owinContext)
{
if (owinContext == null)
{
return "Unknown, owinContext is null";
}
if (owinContext.Request == null)
{
return "Unknown, owinContext.Request is null";
}
var httpContext = owinContext.TryGetHttpContext();
if (httpContext == false)
{
return "Unknown, cannot resolve HttpContext from owinContext";
}
return httpContext.Result.GetCurrentRequestIpAddress();
}
/// <summary>
/// Nasty little hack to get httpcontextbase from an owin context
/// </summary>
/// <param name="owinContext"></param>
/// <returns></returns>
internal static Attempt<HttpContextBase> TryGetHttpContext(this IOwinContext owinContext)
{
var ctx = owinContext.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
return ctx == null ? Attempt<HttpContextBase>.Fail() : Attempt.Succeed(ctx);
}
/// <summary>
/// Gets the back office sign in manager out of OWIN
/// </summary>
@@ -1,118 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security.Cookies;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Identity;
namespace Umbraco.Core.Security
{
/// <summary>
/// Static helper class used to configure a CookieAuthenticationProvider to validate a cookie against a user's session id
/// </summary>
/// <remarks>
/// This uses another cookie to track the last checked time which is done for a few reasons:
/// * We can't use the user's auth ticket to do thsi because we'd be re-issuing the auth ticket all of the time and it would never expire
/// plus the auth ticket size is much larger than this small value
/// * This will execute quite often (every minute per user) and in some cases there might be several requests that end up re-issuing the cookie so the cookie value should be small
/// * We want to avoid the user lookup if it's not required so that will only happen when the time diff is great enough in the cookie
/// </remarks>
internal static class SessionIdValidator
{
public const string CookieName = "UMB_UCONTEXT_C";
public static async Task ValidateSessionAsync(TimeSpan validateInterval, CookieValidateIdentityContext context)
{
if (context.Request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath) == false)
return;
var valid = await ValidateSessionAsync(validateInterval, context.OwinContext, context.Options.CookieManager, context.Options.SystemClock, context.Properties.IssuedUtc, context.Identity);
if (valid == false)
{
context.RejectIdentity();
context.OwinContext.Authentication.SignOut(context.Options.AuthenticationType);
}
}
public static async Task<bool> ValidateSessionAsync(
TimeSpan validateInterval,
IOwinContext owinCtx,
ICookieManager cookieManager,
ISystemClock systemClock,
DateTimeOffset? authTicketIssueDate,
ClaimsIdentity currentIdentity)
{
if (owinCtx == null) throw new ArgumentNullException("owinCtx");
if (cookieManager == null) throw new ArgumentNullException("cookieManager");
if (systemClock == null) throw new ArgumentNullException("systemClock");
DateTimeOffset? issuedUtc = null;
var currentUtc = systemClock.UtcNow;
//read the last checked time from a custom cookie
var lastCheckedCookie = cookieManager.GetRequestCookie(owinCtx, CookieName);
if (lastCheckedCookie.IsNullOrWhiteSpace() == false)
{
DateTimeOffset parsed;
if (DateTimeOffset.TryParse(lastCheckedCookie, out parsed))
{
issuedUtc = parsed;
}
}
//no cookie, use the issue time of the auth ticket
if (issuedUtc.HasValue == false)
{
issuedUtc = authTicketIssueDate;
}
// Only validate if enough time has elapsed
var validate = issuedUtc.HasValue == false;
if (issuedUtc.HasValue)
{
var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
validate = timeElapsed > validateInterval;
}
if (validate == false)
return true;
var manager = owinCtx.GetUserManager<BackOfficeUserManager>();
if (manager == null)
return false;
var userId = currentIdentity.GetUserId<int>();
var user = await manager.FindByIdAsync(userId);
if (user == null)
return false;
var sessionId = currentIdentity.FindFirstValue(Constants.Security.SessionIdClaimType);
if (await manager.ValidateSessionIdAsync(userId, sessionId) == false)
return false;
//we will re-issue the cookie last checked cookie
cookieManager.AppendResponseCookie(
owinCtx,
CookieName,
DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz"),
new CookieOptions
{
HttpOnly = true,
Secure = GlobalSettings.UseSSL || owinCtx.Request.IsSecure,
Path = "/"
});
return true;
}
}
}
@@ -36,7 +36,6 @@ namespace Umbraco.Core.Security
var username = identity.GetUserName();
var session = identity.FindFirstValue(Constants.Security.SessionIdClaimType);
var securityStamp = identity.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType);
var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType);
var startMediaId = identity.FindFirstValue(Constants.Security.StartMediaNodeIdClaimType);
@@ -67,9 +66,8 @@ namespace Umbraco.Core.Security
var roles = identity.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToList();
var allowedApps = identity.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToList();
var userData = new UserData
{
SecurityStamp = securityStamp,
var userData = new UserData(session)
{
SessionId = session,
AllowedApplications = allowedApps.ToArray(),
Culture = culture,
@@ -191,8 +189,7 @@ namespace Umbraco.Core.Security
Constants.Security.StartContentNodeIdClaimType,
Constants.Security.StartMediaNodeIdClaimType,
ClaimTypes.Locality,
Constants.Security.SessionIdClaimType,
Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType
Constants.Security.SessionIdClaimType
};
}
}
@@ -229,7 +226,7 @@ namespace Umbraco.Core.Security
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
{
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this));
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
}
}
@@ -310,11 +307,6 @@ namespace Umbraco.Core.Security
get { return UserData.SessionId; }
}
public string SecurityStamp
{
get { return UserData.SecurityStamp; }
}
public string[] Roles
{
get { return UserData.Roles; }
+4 -10
View File
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Security
/// Use this constructor to create/assign new UserData to the ticket
/// </summary>
/// <param name="sessionId">
/// The current sessionId for the user
/// The security stamp for the user
/// </param>
public UserData(string sessionId)
{
@@ -29,18 +29,12 @@ namespace Umbraco.Core.Security
Roles = new string[] { };
}
/// <summary>
/// This is the 'sessionId' for validation
/// </summary>
[DataMember(Name = "sessionId")]
public string SessionId { get; set; }
/// <summary>
/// This is the 'security stamp' for validation
/// </summary>
[DataMember(Name = "securityStamp")]
public string SecurityStamp { get; set; }
[DataMember(Name = "sessionId")]
public string SessionId { get; set; }
[DataMember(Name = "id")]
public object Id { get; set; }
-85
View File
@@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -26,86 +22,5 @@ namespace Umbraco.Core.Services
uow.Commit();
}
}
/// <summary>
/// Returns paged items in the audit trail for a given entity
/// </summary>
/// <param name="entityId"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection">
/// By default this will always be ordered descending (newest first)
/// </param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// Optional filter to be applied
/// </param>
/// <returns></returns>
public IEnumerable<IAuditItem> GetPagedItemsByEntity(int entityId, long pageIndex, int pageSize, out long totalRecords,
Direction orderDirection = Direction.Descending,
AuditType[] auditTypeFilter = null,
IQuery<IAuditItem> customFilter = null)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
if (entityId == Constants.System.Root || entityId <= 0)
{
totalRecords = 0;
return Enumerable.Empty<IAuditItem>();
}
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
var query = Query<IAuditItem>.Builder.Where(x => x.Id == entityId);
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderDirection, auditTypeFilter, customFilter);
}
}
/// <summary>
/// Returns paged items in the audit trail for a given user
/// </summary>
/// <param name="userId"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection">
/// By default this will always be ordered descending (newest first)
/// </param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// Optional filter to be applied
/// </param>
/// <returns></returns>
public IEnumerable<IAuditItem> GetPagedItemsByUser(int userId, long pageIndex, int pageSize, out long totalRecords, Direction orderDirection = Direction.Descending, AuditType[] auditTypeFilter = null, IQuery<IAuditItem> customFilter = null)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
if (userId < 0)
{
totalRecords = 0;
return Enumerable.Empty<IAuditItem>();
}
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
var query = Query<IAuditItem>.Builder.Where(x => x.UserId == userId);
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderDirection, auditTypeFilter, customFilter);
}
}
}
}
@@ -1344,6 +1344,40 @@ namespace Umbraco.Core.Services
return content;
}
public void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0)
{
using (new WriteLock(Locker))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateContentBlueprintRepository(uow);
var contentTypeIdsA = contentTypeIds.ToArray();
var query = new Query<IContent>();
if (contentTypeIdsA.Length > 0)
{
query.Where(x => contentTypeIdsA.Contains(x.ContentTypeId));
}
var blueprints = repository.GetByQuery(query).Select(x =>
{
((Content) x).IsBlueprint = true;
return x;
}).ToArray();
foreach (var blueprint in blueprints)
{
repository.Delete(blueprint);
}
uow.Events.Dispatch(DeletedBlueprint, this, new DeleteEventArgs<IContent>(blueprints), "DeletedBlueprint");
uow.Commit();
}
}
public void DeleteBlueprintsOfType(int contentTypeId, int userId = 0)
{
DeleteBlueprintsOfTypes(new[] {contentTypeId}, userId);
}
/// <summary>
/// Saves a single <see cref="IContent"/> object
/// </summary>
@@ -2542,6 +2576,7 @@ namespace Umbraco.Core.Services
Audit(uow, AuditType.Publish, "Save and Publish performed by user", userId, content.Id);
uow.Commit();
return Attempt.If(publishStatus.StatusType == PublishStatusType.Success, publishStatus);
}
}
@@ -920,7 +920,9 @@ namespace Umbraco.Core.Services
var deletedContentTypes = new List<IContentType> { contentType };
deletedContentTypes.AddRange(GetDescendants(contentType));
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
var ids = deletedContentTypes.Select(x => x.Id).ToArray();
_contentService.DeleteContentOfTypes(ids, userId);
_contentService.DeleteBlueprintsOfTypes(ids);
repository.Delete(contentType);
deleteEventArgs.DeletedEntities = deletedContentTypes.DistinctBy(x => x.Id);
@@ -1,58 +1,9 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
public interface IAuditService : IService
{
void Add(AuditType type, string comment, int userId, int objectId);
/// <summary>
/// Returns paged items in the audit trail for a given entity
/// </summary>
/// <param name="entityId"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection">
/// By default this will always be ordered descending (newest first)
/// </param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// Optional filter to be applied
/// </param>
/// <returns></returns>
IEnumerable<IAuditItem> GetPagedItemsByEntity(int entityId, long pageIndex, int pageSize, out long totalRecords,
Direction orderDirection = Direction.Descending,
AuditType[] auditTypeFilter = null,
IQuery<IAuditItem> customFilter = null);
/// <summary>
/// Returns paged items in the audit trail for a given user
/// </summary>
/// <param name="userId"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderDirection">
/// By default this will always be ordered descending (newest first)
/// </param>
/// <param name="auditTypeFilter">
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
/// so we need to do that here
/// </param>
/// <param name="customFilter">
/// Optional filter to be applied
/// </param>
/// <returns></returns>
IEnumerable<IAuditItem> GetPagedItemsByUser(int userId, long pageIndex, int pageSize, out long totalRecords,
Direction orderDirection = Direction.Descending,
AuditType[] auditTypeFilter = null,
IQuery<IAuditItem> customFilter = null);
}
}
+3 -1
View File
@@ -101,7 +101,9 @@ namespace Umbraco.Core.Services
IContent GetBlueprintById(Guid id);
void SaveBlueprint(IContent content, int userId = 0);
void DeleteBlueprint(IContent content, int userId = 0);
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
void DeleteBlueprintsOfType(int contentTypeId, int userId = 0);
void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0);
/// <summary>
/// Gets all XML entries found in the cmsContentXml table based on the given path
+1 -30
View File
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
@@ -12,35 +11,7 @@ namespace Umbraco.Core.Services
/// Defines the UserService, which is an easy access to operations involving <see cref="IProfile"/> and eventually Users.
/// </summary>
public interface IUserService : IMembershipUserService
{
/// <summary>
/// Creates a database entry for starting a new login session for a user
/// </summary>
/// <param name="userId"></param>
/// <param name="requestingIpAddress"></param>
/// <returns></returns>
Guid CreateLoginSession(int userId, string requestingIpAddress);
/// <summary>
/// Validates that a user login session is valid/current and hasn't been closed
/// </summary>
/// <param name="userId"></param>
/// <param name="sessionId"></param>
/// <returns></returns>
bool ValidateLoginSession(int userId, Guid sessionId);
/// <summary>
/// Removes the session's validity
/// </summary>
/// <param name="sessionId"></param>
void ClearLoginSession(Guid sessionId);
/// <summary>
/// Removes all valid sessions for the user
/// </summary>
/// <param name="userId"></param>
int ClearLoginSessions(int userId);
{
/// <summary>
/// This is basically facets of UserStates key = state, value = count
/// </summary>
+62 -5
View File
@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
@@ -11,6 +12,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
@@ -41,7 +43,7 @@ namespace Umbraco.Core.Services
if (userService == null) throw new ArgumentNullException("userService");
_dataTypeService = dataTypeService;
_userService = userService;
}
}
/// <summary>
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
@@ -61,7 +63,7 @@ namespace Umbraco.Core.Services
{
var parent = GetById(parentId);
return CreateMedia(name, parent, mediaTypeAlias, userId);
}
}
/// <summary>
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
@@ -729,10 +731,65 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMedia"/></returns>
public IMedia GetMediaByPath(string mediaPath)
{
var umbracoFileValue = mediaPath;
const string Pattern = ".*[_][0-9]+[x][0-9]+[.].*";
var isResized = Regex.IsMatch(mediaPath, Pattern);
// If the image has been resized we strip the "_403x328" of the original "/media/1024/koala_403x328.jpg" url.
if (isResized)
{
var underscoreIndex = mediaPath.LastIndexOf('_');
var dotIndex = mediaPath.LastIndexOf('.');
umbracoFileValue = string.Concat(mediaPath.Substring(0, underscoreIndex), mediaPath.Substring(dotIndex));
}
Func<string, Sql> createSql = url => new Sql().Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyTypeDto>(x => x.Alias == "umbracoFile")
.Where<PropertyDataDto>(x => x.VarChar == url);
var sql = createSql(umbracoFileValue);
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetMediaByPath(mediaPath);
var propertyDataDto = uow.Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql).FirstOrDefault();
// If the stripped-down url returns null, we try again with the original url.
// Previously, the function would fail on e.g. "my_x_image.jpg"
if (propertyDataDto == null)
{
sql = createSql(mediaPath);
propertyDataDto = uow.Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql).FirstOrDefault();
}
// If no reults far, try getting from a json value stored in the ntext column query
if (propertyDataDto == null)
{
var ntextQuery = new Sql().Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyTypeDto>(x => x.Alias == "umbracoFile")
.Where("dataNtext LIKE @0", "%" + umbracoFileValue + "%");
propertyDataDto = uow.Database.Fetch<PropertyDataDto, PropertyTypeDto>(ntextQuery).FirstOrDefault();
}
// If still no results, try getting from a json value stored in the nvarchar column
if (propertyDataDto == null)
{
var nvarcharQuery = new Sql().Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyTypeDto>(x => x.Alias == "umbracoFile")
.Where("dataNvarchar LIKE @0", "%" + umbracoFileValue + "%");
propertyDataDto = uow.Database.Fetch<PropertyDataDto, PropertyTypeDto>(nvarcharQuery).FirstOrDefault();
}
return propertyDataDto == null ? null : GetById(propertyDataDto.NodeId);
}
}
@@ -964,7 +1021,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
{
saveEventArgs.CanCancel = false;
saveEventArgs.CanCancel = false;
uow.Events.Dispatch(Saved, this, saveEventArgs);
}
+1 -1
View File
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Services
IQuery<IMember> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter) || x.Email.Contains(filter));
}
var repository = RepositoryFactory.CreateMemberRepository(uow);
@@ -1748,9 +1748,10 @@ namespace Umbraco.Core.Services
internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false)
{
var metaData = GetPackageMetaData(packageFilePath);
if (raiseEvents)
{
var metaData = GetPackageMetaData(packageFilePath);
{
if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs<string>(packageFilePath, metaData), this))
{
var initEmpty = new InstallationSummary().InitEmpty();
@@ -1762,7 +1763,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
{
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, false), this);
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, metaData, false), this);
}
return installationSummary;
-41
View File
@@ -558,47 +558,6 @@ namespace Umbraco.Core.Services
}
}
public Guid CreateLoginSession(int userId, string requestingIpAddress)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateUserRepository(uow);
var session = repository.CreateLoginSession(userId, requestingIpAddress);
uow.Commit();
return session;
}
}
public int ClearLoginSessions(int userId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateUserRepository(uow);
var count = repository.ClearLoginSessions(userId);
uow.Commit();
return count;
}
}
public void ClearLoginSession(Guid sessionId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateUserRepository(uow);
repository.ClearLoginSession(sessionId);
uow.Commit();
}
}
public bool ValidateLoginSession(int userId, Guid sessionId)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserRepository(uow);
return repository.ValidateLoginSession(userId, sessionId);
}
}
public IDictionary<UserState, int> GetUserStates()
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Strings
{
foreach (var node in _umbracoSettings.RequestHandler.CharCollection)
{
if(string.IsNullOrEmpty(node.Char) == false)
if (string.IsNullOrEmpty(node.Char) == false)
_urlReplaceCharacters[node.Char] = node.Replacement;
}
}
@@ -109,7 +109,7 @@ namespace Umbraco.Core.Strings
private void EnsureNotFrozen()
{
if (_frozen)
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
}
/// <summary>
@@ -176,7 +176,7 @@ namespace Umbraco.Core.Strings
}).WithConfig(CleanStringType.Alias, new Config
{
PreFilter = ApplyUrlReplaceCharacters,
IsTerm = (c, leading) => leading
IsTerm = (c, leading) => leading
? char.IsLetter(c) // only letters
: (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore
StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase,
@@ -215,12 +215,12 @@ namespace Umbraco.Core.Strings
return new Config
{
PreFilter = PreFilter,
PostFilter = PostFilter,
PostFilter = PostFilter,
IsTerm = IsTerm,
StringType = StringType,
BreakTermsOnUpper = BreakTermsOnUpper,
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
GreedyAcronyms = GreedyAcronyms,
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
GreedyAcronyms = GreedyAcronyms,
Separator = Separator
};
}
@@ -338,9 +338,9 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// Gets the JavaScript code defining client-side short string services.
/// </summary>
public string GetShortStringServicesJavaScript(string controllerPath)
{
return string.Format(SssjsFormat,
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
{
return string.Format(SssjsFormat,
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
}
#endregion
@@ -467,7 +467,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// Cleans a string.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <returns>The clean string.</returns>
/// <remarks>The string is cleaned in the context of the default culture.</remarks>
@@ -480,7 +480,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// Cleans a string, using a specified separator.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="separator">The separator.</param>
/// <returns>The clean string.</returns>
@@ -494,7 +494,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// Cleans a string in the context of a specified culture.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="culture">The culture.</param>
/// <returns>The clean string.</returns>
@@ -507,7 +507,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// Cleans a string in the context of a specified culture, using a specified separator.
/// </summary>
/// <param name="text">The text to clean.</param>
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
/// strings are cleaned up to camelCase and Ascii.</param>
/// <param name="separator">The separator.</param>
/// <param name="culture">The culture.</param>
@@ -554,7 +554,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
text = Utf8ToAsciiConverter.ToAsciiString(text);
break;
case CleanStringType.TryAscii:
const char ESC = (char) 27;
const char ESC = (char)27;
var ctext = Utf8ToAsciiConverter.ToAsciiString(text, ESC);
if (ctext.Contains(ESC) == false) text = ctext;
break;
@@ -568,8 +568,8 @@ function validateSafeAlias(input, value, immediate, callback) {{
// apply post-filter
if (config.PostFilter != null)
text = config.PostFilter(text);
text = config.PostFilter(text);
return text;
}
@@ -839,7 +839,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
{
term = term.Substring(i);
term.CopyTo(0, output, opos, term.Length);
opos += term.Length;
opos += term.Length;
}
break;
@@ -914,21 +914,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// <returns>The filtered string.</returns>
public virtual string ReplaceMany(string text, IDictionary<string, string> replacements)
{
// be safe
if (text == null)
{
throw new ArgumentNullException("text");
}
if (replacements == null)
{
throw new ArgumentNullException("replacements");
}
// Have done various tests, implementing my own "super fast" state machine to handle
// replacement of many items, or via regexes, but on short strings and not too
// many replacements (which prob. is going to be our case) nothing can beat this...
// (at least with safe and checked code -- we don't want unsafe/unchecked here)
foreach (KeyValuePair<string, string> item in replacements)
{
text = text.Replace(item.Key, item.Value);
}
// Note that it will do chained-replacements ie replaced items can be replaced
// in turn by another replacement (ie the order of replacements is important)
return replacements.Aggregate(text, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
return text;
}
/// <summary>
@@ -940,15 +941,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
/// <returns>The filtered string.</returns>
public virtual string ReplaceMany(string text, char[] chars, char replacement)
{
// be safe
if (text == null)
{
throw new ArgumentNullException("text");
}
if (chars == null)
{
throw new ArgumentNullException("chars");
}
// see note above
for (int i = 0; i < chars.Length; i++)
{
text = text.Replace(chars[i], replacement);
}
return chars.Aggregate(text, (current, c) => current.Replace(c, replacement));
return text;
}
#endregion
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Sync
if (newApplicationUrl)
{
appContext._umbracoApplicationDomains.Add(applicationUrl);
LogHelper.Info(typeof(ApplicationUrlHelper), $"New ApplicationUrl detected: {applicationUrl}");
LogHelper.Info(typeof(ApplicationUrlHelper), string.Format("New ApplicationUrl detected: {0}", applicationUrl));
}
}
@@ -169,4 +169,4 @@ namespace Umbraco.Core.Sync
return url.TrimEnd('/');
}
}
}
}
@@ -87,8 +87,7 @@ namespace Umbraco.Core.Sync
{
UtcStamp = DateTime.UtcNow,
Instructions = JsonConvert.SerializeObject(instructions, Formatting.None),
OriginIdentity = LocalIdentity,
InstructionCount = instructions.Sum(x => x.JsonIdCount)
OriginIdentity = LocalIdentity
};
ApplicationContext.DatabaseContext.Database.Insert(dto);
@@ -166,10 +165,10 @@ namespace Umbraco.Core.Sync
}
else
{
//check for how many instructions there are to process, each row contains a count of the number of instructions contained in each
//row so we will sum these numbers to get the actual count.
var count = _appContext.DatabaseContext.Database
.ExecuteScalar<int>("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
//check for how many instructions there are to process
//TODO: In 7.6 we need to store the count of instructions per row since this is not affective because there can be far more than one (if not thousands)
// of instructions in a single row.
var count = _appContext.DatabaseContext.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
if (count > Options.MaxProcessingInstructionCount)
{
//too many instructions, proceed to cold boot
@@ -206,7 +205,7 @@ namespace Umbraco.Core.Sync
/// <summary>
/// Synchronize the server (throttled).
/// </summary>
protected internal void Sync()
protected void Sync()
{
lock (_locko)
{
+4 -35
View File
@@ -18,10 +18,7 @@ namespace Umbraco.Core.Sync
// need this public, parameter-less constructor so the web service messenger
// can de-serialize the instructions it receives
public RefreshInstruction()
{
//set default - this value is not used for reading after it's been deserialized, it's only used for persisting the instruction to the db
JsonIdCount = 1;
}
{ }
// need this public one so it can be de-serialized - used by the Json thing
// otherwise, should use GetInstructions(...)
@@ -33,16 +30,12 @@ namespace Umbraco.Core.Sync
IntId = intId;
JsonIds = jsonIds;
JsonPayload = jsonPayload;
//set default - this value is not used for reading after it's been deserialized, it's only used for persisting the instruction to the db
JsonIdCount = 1;
}
private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType)
{
RefresherId = refresher.UniqueIdentifier;
RefreshType = refreshType;
//set default - this value is not used for reading after it's been deserialized, it's only used for persisting the instruction to the db
JsonIdCount = 1;
}
private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType, Guid guidId)
@@ -57,21 +50,9 @@ namespace Umbraco.Core.Sync
IntId = intId;
}
/// <summary>
/// A private constructor to create a new instance
/// </summary>
/// <param name="refresher"></param>
/// <param name="refreshType"></param>
/// <param name="json"></param>
/// <param name="idCount">
/// When the refresh method is <see cref="RefreshMethodType.RefreshByIds"/> we know how many Ids are being refreshed so we know the instruction
/// count which will be taken into account when we store this count in the database.
/// </param>
private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType, string json, int idCount = 1)
private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType, string json)
: this(refresher, refreshType)
{
JsonIdCount = idCount;
if (refreshType == RefreshMethodType.RefreshByJson)
JsonPayload = json;
else
@@ -96,12 +77,8 @@ namespace Umbraco.Core.Sync
case MessageType.RefreshById:
if (idType == null)
throw new InvalidOperationException("Cannot refresh by id if idType is null.");
if (idType == typeof(int))
{
// bulk of ints is supported
var intIds = ids.Cast<int>().ToArray();
return new[] { new RefreshInstruction(refresher, RefreshMethodType.RefreshByIds, JsonConvert.SerializeObject(intIds), intIds.Length) };
}
if (idType == typeof (int)) // bulk of ints is supported
return new[] { new RefreshInstruction(refresher, RefreshMethodType.RefreshByIds, JsonConvert.SerializeObject(ids.Cast<int>().ToArray())) };
// else must be guids, bulk of guids is not supported, iterate
return ids.Select(x => new RefreshInstruction(refresher, RefreshMethodType.RefreshByGuid, (Guid) x));
@@ -144,14 +121,6 @@ namespace Umbraco.Core.Sync
/// </summary>
public string JsonIds { get; set; }
/// <summary>
/// Gets or sets the number of Ids contained in the JsonIds json value
/// </summary>
/// <remarks>
/// This is used to determine the instruction count per row
/// </remarks>
public int JsonIdCount { get; set; }
/// <summary>
/// Gets or sets the payload data value.
/// </summary>
+4 -5
View File
@@ -26,7 +26,7 @@ namespace Umbraco.Core
{ AnyGuid, UdiType.GuidUdi },
{ Document, UdiType.GuidUdi },
{ DocumentBlueprint, UdiType.GuidUdi },
{ DocumentBluePrint, UdiType.GuidUdi },
{ Media, UdiType.GuidUdi },
{ Member, UdiType.GuidUdi },
{ DictionaryItem, UdiType.GuidUdi },
@@ -68,7 +68,7 @@ namespace Umbraco.Core
public const string Document = "document";
public const string DocumentBlueprint = "document-blueprint";
public const string DocumentBluePrint = "document-blueprint";
public const string Media = "media";
public const string Member = "member";
@@ -80,7 +80,6 @@ namespace Umbraco.Core
public const string DocumentType = "document-type";
public const string DocumentTypeContainer = "document-type-container";
//TODO: What is this? This alias is only used for the blue print tree to render the blueprint's document type, it's not a real udi type
public const string DocumentTypeBluePrints = "document-type-blueprints";
public const string MediaType = "media-type";
public const string MediaTypeContainer = "media-type-container";
@@ -119,7 +118,7 @@ namespace Umbraco.Core
case UmbracoObjectTypes.Document:
return Document;
case UmbracoObjectTypes.DocumentBlueprint:
return DocumentBlueprint;
return DocumentBluePrint;
case UmbracoObjectTypes.Media:
return Media;
case UmbracoObjectTypes.Member:
@@ -164,7 +163,7 @@ namespace Umbraco.Core
{
case Document:
return UmbracoObjectTypes.Document;
case DocumentBlueprint:
case DocumentBluePrint:
return UmbracoObjectTypes.DocumentBlueprint;
case Media:
return UmbracoObjectTypes.Media;
+1 -1
View File
@@ -132,7 +132,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IContent entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(entity.IsBlueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, entity.Key).EnsureClosed();
return new GuidUdi(entity.IsBlueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, entity.Key).EnsureClosed();
}
/// <summary>
+6 -20
View File
@@ -43,12 +43,15 @@
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
<Reference Include="ClientDependency.Core, Version=1.9.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.6\lib\net45\ClientDependency.Core.dll</HintPath>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll</HintPath>
</Reference>
@@ -105,8 +108,6 @@
</Reference>
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Linq.Expressions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
@@ -178,7 +179,6 @@
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
<Compile Include="Collections\DeepCloneableList.cs" />
<Compile Include="Collections\ListCloneBehavior.cs" />
<Compile Include="Collections\TypeList.cs" />
<Compile Include="ConcurrentHashSet.cs" />
<Compile Include="Configuration\BaseRest\IBaseRestSection.cs" />
<Compile Include="Configuration\BaseRest\IExtension.cs" />
@@ -239,7 +239,6 @@
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoSettings\AppCodeFileExtensionsCollection.cs" />
<Compile Include="Configuration\UmbracoSettings\AppCodeFileExtensionsElement.cs" />
<Compile Include="Configuration\UmbracoSettings\BackOfficeElement.cs" />
<Compile Include="Configuration\UmbracoSettings\CharCollection.cs" />
<Compile Include="Configuration\UmbracoSettings\CharElement.cs" />
<Compile Include="Configuration\CommaDelimitedConfigurationElement.cs" />
@@ -248,7 +247,6 @@
<Compile Include="Configuration\UmbracoSettings\ContentErrorPageElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentErrorsElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentSectionExtensions.cs" />
<Compile Include="Configuration\UmbracoSettings\IBackOfficeSection.cs" />
<Compile Include="Configuration\UmbracoSettings\ImagingAutoFillPropertiesCollection.cs" />
<Compile Include="Configuration\UmbracoSettings\ImagingAutoFillUploadFieldElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentImagingElement.cs" />
@@ -284,7 +282,6 @@
<Compile Include="Configuration\UmbracoSettings\ISecuritySection.cs" />
<Compile Include="Configuration\UmbracoSettings\IServer.cs" />
<Compile Include="Configuration\UmbracoSettings\ITemplatesSection.cs" />
<Compile Include="Configuration\UmbracoSettings\ITourSection.cs" />
<Compile Include="Configuration\UmbracoSettings\IUmbracoSettingsSection.cs" />
<Compile Include="Configuration\UmbracoSettings\IViewStateMoverModuleSection.cs" />
<Compile Include="Configuration\UmbracoSettings\IWebRoutingSection.cs" />
@@ -315,7 +312,6 @@
<Compile Include="Configuration\UmbracoSettings\ServerCollection.cs" />
<Compile Include="Configuration\UmbracoSettings\ServerElement.cs" />
<Compile Include="Configuration\UmbracoSettings\TemplatesElement.cs" />
<Compile Include="Configuration\UmbracoSettings\TourConfigElement.cs" />
<Compile Include="Configuration\UmbracoSettings\UmbracoConfigurationElement.cs" />
<Compile Include="Configuration\UmbracoSettings\UmbracoSettingsSection.cs" />
<Compile Include="Configuration\UmbracoSettings\UrlReplacingElement.cs" />
@@ -364,7 +360,6 @@
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
<Compile Include="Models\EntityBase\EntityPath.cs" />
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
<Compile Include="Models\IAuditItem.cs" />
<Compile Include="Models\IUserControl.cs" />
<Compile Include="Models\Membership\ContentPermissionSet.cs" />
<Compile Include="Models\Membership\EntityPermissionCollection.cs" />
@@ -376,8 +371,6 @@
<Compile Include="Models\Membership\UserState.cs" />
<Compile Include="Models\Membership\UserType.cs" />
<Compile Include="Models\PublishedContent\PublishedContentTypeConverter.cs" />
<Compile Include="Models\Rdbms\MediaDto.cs" />
<Compile Include="Models\Rdbms\UserLoginDto.cs" />
<Compile Include="Models\Rdbms\UserStartNodeDto.cs" />
<Compile Include="Models\UserControl.cs" />
<Compile Include="OrderedHashSet.cs" />
@@ -539,18 +532,12 @@
<Compile Include="Persistence\LockedRepository.cs" />
<Compile Include="Persistence\LockingRepository.cs" />
<Compile Include="Persistence\Mappers\AccessMapper.cs" />
<Compile Include="Persistence\Mappers\AuditMapper.cs" />
<Compile Include="Persistence\Mappers\DomainMapper.cs" />
<Compile Include="Persistence\Mappers\ExternalLoginMapper.cs" />
<Compile Include="Persistence\Mappers\MigrationEntryMapper.cs" />
<Compile Include="Persistence\Mappers\UserGroupMapper.cs" />
<Compile Include="Persistence\Migrations\LocalMigrationContext.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourOneZero\AddPreviewXmlTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddTourDataUserColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddIndexToPropertyTypeAliasColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddInstructionCountColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddCmsMediaTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddUserLoginTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\AddIndexToDictionaryKeyColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\EnsureContentTemplatePermissions.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\ReduceDictionaryKeyColumnsSize.cs" />
@@ -698,13 +685,11 @@
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
<Compile Include="Security\IMembershipProviderPasswordHasher.cs" />
<Compile Include="Security\IUserAwarePasswordHasher.cs" />
<Compile Include="Security\IUserSessionStore.cs" />
<Compile Include="Security\MachineKeyGenerator.cs" />
<Compile Include="Security\MembershipProviderPasswordHasher.cs" />
<Compile Include="Security\EmailService.cs" />
<Compile Include="Security\MembershipProviderPasswordValidator.cs" />
<Compile Include="Security\OwinExtensions.cs" />
<Compile Include="Security\SessionIdValidator.cs" />
<Compile Include="Security\UmbracoEmailMessage.cs" />
<Compile Include="Security\UserAwareMembershipProviderPasswordHasher.cs" />
<Compile Include="SemVersionExtensions.cs" />
@@ -1546,6 +1531,7 @@
<Compile Include="ReadLock.cs" />
<Compile Include="TypeFinder.cs" />
<Compile Include="TypeHelper.cs" />
<Compile Include="Collections\CompositeTypeTypeKey.cs" />
<Compile Include="Udi.cs" />
<Compile Include="UdiDefinitionAttribute.cs" />
<Compile Include="UdiEntityType.cs" />

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