Compare commits

..

169 Commits

Author SHA1 Message Date
Warren Buckley ac496b0cf6 Updates version to beta02 - after Warren forgot to merge & push AccessToInternals for Forms before public beta 2017-03-20 15:40:15 +00:00
Warren Buckley 6036136938 Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6
# Conflicts:
#	build/UmbracoVersion.txt
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
2017-03-20 14:55:29 +00:00
Sebastiaan Janssen f4eb37d44d Missing null check (for unit test) 2017-03-17 12:11:28 +01:00
Sebastiaan Janssen c79aaa9c48 Bumps version 2017-03-17 11:49:42 +01:00
Sebastiaan Janssen e3bc6f148a New installer background image 2017-03-17 11:35:15 +01:00
Warren Buckley a43bd13e6a Merge pull request #1798 from umbraco/temp-U4-9621
Fixes: U4-9621 More UI color tweaks
2017-03-16 15:31:30 +00:00
Warren Buckley 6aa00c52dc Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6 2017-03-16 15:08:33 +00:00
Mads Rasmussen 30d5bfa7b4 move nonode css to less file, update grunt build + update no node colors + font 2017-03-16 15:49:59 +01:00
Stephan 9b8db111dd Merge pull request #1790 from umbraco/temp-U4-9611
U4-9611 Create Property Value Converters for all new UDI Property Edi…
2017-03-16 14:36:17 +01:00
Stephan 7b506fadc6 U4-9611 - minor fix 2017-03-16 14:35:54 +01:00
Claus 1ce44565a3 Merge pull request #1764 from umbraco/temp-u4-9462
U4-9462 units of work cleanup
2017-03-16 13:12:32 +01:00
Stephan e70e651901 U4-9462 - minor fix 2017-03-16 13:10:53 +01:00
Mads Rasmussen 00b0515fc1 Revert "less bright and "dangerous" alerts, notifications and validation messages"
This reverts commit 691c13d1e1.
2017-03-16 10:31:48 +01:00
Morten Christensen d8c04b1f67 Merge pull request #1799 from umbraco/temp-U4-9632
U4-9632 Ensure GUID generation on updated entity types in v7.6 is unique
2017-03-16 10:09:31 +01:00
Shannon 172ef8c379 U4-7093 If allowManuallyChangingPassword=false on new install, installation doesn't work 2017-03-16 18:59:06 +11:00
Claus 7e1f045c09 U4-9632 Ensure GUID generation on updated entity types in v7.6 is unique
removing unused using statements from other migrations.
2017-03-16 08:19:03 +01:00
Sebastiaan Janssen d2fdf7b647 Check if MediaPicker is configured as single or multiple and give back appropriate result for each (IPublishedContent vs IEnumerable<IPublishedContent>) 2017-03-15 23:22:53 +01:00
Sebastiaan Janssen e1942d96d0 Incorporate Stephane's feedback: if we already know we're getting list of int or udi, we don't need to cast, or even test for the PropertyEditorAlias 2017-03-15 23:22:53 +01:00
Stephan 496e6c1711 U4-9462 - missed one safeXml.AcceptChanges 2017-03-15 14:50:42 +01:00
Mads Rasmussen c9fc0fbed1 Update installer gray buttons to purple buttons + align label with input 2017-03-15 14:35:11 +01:00
Stephan 3121ea6111 Merge branch 'dev-v7.6' into temp-u4-9462 2017-03-15 13:48:27 +01:00
Stephan 59ecc6e109 Merge branch 'dev-v7.6' into temp-U4-9611 2017-03-15 13:00:07 +01:00
Stephan eb42b9a4b6 Merge pull request #1796 from umbraco/temp-U4-6566
U4-6566 Membership provider `useLegacyEncoding` should default to `false`
2017-03-15 12:37:09 +01:00
Stephan 82660cf6af Merge branch 'dev-v7.6' into temp-U4-9611 2017-03-15 12:10:27 +01:00
Stephan 54afd3d954 Fix failing test 2017-03-15 12:08:52 +01:00
Mads Rasmussen 9ee3471153 add font smoothing to installer 2017-03-15 10:38:42 +01:00
Mads Rasmussen 691c13d1e1 less bright and "dangerous" alerts, notifications and validation messages 2017-03-15 10:26:05 +01:00
Sebastiaan Janssen 241ccf00a5 U4-6566 Membership provider useLegacyEncoding should default to false 2017-03-14 17:05:24 +01:00
Sebastiaan Janssen 1a0046df95 Merge pull request #1795 from umbraco/temp-U4-9498
U4-9498 LocalLinks as UDI
2017-03-14 15:54:03 +01:00
Warren Buckley 30f63eefb3 Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6 2017-03-14 10:18:00 +00:00
Warren Buckley 6114193fd5 Bump version to alpha 75 2017-03-14 10:17:43 +00:00
Warren Buckley 82420605ef Allow Forms Assemblies to access internals in Umbraco.Core - Required to use AppContext.ScopeProvider for Scope Events for Deploy 2017-03-14 10:01:23 +00:00
Sebastiaan Janssen 3bddceb17b Put the rewrite section in system.webServer where it belongs 2017-03-14 11:00:41 +01:00
Sebastiaan Janssen a2ca753dd9 Use RelatedLink class instead of weird extra inline class, convert UDI values 2017-03-14 10:26:13 +01:00
Sebastiaan Janssen 6f516a15aa Boyscout cleanup 2017-03-14 10:25:10 +01:00
Sebastiaan Janssen 223ed41c53 Use the extension method to get published content item - consistent with other PVCs 2017-03-14 10:24:31 +01:00
Sebastiaan Janssen d2a3932626 Merge branch 'dev-v7.6' into temp-U4-9611 2017-03-14 10:22:39 +01:00
Sebastiaan Janssen 27fab61646 Merge pull request #1792 from umbraco/temp-U4-9497
U4-9497 Update Related Links Property Editor to support UDIs
2017-03-14 10:14:45 +01:00
Shannon 05f8870424 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-03-14 17:25:40 +11:00
Shannon 4a829154db Adds documentation link to IIS Rewrite rules 2017-03-14 17:10:39 +11:00
Shannon f8073f429f adds debug transforms to ensure that any urlrewriting stuff is removed when the sln is built 2017-03-14 16:36:15 +11:00
Shannon 0a3220df85 Fixes null check, adds another test case 2017-03-14 16:26:17 +11:00
Shannon Deminick 04d37c590b Merge pull request #1786 from umbraco/temp-U4-9004
U4-9004 Remove URLRewriting.net dependency
2017-03-14 16:25:41 +11:00
Shannon 9a57f463ce Updates LocalLinks to be UDI, this will support both INT and UDI as LocalLink but when a new LocalLink is picked, it will use the UDI so eventually the INT will be gone 2017-03-14 15:31:30 +11:00
Mads Rasmussen fdfae0f78a increase font size for template insert description 2017-03-13 22:43:24 +01:00
Mads Rasmussen 9ebe7f683a increase font size for validation label 2017-03-13 22:40:12 +01:00
Mads Rasmussen 185af08e75 increase header description font-size 2017-03-13 21:02:43 +01:00
Mads Rasmussen 874c679bfe update tree header 2017-03-13 20:53:55 +01:00
Mads Rasmussen 76a6449ffa increase font size on actions menu 2017-03-13 20:47:36 +01:00
Mads Rasmussen fd8e200bd7 make property editor placeholder lighter + increase font size 2017-03-13 20:38:02 +01:00
Mads Rasmussen aa7e739b0e increase sections label font size 2017-03-13 20:09:44 +01:00
Mads Rasmussen 97f379ff44 add more contrast to placeholder text 2017-03-13 20:06:57 +01:00
Sebastiaan Janssen 3904f9c503 Centralized getting an IPublishedContent item from a Udi in a single extension method so that we're not repeating that code all over the place all the time 2017-03-13 15:49:15 +01:00
Warren Buckley 7753993987 Adds in more checks for the UDI or int to be stored - as there is a similar call to open the dialog to pick content from another function name - unknown why
Same for persisting data
2017-03-13 13:48:13 +00:00
Shannon 8f48da8bb0 Gets the related links editor working with the old property value converter too, udpates the install script so that works and updates tests to reference the correct one, adds GUID overloads to the UrlProvider 2017-03-13 16:58:41 +11:00
Shannon aba325e109 Creates UDI Related Links Property Editor and deprecates the old one 2017-03-13 16:14:30 +11:00
Shannon 2dd31f0f05 reverts the change for the showing an error if the node doesn't exist - it was for a start node (i.e. based on a user), not for an existing picked node 2017-03-13 16:00:56 +11:00
Shannon d42d96e166 Fixes issue with new picker logic when a picked node no longer exist, this would result in a 404 error which would actually show the red error and the dialog would die, instead we handle the error and initialize the tree when were ready 2017-03-13 15:04:35 +11:00
Shannon 3571c238b4 Renames the new UDI pickers to still be suffixed with "PropertyEditor" to make things more consistent 2017-03-13 12:59:36 +11:00
Shannon 2087332b69 removes committed Deploy dashboard config 2017-03-13 12:58:44 +11:00
Shannon dc71f9cd5e Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2017-03-13 12:39:27 +11:00
Shannon 99ed4d6cb9 Makes umbraco.GlobalSettings.UmbracoMvcArea available since we haven't been able to get the GlobalSettings into the right public classes yet. 2017-03-13 12:38:08 +11:00
Shannon Deminick 3646cfb47e Merge pull request #1791 from soreng/patch-3
Removed weird comment
2017-03-12 21:37:44 +01:00
Søren Gregersen 1b7ce8bcde Removed weird comment
removed "this" as remark for NewPassword
2017-03-12 21:20:24 +01:00
Sebastiaan Janssen 89c84676dd U4-9611 Create Property Value Converters for all new UDI Property Editors 2017-03-11 16:44:57 +01:00
Shannon 1c7b374c42 Fixes new property value converters to shadow their old ones correctly 2017-03-10 12:27:29 +01:00
Shannon 7100a00ef1 fix merges 2017-03-10 12:22:44 +01:00
Shannon df04100ff6 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6
# Conflicts:
#	build/UmbracoVersion.txt
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs
#	src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/MediaService.cs
#	src/Umbraco.Core/Umbraco.Core.csproj
#	src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
#	src/Umbraco.Tests/Umbraco.Tests.csproj
#	src/Umbraco.Web.UI.Client/src/less/tree.less
#	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
2017-03-10 10:40:28 +01:00
Stephan b893df035b Files were committed by mistake 2017-03-10 08:48:26 +01:00
Sebastiaan Janssen 67c6146f96 Merge pull request #1787 from umbraco/temp-u4-9595
U4-9595 - improve log error msg on thread aborts on timeouts
2017-03-09 15:59:47 +01:00
Stephan 6439e2fdd0 Merge dev-v7.6 into temp-u4-9462 2017-03-09 15:29:26 +01:00
Sebastiaan Janssen 13aa615745 U4-9004 Remove URLRewriting.net dependency 2017-03-09 11:41:36 +01:00
Stephan b8c0d4c4ea U4-9595 - improve log error msg on thread aborts on timeouts 2017-03-09 11:35:06 +01:00
Stephan 6992b0319a Version 7.6-alpha074 2017-03-08 18:59:27 +01:00
Stephan d1111009e3 Fix SemVer lib version 2017-03-08 18:45:00 +01:00
Sebastiaan Janssen 6c624ca08a Merge pull request #1785 from CreunaAB/fix/add-missing-sv-translation
Adds missing swedish translation for document type without template
2017-03-08 15:21:55 +01:00
Shannon Deminick 1722831bf5 Merge pull request #1640 from umbraco/temp-u4-7318
Value Converters for All Core Property Editors
2017-03-08 14:29:40 +01:00
Shannon 5291558b23 Further refactoring, using attributes, moving and removing some classes, using DI where necessary. 2017-03-08 14:27:39 +01:00
nengberg 8a133938e6 Adds missing swedish translation for document type without template 2017-03-08 09:57:32 +01:00
hartvig c1b3f1977d Merge pull request #1768 from danieland/dev-v7
U4-9571: Legacy icons look weird
2017-03-07 18:58:13 +01:00
hartvig f086156d48 Merge pull request #1781 from majken92/dev-v7
Updating sv.xml with correct translation
2017-03-07 18:53:43 +01:00
hartvig 7080013dd6 Merge pull request #1777 from jamescoxhead/U4-9373
U4-9373 Fix for duplicate dashboards after upgrading
2017-03-07 18:45:50 +01:00
Michael Razmgah b080825bb2 Updating sv.xml with correct translation 2017-03-06 21:31:42 +01:00
Stephan 8bb696bf9a Merge pull request #1776 from umbraco/temp-U4-9587
U4-9587 RebuildXmlStructures doesn't clear out stale data so there is…
2017-03-06 14:51:50 +01:00
Shannon 55e8451513 changes to in groups of 2000 2017-03-06 14:44:41 +01:00
Shannon 7e4e2a1d5d Fixes query when rebuilding xml structures for a content type 2017-03-06 14:42:02 +01:00
Stephan 79d4956b75 Merge branch 'dev-v7' into temp-U4-9587 2017-03-03 13:26:43 +01:00
James Coxhead 9acfd8f5d2 Updated dashboard config transform
Fix for dupicate dashboards after upgrading
2017-03-02 21:02:25 +00:00
Shannon 0b530ce181 Fixes rebuilding xml structures when a content type is specified, we need to filter on that when looking for orphaned items. 2017-03-02 19:17:39 +01:00
Shannon 402835d72d Merge branch 'Colletz-U4-9573' into dev-v7 2017-03-02 18:45:06 +01:00
Shannon 08d579ec87 Fixes a bunch of id assignments in PublicAccessRepository along with clearing out old entries that are flagged for removal, adds a lot more assertions for retrieving items and their rules. 2017-03-02 18:44:42 +01:00
Shannon 8b92755487 Merge branch 'U4-9573' of https://github.com/Colletz/Umbraco-CMS into Colletz-U4-9573 2017-03-02 17:55:16 +01:00
Shannon 01b48107f3 ensures that the content type is not used in the query when it is null. 2017-03-02 17:45:21 +01:00
Shannon a546803970 Need to also update the health check check not just the old endpoint for non trashed media. 2017-03-02 17:40:39 +01:00
Shannon 96c28c2611 U4-9587 RebuildXmlStructures doesn't clear out stale data so there is unpublished or trashed items remaining in the xml table, xml data integrity check is misleading due to the media lookup 2017-03-02 17:28:34 +01:00
Shannon 65a22417f7 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2017-03-02 16:54:37 +01:00
Shannon 6c271e7af9 Fixes issue with U4-9456 when we use the withCache flag we do not add that to the defs collection so an error would occur if one was resolved from cache. 2017-03-02 16:54:25 +01:00
Stephan a85cafe7ab Merge pull request #1772 from umbraco/temp-U4-9577
U4-9577 Ability to store the xml content file in diff storage locatio…
2017-03-02 11:42:44 +01:00
Stephan 41d91ae791 Merge pull request #1758 from umbraco/temp-U4-9536
Updates Content/Entity repos to deal with cases where there is corrupt newest/published flags
2017-03-02 11:17:56 +01:00
Shannon Deminick dca5a26fe4 Merge pull request #1774 from umbraco/temp-9586-async-content-xml-save
Removes async from filestream instance
2017-03-02 10:49:31 +01:00
Shannon 7e8f6d391f Just to be sure, moves the text replacement outside of the using - though that wouldn't make any diff 2017-03-02 10:48:11 +01:00
Shannon 7aa00ee6e0 Removes unused method that also uses the async flag for file stream - which we know in some cases causes fcn issues, fixes streams not being closed property if there are exceptions 2017-03-02 10:37:04 +01:00
Niels Hartvig 2e027e6195 Removes async from filestream instance 2017-03-02 10:33:00 +01:00
Shannon a9c5877e5b Merge branch 'refs/heads/dev-v7.6' into temp-u4-7318
# Conflicts:
#	src/Umbraco.Web.UI/config/umbracoSettings.config
#	src/Umbraco.Web/Umbraco.Web.csproj
2017-03-01 15:04:00 +01:00
Shannon 337ba4ef34 U4-9577 Ability to store the xml content file in diff storage locations: Default, Environment Temp or ASP.NET temp location 2017-02-28 23:53:12 +01:00
Colletz 0f32c2d680 PublicAccess - Ensure correct ordering on join
Ensured the correct order on JOIN for the subsequent mapping on AccessDto and AccessRuleDto.
2017-02-28 12:43:49 +01:00
Shannon 96a18ec8e9 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into temp-U4-9536
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
2017-02-27 15:24:55 +01:00
Shannon 65c39a3117 Fixes issue with returning multiple versions and mapping their property values, adds more assertions 2017-02-27 15:19:59 +01:00
Claus 15150f9a16 Merge pull request #1763 from umbraco/temp-U4-9545
U4-9545 EntityRepository performs poorly for Media due to unnecessary outer joins
2017-02-27 12:00:06 +01:00
Claus 259879c964 just cleaning some using statements and fixing a few typos. 2017-02-27 11:59:19 +01:00
Daniel Sune Andreasen ed87789abe collides with .legacy-custom-file 2017-02-27 11:14:37 +01:00
Shannon 09492fa779 Ensures that the published data retrieved uses the latest content version PK instead of by date in case dates are exactly the same. 2017-02-24 14:14:28 +11:00
Shannon 8122c0b352 Simplifies the includeAllVersions check 2017-02-24 14:00:38 +11:00
Shannon 28f0ab1001 Fixes U4-9456, ensures that property sets are mapped to a content version instead of an Id, adds more unit tests, ensures that if this warning ever occurs in a test that the test will fail. 2017-02-24 13:51:14 +11:00
Shannon 266f82b6c5 Fixes issue with returning all versions, adds more tests/assertions, updates content and media repository to double check that the versions match before returning from cache. 2017-02-24 13:23:27 +11:00
Shannon 813a8956d3 Gets EntityRepository to deal with corrupted newest/published flags, adds tests and lots of assertions for each method 2017-02-24 12:27:36 +11:00
Shannon Deminick 0a8fa2be4d Merge pull request #1761 from abjerner/patch-16
Added support for ignoring HTTP errors directly from the Angular $http options
2017-02-23 15:50:22 +11:00
Anders Bjerner 6e347dd32c Added some extra validation 2017-02-22 17:28:40 +01:00
Sebastiaan Janssen 33c9e2b58d Merge pull request #1767 from umbraco/temp-u4-9560
U4-9560 - fix db issue
2017-02-22 16:27:20 +01:00
Stephan 16f8f6036c U4-9560 - fix db issue 2017-02-22 15:52:02 +01:00
Sebastiaan Janssen 76b696e3bf U4-9559 Security: files of type xhtml should not be allowed to be uploaded to the media section 2017-02-22 11:12:24 +01:00
Shannon 7cadbb6398 Backports some required EntityRepository changes, starts adding the custom collection to remove duplicate (throw err currently) 2017-02-22 21:09:25 +11:00
Emil Wangaa bf22399aba Fixup linendings for EntityRepository 2017-02-22 10:34:46 +01:00
Sebastiaan Janssen 0b9a3ef68a Bump version 2017-02-22 10:26:37 +01:00
Shannon f8d6c7e7d0 Fixes expression tree changes 2017-02-22 18:34:55 +11:00
Shannon 90ba9a1a3a Adds new overload to IMediaService.GetPagedChildren to filter on media type ids which turns out to be much easier than filtering on media type aliases, however i did all of the work to make that happen including unit tests and then it turned out to not be required but we now have the code if necessary, i've left comments about it. I've backported some updates from 7.6 for the SqlIn stuff for the ExpressionVisitor which we still use in the media type id filtering. I updated the JS to query for the folders which all works now. 2017-02-22 17:22:22 +11:00
Shannon 6815731da1 adds failing test that i'll need to fix 2017-02-22 13:31:04 +11:00
Stephan 4d24e7bef8 U4-9462 - more units of work cleanup 2017-02-21 13:19:58 +01:00
Stephan 8d5f7af780 U4-9462 - cleanup file unit of work 2017-02-21 13:19:58 +01:00
Stephan 08c8b84a10 U4-9462 - cleanup units of work, code, fixmes 2017-02-21 13:19:58 +01:00
Sebastiaan Janssen 52dce66598 Bump version 2017-02-21 08:49:34 +01:00
Shannon 255fec84bd Merge branch 'refs/heads/dev-v7' into temp-U4-9536 2017-02-21 17:56:39 +11:00
Shannon 9142314d39 U4-9522 Media recycle bin does not show folders 2017-02-21 14:18:49 +11:00
Shannon 27164093ea FIxes: U4-9547, Fixes: U4-9546 even though GetChildFolders isn't used anymore i made it work slightly faster 2017-02-20 18:08:55 +11:00
Shannon 67312d03d0 Fixes media query in EntityRepository, it doesn't require outer joins to get the published version, this also enhances the content query to do an inner join on cmsDocument to get the newest instead of an outer join. 2017-02-20 17:24:10 +11:00
Anders Bjerner ad9ae867c0 Added support for ignoring HTTP errors directly from the Angular $http options 2017-02-16 19:22:26 +01:00
Shannon af287c387e Adds test to show that the content repo can deal with corrupted data, this fix actually simplifies a bunch of logic too and should consume slightly less memory, have added some TODOs in the code and need to then write more tests and code to deal with this in the EntityRepository. 2017-02-16 18:54:44 +11:00
Sebastiaan Janssen acf10eeef0 U4-9532 logic in ContentRepository.ClearPublished is inefficient - cherry picked from 7.6.0 2017-02-16 08:11:35 +01:00
Stephan 44b90bd4f3 Merge branch 'dev-v7.6' into temp-u4-7318 2016-12-05 17:08:19 +01:00
Jeavon 3e558af18f Merge branch 'dev-v7' into temp-u4-7318 2016-12-05 12:21:02 +00:00
Jeavon 3774d4fc62 Adding comments to the Slider, Tags & Multiple Media picker values converters about the need to cache the prevalues 2016-12-05 12:16:43 +00:00
Jeavon a24acdb8ce Added value converter for the slider property editor and and Range class to be returned when range mode is enabled 2016-12-05 12:13:47 +00:00
Jeavon f91d5b53c1 Added a basic value converter for the tags property editor 2016-12-05 10:58:09 +00:00
Jeavon c053adc9b2 Move the Upload editor value converter from Lars to Core from Web 2016-11-03 17:06:26 +00:00
Jeavon e3bc588164 Merge pull request #1555 from lars-erik/temp-u4-7318
Added converter for upload field
2016-11-03 17:01:58 +00:00
Jeavon 392319d26c Adding check for converter enablement to James's converters that need it 2016-11-03 16:43:23 +00:00
Jeavon 584638977c Merge pull request #1570 from jamescoxhead/U4-7318
U4-7318 Core property value converters
2016-11-03 15:08:29 +00:00
Jeavon be8632db1c Adding EnablePropertyValueConverters setting to umbracoSettings.config so that all the new converters can be disabled.
Readded existing JArray converter for RelatedLinks but renamed to LegacyRelatedLinksEditorValueConvertor
2016-11-03 13:30:41 +00:00
Jeavon 094514b91a Merge branch 'dev-v7' into temp-u4-7318
# Conflicts:
#	src/Umbraco.Web/Umbraco.Web.csproj
2016-11-03 11:31:42 +00:00
James Coxhead 3c43f4f3c5 Added member picker value converter 2016-11-02 23:37:32 +00:00
James Coxhead 12f9392db9 Added user picker value converter 2016-11-02 21:52:27 +00:00
James Coxhead d787cb6ad9 Added radio button list converter 2016-11-02 21:35:42 +00:00
James Coxhead db02c3b73c Added member group picker value converter 2016-11-02 21:26:41 +00:00
James Coxhead a10214d82b Added dropdown with keys value converter 2016-11-01 23:53:55 +00:00
James Coxhead bc61054931 Added dropdown list value converter 2016-11-01 23:46:32 +00:00
James Coxhead 0becdccb68 Added dropdown list multiple with keys value converter 2016-11-01 23:38:05 +00:00
James Coxhead cee92518ea Added dropdown list multiple value converter 2016-11-01 21:44:17 +00:00
James Coxhead a34a8e180d Added checkbox list converter 2016-10-29 23:32:56 +01:00
James Coxhead f9f48753de Updated colour picker converter to return string 2016-10-29 22:51:36 +01:00
James Coxhead c9af13df78 Added email address converter 2016-10-29 22:45:48 +01:00
Lars-Erik Aabech f66b456d7c Added converter for upload field 2016-10-29 09:44:45 +02:00
Jeavon 6d722c5591 Merge branch 'temp-u4-7318' of https://github.com/umbraco/Umbraco-CMS into temp-u4-7318 2016-08-17 10:24:28 +01:00
Jeavon 9ed9aef1d3 Merge branch 'dev-v7' into temp-u4-7318
# Conflicts:
#	src/Umbraco.Web/Umbraco.Web.csproj
2016-08-17 10:16:05 +01:00
Stephan 0cc398130d Merge pull request #1311 from Jeavon/temp-u4-7318
U4-7318 - Initial import of core value converters for Stephan
2016-08-16 15:29:17 +02:00
Jeavon 927f48985e Latest updates from Core Value Converters package including massive simplification of RelatedLinks and exclusion of special property aliases in MNTP 2016-08-03 20:45:01 +01:00
Jeavon 3b31b92f1f Adding a type converter for RelatedLinks so that implementations using JArray (from official docs) still work (e.g. Model.Content.GetPropertyValue<JArray>("relatedLinks")) 2016-06-21 15:20:17 +01:00
Jeavon aaf725a498 Adding Id to the Related Link model 2016-06-21 12:49:45 +01:00
Jeavon Leopold 36aa166a95 Converters and models to support existing GetPropertyValue<int> and GetPropertyValue<string> code 2016-06-13 16:16:12 +02:00
Jeavon Leopold e7754d313e Initially adding the Core Value Converters package into Core! Currently this will break all the existing things but it makes views insanely simple with ModelsBuilder!! 2016-06-12 16:36:26 +02:00
238 changed files with 6653 additions and 2925 deletions
+2 -3
View File
@@ -36,10 +36,9 @@
<dependency id="Examine" version="[0.1.81, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.2, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.2, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
<dependency id="semver" version="[2.0.4, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.6.0, 5.0.0)" />
</dependencies>
</metadata>
@@ -41,16 +41,6 @@
views/dashboard/developer/examinemanagement.html
</control>
</tab>
<tab caption="Health Check" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
<control>
views/dashboard/developer/healthcheck.html
</control>
</tab>
<tab caption="Redirect URL Management" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
<control>
views/dashboard/developer/redirecturls.html
</control>
</tab>
</section>
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
@@ -80,4 +70,26 @@
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="RedirectUrlManagement" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<areas>
<area>content</area>
</areas>
<tab caption="Redirect URL Management">
<control>
views/dashboard/developer/redirecturls.html
</control>
</tab>
</section>
<section alias="UmbracoHealthCheck" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<areas>
<area>developer</area>
</areas>
<tab caption="Health Check">
<control>
views/dashboard/developer/healthcheck.html
</control>
</tab>
</section>
</dashBoard>
-1
View File
@@ -53,7 +53,6 @@ if ($project) {
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
# Delete files Umbraco depends upon
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
+1 -1
View File
@@ -1,3 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.6.0
alpha073
beta02
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.0")]
[assembly: AssemblyInformationalVersion("7.6.0-alpha073")]
[assembly: AssemblyInformationalVersion("7.6.0-beta02")]
+3 -3
View File
@@ -1,8 +1,6 @@
using System;
using System.Configuration;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
@@ -163,7 +161,9 @@ namespace Umbraco.Core
/// </summary>
public static ApplicationContext Current { get; internal set; }
// fixme
/// <summary>
/// Gets the scope provider.
/// </summary>
internal IScopeProvider ScopeProvider { get { return _databaseContext == null ? null : _databaseContext.ScopeProvider; } }
/// <summary>
@@ -22,12 +22,12 @@ namespace Umbraco.Core.Cache
{
private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
: base(cache)
{
{
if (options == null) throw new ArgumentNullException("options");
_options = options;
_options = options;
}
public override IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
@@ -244,9 +244,7 @@ namespace Umbraco.Core.Cache
/// <inheritdoc />
public override void ClearAll()
{
// fixme the cache should NOT contain anything else so we can clean all, can't we?
Cache.ClearAllCache();
//Cache.ClearCacheByKeySearch(GetEntityTypeCacheKey());
}
}
}
@@ -18,10 +18,17 @@ namespace Umbraco.Core.Cache
// it is not *that* complicated but then RepositoryBase needs to have a TRepository generic
// type parameter and it all becomes convoluted - keeping it simple for the time being.
// fixme explain
/// <summary>
/// Creates a scoped version of this cache policy.
/// </summary>
/// <param name="runtimeCache">The global isolated runtime cache for this policy.</param>
/// <param name="scope">The scope.</param>
/// <remarks>When a policy is scoped, it means that it has been created with a scoped
/// isolated runtime cache, and now it needs to be wrapped into something that can apply
/// changes to the global isolated runtime cache.</remarks>
IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope);
/// <summary>
/// <summary>
/// Gets an entity from the cache, else from the repository.
/// </summary>
/// <param name="id">The identifier.</param>
@@ -0,0 +1,9 @@
namespace Umbraco.Core.Configuration
{
internal enum ContentXmlStorage
{
Default,
AspNetTemp,
EnvironmentTemp
}
}
@@ -517,12 +517,25 @@ namespace Umbraco.Core.Configuration
}
internal static bool ContentCacheXmlStoredInCodeGen
{
get { return ContentCacheXmlStorageLocation == ContentXmlStorage.AspNetTemp; }
}
internal static ContentXmlStorage ContentCacheXmlStorageLocation
{
get
{
//defaults to false
return ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp")
&& bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"]); //default to false
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLStorage"))
{
return Enum<ContentXmlStorage>.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]);
}
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp"))
{
return bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"])
? ContentXmlStorage.AspNetTemp
: ContentXmlStorage.Default;
}
return ContentXmlStorage.Default;
}
}
@@ -177,6 +177,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return GetOptionalTextElement("EnableInheritedMediaTypes", true); }
}
[ConfigurationProperty("EnablePropertyValueConverters")]
internal InnerTextConfigurationElement<bool> EnablePropertyValueConverters
{
get { return GetOptionalTextElement("EnablePropertyValueConverters", false); }
}
string IContentSection.NotificationEmailAddress
{
get { return Notifications.NotificationEmailAddress; }
@@ -326,5 +332,9 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
get { return EnableInheritedMediaTypes; }
}
bool IContentSection.EnablePropertyValueConverters
{
get { return EnablePropertyValueConverters; }
}
}
}
@@ -69,5 +69,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
bool EnableInheritedDocumentTypes { get; }
bool EnableInheritedMediaTypes { get; }
bool EnablePropertyValueConverters { get; }
}
}
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "alpha073"; } }
public static string CurrentComment { get { return "beta02"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+10
View File
@@ -89,6 +89,11 @@ namespace Umbraco.Core
/// </summary>
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
/// <summary>
/// Guid for a Document object.
/// </summary>
public static readonly Guid MediaGuid = new Guid(Media);
/// <summary>
/// Guid for the Media Recycle Bin.
/// </summary>
@@ -148,6 +153,11 @@ namespace Umbraco.Core
/// </summary>
public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
/// <summary>
/// Guid for a Template object.
/// </summary>
public static readonly Guid TemplateTypeGuid = new Guid(Template);
/// <summary>
/// Guid for a Lock object.
/// </summary>
@@ -289,11 +289,14 @@ namespace Umbraco.Core
/// </summary>
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string RelatedLinks = "71B8AD1A-8DC2-425C-B6B8-FAA158075E63";
[Obsolete("This is an obsoleted picker, use RelatedLinks2Alias instead")]
public const string RelatedLinksAlias = "Umbraco.RelatedLinks";
/// <summary>
/// Alias for the Related Links datatype.
/// Alias for the Related Links property editor.
/// </summary>
public const string RelatedLinksAlias = "Umbraco.RelatedLinks";
public const string RelatedLinks2Alias = "Umbraco.RelatedLinks2";
/// <summary>
/// Guid for the Slider datatype.
-1
View File
@@ -173,7 +173,6 @@ namespace Umbraco.Core
return new ServiceContext(
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
new PetaPocoUnitOfWorkProvider(scopeProvider),
new FileUnitOfWorkProvider(scopeProvider),
ApplicationCache,
ProfilingLogger.Logger,
msgFactory);
+5 -35
View File
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlServerCe;
using System.IO;
@@ -34,7 +33,7 @@ namespace Umbraco.Core
private string _connectionString;
private string _providerName;
private DatabaseSchemaResult _result;
private DateTime? _connectionLastChecked = null;
private DateTime? _connectionLastChecked;
/// <summary>
/// The number of minutes to throttle the checks to CanConnect
@@ -99,10 +98,10 @@ namespace Umbraco.Core
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
var asDbFactory2 = factory as IDatabaseFactory2;
ScopeProvider = asDbFactory2 == null
? new ScopeProvider(new DatabaseFactoryWrapper(factory))
ScopeProvider = asDbFactory2 == null
? new ScopeProvider(new DatabaseFactoryWrapper(factory))
: new ScopeProvider(asDbFactory2);
_logger = logger;
_configured = true;
}
@@ -197,42 +196,13 @@ namespace Umbraco.Core
{
throw new InvalidOperationException("Cannot create a database instance, there is no available connection string");
}
return ScopeProvider.GetAmbientOrNoScope().Database;
//var scope = ScopeProvider.AmbientScope;
//return scope != null ? scope.Database : ScopeProvider.CreateNoScope().Database;
}
}
/// <summary>
/// Replaces the "ambient" database (if any) and by a new temp database.
/// </summary>
/// <remarks>
/// <para>The returned IDisposable *must* be diposed in order to properly dispose the temp database and
/// restore the original "ambient" database (if any).</para>
/// <para>This is to be used in background tasks to ensure that they have an "ambient" database which
/// will be properly removed from call context and does not interfere with anything else. In most case
/// it is not replacing anything, just temporarily installing a database in context.</para>
/// </remarks>
// fixme - this should just entirely be replaced by Scope?
/*
public virtual IDisposable UseSafeDatabase(bool force = false)
{
var factory = _factory as DefaultDatabaseFactory;
if (factory == null) throw new NotSupportedException();
if (DefaultDatabaseFactory.HasAmbientDatabase)
{
return force
? new UsingDatabase(DefaultDatabaseFactory.DetachAmbientDatabase(), factory.CreateDatabase())
: new UsingDatabase(null, null);
}
// create a new, temp, database (will be disposed with UsingDatabase)
return new UsingDatabase(null, factory.CreateDatabase());
}
*/
/// <summary>
/// Boolean indicating whether the database has been configured
/// </summary>
+16
View File
@@ -296,5 +296,21 @@ namespace Umbraco.Core
&& list1Groups.All(g => g.Count() == list2Groups[g.Key].Count());
}
///<summary>
/// Returns the items of the given enumerable as a pure enumerable.
/// <remarks>
/// When quering lists using methods such as <see cref="M:List.Where"/>, the result, despite appearing to look like and quack like an
/// <see cref="T:Enumerable{T}"/> the type is actually an instance of <see cref="T:System.Linq.Enumerable.WhereEnumerableIterator"/>
/// </remarks>
/// </summary>
///<param name="source">The item to find.</param>
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
internal static IEnumerable<T> Yield<T>(this IEnumerable<T> source)
{
foreach (var element in source)
{
yield return element;
}
}
}
}
@@ -16,13 +16,17 @@ namespace Umbraco.Core.Events
protected override void ScopeExitCompleted()
{
// fixme - we'd need to de-duplicate events somehow, etc - and the deduplication should be last in wins
// processing only the last instance of each event...
// this is probably far from perfect, because if eg a content is saved in a list
// and then as a single content, the two events will probably not be de-duplicated,
// but it's better than nothing
foreach (var e in GetEvents(EventDefinitionFilter.All))
foreach (var e in GetEvents(EventDefinitionFilter.LastIn))
{
e.RaiseEvent();
// fixme - not sure I like doing it here - but then where? how?
// separating concerns means that this should probably not be here,
// but then where should it be (without making things too complicated)?
var delete = e.Args as IDeletingMediaFilesEventArgs;
if (delete != null && delete.MediaFilesToDelete.Count > 0)
MediaFileSystem.DeleteMediaFiles(delete.MediaFilesToDelete);
@@ -35,13 +39,7 @@ namespace Umbraco.Core.Events
{
get
{
if (_mediaFileSystem != null) return _mediaFileSystem;
// fixme - insane! reading config goes cross AppDomain and serializes context?
using (new SafeCallContext())
{
return _mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem;
}
return _mediaFileSystem ?? (_mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem);
}
}
}
+2
View File
@@ -1,10 +1,12 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
{
/// <summary>
/// Represents a guid-based entity identifier.
/// </summary>
[TypeConverter(typeof(UdiTypeConverter))]
public class GuidUdi : Udi
{
/// <summary>
@@ -45,7 +45,8 @@ namespace Umbraco.Core.IO
private IScopeProviderInternal ScopeProvider
{
// fixme - 'course this is bad, but enough for now
// this is bad, but enough for now, and we'll refactor
// in v8 when we'll get rid of this class' singleton
// beware: means that we capture the "current" scope provider - take care in tests!
get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; }
}
+2 -26
View File
@@ -302,7 +302,7 @@ namespace Umbraco.Core.IO
{
var property = GetProperty(content, propertyTypeAlias);
var svalue = property.Value as string;
var oldpath = svalue == null ? null : GetRelativePath(svalue); // FIXME DELETE?
var oldpath = svalue == null ? null : GetRelativePath(svalue);
if (string.IsNullOrWhiteSpace(oldpath) == false && oldpath != filepath)
DeleteFile(oldpath, true);
property.Value = GetUrl(filepath);
@@ -466,27 +466,6 @@ namespace Umbraco.Core.IO
var dir = Path.GetDirectoryName(file);
DeleteDirectory(dir, true);
}
// I don't even understand...
/*
var relativeFilePath = GetRelativePath(file); // fixme - should be relative already
if (FileExists(relativeFilePath) == false) return;
var parentDirectory = Path.GetDirectoryName(relativeFilePath);
// don't want to delete the media folder if not using directories.
if (_contentSection.UploadAllowDirectories && parentDirectory != GetRelativePath("/"))
{
//issue U4-771: if there is a parent directory the recursive parameter should be true
DeleteDirectory(parentDirectory, string.IsNullOrEmpty(parentDirectory) == false);
}
else
{
DeleteFile(file, true);
}
*/
}
catch (Exception e)
{
@@ -549,7 +528,7 @@ namespace Umbraco.Core.IO
PropertyType propertyType)
{
// get the original image from the original stream
if (filestream.CanSeek) filestream.Seek(0, 0); // fixme - what if we cannot seek?
if (filestream.CanSeek) filestream.Seek(0, 0);
using (var image = Image.FromStream(filestream))
{
return GenerateThumbnails(image, filepath, propertyType);
@@ -658,9 +637,6 @@ namespace Umbraco.Core.IO
var rect = new Rectangle(0, 0, width, height);
graphics.DrawImage(originImage, rect, 0, 0, originImage.Width, originImage.Height, GraphicsUnit.Pixel);
// copy metadata
// fixme - er... no?
// get an encoder - based upon the file type
var extension = (Path.GetExtension(resizedFilepath) ?? "").TrimStart('.').ToLowerInvariant();
var encoders = ImageCodecInfo.GetImageEncoders();
+6 -2
View File
@@ -155,7 +155,9 @@ namespace Umbraco.Core.IO
if (directory == null) throw new InvalidOperationException("Could not get directory.");
Directory.CreateDirectory(directory); // ensure it exists
if (stream.CanSeek) // fixme - what else?
// if can seek, be safe and go back to start, else...
// hope that the stream hasn't been read already
if (stream.CanSeek)
stream.Seek(0, 0);
using (var destination = (Stream) File.Create(fullPath))
@@ -286,7 +288,9 @@ namespace Umbraco.Core.IO
var opath = path;
path = EnsureDirectorySeparatorChar(path);
// fixme - this part should go!
// TODO in v8 this should be cleaned up
// the first part should probably removed
// not sure what we are doing here - so if input starts with a (back) slash,
// we assume it's not a FS relative path and we try to convert it... but it
// really makes little sense?
+18 -4
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Linq;
@@ -72,15 +73,28 @@ namespace Umbraco.Core.IO
{
get
{
if (GlobalSettings.ContentCacheXmlStoredInCodeGen && SystemUtilities.GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted)
{
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
switch (GlobalSettings.ContentCacheXmlStorageLocation)
{
case ContentXmlStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
case ContentXmlStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
appDomainHash);
return Path.Combine(cachePath, "umbraco.config");
case ContentXmlStorage.Default:
return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
default:
throw new ArgumentOutOfRangeException();
}
return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
}
}
[Obsolete("Use GlobalSettings.ContentCacheXmlStoredInCodeGen instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
internal static bool ContentCacheXmlStoredInCodeGen
{
get { return GlobalSettings.ContentCacheXmlStoredInCodeGen; }
+27 -4
View File
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using log4net;
@@ -62,12 +63,34 @@ namespace Umbraco.Core.Logging
public void Error(Type callingType, string message, Exception exception)
{
var logger = LogManager.GetLogger(callingType);
if (logger != null)
logger.Error((message), exception);
var logger = LogManager.GetLogger(callingType);
if (logger == null) return;
if (IsTimeoutThreadAbortException(exception))
{
message += "\r\nThe thread has been aborted, because the request has timed out.";
}
logger.Error(message, exception);
}
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
private static bool IsTimeoutThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
if (abort.ExceptionState == null) return false;
var stateType = abort.ExceptionState.GetType();
if (stateType.FullName != "System.Web.HttpApplication+CancelModuleException") return false;
var timeoutField = stateType.GetField("_timeout", BindingFlags.Instance | BindingFlags.NonPublic);
if (timeoutField == null) return false;
return (bool) timeoutField.GetValue(abort.ExceptionState);
}
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
{
var logger = LogManager.GetLogger(callingType);
if (logger == null || logger.IsWarnEnabled == false) return;
+12 -13
View File
@@ -7,7 +7,6 @@ using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.IO;
using Umbraco.Core.Media;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
@@ -42,7 +41,7 @@ namespace Umbraco.Core.Models
/// * The item exists and is published
/// * A call to ContentService.Save is made
/// * The item has not been modified whatsoever apart from changing it's published status from published to saved
///
///
/// In this case, there is no reason to make any database changes at all
/// </remarks>
internal static bool RequiresSaving(this IContent entity)
@@ -62,7 +61,7 @@ namespace Umbraco.Core.Models
/// * The item exists and is published
/// * A call to ContentService.Save is made
/// * The item has not been modified whatsoever apart from changing it's published status from published to saved
///
///
/// In this case, there is no reason to make any database changes at all
/// </remarks>
internal static bool RequiresSaving(this IContent entity, PublishedState publishedState)
@@ -70,7 +69,7 @@ namespace Umbraco.Core.Models
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
//check if any user prop has changed
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
//We need to know if any other property apart from Published was changed here
//don't create a new version if the published state has changed to 'Save' but no data has actually been changed
if (publishedChanged && entity.Published == false && propertyValueChanged == false)
@@ -302,9 +301,9 @@ namespace Umbraco.Core.Models
return content.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Contains(recycleBinId.ToInvariantString());
}
/// <summary>
/// Removes characters that are not valide XML characters from all entity properties
/// Removes characters that are not valide XML characters from all entity properties
/// of type string. See: http://stackoverflow.com/a/961504/5018
/// </summary>
/// <returns></returns>
@@ -456,7 +455,7 @@ namespace Umbraco.Core.Models
/// <param name="value">The uploaded <see cref="HttpPostedFileBase"/>.</param>
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
{
// ensure we get the filename without the path in IE in intranet mode
// ensure we get the filename without the path in IE in intranet mode
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
var filename = value.FileName;
var pos = filename.LastIndexOf(@"\", StringComparison.InvariantCulture);
@@ -468,10 +467,10 @@ namespace Umbraco.Core.Models
if (pos > 0)
filename = filename.Substring(pos + 1);
// get a safe filename - should this be done by MediaHelper?
// get a safe & clean filename
filename = IOHelper.SafeFileName(filename);
if (string.IsNullOrWhiteSpace(filename)) return;
filename = filename.ToLower(); // fixme - er... why?
filename = filename.ToLower();
FileSystemProviderManager.Current.MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, value.InputStream);
}
@@ -513,10 +512,10 @@ namespace Umbraco.Core.Models
{
if (filename == null || filestream == null) return;
// get a safe filename - should this be done by MediaHelper?
// get a safe & clean filename
filename = IOHelper.SafeFileName(filename);
if (string.IsNullOrWhiteSpace(filename)) return;
filename = filename.ToLower(); // fixme - er... why?
filename = filename.ToLower();
FileSystemProviderManager.Current.MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, filestream);
}
@@ -548,7 +547,7 @@ namespace Umbraco.Core.Models
#endregion
#region User/Profile methods
/// <summary>
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
/// </summary>
@@ -623,7 +622,7 @@ namespace Umbraco.Core.Models
///// <param name="tagGroup"></param>
///// <returns></returns>
///// <remarks>
///// The tags returned are only relavent for published content & saved media or members
///// The tags returned are only relavent for published content & saved media or members
///// </remarks>
//public static IEnumerable<ITag> GetTags(this IContentBase content, string propertyTypeAlias, string tagGroup = "default")
//{
@@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
//fixme: This whole thing needs to go, it's super hacky and doens't need to exist in the first place
internal static class ContentTypeExtensions
{
/// <summary>
/// Get all descendant content types
/// </summary>
/// <param name="contentType"></param>
/// <param name="contentTypeService"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType, IContentTypeService contentTypeService)
{
if (contentType is IContentType)
{
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
.SelectRecursive(type => contentTypeService.GetContentTypeChildren(type.Id));
return descendants;
}
if (contentType is IMediaType)
{
var descendants = contentTypeService.GetMediaTypeChildren(contentType.Id)
.SelectRecursive(type => contentTypeService.GetMediaTypeChildren(type.Id));
return descendants;
}
//No other content types have children (i.e. member types)
return Enumerable.Empty<IContentTypeBase>();
}
/// <summary>
/// Get all descendant content types
/// </summary>
/// <param name="contentType"></param>
/// <param name="contentTypeService"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType, ContentTypeServiceBase contentTypeService)
{
var cService = contentTypeService as IContentTypeService;
return cService == null ? Enumerable.Empty<IContentTypeBase>() : contentType.Descendants(cService);
}
/// <summary>
/// Get all descendant and self content types
/// </summary>
/// <param name="contentType"></param>
/// <param name="contentTypeService"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> DescendantsAndSelf(this IContentTypeBase contentType, IContentTypeService contentTypeService)
{
var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants(contentTypeService));
return descendantsAndSelf;
}
/// <summary>
/// Get all descendant and self content types
/// </summary>
/// <param name="contentType"></param>
/// <param name="contentTypeService"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> DescendantsAndSelf(this IContentTypeBase contentType, ContentTypeServiceBase contentTypeService)
{
var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants(contentTypeService));
return descendantsAndSelf;
}
///// <summary>
///// Returns the descendant content type Ids for the given content type
///// </summary>
///// <param name="contentType"></param>
///// <returns></returns>
//public static IEnumerable<int> DescendantIds(this IContentTypeBase contentType)
//{
// return ((ContentTypeService) ApplicationContext.Current.Services.ContentTypeService)
// .GetDescendantContentTypeIds(contentType.Id);
//}
}
}
@@ -69,6 +69,7 @@ namespace Umbraco.Core.Models
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
//TODO: Instead of 'new' this should explicitly implement one of the collection interfaces members
internal new void Add(PropertyType item)
{
using (new WriteLock(_addLocker))
@@ -110,6 +110,12 @@ namespace Umbraco.Core.Models
_ruleCollection.Clear();
}
internal void ClearRemovedRules()
{
_removedRules.Clear();
}
[DataMember]
public int LoginNodeId
{
@@ -0,0 +1,63 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// The published content enumerable, this model is to allow ToString to be overriden for value converters to support legacy requests for string values
/// </summary>
public class PublishedContentEnumerable : IEnumerable<IPublishedContent>
{
/// <summary>
/// The items in the collection
/// </summary>
private readonly IEnumerable<IPublishedContent> _items;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedContentEnumerable"/> class.
/// </summary>
/// <param name="publishedContent">
/// The published content items
/// </param>
public PublishedContentEnumerable(IEnumerable<IPublishedContent> publishedContent)
{
if (publishedContent == null) throw new ArgumentNullException("publishedContent");
_items = publishedContent;
}
/// <summary>
/// The ToString method to convert the objects back to CSV
/// </summary>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
public override string ToString()
{
return string.Join(",", _items.Select(x => x.Id));
}
/// <summary>
/// The get enumerator.
/// </summary>
/// <returns>
/// The <see cref="IEnumerator"/>.
/// </returns>
public IEnumerator<IPublishedContent> GetEnumerator()
{
return _items.GetEnumerator();
}
/// <summary>
/// The get enumerator.
/// </summary>
/// <returns>
/// The <see cref="IEnumerator"/>.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
[TypeConverter(typeof(PublishedContentTypeConverter))]
public class PublishedContentExtended : PublishedContentWrapped, IPublishedContentExtended
{
#region Constructor
@@ -186,6 +187,11 @@ namespace Umbraco.Core.Models.PublishedContent
}
#endregion
public override string ToString()
{
return Id.ToString();
}
}
}
@@ -0,0 +1,39 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
internal class PublishedContentTypeConverter : TypeConverter
{
private static readonly Type[] ConvertableTypes = new[]
{
typeof(int)
};
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ConvertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType))
|| base.CanConvertFrom(context, destinationType);
}
public override object ConvertTo(
ITypeDescriptorContext context,
CultureInfo culture,
object value,
Type destinationType)
{
var publishedContent = value as IPublishedContent;
if (publishedContent == null)
return null;
if (TypeHelper.IsTypeAssignableFrom<int>(destinationType))
{
return publishedContent.Id;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
+52
View File
@@ -0,0 +1,52 @@
using System;
namespace Umbraco.Core.Models
{
// <summary>The Range class. Adapted from http://stackoverflow.com/questions/5343006/is-there-a-c-sharp-type-for-representing-an-integer-range</summary>
/// <typeparam name="T">Generic parameter.</typeparam>
public class Range<T> where T : IComparable<T>
{
/// <summary>Minimum value of the range.</summary>
public T Minimum { get; set; }
/// <summary>Maximum value of the range.</summary>
public T Maximum { get; set; }
/// <summary>Presents the Range in readable format.</summary>
/// <returns>String representation of the Range</returns>
public override string ToString()
{
return string.Format("{0},{1}", this.Minimum, this.Maximum);
}
/// <summary>Determines if the range is valid.</summary>
/// <returns>True if range is valid, else false</returns>
public bool IsValid()
{
return this.Minimum.CompareTo(this.Maximum) <= 0;
}
/// <summary>Determines if the provided value is inside the range.</summary>
/// <param name="value">The value to test</param>
/// <returns>True if the value is inside Range, else false</returns>
public bool ContainsValue(T value)
{
return (this.Minimum.CompareTo(value) <= 0) && (value.CompareTo(this.Maximum) <= 0);
}
/// <summary>Determines if this Range is inside the bounds of another range.</summary>
/// <param name="Range">The parent range to test on</param>
/// <returns>True if range is inclusive, else false</returns>
public bool IsInsideRange(Range<T> range)
{
return this.IsValid() && range.IsValid() && range.ContainsValue(this.Minimum) && range.ContainsValue(this.Maximum);
}
/// <summary>Determines if another range is inside the bounds of this range.</summary>
/// <param name="Range">The child range to test</param>
/// <returns>True if range is inside, else false</returns>
public bool ContainsRange(Range<T> range)
{
return this.IsValid() && range.IsValid() && this.ContainsValue(range.Minimum) && this.ContainsValue(range.Maximum);
}
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models.Rdbms
internal class DataTypeDto
{
[Column("pk")]
[PrimaryKeyColumn(IdentitySeed = 30)]
[PrimaryKeyColumn(IdentitySeed = 40)]
public int PrimaryKey { get; set; }
[Column("nodeId")]
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models.Rdbms
[ExplicitColumns]
internal class NodeDto
{
public const int NodeIdSeed = 1050;
public const int NodeIdSeed = 1060;
[Column("id")]
[PrimaryKeyColumn(Name = "PK_structure", IdentitySeed = NodeIdSeed)]
@@ -28,17 +28,17 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory<IMedia,ContentVersionDto>
public IMember BuildEntity(MemberDto dto)
public static IMember BuildEntity(MemberDto dto, IMemberType contentType)
{
var member = new Member(
dto.ContentVersionDto.ContentDto.NodeDto.Text,
dto.Email, dto.LoginName, dto.Password, _contentType);
dto.Email, dto.LoginName, dto.Password, contentType);
try
{
member.DisableChangeTracking();
member.Id = _id;
member.Id = dto.NodeId;
member.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId;
member.Path = dto.ContentVersionDto.ContentDto.NodeDto.Path;
member.CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value;
@@ -62,6 +62,12 @@ namespace Umbraco.Core.Persistence.Factories
}
}
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
public IMember BuildEntity(MemberDto dto)
{
return BuildEntity(dto, _contentType);
}
public MemberDto BuildDto(IMember entity)
{
var dto = new MemberDto
@@ -6,6 +6,7 @@ using System.Reflection;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Factories
{
@@ -17,7 +18,7 @@ namespace Umbraco.Core.Persistence.Factories
//figure out what extra properties we have that are not on the IUmbracoEntity and add them to additional data
foreach (var k in originalEntityProperties.Keys
.Select(x => new { orig = x, title = x.ConvertCase(StringAliasCaseType.PascalCase) })
.Select(x => new { orig = x, title = x.ToCleanString(CleanStringType.PascalCase | CleanStringType.Ascii | CleanStringType.ConvertCase) })
.Where(x => entityProps.InvariantContains(x.title) == false))
{
entity.AdditionalData[k.title] = originalEntityProperties[k.orig];
@@ -75,65 +76,6 @@ namespace Umbraco.Core.Persistence.Factories
entity.EnableChangeTracking();
}
}
public UmbracoEntity BuildEntity(EntityRepository.UmbracoEntityDto dto)
{
var entity = new UmbracoEntity(dto.Trashed)
{
CreateDate = dto.CreateDate,
CreatorId = dto.UserId.Value,
Id = dto.NodeId,
Key = dto.UniqueId,
Level = dto.Level,
Name = dto.Text,
NodeObjectTypeId = dto.NodeObjectType.Value,
ParentId = dto.ParentId,
Path = dto.Path,
SortOrder = dto.SortOrder,
HasChildren = dto.Children > 0,
ContentTypeAlias = dto.Alias ?? string.Empty,
ContentTypeIcon = dto.Icon ?? string.Empty,
ContentTypeThumbnail = dto.Thumbnail ?? string.Empty,
};
entity.IsPublished = dto.PublishedVersion != default(Guid) || (dto.NewestVersion != default(Guid) && dto.PublishedVersion == dto.NewestVersion);
entity.IsDraft = dto.NewestVersion != default(Guid) && (dto.PublishedVersion == default(Guid) || dto.PublishedVersion != dto.NewestVersion);
entity.HasPendingChanges = (dto.PublishedVersion != default(Guid) && dto.NewestVersion != default(Guid)) && dto.PublishedVersion != dto.NewestVersion;
if (dto.UmbracoPropertyDtos != null)
{
foreach (var propertyDto in dto.UmbracoPropertyDtos)
{
entity.AdditionalData[propertyDto.PropertyAlias] = new UmbracoEntity.EntityProperty
{
PropertyEditorAlias = propertyDto.PropertyEditorAlias,
Value = propertyDto.NTextValue.IsNullOrWhiteSpace()
? propertyDto.NVarcharValue
: propertyDto.NTextValue.ConvertToJsonIfPossible()
};
}
}
return entity;
}
public EntityRepository.UmbracoEntityDto BuildDto(UmbracoEntity entity)
{
var node = new EntityRepository.UmbracoEntityDto
{
CreateDate = entity.CreateDate,
Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
NodeId = entity.Id,
NodeObjectType = entity.NodeObjectTypeId,
ParentId = entity.ParentId,
Path = entity.Path,
SortOrder = entity.SortOrder,
Text = entity.Name,
Trashed = entity.Trashed,
UniqueId = entity.Key,
UserId = entity.CreatorId
};
return node;
}
}
}
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Mappers
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal BaseMapper ResolveMapperByType(Type type)
public virtual BaseMapper ResolveMapperByType(Type type)
{
return _mapperCache.GetOrAdd(type, type1 =>
{
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Persistence.Mappers
return Attempt<BaseMapper>.Succeed(mapper);
}
internal string GetMapping(Type type, string propertyName)
public virtual string GetMapping(Type type, string propertyName)
{
var mapper = ResolveMapperByType(type);
var result = mapper.Map(propertyName);
@@ -130,8 +130,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1040, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1040", SortOrder = 2, UniqueId = new Guid("21e798da-e06e-4eda-a511-ed257f78d4fa"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now });
@@ -141,6 +140,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//TODO: We're not creating these for 7.0
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
@@ -246,8 +246,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -26, DataTypeId = Constants.System.DefaultContentListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
@@ -259,6 +258,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 27, DataTypeId = 1047, PropertyEditorAlias = Constants.PropertyEditors.MemberPicker2Alias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 28, DataTypeId = 1048, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 29, DataTypeId = 1049, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 30, DataTypeId = 1050, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinks2Alias, DbType = "Ntext" });
//TODO: We're not creating these for 7.0
//_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 19, DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" });
@@ -1,6 +1,5 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
@@ -1,6 +1,5 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -44,7 +43,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
private static string UpdateMacroGuids(Database database)
{
var updates = database.Query<dynamic>("SELECT id, macroAlias FROM cmsMacro")
.Select(macro => Tuple.Create((int) macro.id, ((string) macro.macroAlias).ToGuid()))
.Select(macro => Tuple.Create((int) macro.id, ("macro____" + (string) macro.macroAlias).ToGuid()))
.ToList();
foreach (var update in updates)
@@ -58,7 +57,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
var updates = database.Query<dynamic>(@"SELECT cmsMacroProperty.id id, macroPropertyAlias propertyAlias, cmsMacro.macroAlias macroAlias
FROM cmsMacroProperty
JOIN cmsMacro ON cmsMacroProperty.macro=cmsMacro.id")
.Select(prop => Tuple.Create((int) prop.id, ((string) prop.macroAlias + "____" + (string) prop.propertyAlias).ToGuid()))
.Select(prop => Tuple.Create((int) prop.id, ("macro____" + (string) prop.macroAlias + "____" + (string) prop.propertyAlias).ToGuid()))
.ToList();
foreach (var update in updates)
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -32,7 +31,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
private static string UpdateRelationTypeGuids(Database database)
{
var updates = database.Query<dynamic>("SELECT id, alias, name FROM umbracoRelationType")
.Select(relationType => Tuple.Create((int) relationType.id, ((string) relationType.alias + "____" + (string) relationType.name).ToGuid()))
.Select(relationType => Tuple.Create((int) relationType.id, ("relationType____" + (string) relationType.alias + "____" + (string) relationType.name).ToGuid()))
.ToList();
foreach (var update in updates)
@@ -1,5 +1,4 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -546,7 +546,7 @@ namespace Umbraco.Core.Persistence.Querying
&& methodArgs.Length == 1
&& methodArgs[0].NodeType == ExpressionType.MemberAccess
&& TypeHelper.IsTypeAssignableFrom<IEnumerable>(m.Arguments[0].Type))
{
{
goto case "SqlIn";
}
@@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -12,17 +13,19 @@ namespace Umbraco.Core.Persistence.Querying
/// <remarks>This object is stateful and cannot be re-used to parse an expression.</remarks>
internal class ModelToSqlExpressionVisitor<T> : ExpressionVisitorBase
{
private readonly MappingResolver _mappingResolver;
private readonly BaseMapper _mapper;
public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, BaseMapper mapper)
public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, MappingResolver mappingResolver)
: base(sqlSyntax)
{
_mapper = mapper;
_mapper = mappingResolver.ResolveMapperByType(typeof(T));
_mappingResolver = mappingResolver;
}
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
public ModelToSqlExpressionVisitor()
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current.ResolveMapperByType(typeof(T)))
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current)
{ }
protected override string VisitMemberAccess(MemberExpression m)
@@ -36,7 +39,7 @@ namespace Umbraco.Core.Persistence.Querying
{
var field = _mapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException("The mapper returned an empty field for the member name: " + m.Member.Name);
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
@@ -50,13 +53,42 @@ namespace Umbraco.Core.Persistence.Querying
{
var field = _mapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException("The mapper returned an empty field for the member name: " + m.Member.Name);
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
return string.Empty;
}
if (m.Expression != null
&& m.Expression.Type != typeof(T)
&& TypeHelper.IsTypeAssignableFrom<IUmbracoEntity>(m.Expression.Type)
&& EndsWithConstant(m) == false)
{
//if this is the case, it means we have a sub expression / nested property access, such as: x.ContentType.Alias == "Test";
//and since the sub type (x.ContentType) is not the same as x, we need to resolve a mapper for x.ContentType to get it's mapped SQL column
//don't execute if compiled
if (Visited == false)
{
var subMapper = _mappingResolver.ResolveMapperByType(m.Expression.Type);
if (subMapper == null)
throw new NullReferenceException("No mapper found for type " + m.Expression.Type);
var field = subMapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
return string.Empty;
}
//TODO: When m.Expression.NodeType == ExpressionType.Constant and it's an expression like: content => aliases.Contains(content.ContentType.Alias);
// then an SQL parameter will be added for aliases as an array, however in SqlIn on the subclass it will manually add these SqlParameters anyways,
// however the query will still execute because the SQL that is written will only contain the correct indexes of SQL parameters, this would be ignored,
// I'm just unsure right now due to time constraints how to make it correct. It won't matter right now and has been working already with this bug but I've
// only just discovered what it is actually doing.
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
@@ -71,5 +103,24 @@ namespace Umbraco.Core.Persistence.Querying
return string.Empty;
}
/// <summary>
/// Determines if the MemberExpression ends in a Constant value
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
private bool EndsWithConstant(MemberExpression m)
{
Expression expr = m;
while (expr is MemberExpression)
{
var memberExpr = expr as MemberExpression;
expr = memberExpr.Expression;
}
var constExpr = expr as ConstantExpression;
return constExpr != null;
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId, sql);
var content = CreateContentFromDto(dto, sql);
return content;
}
@@ -134,6 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
//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);
if (queryType == BaseQueryType.FullSingle)
{
@@ -260,6 +263,39 @@ namespace Umbraco.Core.Persistence.Repositories
}
baseId = xmlItems[xmlItems.Count - 1].NodeId;
}
//now delete the items that shouldn't be there
var sqlAllIds = translate(0, GetBaseQuery(BaseQueryType.Ids));
var allContentIds = Database.Fetch<int>(sqlAllIds);
var docObjectType = Guid.Parse(Constants.ObjectTypes.Document);
var xmlIdsQuery = new Sql()
.Select("DISTINCT cmsContentXml.nodeId")
.From<ContentXmlDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentXmlDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (contentTypeIdsA.Length > 0)
{
xmlIdsQuery.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>(SqlSyntax)
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
xmlIdsQuery.Where<NodeDto>(dto => dto.NodeObjectType == docObjectType, SqlSyntax);
var allXmlIds = Database.Fetch<int>(xmlIdsQuery);
var toRemove = allXmlIds.Except(allContentIds).ToArray();
if (toRemove.Length > 0)
{
foreach (var idGroup in toRemove.InGroupsOf(2000))
{
Database.Execute("DELETE FROM cmsContentXml WHERE nodeId IN (@ids)", new { ids = idGroup });
}
}
}
public override IEnumerable<IContent> GetAllVersions(int id)
@@ -273,12 +309,13 @@ namespace Umbraco.Core.Persistence.Repositories
var sqlFull = translate(GetBaseQuery(BaseQueryType.FullMultiple));
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true);
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true, includeAllVersions:true);
}
public override IContent GetByVersion(Guid versionId)
{
var sql = GetBaseQuery(BaseQueryType.FullSingle);
//TODO: cmsContentVersion.VersionId has a Unique Index constraint applied, seems silly then to also add OrderByDescending since it would be impossible to return more than one.
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
@@ -287,7 +324,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateContentFromDto(dto, versionId, sql);
var content = CreateContentFromDto(dto, sql);
return content;
}
@@ -297,7 +334,8 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql()
.Select("*")
.From<DocumentDto>(SqlSyntax)
.InnerJoin<ContentVersionDto>(SqlSyntax).On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentVersionDto>(SqlSyntax)
.On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.VersionId == versionId, SqlSyntax)
.Where<DocumentDto>(x => x.Newest != true, SqlSyntax);
var dto = Database.Fetch<DocumentDto, ContentVersionDto>(sql).FirstOrDefault();
@@ -317,7 +355,8 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql()
.Select("*")
.From<DocumentDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentVersionDto>()
.On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.NodeId == id)
.Where<ContentVersionDto>(x => x.VersionDate < versionDate)
.Where<DocumentDto>(x => x.Newest != true);
@@ -558,6 +597,7 @@ namespace Umbraco.Core.Persistence.Repositories
//if (((ICanBeDirty)entity).IsPropertyDirty("Published") && (entity.Published || publishedState == PublishedState.Unpublished))
if (entity.ShouldClearPublishedFlagForPreviousVersions(publishedState, shouldCreateNewVersion))
{
//TODO: This perf can be improved, it could easily be UPDATE WHERE.... (one SQL call instead of many)
var publishedDocs = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND published = @IsPublished", new { Id = entity.Id, IsPublished = true });
foreach (var doc in publishedDocs)
{
@@ -571,6 +611,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
//Look up (newest) entries by id in cmsDocument table to set newest = false
//TODO: This perf can be improved, it could easily be UPDATE WHERE.... (one SQL call instead of many)
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
foreach (var documentDto in documentDtos)
{
@@ -898,7 +939,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
return base.GetDatabaseFieldNameForOrderBy(orderBy);
}
/// <summary>
/// This is the underlying method that processes most queries for this repository
/// </summary>
@@ -909,8 +950,12 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
/// </param>
/// <param name="withCache"></param>
/// <param name="includeAllVersions">
/// Generally when querying for content we only want to return the most recent version of the content item, however in some cases like when
/// we want to return all versions of a content item, we can't simply return the latest
/// </param>
/// <returns></returns>
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false, bool includeAllVersions = false)
{
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
@@ -929,13 +974,12 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
}
var publishedSql = new Sql(@"SELECT *
FROM cmsDocument AS doc2
INNER JOIN
(" + parsedOriginalSql + @") as docData
ON doc2.nodeId = docData.nodeId
WHERE doc2.published = 1
ORDER BY doc2.nodeId
//order by update date DESC, if there is corrupted published flags we only want the latest!
var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.newest
FROM cmsDocument INNER JOIN cmsContentVersion ON cmsContentVersion.VersionId = cmsDocument.versionId
WHERE cmsDocument.published = 1 AND cmsDocument.nodeId IN
(" + parsedOriginalSql + @")
ORDER BY cmsContentVersion.id DESC
", sqlFull.Arguments);
//go and get the published version data, we do a Query here and not a Fetch so we are
@@ -950,9 +994,9 @@ ORDER BY doc2.nodeId
publishedDataCollection.Add(publishedDto);
}
var content = new IContent[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IContent, bool>>();
var defs = new DocumentDefinitionCollection(includeAllVersions);
var templateIds = new List<int>();
//track the looked up content types, even though the content types are cached
@@ -960,9 +1004,8 @@ ORDER BY doc2.nodeId
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IContentType>();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
DocumentPublishedReadOnlyDto publishedDto;
publishedDataCollection.TryGetValue(dto.NodeId, out publishedDto);
@@ -970,10 +1013,10 @@ ORDER BY doc2.nodeId
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IContent>(GetCacheIdKey<IContent>(dto.NodeId));
//only use this cached version if the dto returned is also the publish version, they must match
if (cached != null && cached.Published && dto.Published)
//only use this cached version if the dto returned is also the publish version, they must match and be teh same version
if (cached != null && cached.Version == dto.VersionId && cached.Published && dto.Published)
{
content[i] = cached;
content.Add(new Tuple<IContent, bool>(cached, true));
continue;
}
}
@@ -991,21 +1034,16 @@ ORDER BY doc2.nodeId
contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
}
content[i] = ContentFactory.BuildEntity(dto, contentType, publishedDto);
// need template
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
templateIds.Add(dto.TemplateId.Value);
// track the definition and if it's successfully added or updated then processed
if (defs.AddOrUpdate(new DocumentDefinition(dto, contentType)))
{
// assign template
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
templateIds.Add(dto.TemplateId.Value);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.VersionId,
dto.ContentVersionDto.VersionDate,
dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
contentType
));
content.Add(new Tuple<IContent, bool>(ContentFactory.BuildEntity(dto, contentType, publishedDto), false));
}
}
// load all required templates in 1 query
@@ -1015,38 +1053,38 @@ ORDER BY doc2.nodeId
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign template and property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
var def = defs[includeAllVersions ? (ValueType)cc.Version : cc.Id];
// complete the item
var cc = content[dtoIndex];
var dto = dtos[dtoIndex];
ITemplate template = null;
if (dto.TemplateId.HasValue)
templates.TryGetValue(dto.TemplateId.Value, out template); // else null
if (def.DocumentDto.TemplateId.HasValue)
templates.TryGetValue(def.DocumentDto.TemplateId.Value, out template); // else null
cc.Template = template;
cc.Properties = propertyData[cc.Id];
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
/// <summary>
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId, Sql docSql)
private IContent CreateContentFromDto(DocumentDto dto, Sql docSql)
{
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
@@ -1058,11 +1096,11 @@ ORDER BY doc2.nodeId
content.Template = _templateRepository.Get(dto.TemplateId.Value);
}
var docDef = new DocumentDefinition(dto.NodeId, versionId, content.UpdateDate, content.CreateDate, contentType);
var docDef = new DocumentDefinition(dto, contentType);
var properties = GetPropertyCollection(docSql, new[] { docDef });
content.Properties = properties[dto.NodeId];
content.Properties = properties[dto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -104,7 +104,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (objectTypes.Any())
{
sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", objectTypes);
sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", new {objectTypes = objectTypes});
}
return Database.Fetch<string>(sql);
@@ -1,19 +1,14 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using Umbraco.Core.Models;
using Umbraco.Core;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -187,10 +182,12 @@ namespace Umbraco.Core.Persistence.Repositories
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
var sql = GetFullSqlForEntityType(key, isContent, isMedia, objectTypeId);
var factory = new UmbracoEntityFactory();
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
@@ -198,14 +195,16 @@ namespace Umbraco.Core.Persistence.Repositories
}
else
{
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
if (nodeDto == null)
return null;
var factory = new UmbracoEntityFactory();
var entity = factory.BuildEntityFromDynamic(nodeDto);
return entity;
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
var found = collection.FirstOrDefault();
return found != null ? found.BuildFromDynamic() : null;
}
@@ -230,28 +229,29 @@ namespace Umbraco.Core.Persistence.Repositories
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
var sql = GetFullSqlForEntityType(id, isContent, isMedia, objectTypeId);
var factory = new UmbracoEntityFactory();
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
return entities.FirstOrDefault();
}
else
{
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
if (nodeDto == null)
return null;
var factory = new UmbracoEntityFactory();
var entity = factory.BuildEntityFromDynamic(nodeDto);
return entity;
{
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
var found = collection.FirstOrDefault();
return found != null ? found.BuildFromDynamic() : null;
}
}
public virtual IEnumerable<IUmbracoEntity> GetAll(Guid objectTypeId, params int[] ids)
@@ -288,21 +288,21 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
foreach (var entity in entities)
{
yield return entity;
}
return entities;
}
else
{
var dtos = _work.Database.Fetch<dynamic>(sql);
foreach (var entity in dtos.Select(dto => factory.BuildEntityFromDynamic(dto)))
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
yield return entity;
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
return collection.Select(x => x.BuildFromDynamic()).ToList();
}
}
@@ -347,7 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
});
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, mediaSql);
return entities;
@@ -356,8 +356,15 @@ namespace Umbraco.Core.Persistence.Repositories
{
//use dynamic so that we can get ALL properties from the SQL so we can chuck that data into our AdditionalData
var finalSql = entitySql.Append(GetGroupBy(isContent, false));
var dtos = _work.Database.Fetch<dynamic>(finalSql);
return dtos.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(finalSql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
return collection.Select(x => x.BuildFromDynamic()).ToList();
}
}
@@ -468,9 +475,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (isContent)
{
//only content has this info
//only content has/needs this info
columns.Add("published.versionId as publishedVersion");
columns.Add("document.versionId as newestVersion");
columns.Add("contentversion.id as versionId");
}
columns.Add("contenttype.alias");
@@ -485,21 +493,22 @@ namespace Umbraco.Core.Persistence.Repositories
var entitySql = new Sql()
.Select(columns.ToArray())
.From("umbracoNode umbracoNode");
if (isContent || isMedia)
{
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
if (isContent)
{
//only content has this info
entitySql
//only content has/needs this info
entitySql
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
.InnerJoin("cmsContentVersion contentversion").On("contentversion.VersionId = document.versionId")
.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1) as published")
.On("umbracoNode.id = published.nodeId");
}
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
}
if (isCount == false)
@@ -546,7 +555,7 @@ namespace Umbraco.Core.Persistence.Repositories
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
{
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
.Where("umbracoNode.uniqueID = @UniqueID", new {UniqueID = key});
if (isContent)
{
@@ -609,13 +618,14 @@ namespace Umbraco.Core.Persistence.Repositories
{
columns.Add("published.versionId");
columns.Add("document.versionId");
columns.Add("contentversion.id");
}
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
columns.Add("contenttype.isContainer");
columns.Add("contenttype.isContainer");
}
var sql = new Sql()
.GroupBy(columns.ToArray());
@@ -626,7 +636,7 @@ namespace Umbraco.Core.Persistence.Repositories
return sql;
}
#endregion
/// <summary>
@@ -652,33 +662,7 @@ namespace Umbraco.Core.Persistence.Repositories
return _work.Database.ExecuteScalar<int>(sql) > 0;
}
#region umbracoNode POCO - Extends NodeDto
[TableName("umbracoNode")]
[PrimaryKey("id")]
[ExplicitColumns]
internal class UmbracoEntityDto : NodeDto
{
[Column("children")]
public int Children { get; set; }
[Column("publishedVersion")]
public Guid PublishedVersion { get; set; }
[Column("newestVersion")]
public Guid NewestVersion { get; set; }
[Column("alias")]
public string Alias { get; set; }
[Column("icon")]
public string Icon { get; set; }
[Column("thumbnail")]
public string Thumbnail { get; set; }
[ResultColumn]
public List<UmbracoPropertyDto> UmbracoPropertyDtos { get; set; }
}
#region private classes
[ExplicitColumns]
internal class UmbracoPropertyDto
@@ -762,6 +746,99 @@ namespace Umbraco.Core.Persistence.Repositories
return prev;
}
}
private class EntityDefinitionCollection : KeyedCollection<int, EntityDefinition>
{
protected override int GetKeyForItem(EntityDefinition item)
{
return item.Id;
}
/// <summary>
/// if this key already exists if it does then we need to check
/// if the existing item is 'older' than the new item and if that is the case we'll replace the older one
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool AddOrUpdate(EntityDefinition item)
{
if (Dictionary == null)
{
base.Add(item);
return true;
}
var key = GetKeyForItem(item);
EntityDefinition found;
if (TryGetValue(key, out found))
{
//it already exists and it's older so we need to replace it
if (item.VersionId > found.VersionId)
{
var currIndex = Items.IndexOf(found);
if (currIndex == -1)
throw new IndexOutOfRangeException("Could not find the item in the list: " + found.Id);
//replace the current one with the newer one
SetItem(currIndex, item);
return true;
}
//could not add or update
return false;
}
base.Add(item);
return true;
}
private bool TryGetValue(int key, out EntityDefinition val)
{
if (Dictionary == null)
{
val = null;
return false;
}
return Dictionary.TryGetValue(key, out val);
}
}
private class EntityDefinition
{
private readonly UmbracoEntityFactory _factory;
private readonly dynamic _entity;
private readonly bool _isContent;
private readonly bool _isMedia;
public EntityDefinition(UmbracoEntityFactory factory, dynamic entity, bool isContent, bool isMedia)
{
_factory = factory;
_entity = entity;
_isContent = isContent;
_isMedia = isMedia;
}
public IUmbracoEntity BuildFromDynamic()
{
return _factory.BuildEntityFromDynamic(_entity);
}
public int Id
{
get { return _entity.id; }
}
public int VersionId
{
get
{
if (_isContent || _isMedia)
{
return _entity.versionId;
}
return _entity.id;
}
}
}
#endregion
}
}
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="serializer">The serializer to convert TEntity to Xml</param>
/// <param name="groupSize">Structures will be rebuilt in chunks of this size</param>
/// <param name="contentTypeIds"></param>
void RebuildXmlStructures(Func<TEntity, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null);
void RebuildXmlStructures(Func<TEntity, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null);
/// <summary>
/// Get the total count of entities
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, dto.VersionId, sql);
var content = CreateMediaFromDto(dto, sql);
return content;
}
@@ -94,6 +94,9 @@ namespace Umbraco.Core.Persistence.Repositories
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(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;
}
@@ -161,25 +164,27 @@ namespace Umbraco.Core.Persistence.Repositories
{
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sqlFull);
var content = new IMedia[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IMedia, bool>>();
var defs = new DocumentDefinitionCollection();
//track the looked up content types, even though the content types are cached
// they still need to be deep cloned out of the cache and we don't want to add
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IMediaType>();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
// if the cache contains the item, use it
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IMedia>(GetCacheIdKey<IMedia>(dto.NodeId));
if (cached != null)
//only use this cached version if the dto returned is the same version - this is just a safety check, media doesn't
//store different versions, but just in case someone corrupts some data we'll double check to be sure.
if (cached != null && cached.Version == dto.VersionId)
{
content[i] = cached;
content.Add(new Tuple<IMedia, bool>(cached, true));
continue;
}
}
@@ -197,39 +202,34 @@ namespace Umbraco.Core.Persistence.Repositories
contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
contentTypes[dto.ContentDto.ContentTypeId] = contentType;
}
content[i] = MediaFactory.BuildEntity(dto, contentType);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.VersionId,
dto.VersionDate,
dto.ContentDto.NodeDto.CreateDate,
contentType
));
// track the definition and if it's successfully added or updated then processed
if (defs.AddOrUpdate(new DocumentDefinition(dto, contentType)))
{
content.Add(new Tuple<IMedia, bool>(MediaFactory.BuildEntity(dto, contentType), false));
}
}
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
// complete the item
var cc = content[dtoIndex];
cc.Properties = propertyData[cc.Id];
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
public override IMedia GetByVersion(Guid versionId)
@@ -243,7 +243,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, versionId, sql);
var content = CreateMediaFromDto(dto, sql);
return content;
}
@@ -263,10 +263,12 @@ namespace Umbraco.Core.Persistence.Repositories
// get the next group of nodes
var query = GetBaseQuery(false);
if (contentTypeIdsA.Length > 0)
query = query
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
{
query = query.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
query = query
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
.Where<NodeDto>(x => x.Trashed == false, SqlSyntax)
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
var sql = SqlSyntax.SelectTop(query, groupSize);
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
@@ -290,7 +292,38 @@ namespace Umbraco.Core.Persistence.Repositories
Logger.Error<MediaRepository>("Could not rebuild XML for nodeId=" + xmlItem.NodeId, e);
}
}
baseId = xmlItems.Last().NodeId;
baseId = xmlItems[xmlItems.Count - 1].NodeId;
}
//now delete the items that shouldn't be there
var allMediaIds = Database.Fetch<int>(GetBaseQuery(BaseQueryType.Ids).Where<NodeDto>(x => x.Trashed == false, SqlSyntax));
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
var xmlIdsQuery = new Sql()
.Select("DISTINCT cmsContentXml.nodeId")
.From<ContentXmlDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentXmlDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (contentTypeIdsA.Length > 0)
{
xmlIdsQuery.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>(SqlSyntax)
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
xmlIdsQuery.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType, SqlSyntax);
var allXmlIds = Database.Fetch<int>(xmlIdsQuery);
var toRemove = allXmlIds.Except(allMediaIds).ToArray();
if (toRemove.Length > 0)
{
foreach (var idGroup in toRemove.InGroupsOf(2000))
{
Database.Execute("DELETE FROM cmsContentXml WHERE nodeId IN (@ids)", new { ids = idGroup });
}
}
}
@@ -526,20 +559,19 @@ namespace Umbraco.Core.Persistence.Repositories
/// Private method to create a media object from a ContentDto
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
private IMedia CreateMediaFromDto(ContentVersionDto dto, Sql docSql)
{
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
var media = MediaFactory.BuildEntity(dto, contentType);
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
var docDef = new DocumentDefinition(dto, contentType);
var properties = GetPropertyCollection(new PagingSqlQuery(docSql), new[] { docDef });
media.Properties = properties[dto.NodeId];
media.Properties = properties[dto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -54,7 +54,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMemberFromDto(dto, dto.ContentVersionDto.VersionId, sql);
var content = CreateMemberFromDto(dto, sql);
return content;
@@ -448,16 +448,16 @@ namespace Umbraco.Core.Persistence.Repositories
var memberType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.NodeId);
var media = factory.BuildEntity(dto);
var member = factory.BuildEntity(dto);
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.ContentVersionDto, memberType) });
media.Properties = properties[dto.NodeId];
member.Properties = properties[dto.ContentVersionDto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
((Entity)media).ResetDirtyProperties(false);
return media;
((Entity)member).ResetDirtyProperties(false);
return member;
}
@@ -658,20 +658,21 @@ namespace Umbraco.Core.Persistence.Repositories
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
var content = new IMember[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IMember, bool>>();
var defs = new DocumentDefinitionCollection();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
// if the cache contains the item, use it
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IMember>(GetCacheIdKey<IMember>(dto.NodeId));
if (cached != null)
//only use this cached version if the dto returned is the same version - this is just a safety check, members dont
//store different versions, but just in case someone corrupts some data we'll double check to be sure.
if (cached != null && cached.Version == dto.ContentVersionDto.VersionId)
{
content[i] = cached;
content.Add(new Tuple<IMember, bool>(cached, true));
continue;
}
}
@@ -679,60 +680,54 @@ namespace Umbraco.Core.Persistence.Repositories
// else, need to fetch from the database
// content type repository is full-cache so OK to get each one independently
var contentType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(contentType, NodeObjectTypeId, dto.NodeId);
content[i] = factory.BuildEntity(dto);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.ContentVersionDto.VersionId,
dto.ContentVersionDto.VersionDate,
dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
contentType
));
if (defs.AddOrUpdate(new DocumentDefinition(dto.ContentVersionDto, contentType)))
{
content.Add(new Tuple<IMember, bool>(MemberFactory.BuildEntity(dto, contentType), false));
}
}
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
// complete the item
var cc = content[dtoIndex];
cc.Properties = propertyData[cc.Id];
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
((Entity)cc).ResetDirtyProperties(false);
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
/// <summary>
/// Private method to create a member object from a MemberDto
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IMember CreateMemberFromDto(MemberDto dto, Guid versionId, Sql docSql)
private IMember CreateMemberFromDto(MemberDto dto, Sql docSql)
{
var memberType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.ContentVersionDto.NodeId);
var member = factory.BuildEntity(dto);
var docDef = new DocumentDefinition(dto.ContentVersionDto.NodeId, versionId, member.UpdateDate, member.CreateDate, memberType);
var docDef = new DocumentDefinition(dto.ContentVersionDto, memberType);
var properties = GetPropertyCollection(docSql, new[] { docDef });
member.Properties = properties[dto.ContentVersionDto.NodeId];
member.Properties = properties[dto.ContentVersionDto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
protected internal new IScopeUnitOfWork UnitOfWork
{
get { return (IScopeUnitOfWork)base.UnitOfWork; }
get { return base.UnitOfWork; }
}
protected UmbracoDatabase Database
@@ -75,10 +75,5 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Execute(delete, new { Id = GetEntityId(entity) });
}
}
protected virtual TId GetEntityId(TEntity entity)
{
return (TId)(object)entity.Id;
}
}
}
@@ -38,10 +38,9 @@ namespace Umbraco.Core.Persistence.Repositories
{
sql.Where("umbracoAccess.id IN (@ids)", new { ids = ids });
}
sql.OrderBy<AccessDto>(x => x.NodeId, SqlSyntax);
var factory = new PublicAccessEntryFactory();
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
return dtos.Select(factory.BuildEntity);
}
@@ -53,6 +52,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = translator.Translate();
var factory = new PublicAccessEntryFactory();
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
return dtos.Select(factory.BuildEntity);
}
@@ -63,7 +63,9 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Select("*")
.From<AccessDto>(SqlSyntax)
.LeftJoin<AccessRuleDto>(SqlSyntax)
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId);
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId)
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
.OrderBy<AccessDto>(dto => dto.Id, SqlSyntax);
return sql;
}
@@ -104,6 +106,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
rule.AccessId = entity.Key;
Database.Insert(rule);
//update the id so HasEntity is correct
var entityRule = entity.Rules.First(x => x.Key == rule.Id);
entityRule.Id = entityRule.Key.GetHashCode();
//double make sure that this is set since it is possible to add rules via ctor without AddRule
entityRule.AccessEntryId = entity.Key;
}
entity.ResetDirtyProperties();
@@ -124,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (rule.HasIdentity)
{
var count = Database.Update(dto.Rules.Single(x => x.Id == rule.Key));
var count = Database.Update(dto.Rules.First(x => x.Id == rule.Key));
if (count == 0)
{
throw new InvalidOperationException("No rows were updated for the access rule");
@@ -150,6 +157,8 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Delete<AccessRuleDto>("WHERE id=@Id", new {Id = removedRule});
}
entity.ClearRemovedRules();
entity.ResetDirtyProperties();
}
@@ -158,4 +167,4 @@ namespace Umbraco.Core.Persistence.Repositories
return entity.Key;
}
}
}
}
@@ -13,10 +13,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
internal abstract class RepositoryBase : DisposableObject
{
private readonly IUnitOfWork _work;
private readonly IScopeUnitOfWork _work;
private readonly CacheHelper _globalCache;
protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger)
protected RepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger)
{
if (work == null) throw new ArgumentNullException("work");
if (cache == null) throw new ArgumentNullException("cache");
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Returns the Unit of Work added to the repository
/// </summary>
protected internal IUnitOfWork UnitOfWork
protected internal IScopeUnitOfWork UnitOfWork
{
get { return _work; }
}
@@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories
internal abstract class RepositoryBase<TId, TEntity> : RepositoryBase, IRepositoryQueryable<TId, TEntity>, IUnitOfWorkRepository
where TEntity : class, IAggregateRoot
{
protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger)
protected RepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger)
: base(work, cache, logger)
{
}
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (_isolatedCache != null) return _isolatedCache;
var scope = ((ScopeUnitOfWork) UnitOfWork).Scope; // fixme cast!
var scope = UnitOfWork.Scope;
IsolatedRuntimeCache provider;
switch (scope.RepositoryCacheMode)
{
@@ -179,14 +179,17 @@ namespace Umbraco.Core.Persistence.Repositories
if (GlobalCache == CacheHelper.NoCache)
return _cachePolicy = NoRepositoryCachePolicy<TEntity, TId>.Instance;
// create the cache policy using IsolatedCache which is either global
// or scoped depending on the repository cache mode for the current scope
_cachePolicy = CreateCachePolicy(IsolatedCache);
var scope = ((ScopeUnitOfWork) UnitOfWork).Scope; // fixme cast!
var scope = UnitOfWork.Scope;
switch (scope.RepositoryCacheMode)
{
case RepositoryCacheMode.Default:
break;
case RepositoryCacheMode.Scoped:
_cachePolicy = _cachePolicy.Scoped(GetIsolatedCache(GlobalCache.IsolatedRuntimeCache), scope);
var globalIsolatedCache = GetIsolatedCache(GlobalCache.IsolatedRuntimeCache);
_cachePolicy = _cachePolicy.Scoped(globalIsolatedCache, scope);
break;
default:
throw new Exception("oops: cache mode.");
@@ -21,7 +21,9 @@ namespace Umbraco.Core.Persistence.Repositories
: base(work, CacheHelper.NoCache, logger, sqlSyntax)
{
// managing the cache our own way (no policy etc)
// fixme - ServerRegistrationRepository does *not* implement scoped cache at the moment!
// note: this means that the ServerRegistrationRepository does *not* implement scoped cache,
// and this is because the repository is special and should not participate in scopes
// (cleanup in v8)
_globalCache = globalCache;
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Linq;
using System.Text;
@@ -33,6 +34,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IContentSection _contentSection;
/// <summary>
/// This is used for unit tests ONLY
/// </summary>
internal static bool ThrowOnWarning = false;
protected VersionableRepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, IContentSection contentSection)
: base(work, cache, logger, sqlSyntax)
{
@@ -503,7 +509,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="sql"></param>
/// <param name="documentDefs"></param>
/// <returns></returns>
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
protected IDictionary<Guid, PropertyCollection> GetPropertyCollection(
Sql sql,
IReadOnlyCollection<DocumentDefinition> documentDefs)
{
@@ -516,11 +522,11 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="pagingSqlQuery"></param>
/// <param name="documentDefs"></param>
/// <returns></returns>
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
protected IDictionary<Guid, PropertyCollection> GetPropertyCollection(
PagingSqlQuery pagingSqlQuery,
IReadOnlyCollection<DocumentDefinition> documentDefs)
{
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
if (documentDefs.Count == 0) return new Dictionary<Guid, PropertyCollection>();
//initialize to the query passed in
var docSql = pagingSqlQuery.PrePagedSql;
@@ -576,16 +582,16 @@ ON cmsPropertyData.propertytypeid = cmsPropertyType.id
INNER JOIN
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
ORDER BY contentNodeId, propertytypeid
ORDER BY contentNodeId, versionId, propertytypeid
", docSql.Arguments);
//This does NOT fetch all data into memory in a list, this will read
// over the records as a data reader, this is much better for performance and memory,
// but it means that during the reading of this data set, nothing else can be read
// from SQL server otherwise we'll get an exception.
var allPropertyData = Database.Query<PropertyDataDto>(propSql);
var result = new Dictionary<int, PropertyCollection>();
var result = new Dictionary<Guid, PropertyCollection>();
var propertiesWithTagSupport = new Dictionary<string, SupportTagsAttribute>();
//used to track the resolved composition property types per content type so we don't have to re-resolve (ToArray) the list every time
var resolvedCompositionProperties = new Dictionary<int, PropertyType[]>();
@@ -594,11 +600,13 @@ ORDER BY contentNodeId, propertytypeid
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
var hasCurrent = false; // initially there is no enumerator.Current
var comparer = new DocumentDefinitionComparer(SqlSyntax);
try
{
//This must be sorted by node id because this is how we are sorting the query to lookup property types above,
// which allows us to more efficiently iterate over the large data set of property values
foreach (var def in documentDefs.OrderBy(x => x.Id))
foreach (var def in documentDefs.OrderBy(x => x.Id).ThenBy(x => x.Version, comparer))
{
// get the resolved properties from our local cache, or resolve them and put them in cache
PropertyType[] compositionProperties;
@@ -617,15 +625,17 @@ ORDER BY contentNodeId, propertytypeid
var propertyDataDtos = new List<PropertyDataDto>();
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
{
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
//Not checking null on VersionId because it can never be null - no idea why it's set to nullable
// ReSharper disable once PossibleInvalidOperationException
if (propertyDataSetEnumerator.Current.VersionId.Value == def.Version)
{
hasCurrent = false; // enumerator.Current is not available
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
}
else
{
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
}
}
@@ -660,11 +670,19 @@ ORDER BY contentNodeId, propertytypeid
}
}
if (result.ContainsKey(def.Id))
if (result.ContainsKey(def.Version))
{
Logger.Warn<VersionableRepositoryBase<TId, TEntity>>("The query returned multiple property sets for document definition " + def.Id + ", " + def.Composition.Name);
var msg = string.Format("The query returned multiple property sets for document definition {0}, {1}, {2}", def.Id, def.Version, def.Composition.Name);
if (ThrowOnWarning)
{
throw new InvalidOperationException(msg);
}
else
{
Logger.Warn<VersionableRepositoryBase<TId, TEntity>>(msg);
}
}
result[def.Id] = new PropertyCollection(properties);
result[def.Version] = new PropertyCollection(properties);
}
}
finally
@@ -687,8 +705,8 @@ ORDER BY contentNodeId, propertytypeid
case "NAME":
return "umbracoNode.text";
case "PUBLISHED":
return "cmsDocument.published";
case "OWNER":
return "cmsDocument.published";
//TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
return "umbracoNode.nodeUser";
// Members only
@@ -772,25 +790,159 @@ ORDER BY contentNodeId, propertytypeid
/// <returns></returns>
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
internal class DocumentDefinitionCollection : KeyedCollection<ValueType, DocumentDefinition>
{
private readonly bool _includeAllVersions;
/// <summary>
/// Constructor specifying if all versions should be allowed, in that case the key for the collection becomes the versionId (GUID)
/// </summary>
/// <param name="includeAllVersions"></param>
public DocumentDefinitionCollection(bool includeAllVersions = false)
{
_includeAllVersions = includeAllVersions;
}
protected override ValueType GetKeyForItem(DocumentDefinition item)
{
return _includeAllVersions ? (ValueType)item.Version : item.Id;
}
/// <summary>
/// if this key already exists if it does then we need to check
/// if the existing item is 'older' than the new item and if that is the case we'll replace the older one
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool AddOrUpdate(DocumentDefinition item)
{
//if we are including all versions then just add, we aren't checking for latest
if (_includeAllVersions)
{
base.Add(item);
return true;
}
if (Dictionary == null)
{
base.Add(item);
return true;
}
var key = GetKeyForItem(item);
DocumentDefinition found;
if (TryGetValue(key, out found))
{
//it already exists and it's older so we need to replace it
if (item.VersionId > found.VersionId)
{
var currIndex = Items.IndexOf(found);
if (currIndex == -1)
throw new IndexOutOfRangeException("Could not find the item in the list: " + found.Version);
//replace the current one with the newer one
SetItem(currIndex, item);
return true;
}
//could not add or update
return false;
}
base.Add(item);
return true;
}
public bool TryGetValue(ValueType key, out DocumentDefinition val)
{
if (Dictionary == null)
{
val = null;
return false;
}
return Dictionary.TryGetValue(key, out val);
}
}
/// <summary>
/// A custom comparer required for sorting entities by GUIDs to match how the sorting of GUIDs works on SQL server
/// </summary>
/// <remarks>
/// MySql sorts GUIDs as a string, MSSQL sorts based on byte sections, this comparer will allow sorting GUIDs to be the same as how SQL server does
/// </remarks>
private class DocumentDefinitionComparer : IComparer<Guid>
{
private readonly ISqlSyntaxProvider _sqlSyntax;
public DocumentDefinitionComparer(ISqlSyntaxProvider sqlSyntax)
{
_sqlSyntax = sqlSyntax;
}
public int Compare(Guid x, Guid y)
{
//MySql sorts on GUIDs as strings (i.e. normal)
if (_sqlSyntax is MySqlSyntaxProvider)
{
return x.CompareTo(y);
}
//MSSQL doesn't it sorts them on byte sections!
return new SqlGuid(x).CompareTo(new SqlGuid(y));
}
}
internal class DocumentDefinition
{
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
/// </summary>
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
public DocumentDefinition(DocumentDto dto, IContentTypeComposition composition)
{
Id = id;
Version = version;
VersionDate = versionDate;
CreateDate = createDate;
DocumentDto = dto;
ContentVersionDto = dto.ContentVersionDto;
Composition = composition;
}
public int Id { get; set; }
public Guid Version { get; set; }
public DateTime VersionDate { get; set; }
public DateTime CreateDate { get; set; }
public IContentTypeComposition Composition { get; set; }
public DocumentDefinition(ContentVersionDto dto, IContentTypeComposition composition)
{
ContentVersionDto = dto;
Composition = composition;
}
public DocumentDto DocumentDto { get; private set; }
public ContentVersionDto ContentVersionDto { get; private set; }
public int Id
{
get { return ContentVersionDto.NodeId; }
}
public Guid Version
{
get { return DocumentDto != null ? DocumentDto.VersionId : ContentVersionDto.VersionId; }
}
/// <summary>
/// This is used to determien which version is the most recent
/// </summary>
public int VersionId
{
get { return ContentVersionDto.Id; }
}
public DateTime VersionDate
{
get { return ContentVersionDto.VersionDate; }
}
public DateTime CreateDate
{
get { return ContentVersionDto.ContentDto.NodeDto.CreateDate; }
}
public IContentTypeComposition Composition { get; set; }
}
/// <summary>
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence
//if (sqlSyntax == null) throw new ArgumentNullException("sqlSyntax");
if (settings == null) throw new ArgumentNullException("settings");
_cacheHelper = cacheHelper;
_cacheHelper = cacheHelper;
//IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying
// runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Persistence
{
}
[Obsolete("Use the ctor specifying all dependencies instead, NOTE: disableAllCache has zero effect")]
[Obsolete("Use the ctor specifying all dependencies instead, NOTE: disableAllCache has zero effect")]
public RepositoryFactory(bool disableAllCache, CacheHelper cacheHelper)
: this(cacheHelper, LoggerResolver.Current.Logger, SqlSyntaxContext.SqlSyntaxProvider, UmbracoConfig.For.UmbracoSettings())
{
@@ -86,7 +86,7 @@ namespace Umbraco.Core.Persistence
{
}
#endregion
public virtual IExternalLoginRepository CreateExternalLoginRepository(IScopeUnitOfWork uow)
@@ -235,12 +235,13 @@ namespace Umbraco.Core.Persistence
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual IStylesheetRepository CreateStylesheetRepository(IUnitOfWork uow, IDatabaseUnitOfWork db)
{
// note: the second unit of work is ignored.
return new StylesheetRepository(uow, FileSystemProviderManager.Current.StylesheetsFileSystem);
}
public virtual ITemplateRepository CreateTemplateRepository(IScopeUnitOfWork uow)
{
return new TemplateRepository(uow,
return new TemplateRepository(uow,
_cacheHelper,
_logger, _sqlSyntax,
FileSystemProviderManager.Current.MasterPagesFileSystem,
@@ -279,7 +280,7 @@ namespace Umbraco.Core.Persistence
}
public virtual IUserRepository CreateUserRepository(IScopeUnitOfWork uow)
{
{
return new UserRepository(
uow,
//Need to cache users - we look up user information more than anything in the back office!
@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Persistence.UnitOfWork
{
internal class FileUnitOfWork : ScopeUnitOfWork
{
// fixme
// soon as FileUnitOfWork inherits from ScopeUnitOfWork it does not make any sense anymore to keep this class around?!
public FileUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified)
: base(scopeProvider, isolationLevel)
{ }
}
}
@@ -4,10 +4,15 @@ using Umbraco.Core.Scoping;
namespace Umbraco.Core.Persistence.UnitOfWork
{
// note: the concept of "file unit of work" does not make sense anymore in v7.6
// and we should probably remove this class, which is not used anywhere, but for
// the time being we keep it here - just not to break too many things.
/// <summary>
/// Represents a Unit of Work Provider for creating a file unit of work
/// </summary>
public class FileUnitOfWorkProvider : ScopeUnitOfWorkProvider // fixme - what's the point?
[Obsolete("Use the ScopeUnitOfWorkProvider instead.", false)]
public class FileUnitOfWorkProvider : ScopeUnitOfWorkProvider
{
[Obsolete("Use the ctor specifying a IScopeProvider instead")]
public FileUnitOfWorkProvider()
@@ -18,11 +23,8 @@ namespace Umbraco.Core.Persistence.UnitOfWork
: base(scopeProvider)
{ }
// fixme - returning a IScopeUnitOfWork instead of a IUnitOfWork here is a breaking change!
// this is bad, we're going to end up creating // units of work which is ... really bad
public override IScopeUnitOfWork GetUnitOfWork()
{
// fixme - no point returning a FileUnitOfWork if its equivalent to ScopeUnitOfWork
return new ScopeUnitOfWork(ScopeProvider);
}
}
@@ -18,19 +18,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork
// creates a unit of work
// support specifying an isolation level
// support auto-commit - beware!
// fixme - should we be able to specify ALL scope options?
// fixme - that isolation level thing is a pain because of the above existing method
IScopeUnitOfWork GetUnitOfWork(bool commit);
IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool commit = false);
// creates a readonly unit of work
// the readonly unit of work will not accept operations, and will auto-complete
// of course it would be a bad idea to use it for anything else than reading
// fixme - implement that one FOR REAL not as an extension method
// the extension method was a ugly hack
// or maybe we want a autocommit flag in the ctor?
//IScopeUnitOfWork GetReadOnlyUnitOfWork();
//IScopeUnitOfWork GetReadOnlyUnitOfWork(bool autocommit = false);
// support auto-commit - but beware! it will be committed, whatever happens
// TODO in v8 this should all be merged as one single method with optional args
IScopeUnitOfWork GetUnitOfWork(bool readOnly);
IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool readOnly = false);
}
}
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
private readonly IsolationLevel _isolationLevel;
private readonly IScopeProvider _scopeProvider;
private bool _completeScope;
private readonly bool _readOnly;
private IScope _scope;
private Guid _key;
@@ -29,11 +30,11 @@ namespace Umbraco.Core.Persistence.UnitOfWork
/// </summary>
/// <param name="scopeProvider"></param>
/// <param name="isolationLevel"></param>
/// <param name="commit"></param>
/// <param name="readOnly"></param>
/// <remarks>
/// This should normally not be used directly and should be created with the UnitOfWorkProvider
/// </remarks>
internal ScopeUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified, bool commit = false)
internal ScopeUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified, bool readOnly = false)
{
_scopeProvider = scopeProvider;
_isolationLevel = isolationLevel;
@@ -43,7 +44,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
// be false by default
// if set to true... the UnitOfWork is "auto-commit" which means that even in the case of
// an exception, the scope would still be completed - ppl should use it with great care!
_completeScope = commit;
_completeScope = _readOnly = readOnly;
}
/// <summary>
@@ -53,6 +54,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork
/// <param name="repository">The <see cref="IUnitOfWorkRepository" /> participating in the transaction</param>
public void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository)
{
if (_readOnly)
throw new NotSupportedException("This unit of work is read-only.");
_operations.Enqueue(new Operation
{
Entity = entity,
@@ -68,7 +72,10 @@ namespace Umbraco.Core.Persistence.UnitOfWork
/// <param name="repository">The <see cref="IUnitOfWorkRepository" /> participating in the transaction</param>
public void RegisterChanged(IEntity entity, IUnitOfWorkRepository repository)
{
_operations.Enqueue(
if (_readOnly)
throw new NotSupportedException("This unit of work is read-only.");
_operations.Enqueue(
new Operation
{
Entity = entity,
@@ -84,7 +91,10 @@ namespace Umbraco.Core.Persistence.UnitOfWork
/// <param name="repository">The <see cref="IUnitOfWorkRepository" /> participating in the transaction</param>
public void RegisterRemoved(IEntity entity, IUnitOfWorkRepository repository)
{
_operations.Enqueue(
if (_readOnly)
throw new NotSupportedException("This unit of work is read-only.");
_operations.Enqueue(
new Operation
{
Entity = entity,
@@ -116,6 +126,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork
{
// this happens in a scope-managed transaction
if (_readOnly)
throw new NotSupportedException("This unit of work is read-only.");
// in case anything goes wrong
_completeScope = false;
@@ -24,48 +24,28 @@ namespace Umbraco.Core.Persistence.UnitOfWork
return new ScopeUnitOfWork(ScopeProvider);
}
/// <summary>
/// Creates a Unit of work with a new UmbracoDatabase instance for the work item/transaction.
/// </summary>
/// <returns></returns>
/// <remarks>
/// Each PetaPoco UOW uses it's own Database object, not the shared Database object that comes from
/// the ApplicationContext.Current.DatabaseContext.Database. This is because each transaction should use it's own Database
/// and we Dispose of this Database object when the UOW is disposed.
/// fixme NO we dispose of it when the transaction completes
/// fixme just inheritdoc!
/// </remarks>
/// <inheritdoc />
public virtual IScopeUnitOfWork GetUnitOfWork()
{
return new ScopeUnitOfWork(ScopeProvider);
}
/// <summary>
/// Creates a Unit of work with a new UmbracoDatabase instance for the work item/transaction.
/// </summary>
/// <returns></returns>
/// <remarks>
/// Each PetaPoco UOW uses it's own Database object, not the shared Database object that comes from
/// the ApplicationContext.Current.DatabaseContext.Database. This is because each transaction should use it's own Database
/// and we Dispose of this Database object when the UOW is disposed.
/// fixme NO
/// fixme just inheritdoc!
/// </remarks>
/// <inheritdoc />
public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel)
{
return new ScopeUnitOfWork(ScopeProvider, isolationLevel);
}
/// <inheritdoc />
public IScopeUnitOfWork GetUnitOfWork(bool commit)
public IScopeUnitOfWork GetUnitOfWork(bool readOnly)
{
return new ScopeUnitOfWork(ScopeProvider, commit: commit);
return new ScopeUnitOfWork(ScopeProvider, readOnly: readOnly);
}
/// <inheritdoc />
public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool commit)
public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool readOnly)
{
return new ScopeUnitOfWork(ScopeProvider, isolationLevel, commit: commit);
return new ScopeUnitOfWork(ScopeProvider, isolationLevel, readOnly: readOnly);
}
}
}
@@ -47,5 +47,9 @@ using System.Security.Permissions;
[assembly: InternalsVisibleTo("Umbraco.Deploy.UI")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.Cloud")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
//allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IEnumerable<string>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class CheckboxListValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.CheckBoxListAlias);
}
return false;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
var sourceString = (source ?? string.Empty).ToString();
if (string.IsNullOrEmpty(sourceString))
return Enumerable.Empty<string>();
var values =
sourceString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim());
return values;
}
}
}
@@ -1,18 +1,28 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class ColorPickerValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias);
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
// make sure it's a string
return source.ToString();
return source == null ? string.Empty : source.ToString();
}
}
}
@@ -6,6 +6,7 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(DateTime))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DatePickerValueConverter : PropertyValueConverterBase
@@ -3,6 +3,7 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(decimal))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DecimalValueConverter : PropertyValueConverterBase
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IEnumerable<string>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DropdownListMultipleValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListMultipleAlias);
}
return false;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
var sourceString = (source ?? "").ToString();
if (string.IsNullOrEmpty(sourceString))
return Enumerable.Empty<string>();
var values =
sourceString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim());
return values;
}
}
}
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IEnumerable<int>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DropdownListMultipleWithKeysValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistMultiplePublishKeysAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null)
return new int[] { };
var prevalueIds = source.ToString()
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.Select(int.Parse)
.ToArray();
return prevalueIds;
}
}
}
@@ -0,0 +1,28 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DropdownListValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
return source == null ? string.Empty : source.ToString();
}
}
}
@@ -0,0 +1,31 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(int))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DropdownListWithKeysValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistPublishingKeysAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
var intAttempt = source.TryConvertTo<int>();
if (intAttempt.Success)
return intAttempt.Result;
return null;
}
}
}
@@ -0,0 +1,27 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class EmailAddressValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.EmailAddressAlias);
}
return false;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
return source.ToString();
}
}
}
@@ -2,6 +2,7 @@
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(int))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class IntegerValueConverter : PropertyValueConverterBase
@@ -4,6 +4,7 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MarkdownEditorValueConverter : PropertyValueConverterBase
@@ -0,0 +1,27 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MemberGroupPickerValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.MemberGroupPickerAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
return source == null ? string.Empty : source.ToString();
}
}
}
@@ -8,6 +8,7 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IEnumerable<string>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MultipleTextStringValueConverter : PropertyValueConverterBase
@@ -0,0 +1,31 @@
using System;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(int))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class RadioButtonListValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.RadioButtonListAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
var intAttempt = source.TryConvertTo<int>();
if (intAttempt.Success)
return intAttempt.Result;
return null;
}
}
}
@@ -0,0 +1,100 @@
using System;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
public class SliderValueConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
{
private readonly IDataTypeService _dataTypeService;
//TODO: Remove this ctor in v8 since the other one will use IoC
public SliderValueConverter()
: this(ApplicationContext.Current.Services.DataTypeService)
{
}
public SliderValueConverter(IDataTypeService dataTypeService)
{
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
_dataTypeService = dataTypeService;
}
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.SliderAlias);
}
return false;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null)
{
return null;
}
if (IsRangeDataType(propertyType.DataTypeId))
{
var rangeRawValues = source.ToString().Split(',');
var minimumAttempt = rangeRawValues[0].TryConvertTo<decimal>();
var maximumAttempt = rangeRawValues[1].TryConvertTo<decimal>();
if (minimumAttempt.Success && maximumAttempt.Success)
{
return new Range<decimal>() { Maximum = maximumAttempt.Result, Minimum = minimumAttempt.Result };
}
}
var valueAttempt = source.ToString().TryConvertTo<decimal>();
if (valueAttempt.Success)
{
return valueAttempt.Result;
}
// Something failed in the conversion of the strings to decimals
return null;
}
public Type GetPropertyValueType(PublishedPropertyType propertyType)
{
if (IsRangeDataType(propertyType.DataTypeId))
{
return typeof(Range<decimal>);
}
return typeof(decimal);
}
public PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue)
{
return PropertyCacheLevel.Content;
}
/// <summary>
/// Discovers if the slider is set to range mode.
/// </summary>
/// <param name="dataTypeId">
/// The data type id.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
private bool IsRangeDataType(int dataTypeId)
{
// ** This must be cached (U4-8862) **
var enableRange =
_dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId)
.PreValuesAsDictionary.FirstOrDefault(
x => string.Equals(x.Key, "enableRange", StringComparison.InvariantCultureIgnoreCase)).Value;
return enableRange != null && enableRange.Value.TryConvertTo<bool>().Result;
}
}
}
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IEnumerable<string>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class TagsValueConverter : PropertyValueConverterBase
{
private readonly IDataTypeService _dataTypeService;
//TODO: Remove this ctor in v8 since the other one will use IoC
public TagsValueConverter()
: this(ApplicationContext.Current.Services.DataTypeService)
{
}
public TagsValueConverter(IDataTypeService dataTypeService)
{
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
_dataTypeService = dataTypeService;
}
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.TagsAlias);
}
return false;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
// if Json storage type deserialzie and return as string array
if (JsonStorageType(propertyType.DataTypeId))
{
var jArray = JsonConvert.DeserializeObject<JArray>(source.ToString());
return jArray.ToObject<string[]>();
}
// Otherwise assume CSV storage type and return as string array
var csvTags =
source.ToString()
.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.ToArray();
return csvTags;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null)
{
return null;
}
return (string[]) source;
}
/// <summary>
/// Discovers if the tags data type is storing its data in a Json format
/// </summary>
/// <param name="dataTypeId">
/// The data type id.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
private bool JsonStorageType(int dataTypeId)
{
// ** This must be cached (U4-8862) **
var storageType =
_dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId)
.PreValuesAsDictionary.FirstOrDefault(
x => string.Equals(x.Key, "storageType", StringComparison.InvariantCultureIgnoreCase)).Value;
if (storageType != null && storageType.Value.InvariantEquals("Json"))
{
return true;
}
return false;
}
}
}
@@ -6,11 +6,12 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class TextStringValueConverter : PropertyValueConverterBase
{
private readonly static string[] PropertyTypeAliases =
private static readonly string[] PropertyTypeAliases =
{
Constants.PropertyEditors.TextboxAlias,
Constants.PropertyEditors.TextboxMultipleAlias
@@ -4,10 +4,11 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
/// <summary>
/// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used.
/// </summary>
/// <summary>
/// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used.
/// </summary>
// PropertyCacheLevel.Content is ok here because that version of RTE converter does not parse {locallink} nor executes macros
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class TinyMceValueConverter : PropertyValueConverterBase
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
/// <summary>
/// The upload property value converter.
/// </summary>
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class UploadPropertyConverter : PropertyValueConverterBase
{
/// <summary>
/// Checks if this converter can convert the property editor and registers if it can.
/// </summary>
/// <param name="propertyType">
/// The published property type.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters)
{
return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.UploadFieldAlias);
}
return false;
}
/// <summary>
/// Convert the source object to a string
/// </summary>
/// <param name="propertyType">
/// The published property type.
/// </param>
/// <param name="source">
/// The value of the property
/// </param>
/// <param name="preview">
/// The preview.
/// </param>
/// <returns>
/// The <see cref="object"/>.
/// </returns>
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
return (source ?? "").ToString();
}
}
}
@@ -3,6 +3,7 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(bool))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class YesNoValueConverter : PropertyValueConverterBase
@@ -176,6 +176,7 @@ namespace Umbraco.Core.Scoping
}
}
// this is for tests exclusively until we have a proper accessor in v8
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
private static IDictionary HttpContextItems
@@ -324,6 +324,14 @@ namespace Umbraco.Core.Security
throw new MembershipPasswordException("Change password canceled due to password validation failure.");
}
//Special case to allow changing password without validating existing credentials
//This is used during installation only
if (AllowManuallyChangingPassword == false && ApplicationContext.Current != null
&& ApplicationContext.Current.IsConfigured == false && oldPassword == "default")
{
return PerformChangePassword(username, oldPassword, newPassword);
}
if (AllowManuallyChangingPassword == false)
{
if (ValidateUser(username, oldPassword) == false) return false;
File diff suppressed because it is too large Load Diff
+151 -134
View File
@@ -1,22 +1,15 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Threading;
using AutoMapper;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -76,6 +69,7 @@ namespace Umbraco.Core.Services
}
catch (Exception ex)
{
uow.Commit();
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
}
}
@@ -113,6 +107,7 @@ namespace Umbraco.Core.Services
}
catch (Exception ex)
{
uow.Commit();
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
}
}
@@ -139,7 +134,7 @@ namespace Umbraco.Core.Services
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
EntityContainer container,
Guid containerObjectType,
string objectTypeName,
string objectTypeName,
string savedEventName,
int userId)
{
@@ -159,10 +154,9 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
// fixme - how does it work w/name?!
if (uow.Events.DispatchCancelable(savingEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs)))
//if (savingEvent.IsRaisedEventCancelled(new SaveEventArgs<EntityContainer>(container, evtMsgs), this, UowProvider))
{
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
@@ -189,7 +183,7 @@ namespace Umbraco.Core.Services
private EntityContainer GetContainer(int containerId, Guid containerObjectType)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType);
return repo.Get(containerId);
@@ -198,7 +192,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetMediaTypeContainers(int[] containerIds)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid);
return repo.GetAll(containerIds);
@@ -207,7 +201,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetMediaTypeContainers(string name, int level)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid);
return repo.Get(name, level);
@@ -236,7 +230,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid);
return repo.GetAll(containerIds);
@@ -265,7 +259,7 @@ namespace Umbraco.Core.Services
private EntityContainer GetContainer(Guid containerId, Guid containerObjectType)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType);
return repo.Get(containerId);
@@ -274,7 +268,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetContentTypeContainers(string name, int level)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid);
return repo.Get(name, level);
@@ -288,7 +282,11 @@ namespace Umbraco.Core.Services
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid);
var container = repo.Get(containerId);
if (container == null) return OperationStatus.NoOperation(evtMsgs); // fixme commit?
if (container == null)
{
uow.Commit();
return OperationStatus.NoOperation(evtMsgs);
}
if (uow.Events.DispatchCancelable(DeletingContentTypeContainer, this, new DeleteEventArgs<EntityContainer>(container, evtMsgs)))
{
@@ -314,7 +312,11 @@ namespace Umbraco.Core.Services
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid);
var container = repo.Get(containerId);
if (container == null) return OperationStatus.NoOperation(evtMsgs); // fixme commit?
if (container == null)
{
uow.Commit();
return OperationStatus.NoOperation(evtMsgs);
}
if (uow.Events.DispatchCancelable(DeletingMediaTypeContainer, this, new DeleteEventArgs<EntityContainer>(container, evtMsgs)))
{
@@ -340,7 +342,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public IEnumerable<string> GetAllPropertyTypeAliases()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.GetAllPropertyTypeAliases();
@@ -357,7 +359,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.GetAllContentTypeAliases(objectTypes);
@@ -454,7 +456,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IContentType"/></returns>
public IContentType GetContentType(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.Get(id);
@@ -468,7 +470,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IContentType"/></returns>
public IContentType GetContentType(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.Get(alias);
@@ -482,7 +484,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IContentType"/></returns>
public IContentType GetContentType(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.Get(id);
@@ -496,7 +498,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
public IEnumerable<IContentType> GetAllContentTypes(params int[] ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.GetAll(ids);
@@ -510,7 +512,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
public IEnumerable<IContentType> GetAllContentTypes(IEnumerable<Guid> ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.GetAll(ids.ToArray());
@@ -524,7 +526,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
public IEnumerable<IContentType> GetContentTypeChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
var query = Query<IContentType>.Builder.Where(x => x.ParentId == id);
@@ -539,7 +541,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
public IEnumerable<IContentType> GetContentTypeChildren(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
@@ -557,7 +559,7 @@ namespace Umbraco.Core.Services
/// <returns>True if the content type has any children otherwise False</returns>
public bool HasChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
@@ -573,7 +575,7 @@ namespace Umbraco.Core.Services
/// <returns>True if the content type has any children otherwise False</returns>
public bool HasChildren(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
@@ -584,6 +586,27 @@ namespace Umbraco.Core.Services
}
}
public override IEnumerable<IContentTypeBase> GetDescendants(IContentTypeBase contentType)
{
var ctype = contentType as IContentType;
if (ctype != null) return GetDescendants(ctype);
var mtype = contentType as IMediaType;
if (mtype != null) return GetDescendants(mtype);
return Enumerable.Empty<IContentTypeBase>();
}
public IEnumerable<IContentType> GetDescendants(IContentType contentType)
{
return GetContentTypeChildren(contentType.Id)
.SelectRecursive(type => GetContentTypeChildren(type.Id));
}
public IEnumerable<IMediaType> GetDescendants(IMediaType contentType)
{
return GetMediaTypeChildren(contentType.Id)
.SelectRecursive(type => GetMediaTypeChildren(type.Id));
}
/// <summary>
/// This is called after an IContentType is saved and is used to update the content xml structures in the database
/// if they are required to be updated.
@@ -591,42 +614,39 @@ namespace Umbraco.Core.Services
/// <param name="contentTypes">A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing)</param>
private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
{
var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray();
if (toUpdate.Any())
if (toUpdate.Any() == false) return;
var firstType = toUpdate.First();
//if it is a content type then call the rebuilding methods or content
if (firstType is IContentType)
{
var firstType = toUpdate.First();
//if it is a content type then call the rebuilding methods or content
if (firstType is IContentType)
var typedContentService = _contentService as ContentService;
if (typedContentService != null)
{
var typedContentService = _contentService as ContentService;
if (typedContentService != null)
{
typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray());
}
else
{
//this should never occur, the content service should always be typed but we'll check anyways.
_contentService.RePublishAll();
}
typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray());
}
else if (firstType is IMediaType)
else
{
//if it is a media type then call the rebuilding methods for media
var typedContentService = _mediaService as MediaService;
if (typedContentService != null)
{
typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
}
//this should never occur, the content service should always be typed but we'll check anyways.
_contentService.RePublishAll();
}
}
else if (firstType is IMediaType)
{
//if it is a media type then call the rebuilding methods for media
var typedContentService = _mediaService as MediaService;
if (typedContentService != null)
{
typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
}
}
}
public int CountContentTypes()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
return repository.Count(Query<IContentType>.Builder);
@@ -635,7 +655,7 @@ namespace Umbraco.Core.Services
public int CountMediaTypes()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.Count(Query<IMediaType>.Builder);
@@ -753,16 +773,15 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(contentType);
uow.Commit();
}
UpdateContentXmlStructure(contentType); // fixme wtf here?
UpdateContentXmlStructure(contentType);
uow.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(contentType, false));
Audit(uow, AuditType.Save, "Save ContentType performed by user", userId, contentType.Id);
uow.Commit();
}
}
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
{
scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(contentType, false));
scope.Complete();
}
Audit(AuditType.Save, "Save ContentType performed by user", userId, contentType.Id);
}
/// <summary>
@@ -783,7 +802,7 @@ namespace Umbraco.Core.Services
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
foreach (var contentType in asArray)
@@ -798,16 +817,15 @@ namespace Umbraco.Core.Services
//save it all in one go
uow.Commit();
}
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray()); // fixme wtf
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
uow.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(asArray, false));
Audit(uow, AuditType.Save, "Save ContentTypes performed by user", userId, -1);
uow.Commit();
}
}
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
{
scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(asArray, false));
scope.Complete();
}
Audit(AuditType.Save, "Save ContentTypes performed by user", userId, -1);
}
/// <summary>
@@ -817,7 +835,7 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional id of the user issueing the delete</param>
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
public void Delete(IContentType contentType, int userId = 0)
{
{
using (new WriteLock(Locker))
{
using (var uow = UowProvider.GetUnitOfWork())
@@ -829,20 +847,20 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
//If we are deleting this content type, we are also deleting it's descendents!
var deletedContentTypes = new List<IContentType>() {contentType};
deletedContentTypes.AddRange(contentType.Descendants((IContentTypeService)this).OfType<IContentType>());
var deletedContentTypes = new List<IContentType> {contentType};
deletedContentTypes.AddRange(GetDescendants(contentType));
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
repository.Delete(contentType);
uow.Commit();
uow.Events.Dispatch(DeletedContentType, this, new DeleteEventArgs<IContentType>(deletedContentTypes.DistinctBy(x => x.Id), false));
}
Audit(AuditType.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id);
Audit(uow, AuditType.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id);
uow.Commit();
}
}
}
@@ -857,7 +875,7 @@ namespace Umbraco.Core.Services
public void Delete(IEnumerable<IContentType> contentTypes, int userId = 0)
{
var asArray = contentTypes.ToArray();
using (new WriteLock(Locker))
{
using (var uow = UowProvider.GetUnitOfWork())
@@ -874,22 +892,21 @@ namespace Umbraco.Core.Services
var deletedContentTypes = new List<IContentType>(asArray);
foreach (var contentType in asArray)
{
deletedContentTypes.AddRange(contentType.Descendants((IContentTypeService)this).OfType<IContentType>());
deletedContentTypes.AddRange(GetDescendants(contentType));
}
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
foreach (var contentType in asArray)
{
repository.Delete(contentType);
}
uow.Commit();
uow.Events.Dispatch(DeletedContentType, this, new DeleteEventArgs<IContentType>(deletedContentTypes.DistinctBy(x => x.Id), false));
}
Audit(AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
Audit(uow, AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
uow.Commit();
}
}
}
@@ -900,7 +917,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMediaType"/></returns>
public IMediaType GetMediaType(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.Get(id);
@@ -914,7 +931,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMediaType"/></returns>
public IMediaType GetMediaType(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.Get(alias);
@@ -928,7 +945,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMediaType"/></returns>
public IMediaType GetMediaType(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.Get(id);
@@ -942,7 +959,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
public IEnumerable<IMediaType> GetAllMediaTypes(params int[] ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.GetAll(ids);
@@ -956,7 +973,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
public IEnumerable<IMediaType> GetAllMediaTypes(IEnumerable<Guid> ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
return repository.GetAll(ids.ToArray());
@@ -970,7 +987,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
public IEnumerable<IMediaType> GetMediaTypeChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
var query = Query<IMediaType>.Builder.Where(x => x.ParentId == id);
@@ -985,7 +1002,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMediaType"/> objects</returns>
public IEnumerable<IMediaType> GetMediaTypeChildren(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
var found = GetMediaType(id);
@@ -1002,7 +1019,7 @@ namespace Umbraco.Core.Services
/// <returns>True if the media type has any children otherwise False</returns>
public bool MediaTypeHasChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
var query = Query<IMediaType>.Builder.Where(x => x.ParentId == id);
@@ -1017,7 +1034,7 @@ namespace Umbraco.Core.Services
/// <returns>True if the media type has any children otherwise False</returns>
public bool MediaTypeHasChildren(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
var found = GetMediaType(id);
@@ -1035,7 +1052,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(MovingMediaType, this, new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId))))
{
uow.Commit();
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
}
var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid);
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
@@ -1052,8 +1072,8 @@ namespace Umbraco.Core.Services
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
return Attempt.Fail(
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
uow.Commit();
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
}
uow.Commit();
uow.Events.Dispatch(MovedMediaType, this, new MoveEventArgs<IMediaType>(false, evtMsgs, moveInfo.ToArray()));
@@ -1071,7 +1091,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(MovingContentType, this, new MoveEventArgs<IContentType>(evtMsgs, new MoveEventInfo<IContentType>(toMove, toMove.Path, containerId))))
{
uow.Commit();
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
}
var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid);
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
@@ -1088,8 +1111,8 @@ namespace Umbraco.Core.Services
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
return Attempt.Fail(
new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
uow.Commit();
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
}
uow.Commit();
uow.Events.Dispatch(MovedContentType, this, new MoveEventArgs<IContentType>(false, evtMsgs, moveInfo.ToArray()));
@@ -1135,6 +1158,7 @@ namespace Umbraco.Core.Services
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
uow.Commit();
return Attempt.Fail(new OperationStatus<IMediaType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
}
uow.Commit();
@@ -1179,6 +1203,7 @@ namespace Umbraco.Core.Services
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
uow.Commit();
return Attempt.Fail(new OperationStatus<IContentType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
}
uow.Commit();
@@ -1203,23 +1228,21 @@ namespace Umbraco.Core.Services
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
ValidateLocked(mediaType); // throws if invalid
mediaType.CreatorId = userId;
repository.AddOrUpdate(mediaType);
uow.Commit();
}
UpdateContentXmlStructure(mediaType); // fixme wtf
UpdateContentXmlStructure(mediaType);
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
{
scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(mediaType, false));
scope.Complete();
uow.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(mediaType, false));
Audit(uow, AuditType.Save, "Save MediaType performed by user", userId, mediaType.Id);
uow.Commit();
}
Audit(AuditType.Save, "Save MediaType performed by user", userId, mediaType.Id);
}
}
@@ -1231,7 +1254,7 @@ namespace Umbraco.Core.Services
public void Save(IEnumerable<IMediaType> mediaTypes, int userId = 0)
{
var asArray = mediaTypes.ToArray();
using (new WriteLock(Locker))
{
using (var uow = UowProvider.GetUnitOfWork())
@@ -1241,7 +1264,7 @@ namespace Umbraco.Core.Services
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
foreach (var mediaType in asArray)
@@ -1256,15 +1279,14 @@ namespace Umbraco.Core.Services
//save it all in one go
uow.Commit();
}
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray()); // fixme wtf
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
{
scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(asArray, false));
scope.Complete();
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
uow.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(asArray, false));
Audit(uow, AuditType.Save, "Save MediaTypes performed by user", userId, -1);
uow.Commit();
}
Audit(AuditType.Save, "Save MediaTypes performed by user", userId, -1);
}
}
@@ -1292,17 +1314,17 @@ namespace Umbraco.Core.Services
//If we are deleting this content type, we are also deleting it's descendents!
var deletedMediaTypes = new List<IMediaType> { mediaType };
deletedMediaTypes.AddRange(mediaType.Descendants((IContentTypeService)this).OfType<IMediaType>());
deletedMediaTypes.AddRange(GetDescendants(mediaType));
_mediaService.DeleteMediaOfTypes(deletedMediaTypes.Select(x => x.Id), userId);
repository.Delete(mediaType);
uow.Commit();
uow.Events.Dispatch(DeletedMediaType, this, new DeleteEventArgs<IMediaType>(deletedMediaTypes.DistinctBy(x => x.Id), false));
}
Audit(AuditType.Delete, "Delete MediaType performed by user", userId, mediaType.Id);
Audit(uow, AuditType.Delete, "Delete MediaType performed by user", userId, mediaType.Id);
uow.Commit();
}
}
}
@@ -1317,7 +1339,7 @@ namespace Umbraco.Core.Services
//TODO: Share all of this logic with the Delete IContentType methods, no need for code duplication
var asArray = mediaTypes.ToArray();
using (new WriteLock(Locker))
{
using (var uow = UowProvider.GetUnitOfWork())
@@ -1329,12 +1351,12 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
//If we are deleting this content type, we are also deleting it's descendents!
var deletedMediaTypes = new List<IMediaType>(asArray);
foreach (var mediaType in asArray)
{
deletedMediaTypes.AddRange(mediaType.Descendants((IContentTypeService)this).OfType<IMediaType>());
deletedMediaTypes.AddRange(GetDescendants(mediaType));
}
_mediaService.DeleteMediaOfTypes(deletedMediaTypes.Select(x => x.Id), userId);
@@ -1344,12 +1366,11 @@ namespace Umbraco.Core.Services
repository.Delete(mediaType);
}
uow.Commit();
uow.Events.Dispatch(DeletedMediaType, this, new DeleteEventArgs<IMediaType>(deletedMediaTypes.DistinctBy(x => x.Id), false));
}
Audit(AuditType.Delete, "Delete MediaTypes performed by user", userId, -1);
Audit(uow, AuditType.Delete, "Delete MediaTypes performed by user", userId, -1);
uow.Commit();
}
}
}
@@ -1408,14 +1429,10 @@ namespace Umbraco.Core.Services
return dtd.ToString();
}
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var auditRepo = RepositoryFactory.CreateAuditRepository(uow);
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var auditRepo = RepositoryFactory.CreateAuditRepository(uow);
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
#region Event Handlers
@@ -13,9 +13,8 @@ namespace Umbraco.Core.Services
{
public ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{
}
{ }
/// <summary>
/// This is called after an content type is saved and is used to update the content xml structures in the database
/// if they are required to be updated.
@@ -33,7 +32,7 @@ namespace Umbraco.Core.Services
// - a content type changes it's alias OR
// - if a content type has it's property removed OR
// - if a content type has a property whose alias has changed
//here we need to check if the alias of the content type changed or if one of the properties was removed.
//here we need to check if the alias of the content type changed or if one of the properties was removed.
var dirty = contentType as IRememberBeingDirty;
if (dirty == null) continue;
@@ -50,25 +49,30 @@ namespace Umbraco.Core.Services
&& (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias))
{
//If the alias was changed then we only need to update the xml structures for content of the current content type.
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
// content of the current content type and any of the content type's child content types.
if (dirty.WasPropertyDirty("Alias")
&& dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false)
{
//if only the alias changed then only update the current content type
//if only the alias changed then only update the current content type
toUpdate.Add(contentType);
}
else
{
//if a property was deleted or alias changed, then update all content of the current content type
// and all of it's desscendant doc types.
toUpdate.AddRange(contentType.DescendantsAndSelf(this));
// and all of it's desscendant doc types.
toUpdate.Add(contentType);
toUpdate.AddRange(GetDescendants(contentType));
}
}
}
return toUpdate;
}
public virtual IEnumerable<IContentTypeBase> GetDescendants(IContentTypeBase contentType)
{
return Enumerable.Empty<IContentTypeBase>();
}
}
}
+32 -33
View File
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Services
public EntityContainer GetContainer(int containerId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid);
return repo.Get(containerId);
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Services
public EntityContainer GetContainer(Guid containerId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid);
return repo.Get(containerId);
@@ -84,7 +84,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetContainers(string name, int level)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid);
return repo.Get(name, level);
@@ -108,7 +108,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetContainers(int[] containerIds)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid);
return repo.GetAll(containerIds);
@@ -181,7 +181,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IDataTypeDefinition"/></returns>
public IDataTypeDefinition GetDataTypeDefinitionByName(string name)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
return repository.GetByQuery(new Query<IDataTypeDefinition>().Where(x => x.Name == name)).FirstOrDefault();
@@ -195,7 +195,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IDataTypeDefinition"/></returns>
public IDataTypeDefinition GetDataTypeDefinitionById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
return repository.Get(id);
@@ -209,7 +209,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IDataTypeDefinition"/></returns>
public IDataTypeDefinition GetDataTypeDefinitionById(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
var query = Query<IDataTypeDefinition>.Builder.Where(x => x.Key == id);
@@ -238,7 +238,7 @@ namespace Umbraco.Core.Services
/// <returns>Collection of <see cref="IDataTypeDefinition"/> objects with a matching contorl id</returns>
public IEnumerable<IDataTypeDefinition> GetDataTypeDefinitionByPropertyEditorAlias(string propertyEditorAlias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
var query = Query<IDataTypeDefinition>.Builder.Where(x => x.PropertyEditorAlias == propertyEditorAlias);
@@ -253,7 +253,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="IDataTypeDefinition"/> objects</returns>
public IEnumerable<IDataTypeDefinition> GetAllDataTypeDefinitions(params int[] ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
return repository.GetAll(ids);
@@ -267,7 +267,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of string values</returns>
public IEnumerable<string> GetPreValuesByDataTypeId(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
//now convert the collection to a string list
@@ -284,7 +284,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public PreValueCollection GetPreValuesCollectionByDataTypeId(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
return repository.GetPreValuesCollectionByDataTypeId(id);
@@ -298,7 +298,7 @@ namespace Umbraco.Core.Services
/// <returns>PreValue as a string</returns>
public string GetPreValueAsString(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
return repository.GetPreValueAsString(id);
@@ -313,7 +313,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IDataTypeDefinition>(evtMsgs, new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId))))
{
uow.Commit();
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs));
}
var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid);
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
@@ -366,13 +369,12 @@ namespace Umbraco.Core.Services
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
uow.Commit();
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
}
// FIXME transaction!
Audit(AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
Audit(uow, AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
uow.Commit();
}
}
/// <summary>
@@ -411,13 +413,13 @@ namespace Umbraco.Core.Services
dataTypeDefinition.CreatorId = userId;
repository.AddOrUpdate(dataTypeDefinition);
}
uow.Commit();
if (raiseEvents)
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions, false));
}
Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1);
Audit(uow, AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -487,7 +489,6 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
repository.AddOrUpdatePreValues(dataTypeDefinition, values);
uow.Commit();
}
@@ -504,7 +505,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition)))
{
uow.Commit();
return;
}
// if preValues contain the data type, override the data type definition accordingly
if (values != null && values.ContainsKey(Constants.PropertyEditors.PreValueKeys.DataValueType))
@@ -520,12 +524,11 @@ namespace Umbraco.Core.Services
//add/update the prevalues
repository.AddOrUpdatePreValues(dataTypeDefinition, values);
Audit(uow, AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
uow.Commit();
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
}
Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
}
/// <summary>
@@ -542,18 +545,20 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IDataTypeDefinition>(dataTypeDefinition)))
{
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow);
repository.Delete(dataTypeDefinition);
Audit(uow, AuditType.Delete, "Delete DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
uow.Commit();
uow.Events.Dispatch(Deleted, this, new DeleteEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
}
Audit(AuditType.Delete, "Delete DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
}
/// <summary>
@@ -577,14 +582,10 @@ namespace Umbraco.Core.Services
return DataTypesResolver.Current.DataTypes;
}
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var auditRepo = RepositoryFactory.CreateAuditRepository(uow);
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var auditRepo = RepositoryFactory.CreateAuditRepository(uow);
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
#region Event Handlers
@@ -624,7 +625,5 @@ namespace Umbraco.Core.Services
/// </summary>
public static event TypedEventHandler<IDataTypeService, MoveEventArgs<IDataTypeDefinition>> Moved;
#endregion
}
}
+11 -5
View File
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Services
public bool Exists(string domainName)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateDomainRepository(uow);
return repo.Exists(domainName);
@@ -33,7 +33,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IDomain>(domain, evtMsgs)))
{
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
var repository = RepositoryFactory.CreateDomainRepository(uow);
repository.Delete(domain);
@@ -49,7 +52,7 @@ namespace Umbraco.Core.Services
public IDomain GetByName(string name)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDomainRepository(uow);
return repository.GetByName(name);
@@ -58,7 +61,7 @@ namespace Umbraco.Core.Services
public IDomain GetById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateDomainRepository(uow);
return repo.Get(id);
@@ -67,7 +70,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IDomain> GetAll(bool includeWildcards)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateDomainRepository(uow);
return repo.GetAll(includeWildcards);
@@ -76,7 +79,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IDomain> GetAssignedDomains(int contentId, bool includeWildcards)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repo = RepositoryFactory.CreateDomainRepository(uow);
return repo.GetAssignedDomains(contentId, includeWildcards);
@@ -90,7 +93,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDomain>(domainEntity, evtMsgs)))
{
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
var repository = RepositoryFactory.CreateDomainRepository(uow);
repository.AddOrUpdate(domainEntity);
+2 -2
View File
@@ -647,7 +647,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="UmbracoObjectTypes"/></returns>
public virtual UmbracoObjectTypes GetObjectType(int id)
{
using (var uow = UowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var sql = new Sql().Select("nodeObjectType").From<NodeDto>().Where<NodeDto>(x => x.NodeId == id);
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
@@ -663,7 +663,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="UmbracoObjectTypes"/></returns>
public virtual UmbracoObjectTypes GetObjectType(Guid key)
{
using (var uow = UowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var sql = new Sql().Select("nodeObjectType").From<NodeDto>().Where<NodeDto>(x => x.UniqueId == key);
var nodeObjectTypeId = uow.Database.ExecuteScalar<Guid>(sql);
+108 -122
View File
@@ -15,31 +15,21 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
// note
// file unit of work are just IUnitOfWork which is not IDisposable
// they don't really participate in the scope etc ;(
// FIXME not anymore now that Shan's made FileUnitOfWork a normal UOW? then WTF?
/// <summary>
/// Represents the File Service, which is an easy access to operations involving <see cref="IFile"/> objects like Scripts, Stylesheets and Templates
/// </summary>
public class FileService : ScopeRepositoryService, IFileService
{
private readonly IScopeUnitOfWorkProvider _fileUowProvider;
private const string PartialViewHeader = "@inherits Umbraco.Web.Mvc.UmbracoTemplatePage";
private const string PartialViewMacroHeader = "@inherits Umbraco.Web.Macros.PartialViewMacroPage";
public FileService(
IScopeUnitOfWorkProvider fileProvider,
IDatabaseUnitOfWorkProvider dataProvider,
IDatabaseUnitOfWorkProvider provider,
RepositoryFactory repositoryFactory,
ILogger logger,
IEventMessagesFactory eventMessagesFactory)
: base(dataProvider, repositoryFactory, logger, eventMessagesFactory)
{
_fileUowProvider = fileProvider;
}
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{ }
#region Stylesheets
@@ -50,11 +40,9 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="Stylesheet"/> objects</returns>
public IEnumerable<Stylesheet> GetStylesheets(params string[] names)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
// FIXME is it ok to use the same UOW here twice?
// review everywhere in this file!!
var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow);
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
return repository.GetAll(names);
}
}
@@ -66,9 +54,9 @@ namespace Umbraco.Core.Services
/// <returns>A <see cref="Stylesheet"/> object</returns>
public Stylesheet GetStylesheetByName(string name)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow);
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
return repository.Get(name);
}
}
@@ -88,13 +76,14 @@ namespace Umbraco.Core.Services
return;
}
var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow);
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
repository.AddOrUpdate(stylesheet);
uow.Commit();
uow.Events.Dispatch(SavedStylesheet, this, new SaveEventArgs<Stylesheet>(stylesheet, false));
}
Audit(AuditType.Save, "Save Stylesheet performed by user", userId, -1);
uow.Events.Dispatch(SavedStylesheet, this, new SaveEventArgs<Stylesheet>(stylesheet, false));
Audit(uow, AuditType.Save, "Save Stylesheet performed by user", userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -106,7 +95,7 @@ namespace Umbraco.Core.Services
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow);
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
var stylesheet = repository.Get(path);
if (stylesheet == null)
{
@@ -121,12 +110,12 @@ namespace Umbraco.Core.Services
}
repository.Delete(stylesheet);
uow.Commit();
uow.Events.Dispatch(DeletedStylesheet, this, new DeleteEventArgs<Stylesheet>(stylesheet, false));
}
Audit(AuditType.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1);
Audit(uow, AuditType.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -136,9 +125,9 @@ namespace Umbraco.Core.Services
/// <returns>True if Stylesheet is valid, otherwise false</returns>
public bool ValidateStylesheet(Stylesheet stylesheet)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow);
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
return repository.ValidateStylesheet(stylesheet);
}
}
@@ -152,7 +141,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="Script"/> objects</returns>
public IEnumerable<Script> GetScripts(params string[] names)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
return repository.GetAll(names);
@@ -166,7 +155,7 @@ namespace Umbraco.Core.Services
/// <returns>A <see cref="Script"/> object</returns>
public Script GetScriptByName(string name)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
return repository.Get(name);
@@ -180,7 +169,7 @@ namespace Umbraco.Core.Services
/// <param name="userId"></param>
public void SaveScript(Script script, int userId = 0)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(SavingScript, this, new SaveEventArgs<Script>(script)))
{
@@ -190,12 +179,12 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateScriptRepository(uow);
repository.AddOrUpdate(script);
uow.Commit();
uow.Events.Dispatch(SavedScript, this, new SaveEventArgs<Script>(script, false));
}
Audit(AuditType.Save, "Save Script performed by user", userId, -1);
Audit(uow, AuditType.Save, "Save Script performed by user", userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -205,7 +194,7 @@ namespace Umbraco.Core.Services
/// <param name="userId"></param>
public void DeleteScript(string path, int userId = 0)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
var script = repository.Get(path);
@@ -222,12 +211,12 @@ namespace Umbraco.Core.Services
}
repository.Delete(script);
uow.Commit();
uow.Events.Dispatch(DeletedScript, this, new DeleteEventArgs<Script>(script, false));
}
Audit(AuditType.Delete, string.Format("Delete Script performed by user"), userId, -1);
Audit(uow, AuditType.Delete, string.Format("Delete Script performed by user"), userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -237,7 +226,7 @@ namespace Umbraco.Core.Services
/// <returns>True if Script is valid, otherwise false</returns>
public bool ValidateScript(Script script)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
return repository.ValidateScript(script);
@@ -246,7 +235,7 @@ namespace Umbraco.Core.Services
public void CreateScriptFolder(string folderPath)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
((ScriptRepository)repository).AddFolder(folderPath);
@@ -256,7 +245,7 @@ namespace Umbraco.Core.Services
public void DeleteScriptFolder(string folderPath)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
((ScriptRepository)repository).DeleteFolder(folderPath);
@@ -308,12 +297,12 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateTemplateRepository(uow);
repository.AddOrUpdate(template);
uow.Commit();
uow.Events.Dispatch(SavedTemplate, this, new SaveEventArgs<ITemplate>(template, false, evtMsgs));
}
Audit(AuditType.Save, "Save Template performed by user", userId, template.Id);
Audit(uow, AuditType.Save, "Save Template performed by user", userId, template.Id);
uow.Commit();
}
return Attempt.Succeed(new OperationStatus<ITemplate, OperationStatusType>(template, OperationStatusType.Success, evtMsgs));
}
@@ -338,7 +327,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="ITemplate"/> objects</returns>
public IEnumerable<ITemplate> GetTemplates(params string[] aliases)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetAll(aliases).OrderBy(x => x.Name);
@@ -351,7 +340,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="ITemplate"/> objects</returns>
public IEnumerable<ITemplate> GetTemplates(int masterTemplateId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetChildren(masterTemplateId).OrderBy(x => x.Name);
@@ -365,7 +354,7 @@ namespace Umbraco.Core.Services
/// <returns>The <see cref="ITemplate"/> object matching the alias, or null.</returns>
public ITemplate GetTemplate(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.Get(alias);
@@ -379,7 +368,7 @@ namespace Umbraco.Core.Services
/// <returns>The <see cref="ITemplate"/> object matching the identifier, or null.</returns>
public ITemplate GetTemplate(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.Get(id);
@@ -393,7 +382,7 @@ namespace Umbraco.Core.Services
/// <returns>The <see cref="ITemplate"/> object matching the identifier, or null.</returns>
public ITemplate GetTemplate(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
var query = Query<ITemplate>.Builder.Where(x => x.Key == id);
@@ -403,7 +392,7 @@ namespace Umbraco.Core.Services
public IEnumerable<ITemplate> GetTemplateDescendants(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetDescendants(alias);
@@ -417,7 +406,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetDescendants(masterTemplateId);
@@ -431,7 +420,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateChildren(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetChildren(alias);
@@ -445,7 +434,7 @@ namespace Umbraco.Core.Services
/// <returns></returns>
public IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetChildren(masterTemplateId);
@@ -461,7 +450,7 @@ namespace Umbraco.Core.Services
[EditorBrowsable(EditorBrowsableState.Never)]
public TemplateNode GetTemplateNode(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetTemplateNode(alias);
@@ -478,7 +467,7 @@ namespace Umbraco.Core.Services
[EditorBrowsable(EditorBrowsableState.Never)]
public TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.FindTemplateInTree(anyNode, alias);
@@ -502,12 +491,12 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateTemplateRepository(uow);
repository.AddOrUpdate(template);
uow.Commit();
uow.Events.Dispatch(SavedTemplate, this, new SaveEventArgs<ITemplate>(template, false));
}
Audit(AuditType.Save, "Save Template performed by user", userId, template.Id);
Audit(uow, AuditType.Save, "Save Template performed by user", userId, template.Id);
uow.Commit();
}
}
/// <summary>
@@ -529,12 +518,12 @@ namespace Umbraco.Core.Services
{
repository.AddOrUpdate(template);
}
uow.Commit();
uow.Events.Dispatch(SavedTemplate, this, new SaveEventArgs<ITemplate>(templates, false));
}
Audit(AuditType.Save, "Save Template performed by user", userId, -1);
Audit(uow, AuditType.Save, "Save Template performed by user", userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -552,7 +541,7 @@ namespace Umbraco.Core.Services
/// </remarks>
public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.DetermineTemplateRenderingEngine(template);
@@ -566,12 +555,10 @@ namespace Umbraco.Core.Services
/// <param name="userId"></param>
public void DeleteTemplate(string alias, int userId = 0)
{
// fixme - WHY outside of UOW?!
// v8 - that should be part of the uow / scope
var template = GetTemplate(alias);
if (template == null)
{
return;
}
using (var uow = UowProvider.GetUnitOfWork())
{
@@ -584,12 +571,12 @@ namespace Umbraco.Core.Services
}
repository.Delete(template);
uow.Commit();
uow.Events.Dispatch(DeletedTemplate, this, new DeleteEventArgs<ITemplate>(template, false));
}
Audit(AuditType.Delete, "Delete Template performed by user", userId, template.Id);
Audit(uow, AuditType.Delete, "Delete Template performed by user", userId, template.Id);
uow.Commit();
}
}
/// <summary>
@@ -599,7 +586,7 @@ namespace Umbraco.Core.Services
/// <returns>True if Script is valid, otherwise false</returns>
public bool ValidateTemplate(ITemplate template)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.ValidateTemplate(template);
@@ -608,7 +595,7 @@ namespace Umbraco.Core.Services
public Stream GetTemplateFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetFileContentStream(filepath);
@@ -617,17 +604,17 @@ namespace Umbraco.Core.Services
public void SetTemplateFileContent(string filepath, Stream content)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
repository.SetFileContent(filepath, content);
// fixme - no need to commit... always committing?????
uow.Commit();
}
}
public long GetTemplateFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateTemplateRepository(uow);
return repository.GetFileSize(filepath);
@@ -638,7 +625,7 @@ namespace Umbraco.Core.Services
public Stream GetStylesheetFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
return repository.GetFileContentStream(filepath);
@@ -647,16 +634,17 @@ namespace Umbraco.Core.Services
public void SetStylesheetFileContent(string filepath, Stream content)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
repository.SetFileContent(filepath, content);
uow.Commit();
}
}
public long GetStylesheetFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateStylesheetRepository(uow);
return repository.GetFileSize(filepath);
@@ -665,7 +653,7 @@ namespace Umbraco.Core.Services
public Stream GetScriptFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
return repository.GetFileContentStream(filepath);
@@ -674,16 +662,17 @@ namespace Umbraco.Core.Services
public void SetScriptFileContent(string filepath, Stream content)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
repository.SetFileContent(filepath, content);
uow.Commit();
}
}
public long GetScriptFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateScriptRepository(uow);
return repository.GetFileSize(filepath);
@@ -692,7 +681,7 @@ namespace Umbraco.Core.Services
public Stream GetXsltFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateXsltFileRepository(uow);
return repository.GetFileContentStream(filepath);
@@ -701,16 +690,17 @@ namespace Umbraco.Core.Services
public void SetXsltFileContent(string filepath, Stream content)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateXsltFileRepository(uow);
repository.SetFileContent(filepath, content);
uow.Commit();
}
}
public long GetXsltFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateXsltFileRepository(uow);
return repository.GetFileSize(filepath);
@@ -737,9 +727,9 @@ namespace Umbraco.Core.Services
public void CreatePartialViewFolder(string folderPath)
{
var uow = _fileUowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreatePartialViewRepository(uow))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreatePartialViewRepository(uow);
((PartialViewRepository)repository).AddFolder(folderPath);
uow.Commit();
}
@@ -747,9 +737,9 @@ namespace Umbraco.Core.Services
public void CreatePartialViewMacroFolder(string folderPath)
{
var uow = _fileUowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow))
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow);
((PartialViewMacroRepository)repository).AddFolder(folderPath);
uow.Commit();
}
@@ -757,7 +747,7 @@ namespace Umbraco.Core.Services
public void DeletePartialViewFolder(string folderPath)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreatePartialViewRepository(uow);
((PartialViewRepository)repository).DeleteFolder(folderPath);
@@ -767,7 +757,7 @@ namespace Umbraco.Core.Services
public void DeletePartialViewMacroFolder(string folderPath)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow);
((PartialViewMacroRepository)repository).DeleteFolder(folderPath);
@@ -777,7 +767,7 @@ namespace Umbraco.Core.Services
public IPartialView GetPartialView(string path)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreatePartialViewRepository(uow);
return repository.Get(path);
@@ -786,7 +776,7 @@ namespace Umbraco.Core.Services
public IPartialView GetPartialViewMacro(string path)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow);
return repository.Get(path);
@@ -795,7 +785,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IPartialView> GetPartialViewMacros(params string[] names)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow);
return repository.GetAll(names).OrderBy(x => x.Name);
@@ -804,7 +794,7 @@ namespace Umbraco.Core.Services
public IXsltFile GetXsltFile(string path)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateXsltFileRepository(uow);
return repository.Get(path);
@@ -813,7 +803,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IXsltFile> GetXsltFiles(params string[] names)
{
using (var uow = _fileUowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateXsltFileRepository(uow);
return repository.GetAll(names).OrderBy(x => x.Name);
@@ -845,16 +835,16 @@ namespace Umbraco.Core.Services
}
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = GetPartialViewRepository(partialViewType, uow);
repository.AddOrUpdate(partialView);
uow.Commit();
uow.Events.Dispatch(CreatedPartialView, this, new NewEventArgs<IPartialView>(partialView, false, partialView.Alias, -1));
}
Audit(AuditType.Save, string.Format("Save {0} performed by user", partialViewType), userId, -1);
Audit(uow, AuditType.Save, string.Format("Save {0} performed by user", partialViewType), userId, -1);
uow.Commit();
}
return Attempt<IPartialView>.Succeed(partialView);
}
@@ -871,7 +861,7 @@ namespace Umbraco.Core.Services
private bool DeletePartialViewMacro(string path, PartialViewType partialViewType, int userId = 0)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = GetPartialViewRepository(partialViewType, uow);
var partialView = repository.Get(path);
@@ -888,12 +878,12 @@ namespace Umbraco.Core.Services
}
repository.Delete(partialView);
uow.Commit();
uow.Events.Dispatch(DeletedPartialView, this, new DeleteEventArgs<IPartialView>(partialView, false));
}
Audit(AuditType.Delete, string.Format("Delete {0} performed by user", partialViewType), userId, -1);
Audit(uow, AuditType.Delete, string.Format("Delete {0} performed by user", partialViewType), userId, -1);
uow.Commit();
}
return true;
@@ -911,7 +901,7 @@ namespace Umbraco.Core.Services
private Attempt<IPartialView> SavePartialView(IPartialView partialView, PartialViewType partialViewType, int userId = 0)
{
using (var uow = _fileUowProvider.GetUnitOfWork())
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(SavingPartialView, this, new SaveEventArgs<IPartialView>(partialView)))
{
@@ -921,18 +911,19 @@ namespace Umbraco.Core.Services
var repository = GetPartialViewRepository(partialViewType, uow);
repository.AddOrUpdate(partialView);
uow.Commit();
uow.Events.Dispatch(SavedPartialView, this, new SaveEventArgs<IPartialView>(partialView, false));
}
Audit(AuditType.Save, string.Format("Save {0} performed by user", partialViewType), userId, -1);
uow.Events.Dispatch(SavedPartialView, this, new SaveEventArgs<IPartialView>(partialView, false));
Audit(uow, AuditType.Save, string.Format("Save {0} performed by user", partialViewType), userId, -1);
uow.Commit();
}
return Attempt.Succeed(partialView);
}
public bool ValidatePartialView(PartialView partialView)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreatePartialViewRepository(uow);
return repository.ValidatePartialView(partialView);
@@ -941,7 +932,7 @@ namespace Umbraco.Core.Services
public bool ValidatePartialViewMacro(PartialView partialView)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow);
return repository.ValidatePartialView(partialView);
@@ -981,7 +972,7 @@ namespace Umbraco.Core.Services
public Stream GetPartialViewMacroFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = GetPartialViewRepository(PartialViewType.PartialViewMacro, uow);
return repository.GetFileContentStream(filepath);
@@ -1039,7 +1030,6 @@ namespace Umbraco.Core.Services
public void SetPartialViewMacroFileContent(string filepath, Stream content)
{
// FIXME FTW would we use a READONLY unit of work to SET FILE CONTENT
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = GetPartialViewRepository(PartialViewType.PartialViewMacro, uow);
@@ -1050,7 +1040,7 @@ namespace Umbraco.Core.Services
public long GetPartialViewMacroFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = GetPartialViewRepository(PartialViewType.PartialViewMacro, uow);
return repository.GetFileSize(filepath);
@@ -1059,7 +1049,7 @@ namespace Umbraco.Core.Services
public Stream GetPartialViewFileContentStream(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = GetPartialViewRepository(PartialViewType.PartialView, uow);
return repository.GetFileContentStream(filepath);
@@ -1078,7 +1068,7 @@ namespace Umbraco.Core.Services
public long GetPartialViewFileSize(string filepath)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = GetPartialViewRepository(PartialViewType.PartialView, uow);
return repository.GetFileSize(filepath);
@@ -1087,14 +1077,10 @@ namespace Umbraco.Core.Services
#endregion
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
//TODO Method to change name and/or alias of view/masterpage template
@@ -81,6 +81,7 @@ namespace Umbraco.Core.Services
/// </param>
void RebuildXmlStructures(params int[] contentTypeIds);
int CountNotTrashed(string contentTypeAlias = null);
int Count(string contentTypeAlias = null);
int CountChildren(int parentId, string contentTypeAlias = null);
int CountDescendants(int parentId, string contentTypeAlias = null);
@@ -167,6 +168,22 @@ namespace Umbraco.Core.Services
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter);
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -18,12 +15,9 @@ namespace Umbraco.Core.Services
/// </summary>
public class LocalizationService : ScopeRepositoryService, ILocalizationService
{
public LocalizationService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{
}
{ }
/// <summary>
/// Adds or updates a translation for a dictionary item and language
@@ -110,7 +104,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IDictionaryItem"/></returns>
public IDictionaryItem GetDictionaryItemById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
//ensure the lazy Language callback is assigned
@@ -128,7 +122,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="DictionaryItem"/></returns>
public IDictionaryItem GetDictionaryItemById(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
//ensure the lazy Language callback is assigned
@@ -146,7 +140,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IDictionaryItem"/></returns>
public IDictionaryItem GetDictionaryItemByKey(string key)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
//ensure the lazy Language callback is assigned
@@ -164,7 +158,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="IDictionaryItem"/> objects</returns>
public IEnumerable<IDictionaryItem> GetDictionaryItemChildren(Guid parentId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
var query = Query<IDictionaryItem>.Builder.Where(x => x.ParentId == parentId);
@@ -183,7 +177,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="IDictionaryItem"/> objects</returns>
public IEnumerable<IDictionaryItem> GetDictionaryItemDescendants(Guid? parentId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
//ensure the lazy Language callback is assigned
@@ -200,7 +194,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="IDictionaryItem"/> objects</returns>
public IEnumerable<IDictionaryItem> GetRootDictionaryItems()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
var query = Query<IDictionaryItem>.Builder.Where(x => x.ParentId == null);
@@ -219,7 +213,7 @@ namespace Umbraco.Core.Services
/// <returns>True if a <see cref="IDictionaryItem"/> exists, otherwise false</returns>
public bool DictionaryItemExists(string key)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
return repository.Get(key) != null;
@@ -242,14 +236,14 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
repository.AddOrUpdate(dictionaryItem);
uow.Commit();
//ensure the lazy Language callback is assigned
EnsureDictionaryItemLanguageCallback(dictionaryItem);
uow.Commit(); // FIXME do we need this? what's the func above doing?
uow.Events.Dispatch(SavedDictionaryItem, this, new SaveEventArgs<IDictionaryItem>(dictionaryItem, false));
}
Audit(AuditType.Save, "Save DictionaryItem performed by user", userId, dictionaryItem.Id);
// ensure the lazy Language callback is assigned (not using the uow)
EnsureDictionaryItemLanguageCallback(dictionaryItem);
uow.Events.Dispatch(SavedDictionaryItem, this, new SaveEventArgs<IDictionaryItem>(dictionaryItem, false));
Audit(uow, AuditType.Save, "Save DictionaryItem performed by user", userId, dictionaryItem.Id);
uow.Commit();
}
}
/// <summary>
@@ -270,11 +264,12 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
repository.Delete(dictionaryItem);
uow.Commit();
uow.Events.Dispatch(DeletedDictionaryItem, this, new DeleteEventArgs<IDictionaryItem>(dictionaryItem, false));
}
Audit(AuditType.Delete, "Delete DictionaryItem performed by user", userId, dictionaryItem.Id);
uow.Events.Dispatch(DeletedDictionaryItem, this, new DeleteEventArgs<IDictionaryItem>(dictionaryItem, false));
Audit(uow, AuditType.Delete, "Delete DictionaryItem performed by user", userId, dictionaryItem.Id);
uow.Commit();
}
}
/// <summary>
@@ -284,7 +279,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="Language"/></returns>
public ILanguage GetLanguageById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateLanguageRepository(uow);
return repository.Get(id);
@@ -298,7 +293,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="Language"/></returns>
public ILanguage GetLanguageByCultureCode(string cultureName)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateLanguageRepository(uow);
return repository.GetByCultureName(cultureName);
@@ -312,7 +307,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="Language"/></returns>
public ILanguage GetLanguageByIsoCode(string isoCode)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateLanguageRepository(uow);
return repository.GetByIsoCode(isoCode);
@@ -325,7 +320,7 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="ILanguage"/> objects</returns>
public IEnumerable<ILanguage> GetAllLanguages()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateLanguageRepository(uow);
return repository.GetAll();
@@ -348,11 +343,12 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateLanguageRepository(uow);
repository.AddOrUpdate(language);
uow.Commit();
uow.Events.Dispatch(SavedLanguage, this, new SaveEventArgs<ILanguage>(language, false));
}
Audit(AuditType.Save, "Save Language performed by user", userId, language.Id);
uow.Events.Dispatch(SavedLanguage, this, new SaveEventArgs<ILanguage>(language, false));
Audit(uow, AuditType.Save, "Save Language performed by user", userId, language.Id);
uow.Commit();
}
}
/// <summary>
@@ -372,27 +368,24 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateLanguageRepository(uow);
repository.Delete(language);
uow.Commit();
uow.Events.Dispatch(DeletedLanguage, this, new DeleteEventArgs<ILanguage>(language, false));
}
Audit(AuditType.Delete, "Delete Language performed by user", userId, language.Id);
uow.Events.Dispatch(DeletedLanguage, this, new DeleteEventArgs<ILanguage>(language, false));
Audit(uow, AuditType.Delete, "Delete Language performed by user", userId, language.Id);
uow.Commit();
}
}
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
/// <summary>
/// This is here to take care of a hack - the DictionaryTranslation model contains an ILanguage reference which we don't want but
/// This is here to take care of a hack - the DictionaryTranslation model contains an ILanguage reference which we don't want but
/// we cannot remove it because it would be a large breaking change, so we need to make sure it's resolved lazily. This is because
/// if developers have a lot of dictionary items and translations, the caching and cloning size gets much much larger because of
/// if developers have a lot of dictionary items and translations, the caching and cloning size gets much much larger because of
/// the large object graphs. So now we don't cache or clone the attached ILanguage
/// </summary>
private void EnsureDictionaryItemLanguageCallback(IDictionaryItem d)
+14 -18
View File
@@ -57,7 +57,7 @@ namespace Umbraco.Core.Services
/// <returns>An <see cref="IMacro"/> object</returns>
public IMacro GetByAlias(string alias)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMacroRepository(uow);
var q = new Query<IMacro>();
@@ -91,7 +91,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IMacro> GetAll(params int[] ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMacroRepository(uow);
return repository.GetAll(ids);
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Services
public IEnumerable<IMacro> GetAll(params Guid[] ids)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMacroRepository(uow);
return repository.GetAll(ids);
@@ -109,7 +109,7 @@ namespace Umbraco.Core.Services
public IMacro GetById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMacroRepository(uow);
return repository.Get(id);
@@ -118,7 +118,7 @@ namespace Umbraco.Core.Services
public IMacro GetById(Guid id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMacroRepository(uow);
return repository.Get(id);
@@ -151,12 +151,12 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateMacroRepository(uow);
repository.Delete(macro);
uow.Commit();
uow.Events.Dispatch(Deleted, this, new DeleteEventArgs<IMacro>(macro, false));
}
Audit(AuditType.Delete, "Delete Macro performed by user", userId, -1);
Audit(uow, AuditType.Delete, "Delete Macro performed by user", userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -181,12 +181,12 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateMacroRepository(uow);
repository.AddOrUpdate(macro);
uow.Commit();
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMacro>(macro, false));
}
Audit(AuditType.Save, "Save Macro performed by user", userId, -1);
Audit(uow, AuditType.Save, "Save Macro performed by user", userId, -1);
uow.Commit();
}
}
///// <summary>
@@ -208,14 +208,10 @@ namespace Umbraco.Core.Services
// return MacroPropertyTypeResolver.Current.MacroPropertyTypes.FirstOrDefault(x => x.Alias == alias);
//}
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
#region Event Handlers
+187 -164
View File
@@ -11,7 +11,6 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
@@ -28,7 +27,7 @@ namespace Umbraco.Core.Services
public class MediaService : ScopeRepositoryService, IMediaService, IMediaServiceOperations
{
//Support recursive locks because some of the methods that require locking call other methods that require locking.
//Support recursive locks because some of the methods that require locking call other methods that require locking.
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
@@ -67,9 +66,7 @@ namespace Umbraco.Core.Services
var parent = GetById(media.ParentId);
media.Path = string.Concat(parent.IfNotNull(x => x.Path, media.ParentId.ToString()), ",", media.Id);
//we are using GetReadOnlyUnitOfWork because this actually doesn't write anything!
// fixme - IS IT EVEN DOING ANYTHING WITH REPO? NO! SO USE A SCOPE INSTEAD!
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs<IMedia>(media, mediaTypeAlias, parentId)))
{
@@ -79,15 +76,12 @@ namespace Umbraco.Core.Services
}
media.CreatorId = userId;
uow.Events.Dispatch(Created, this, new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId));
Audit(AuditType.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
Audit(uow, AuditType.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
uow.Commit();
return media;
}
}
/// <summary>
@@ -112,9 +106,7 @@ namespace Umbraco.Core.Services
var media = new Models.Media(name, parent, mediaType);
media.Path = string.Concat(parent.Path, ",", media.Id);
//we are using GetReadOnlyUnitOfWork because this actually doesn't write anything!
// fixme
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs<IMedia>(media, mediaTypeAlias, parent)))
{
@@ -127,7 +119,8 @@ namespace Umbraco.Core.Services
uow.Events.Dispatch(Created, this, new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parent));
Audit(AuditType.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
Audit(uow, AuditType.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
uow.Commit();
return media;
}
@@ -157,12 +150,14 @@ namespace Umbraco.Core.Services
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs<IMedia>(media, mediaTypeAlias, parentId)))
{
uow.Commit();
media.WasCancelled = true;
return media;
}
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(media)))
{
uow.Commit();
media.WasCancelled = true;
return media;
}
@@ -170,21 +165,19 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateMediaRepository(uow);
media.CreatorId = userId;
repository.AddOrUpdate(media);
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
// generate preview for blame history?
if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
{
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
}
uow.Commit();
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(media, false));
uow.Events.Dispatch(Created, this, new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId));
}
Audit(AuditType.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
Audit(uow, AuditType.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
uow.Commit();
}
return media;
}
@@ -215,17 +208,18 @@ namespace Umbraco.Core.Services
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs<IMedia>(media, mediaTypeAlias, parent)))
{
uow.Commit();
media.WasCancelled = true;
return media;
}
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(media)))
{
uow.Commit();
media.WasCancelled = true;
return media;
}
var repository = RepositoryFactory.CreateMediaRepository(uow);
media.CreatorId = userId;
repository.AddOrUpdate(media);
@@ -236,13 +230,12 @@ namespace Umbraco.Core.Services
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
}
uow.Commit();
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(media, false));
uow.Events.Dispatch(Created, this, new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parent));
}
Audit(AuditType.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
Audit(uow, AuditType.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
uow.Commit();
}
return media;
}
@@ -254,16 +247,39 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMedia"/></returns>
public IMedia GetById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.Get(id);
}
}
public int CountNotTrashed(string contentTypeAlias = null)
{
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
using (var mediaTypeRepository = RepositoryFactory.CreateMediaTypeRepository(uow))
{
var mediaTypeId = 0;
if (contentTypeAlias.IsNullOrWhiteSpace() == false)
{
var mediaType = mediaTypeRepository.Get(contentTypeAlias);
if (mediaType == null) return 0;
mediaTypeId = mediaType.Id;
}
var query = Query<IMedia>.Builder.Where(media => media.Trashed == false);
if (mediaTypeId > 0)
{
query.Where(media => media.ContentTypeId == mediaTypeId);
}
return repository.Count(query);
}
}
public int Count(string contentTypeAlias = null)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.Count(contentTypeAlias);
@@ -272,7 +288,7 @@ namespace Umbraco.Core.Services
public int CountChildren(int parentId, string contentTypeAlias = null)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.CountChildren(parentId, contentTypeAlias);
@@ -281,7 +297,7 @@ namespace Umbraco.Core.Services
public int CountDescendants(int parentId, string contentTypeAlias = null)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.CountDescendants(parentId, contentTypeAlias);
@@ -297,7 +313,7 @@ namespace Umbraco.Core.Services
{
if (ids.Any() == false) return Enumerable.Empty<IMedia>();
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetAll(ids.ToArray());
@@ -311,7 +327,7 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IMedia"/></returns>
public IMedia GetById(Guid key)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.Key == key);
@@ -326,7 +342,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetByLevel(int level)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.Level == level && x.Path.StartsWith("-21") == false);
@@ -341,7 +357,7 @@ namespace Umbraco.Core.Services
/// <returns>An <see cref="IMedia"/> item</returns>
public IMedia GetByVersion(Guid versionId)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetByVersion(versionId);
@@ -355,7 +371,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetVersions(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetAllVersions(id);
@@ -384,7 +400,7 @@ namespace Umbraco.Core.Services
if (ids.Any() == false)
return new List<IMedia>();
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetAll(ids);
@@ -398,7 +414,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.ParentId == id);
@@ -448,11 +464,30 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter)
{
return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter, null);
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
@@ -460,6 +495,11 @@ namespace Umbraco.Core.Services
// always check for a parent - else it will also get decendants (and then you should use the GetPagedDescendants method)
query.Where(x => x.ParentId == id);
if (contentTypeFilter != null && contentTypeFilter.Length > 0)
{
query.Where(x => contentTypeFilter.Contains(x.ContentTypeId));
}
IQuery<IMedia> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
@@ -511,7 +551,7 @@ namespace Umbraco.Core.Services
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder;
@@ -555,7 +595,7 @@ namespace Umbraco.Core.Services
if (media.ValidatePath() == false)
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", media.Id, media.Path, media.ParentId));
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var pathMatch = media.Path + ",";
@@ -595,7 +635,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetMediaOfMediaType(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.ContentTypeId == id);
@@ -609,7 +649,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetRootMedia()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.ParentId == -1);
@@ -623,7 +663,7 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
public IEnumerable<IMedia> GetMediaInRecycleBin()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.Path.Contains("-21"));
@@ -660,11 +700,11 @@ namespace Umbraco.Core.Services
var sql = createSql(umbracoFileValue);
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var propertyDataDto = uow.Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql).FirstOrDefault();
// If the stripped-down url returns null, we try again with the original url.
// 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)
{
@@ -707,7 +747,7 @@ namespace Umbraco.Core.Services
/// <returns>True if the media has any children otherwise False</returns>
public bool HasChildren(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
var query = Query<IMedia>.Builder.Where(x => x.ParentId == id);
@@ -737,14 +777,13 @@ namespace Umbraco.Core.Services
return;
}
using (var scope = UowProvider.ScopeProvider.CreateScope())
using (var uow = UowProvider.GetUnitOfWork())
{
scope.Complete(); // always complete
var originalPath = media.Path;
if (scope.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, parentId)), "Moving"))
if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, parentId)), "Moving"))
{
uow.Commit();
return;
}
@@ -753,15 +792,13 @@ namespace Umbraco.Core.Services
{
media.ChangeTrashedState(false, parentId);
}
Save(media, userId,
//no events!
false);
Save(media, userId, false); //no events!
//used to track all the moved entities to be given to the event
var moveInfo = new List<MoveEventInfo<IMedia>>
{
new MoveEventInfo<IMedia>(media, originalPath, parentId)
};
{
new MoveEventInfo<IMedia>(media, originalPath, parentId)
};
//Ensure that relevant properties are updated on children
var children = GetChildren(media.Id).ToArray();
@@ -771,14 +808,13 @@ namespace Umbraco.Core.Services
var parentLevel = media.Level;
var parentTrashed = media.Trashed;
var updatedDescendants = UpdatePropertiesOnChildren(children, parentPath, parentLevel, parentTrashed, moveInfo);
Save(updatedDescendants, userId,
//no events!
false);
Save(updatedDescendants, userId, false); //no events!
}
scope.Events.Dispatch(Moved, this, new MoveEventArgs<IMedia>(false, moveInfo.ToArray()), "Moved");
uow.Events.Dispatch(Moved, this, new MoveEventArgs<IMedia>(false, moveInfo.ToArray()), "Moved");
Audit(AuditType.Move, "Move Media performed by user", userId, media.Id);
Audit(uow, AuditType.Move, "Move Media performed by user", userId, media.Id);
uow.Commit();
}
}
}
@@ -807,31 +843,35 @@ namespace Umbraco.Core.Services
//TODO: IT would be much nicer to mass delete all in one trans in the repo level!
var evtMsgs = EventMessagesFactory.Get();
using (var scope = UowProvider.ScopeProvider.CreateScope())
using (var uow = UowProvider.GetUnitOfWork())
{
scope.Complete(); // always
if (scope.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMedia>(media, evtMsgs)))
return OperationStatus.Cancelled(evtMsgs);
var ret = DeleteUow(uow, media, userId, evtMsgs);
uow.Commit();
return ret;
}
}
private Attempt<OperationStatus> DeleteUow(IScopeUnitOfWork uow, IMedia media, int userId, EventMessages evtMsgs)
{
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMedia>(media, evtMsgs)))
{
return OperationStatus.Cancelled(evtMsgs);
}
//Delete children before deleting the 'possible parent'
// delete children first
var children = GetChildren(media.Id);
foreach (var child in children)
{
Delete(child, userId);
DeleteUow(uow, child, userId, evtMsgs);
}
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.Delete(media);
uow.Commit();
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.Delete(media);
var args = new DeleteEventArgs<IMedia>(media, false, evtMsgs);
uow.Events.Dispatch(Deleted, this, args);
}
var args = new DeleteEventArgs<IMedia>(media, false, evtMsgs);
uow.Events.Dispatch(Deleted, this, args);
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
Audit(uow, AuditType.Delete, "Delete Media performed by user", userId, media.Id);
return OperationStatus.Success(evtMsgs);
}
@@ -848,10 +888,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (raiseEvents)
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(media, evtMsgs)))
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(media, evtMsgs)))
return OperationStatus.Cancelled(evtMsgs);
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
if (string.IsNullOrWhiteSpace(media.Name))
@@ -869,13 +909,12 @@ namespace Umbraco.Core.Services
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
}
uow.Commit();
if (raiseEvents)
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(media, false, evtMsgs));
}
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
Audit(uow, AuditType.Save, "Save Media performed by user", userId, media.Id);
uow.Commit();
}
return OperationStatus.Success(evtMsgs);
}
@@ -893,10 +932,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (raiseEvents)
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(asArray, evtMsgs)))
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(asArray, evtMsgs)))
return OperationStatus.Cancelled(evtMsgs);
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
var repository = RepositoryFactory.CreateMediaRepository(uow);
@@ -912,14 +951,12 @@ namespace Umbraco.Core.Services
}
}
//commit the whole lot in one go
uow.Commit();
if (raiseEvents)
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(asArray, false, evtMsgs));
}
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
Audit(uow, AuditType.Save, "Save Media items performed by user", userId, -1);
uow.Commit();
}
return OperationStatus.Success(evtMsgs);
}
@@ -931,18 +968,14 @@ namespace Umbraco.Core.Services
{
using (new WriteLock(Locker))
{
Dictionary<int, IEnumerable<Property>> entities;
List<string> files;
bool success;
var nodeObjectType = new Guid(Constants.ObjectTypes.Media);
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
entities = repository.GetEntitiesInRecycleBin().ToDictionary(key => key.Id, val => (IEnumerable<Property>)val.Properties);
var entities = repository.GetEntitiesInRecycleBin().ToDictionary(key => key.Id, val => (IEnumerable<Property>)val.Properties);
files = ((MediaRepository)repository).GetFilesInRecycleBinForUploadField();
uow.Commit();
var files = ((MediaRepository)repository).GetFilesInRecycleBinForUploadField();
if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files)))
{
@@ -950,17 +983,19 @@ namespace Umbraco.Core.Services
return;
}
success = repository.EmptyRecycleBin();
// FIXME shouldn't we commit here?!
var success = repository.EmptyRecycleBin();
uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files, success));
Audit(uow, AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, -21);
uow.Commit();
}
}
Audit(AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, -21);
}
/// <summary>
/// Deletes all content of the specified types. All Descendants of deleted content that is not of these types is moved to Recycle Bin.
/// </summary>
/// </summary>
/// <param name="mediaTypeIds">Id of the <see cref="IContentType"/></param>
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
public void DeleteMediaOfTypes(IEnumerable<int> mediaTypeIds, int userId = 0)
@@ -985,12 +1020,8 @@ namespace Umbraco.Core.Services
//Determine the items that will need to be recycled (that are children of these content items but not of these content types)
var mediaToRecycle = this.TrackTrashedForDeleteContentOfTypes(mediaTypeIds, rootItems, repository);
// do it INSIDE the UOW because nested UOW kinda should work
// fixme - and then we probably don't need the whole mess?
// nesting UOW works, it's just that the outer one NEEDS to be flushed beforehand
// nevertheless, it would be nicer to create a global scope and inner uow
//move each item to the bin starting with the deepest items
// move each item to the bin starting with the deepest items
// nesting uow - technically supported though not ideal
foreach (var child in mediaToRecycle.OrderByDescending(x => x.Level))
{
MoveToRecycleBinDo(child, userId, true);
@@ -1001,12 +1032,10 @@ namespace Umbraco.Core.Services
Delete(content, userId);
}
uow.Commit();
Audit(AuditType.Delete,
Audit(uow, AuditType.Delete,
string.Format("Delete Media of Types {0} performed by user", string.Join(",", mediaTypeIds)),
userId, Constants.System.Root);
uow.Commit();
}
}
@@ -1058,13 +1087,13 @@ namespace Umbraco.Core.Services
{
uow.Commit();
return OperationStatus.Cancelled(evtMsgs);
}
}
var moveInfo = new List<MoveEventInfo<IMedia>>
{
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)
};
//get descendents to process of the content item that is being moved to trash - must be done before changing the state below,
//get descendents to process of the content item that is being moved to trash - must be done before changing the state below,
//must be processed with shallowest levels first
var descendants = ignoreDescendants ? Enumerable.Empty<IMedia>() : GetDescendants(media).OrderBy(x => x.Level);
@@ -1073,7 +1102,7 @@ namespace Umbraco.Core.Services
repository.DeleteContentXml(media);
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
repository.AddOrUpdate(media);
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
foreach (var descendant in descendants)
{
@@ -1084,12 +1113,11 @@ namespace Umbraco.Core.Services
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
}
uow.Commit();
uow.Events.Dispatch(Trashed, this, new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), "Trashed");
}
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
Audit(uow, AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
uow.Commit();
}
return OperationStatus.Success(evtMsgs);
}
@@ -1119,19 +1147,22 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void DeleteVersions(int id, DateTime versionDate, int userId = 0)
{
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, dateToRetain: versionDate)))
return;
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.DeleteVersions(id, versionDate);
DeleteVersions(uow, id, versionDate, userId);
uow.Commit();
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate));
}
}
Audit(AuditType.Delete, "Delete Media by version date performed by user", userId, -1);
private void DeleteVersions(IScopeUnitOfWork uow, int id, DateTime versionDate, int userId = 0)
{
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, dateToRetain: versionDate)))
return;
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.DeleteVersions(id, versionDate);
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate));
Audit(uow, AuditType.Delete, "Delete Media by version date performed by user", userId, -1);
}
/// <summary>
@@ -1144,28 +1175,28 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User deleting versions of a Content object</param>
public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = 0)
{
using (var scope = UowProvider.ScopeProvider.CreateScope())
{
scope.Complete(); // always
if (scope.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, specificVersion: versionId)))
return;
}
if (deletePriorVersions)
{
var content = GetByVersion(versionId);
DeleteVersions(id, content.UpdateDate, userId);
}
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, specificVersion: versionId)))
{
uow.Commit();
return;
}
if (deletePriorVersions)
{
var content = GetByVersion(versionId);
DeleteVersions(uow, id, content.UpdateDate, userId);
}
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.DeleteVersion(versionId);
uow.Commit();
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, specificVersion: versionId));
}
Audit(AuditType.Delete, "Delete Media by version performed by user", userId, -1);
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, specificVersion: versionId));
Audit(uow, AuditType.Delete, "Delete Media by version performed by user", userId, -1);
uow.Commit();
}
}
/// <summary>
@@ -1204,13 +1235,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (raiseEvents)
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(asArray)))
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(asArray)))
{
uow.Commit();
return false;
}
uow.Commit();
return false;
}
var repository = RepositoryFactory.CreateMediaRepository(uow);
@@ -1238,13 +1266,12 @@ namespace Umbraco.Core.Services
}
}
uow.Commit();
if (raiseEvents)
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(asArray, false));
}
Audit(AuditType.Sort, "Sorting Media performed by user", userId, 0);
Audit(uow, AuditType.Sort, "Sorting Media performed by user", userId, 0);
uow.Commit();
}
return true;
}
@@ -1262,7 +1289,7 @@ namespace Umbraco.Core.Services
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
return repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, null, out totalRecords);
@@ -1282,10 +1309,10 @@ namespace Umbraco.Core.Services
{
var repository = RepositoryFactory.CreateMediaRepository(uow);
repository.RebuildXmlStructures(media => _entitySerializer.Serialize(this, _dataTypeService, _userService, media), contentTypeIds: contentTypeIds.Length == 0 ? null : contentTypeIds);
Audit(uow, AuditType.Publish, "MediaService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
uow.Commit();
}
Audit(AuditType.Publish, "MediaService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
}
/// <summary>
@@ -1334,7 +1361,7 @@ namespace Umbraco.Core.Services
{
Mandate.ParameterNotNullOrEmpty(mediaTypeAlias, "mediaTypeAlias");
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMediaTypeRepository(uow);
var query = Query<IMediaType>.Builder.Where(x => x.Alias == mediaTypeAlias);
@@ -1352,14 +1379,10 @@ namespace Umbraco.Core.Services
}
}
private void Audit(AuditType type, string message, int userId, int objectId)
private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
uow.Commit();
}
var repository = RepositoryFactory.CreateAuditRepository(uow);
repository.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
/// <summary>
@@ -1421,7 +1444,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Delete
/// </summary>
/// </summary>
public static event TypedEventHandler<IMediaService, DeleteRevisionsEventArgs> DeletingVersions;
/// <summary>
+13 -16
View File
@@ -1,11 +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.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -40,12 +37,12 @@ namespace Umbraco.Core.Services
scope.Complete(); // always complete
scope.Events.Dispatch(Saved, this, new SaveEventArgs<IMemberGroup>(e.SavedEntities, false));
}
}
}
#endregion
public IEnumerable<IMemberGroup> GetAll()
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
return repository.GetAll();
@@ -54,7 +51,7 @@ namespace Umbraco.Core.Services
public IMemberGroup GetById(int id)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
return repository.Get(id);
@@ -63,7 +60,7 @@ namespace Umbraco.Core.Services
public IMemberGroup GetByName(string name)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
return repository.GetByName(name);
@@ -74,13 +71,10 @@ namespace Umbraco.Core.Services
{
using (var uow = UowProvider.GetUnitOfWork())
{
if (raiseEvents)
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMemberGroup>(memberGroup)))
{
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMemberGroup>(memberGroup)))
{
uow.Commit();
return;
}
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
@@ -90,7 +84,7 @@ namespace Umbraco.Core.Services
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMemberGroup>(memberGroup, false));
}
}
public void Delete(IMemberGroup memberGroup)
@@ -98,7 +92,10 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork())
{
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMemberGroup>(memberGroup)))
return; // FIXME COMMIT
{
uow.Commit();
return;
}
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
repository.Delete(memberGroup);
uow.Commit();
@@ -118,7 +115,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Save of a member group
/// </summary>
/// </summary>
/// <remarks>
/// We need to proxy these events because the events need to take place at the repo level
/// </remarks>

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