Compare commits

...

689 Commits

Author SHA1 Message Date
mikkelhm 4377d9294e Bump version to 7.6-beta 2017-03-17 11:51:07 +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
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
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
Warren Buckley a3f6fb78f5 Bump version to alpha-73 after downgrade to .NET 4.5 2017-03-08 12:22:47 +00:00
Warren Buckley 736b3565d0 Merge pull request #1784 from umbraco/temp-deploy-257
deploy-257 Downgrade Core and Deploy to framework 4.5
2017-03-08 12:17:08 +00:00
Claus ed782998ef Merge pull request #1779 from umbraco/temp-U4-9521
U4-9521 MediaService.GetPagedChildren should only get children and not descendants
2017-03-08 13:13:23 +01:00
Claus 31d980b0c5 Merge pull request #1782 from umbraco/temp-u4-9605
U4-9605 - debug switch for uncompleted scopes
2017-03-08 13:07:03 +01:00
Claus 9f6e4d4fd5 updating nuspec. 2017-03-08 12:04:48 +01:00
Claus d90658d814 Merge pull request #1783 from umbraco/temp-u4-9588
u4-9588 - filesystems
2017-03-08 11:58:47 +01:00
Claus 7fa8f04b11 deploy-257 Downgrade Core and Deploy to framework 4.5 2017-03-08 11:20:48 +01:00
Stephan bf2232258e U4-9588 - filesystems manager tlc 2017-03-08 11:02:30 +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
Stephan 5bbb44479f U4-9588 - expand filesystems manager 2017-03-07 17:57:45 +01:00
Warren Buckley 5218d31f23 Bumps version to alpha-072 2017-03-07 15:43:29 +00:00
Stephan 9e55f5835c U4-9605 - debug switch for uncompleted scopes 2017-03-07 12:42:44 +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
Claus 1101fc199f Merge pull request #1585 from umbraco/temp-U4-9145
U4-9145 Updating TinyMCE to latest (4.4.3)
2017-03-06 12:14:18 +01:00
Emil Wangaa 6de76571d7 Adds a couple of tests for ContentService.GetPagedChildren 2017-03-03 14:56:41 +01:00
Emil Wangaa 0f535f233e ContentService.GetPagedChildren should also only get children 2017-03-03 14:15:04 +01:00
Emil Wangaa 56da13fa79 MediaService.GetPagedChildren now only gets children even if parent id is root node instead of also getting descendants 2017-03-03 13:45:21 +01:00
Stephan 79d4956b75 Merge branch 'dev-v7' into temp-U4-9587 2017-03-03 13:26:43 +01:00
Mads Rasmussen 05fa58694e Merge pull request #1773 from umbraco/temp-ui-colors
fixes: U4-9583 Update UI colours and typography
2017-03-03 09:50:28 +01:00
Mads Rasmussen ecc8575454 colour tweaks 2017-03-03 09:48:50 +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
Mads Rasmussen df93dfe63c Merge pull request #1766 from umbraco/temp-U4-9538
U4-9538 - Add Keyboard shortcut (overview & template editor)
2017-03-02 16:12:56 +01:00
Mads Rasmussen 711981adab remove comment 2017-03-02 16:10:41 +01:00
Mads Rasmussen 199c5a9606 add keyboard shortcuts to partial view editor 2017-03-02 16:05:31 +01:00
Claus 54efe86020 fixes broken tests... 2017-03-02 16:00:11 +01:00
mikkelhm 589704437f Bump version to alpha071 2017-03-02 15:46:06 +01:00
Mads Rasmussen 9a99ad1416 combine documentation for localize component and attribute directive 2017-03-02 15:28:40 +01:00
Mikkel Holck Madsen a4077df5b7 deploy-245 - Merge pull request #1775 from umbraco/template-virtualpath-fix
Fixes VirtualPath being null on template creation
2017-03-02 15:27:59 +01:00
Mads Rasmussen 5d298e4313 make sure overlays close after shortcut overlay has been opened 2017-03-02 14:45:08 +01:00
Morten Christensen 46ef9146c4 Setting the VirtualPath should be done before we return 2017-03-02 14:40:44 +01:00
Stephan 3c75693e20 Add a few (ignored) tests used for debugging 2017-03-02 14:01:58 +01:00
Mads Rasmussen b67286f40d make showOverlay optional 2017-03-02 13:52:56 +01:00
mikkelhm 32ad98cde2 Bump version to alpha070 2017-03-02 13:33:12 +01:00
Mads Rasmussen dabeaa26e6 fix documentation 2017-03-02 13:14:02 +01:00
Mads Rasmussen 6c3f1c0e32 add mac/win versions of keyboard shortcuts 2017-03-02 13:04:55 +01:00
Mikkel Holck Madsen f4b1df1ede U4-9575 - Merge pull request #1770 from umbraco/temp-cloud-env-title
Dev Night - Display Deploy Cloud Env in <title>
2017-03-02 12:55:08 +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
Mads Rasmussen 13cf9f46e7 fix ace shortcut overwrites on mac 2017-03-02 11:29:52 +01:00
Mads Rasmussen d062b51326 fix reference to notificationsService 2017-03-02 11:20:08 +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
Warren Buckley 2b0f2577b5 Uppercases the Section name in the page <title> & if Deploy installed grab the CurrentWorkspace from the global JS obj 2017-02-28 21:56:30 +00:00
Mads Rasmussen c2aa137293 more colour tweaking 2017-02-28 21:20:42 +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
Mads Rasmussen 555e0a2281 change blue button to green button 2017-02-27 21:21:38 +01:00
Mads Rasmussen 091a89b162 update colours 2017-02-27 21:21:20 +01:00
Mads Rasmussen 0eab0b606c remove border on reset password input 2017-02-27 21:20:32 +01:00
Mads Rasmussen 1fe06a0c9e update logo colour 2017-02-27 21:19:57 +01:00
Mads Rasmussen 6022c87540 clean up 2017-02-27 16:12:44 +01:00
Mads Rasmussen 06d7ae3861 update text colours / icon colours 2017-02-27 15:40:14 +01:00
Mads Rasmussen 3d4f999c07 small health check tweaks 2017-02-27 15:39:47 +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
Mads Rasmussen 3b7a83ab14 small colour improvements 2017-02-27 15:10:11 +01:00
Mads Rasmussen 796d665913 update grid colours 2017-02-27 15:07:19 +01:00
Mads Rasmussen 458e890c08 update health check colours 2017-02-27 15:06:52 +01:00
Mads Rasmussen e32604183c update login colours 2017-02-27 15:05:57 +01:00
Mads Rasmussen 099b05dbbc update a loooot of gray colors 2017-02-27 13:26:28 +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
Mads Rasmussen 4cf7ae4b4d increase base font size 2017-02-27 10:08:10 +01:00
Mads Rasmussen 757b720a68 increase all small font sizes 2017-02-24 13:55:41 +01:00
Mads Rasmussen c8968edd65 add margin bottom to item picker search field 2017-02-24 12:49:38 +01:00
Mads Rasmussen 58b4201eeb update query builder + insert code dialog 2017-02-24 12:45:34 +01:00
mikkelhm a39557a3a7 Bump version to alpha068 2017-02-24 12:31:59 +01:00
Mads Rasmussen 46eda4a3c3 update document type editor colours 2017-02-24 12:01:28 +01:00
Mads Rasmussen 89ebad2fbc fix colours + increase font-size in breadcrumb 2017-02-24 11:38:18 +01:00
Mads Rasmussen 815a288bcb update tree + sections 2017-02-24 11:37:40 +01:00
Mads Rasmussen 67bcd517bf test warmer version of turquoise 2017-02-24 11:36:07 +01:00
Mads Rasmussen 915503fb51 update content grid colours 2017-02-24 11:35:36 +01:00
Mads Rasmussen ddefdf2627 increase font size in notifications 2017-02-24 09:12:06 +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
Stephan 2239316889 Fix RelationRepository, debugging 2017-02-23 19:00:42 +01:00
Mads Rasmussen 2289938486 update button colours 2017-02-23 16:01:58 +01:00
Mads Rasmussen 2b8db9d1b5 set preview button to style "info" 2017-02-23 14:56:51 +01:00
Mads Rasmussen 14c903f6a3 set colour on editor navigation to turquoise 2017-02-23 14:56:13 +01:00
Mads Rasmussen b8a50b8da3 increase border-width on checkmark circle in media section 2017-02-23 14:54:47 +01:00
Mads Rasmussen 09300bba71 make checkmark in content picker green 2017-02-23 14:54:04 +01:00
Mads Rasmussen f716479d01 increase font size + line-height on property help text 2017-02-23 14:53:35 +01:00
Mads Rasmussen fa5044b011 make labels black 2017-02-23 14:52:53 +01:00
Mads Rasmussen 0aefbc045d add Lato as main font family 2017-02-23 14:25:33 +01:00
Mads Rasmussen 09788f1ab4 update base button colours 2017-02-23 13:34:38 +01:00
Mads Rasmussen 3a58cb35f8 update base form colours 2017-02-23 13:33:55 +01:00
Mads Rasmussen 8f47722d7d update base font colour 2017-02-23 13:32:45 +01:00
Mads Rasmussen ebed7c40ed update tree item hover colour 2017-02-23 13:32:19 +01:00
Mads Rasmussen 8c54e65861 update color on locked field component 2017-02-23 12:49:55 +01:00
Mads Rasmussen 157f9f3285 update umb-node-preview colours 2017-02-23 12:22:41 +01:00
Mads Rasmussen f2cefac866 update colours for package repo + installed packages 2017-02-23 12:14:08 +01:00
Mads Rasmussen cbcbb895ec Update header input + search input colours 2017-02-23 10:40:41 +01:00
Mads Rasmussen b98e96f758 add grayscale variables 2017-02-23 10:38:57 +01:00
Mads Rasmussen 9b033a3204 update icon picker + cards hover color 2017-02-23 10:10:34 +01:00
Mads Rasmussen 235014c8ca use new green for progress bars 2017-02-23 09:29:16 +01:00
Mads Rasmussen d04947a2d3 remove text indent on button text 2017-02-23 09:27:45 +01: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
Per Ploug d3582e2296 An ID is required on all items edited in backoffice editors
The ID is required when an item is saved, as the routing will
automatically redirect based on this ID - files, does not have an ID -
so the filepath is used in the same as it is used for the tree
2017-02-22 15:47:36 +00: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
Mads Rasmussen 49ff36155c update required field color 2017-02-22 13:38:04 +01:00
Mads Rasmussen 512de60693 update active tree item color 2017-02-22 13:37:28 +01:00
Mads Rasmussen a064ef4aa7 update media grid, folder grid + load indicator colours 2017-02-22 13:36:22 +01:00
Mads Rasmussen 2210bc3f79 update table colors 2017-02-22 13:35:21 +01:00
Warren Buckley b6bc83ba71 Moves the bulky JSON objects for shortcuts to show in the shortcut overviews into helper service so can be reused a bit easier 2017-02-22 11:53:36 +00:00
Warren Buckley 8f43e9450a Update JS editor to use simplier localizationMany as opposed to nested promises for sucess & error notifications 2017-02-22 11:01:05 +00:00
Warren Buckley f3242e8d6a Adds in keyboard shortcut dialog & generic keyboard shortcuts (common to all ACE editors) to the JS editor 2017-02-22 11:00:52 +00:00
Warren Buckley f9835d3ec5 Move snippets & completion out of onLoad callback out onto config object for the template editor 2017-02-22 11:00:27 +00:00
Warren Buckley 49bcf413a4 Adds the auto-complete & snippets for the JS/Scripts ACE Editor config 2017-02-22 11:00:17 +00:00
Warren Buckley bcfea6986c Updates the localizationService ugly nested promises to the new localizeMany function 2017-02-22 10:59:33 +00:00
Warren Buckley 29b297e072 Add in UI translation items 2017-02-22 10:59:12 +00:00
Warren Buckley 70accfa95a Uses new localizationService.format function for the shortcuts dialog 2017-02-22 10:58:57 +00:00
Warren Buckley b764a47e7e Adds in new format function to localizationService simialr to C# String.Format() usign %0% as tokens.
Documents the new functions added.
2017-02-22 10:58:27 +00:00
Warren Buckley fc7cba1da9 Add in localizeMany & concat to localizationService as dont like seeing nested promises in our code base to fetch two items to pass to notificationService 2017-02-22 10:58:07 +00:00
Warren Buckley 883980ab8d Update localizationService documentation about the usage of %0% tokens being replaced with passed in values 2017-02-22 10:57:52 +00:00
Warren Buckley 23abbdb288 Update Localize Directive (attribute & element) with some specifics in documentation about the format of the string for the key. Localize attribute now supports a key without having to be prefixed with @ 2017-02-22 10:57:32 +00:00
Warren Buckley 652a7a3655 Update more translation keys from Per's update to the template editor (Will need to merge in after this) 2017-02-22 10:56:46 +00:00
Warren Buckley 8f73514c1d An initial start of localising the keyboard shortcut dialog for template editor (Only adding keys into en.xml for now) 2017-02-22 10:56:18 +00:00
Warren Buckley 304b863b02 Adds in keyboard shortcuts to power the dialog/UI and adds in the custom keyboard bindings for opening our cusotm dialogs for inserting macros, partials etc 2017-02-22 10:55:59 +00:00
Warren Buckley f0bdb1a2e9 Updates ACE Editor Directive to load in the additional library that enables simple auto-complete 2017-02-22 10:55:44 +00:00
Warren Buckley 6fb3c91d3f Updates Keyboard Shorcut directive in template editor view to use the new attribute on the directive to pass in show overlay bool 2017-02-22 10:55:14 +00:00
Warren Buckley b9095629ed Update Keyboard Shortcut Directive to support a callback function being passed in & the bool thjat toggles the overlay/div from being shown 2017-02-22 10:54:54 +00:00
Mads Rasmussen f1ec692a73 update umb-overlay colours 2017-02-22 11:48:11 +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
Mads Rasmussen 1a2814a964 update color on navigation border + resize navigation 2017-02-22 11:01:34 +01:00
Mads Rasmussen 28d6622269 update stand alone tab border color 2017-02-22 10:55:14 +01:00
Mads Rasmussen 86971179ee update tabs border color 2017-02-22 10:52:39 +01:00
Mads Rasmussen 9c4eacf330 update main editor header and footer colors 2017-02-22 10:39:26 +01:00
Mads Rasmussen 251a67d653 update section colors 2017-02-22 10:38:34 +01: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
Mads Rasmussen abe92eabba update modals header + border colors 2017-02-22 10:20:37 +01:00
Mads Rasmussen 0e76b27a2d add new color variables 2017-02-22 10:06:22 +01:00
Stephan 1a37d88855 ShadowFS in App_Data/TEMP 2017-02-22 10:05:53 +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
Claus 2d5ffabe1e adding missing files from last commits. 2017-02-21 18:15:11 +01:00
Stephan f61b7579a2 Version 7.6-alpha066 2017-02-21 17:13:34 +01:00
Stephan 86a3780c61 Cleanup IFileSource for Deploy/IFileSource 2017-02-21 16:01:01 +01: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
Emil Wangaa 552909fde2 Merge pull request #1753 from umbraco/temp-U4-9293
Fixes: U4-9293 Search the entire media section in Media Picker when inserting an image into content
2017-02-21 12:00:26 +01:00
Emil Wangaa 7adae4d345 Merge pull request #1755 from umbraco/temp-U4-9470
U4-9470 Mini list view: only show expand option for nodes with children
2017-02-21 09:00:52 +01:00
Sebastiaan Janssen 52dce66598 Bump version 2017-02-21 08:49:34 +01:00
Emil Wangaa d747cf69c3 Fixes typo in comment 2017-02-21 08:23:21 +01:00
Shannon 255fec84bd Merge branch 'refs/heads/dev-v7' into temp-U4-9536 2017-02-21 17:56:39 +11:00
Shannon bc5e3b4d66 Fixes issue of moving an item to the root, it will throw a JS error because target.nodeType is null 2017-02-21 15:44:49 +11:00
Shannon febeb82d10 Fixes the EntityController.GetPagedDescendants to not return items in the recycle bin, added some tests. 2017-02-21 15:43:46 +11:00
Shannon 9142314d39 U4-9522 Media recycle bin does not show folders 2017-02-21 14:18:49 +11:00
Shannon 1c2b2c1409 Merge branch 'refs/heads/temp-U4-9470' into temp-U4-9293 2017-02-21 13:54:21 +11:00
Shannon b4eb9f333e Gets the member picker working with mini list views, falls back to Examine search for when searching on member types - since the EntityService doesn't support that currently, gets the icon mapped correctly for members, 2017-02-21 13:49:58 +11:00
Shannon af00a421cd Updates EntityController to deal with special Members root node id 2017-02-20 21:23:09 +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
Stephan fed06c88e8 Version 7.6-alpha065 2017-02-17 14:28:26 +01:00
Stephan 5dec2861d9 Fix event name issue 2017-02-17 14:28:26 +01:00
Stephan 23b3bb37ee Scope - fix issue with EventMessages 2017-02-17 13:10:22 +01:00
Emil Wangaa 4dabb606e7 Fixes issue with the mediapicker search getting 404 and loading failing because of missing property values for folders 2017-02-17 09:53:23 +01:00
Mads Rasmussen d5f66ebe02 update image properties to match media grid component 2017-02-16 19:59:45 +01:00
Anders Bjerner ad9ae867c0 Added support for ignoring HTTP errors directly from the Angular $http options 2017-02-16 19:22:26 +01:00
Stephan c7783d1cd1 Merge pull request #1759 from umbraco/temp-deploy-214
deploy-214 Add a "pretty" name to the IEntity or lookup a name when one is not immediately available
2017-02-16 18:45:31 +01:00
Stephan 2104b109f2 Merge pull request #1746 from umbraco/temp-U4-9509
U4-9509 Fix bugs in shadow filesystem
2017-02-16 18:43:04 +01:00
Stephan 578ca7d41d Merge branch dev-v7.6 into temp-U4-9509 2017-02-16 18:38:22 +01:00
Emil Wangaa bd38dde1fc Adds GetPagedDescendants to EntityController
Implements GetPagedDescendants in the mediapicker Search
Removes duplicate ExamineSearch and Search endpoint code from MediaController
2017-02-16 14:41:50 +01:00
Claus 42c23da9f5 removing IPrettyArtifact and moving properties to IArtifact instead. 2017-02-16 12:54:42 +01:00
Emil Wangaa cab1536a30 Merge remote-tracking branch 'origin/temp-U4-9470' into temp-U4-9293 2017-02-16 12:46:35 +01:00
Claus bbd9e4f0fd updating tinymce to 4.5.3. 2017-02-16 12:16:11 +01:00
Claus bf9a408c50 U4-9145 Updating TinyMCE to latest (4.4.3) 2017-02-16 12:13:48 +01:00
Claus 33d35fd9f7 bumping version just to be sure. 2017-02-16 10:01:37 +01:00
Claus cc885c1231 Merge pull request #1750 from umbraco/deploy-219
deploy-219 - files management
2017-02-16 09:52:59 +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
Shannon 422dd1a627 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-02-16 13:22:59 +11:00
Sebastiaan Janssen 759e444624 Merge pull request #1467 from ArnoldV/dev-v7
U4-8990 Updated Dutch Language File
2017-02-15 22:39:44 +01:00
Sebastiaan Janssen 2a7ef5de26 Merge pull request #1756 from umbraco/temp-U4-9512
U4-9512 Missing index on umbracoUser2NodePermission
2017-02-15 15:14:33 +01:00
Claus 43e892563d Merge branch 'aarym-u4-9491' into dev-v7.6 2017-02-15 14:17:43 +01:00
Shannon 4d1e64b279 U4-9512 Missing index on umbracoUser2NodePermission 2017-02-15 21:51:14 +11:00
Shannon 975c97cfb0 Doh! Changed update to Execute 2017-02-15 21:24:45 +11:00
Shannon 0c613347ae Updates ClearPublished logic to be done in a single SQL statement instead of several 2017-02-15 21:22:08 +11:00
Mads Rasmussen 83f75fdaff nested mini list views: use visibility hidden instead of ng-if to better align list items 2017-02-15 11:00:35 +01:00
Mads Rasmussen 487792920b only show published state for content 2017-02-15 10:40:24 +01:00
Shannon 6ae06ad2e0 Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9470
# Conflicts:
#	src/Umbraco.Web/Editors/EntityController.cs
2017-02-15 17:41:12 +11:00
Shannon 8387c435d4 Gets mini list view working so that only nodes with children show the arrow, added GetPagedChildren to EntityController 2017-02-15 17:40:10 +11:00
Shannon 5807bbccc4 revert change to petapoco, we will calc the total manually for this due to an outer join/aggregate, adds GetDescendents + tests for EntityService 2017-02-15 16:38:43 +11:00
Shannon 1bfc041bbe Adds Paged query to entity repo/service + tests, had to fix paged queries in petapoco to strip ending GROUP BY otherwise the COUNT is incorrect 2017-02-15 15:13:23 +11:00
Claus a5ca058cb2 adding another wildcard test for ShadowFileSystem. 2017-02-14 15:14:21 +01:00
Claus 88a1ad04aa ensuring filter is applied to the shadow filesystem when using GetFiles.
added tests for various filters.
2017-02-14 14:57:04 +01:00
Warren Buckley e619c402b4 Merge branch 'temp-U4-9310' into dev-v7.6
# Conflicts:
#	src/Umbraco.Core/UdiEntityType.cs
2017-02-14 11:53:38 +00:00
Warren Buckley c9294e5281 In the init DB creation the Media & Member Picker was inserted into the DB the wrong way round - now assigned with the correct name for the DataType 2017-02-14 11:37:42 +00:00
Stephan 0074f57970 Version 7.6-alpha063 2017-02-14 11:23:20 +01:00
Stephan 9b4a6f2761 Merge origin/dev-v7.6 into deploy-219 2017-02-14 11:22:03 +01:00
Stephan f889b5206c Scope - handle publishing events 2017-02-14 11:11:40 +01:00
Stephan 507d7dd4f0 Scope - forgot to complete some scopes 2017-02-14 11:11:40 +01:00
Stephan 55c5b41693 Scope - report completion 2017-02-14 11:11:39 +01:00
Stephan b58d8677b3 Scope - bugfixing 2017-02-14 11:11:39 +01:00
Shannon f30d7fc68c Fixes nuspec to be net45 as a min 2017-02-14 14:29:23 +11:00
aaron.morey f5a204d1de U4-9491 feedback to implement into core css, be more specific with class naming & with usage and to implement a lighter red color for appearance 2017-02-14 09:14:05 +11:00
Warren Buckley d504d8f54e Update Core Deploy EntityTypes for Forms (Workflow is part of main form artifact) and we dont deploy records. Changing to PreValue & DataSources 2017-02-13 15:54:39 +00:00
Mads Rasmussen 7c049b55a8 media picker - search media library instead of filter current folder 2017-02-13 14:36:39 +01:00
Claus b519d68e1a fixing PartialViewMacrosTree and ScriptTree in trees.Release.config. 2017-02-13 13:34:35 +01:00
Claus deb8d652c5 fixing PartialViewsTreeController reference in trees.Release.config. 2017-02-13 12:44:16 +01:00
Emil Wangaa 051b3f2e6a Allows get for search media endpoint 2017-02-13 11:23:21 +01:00
Emil Wangaa 21f947efbd Moves media search to MediaController and implements paging for the endpoint 2017-02-13 11:21:09 +01:00
Sebastiaan Janssen a68f4e284a Merge pull request #1752 from umbraco/temp-U4-9517
U4-9517 BackOfficeSignInManager doesn't automatically keep LastLoginD…
2017-02-13 10:38:41 +01:00
Shannon 90b43584d2 Oops, fixes issue with attemping to reduce code but the 'section' parameter isn't the same in the config 'type' so needs to be manually applied like it was before. Fixes MultipleMediaPickerPropertyEditor to be multiple by default (is a bug in current versions too) 2017-02-13 19:57:21 +11:00
Emil Wangaa 9461e35028 Adds endpoint for searching media for the mediapicker 2017-02-13 09:54:50 +01:00
Stephan 12dd01dd29 Scope - refactor call context 2017-02-13 09:05:33 +01:00
Stephan c64e3a8908 Scope - refactor event dispatching 2017-02-13 09:05:32 +01:00
Shannon d554417fde U4-9517 BackOfficeSignInManager doesn't automatically keep LastLoginDate set on users 2017-02-13 16:47:04 +11:00
Stephan 74e8390bda Scope - enable http vs call context switching 2017-02-11 09:56:15 +01:00
Stephan 4f9bbdf7f7 Scope - Fix BulkInsertRecords, ensure a db connection is open 2017-02-11 09:56:12 +01:00
Stephan 67fc8b6215 Scope - fix media files deletion 2017-02-11 09:55:32 +01:00
Sebastiaan Janssen 3840ac2fed Merge pull request #1743 from umbraco/temp-U4-9484
U4-9484 Implement correct tree menu logic for partialviews, partialviewmacros and scripts
2017-02-10 17:04:41 +01:00
Sebastiaan Janssen 7c64f1aa0d Merge pull request #1745 from umbraco/temp-U4-7385
Fixes: U4-7385 Improve UI for listview - Make it clearer that users can search children
2017-02-10 16:43:35 +01:00
Claus 771f8d92f2 adding in missing extension method stuff for some udis. 2017-02-10 14:44:56 +01:00
Stephan 82c18955b0 Version 7.6-alpha060 2017-02-10 14:38:50 +01:00
Claus eedcfc122b Merge pull request #1747 from umbraco/temp-U4-9513
U4-9513 Empty recycle bin SQL logic can SQL to timeout due to query i…
2017-02-10 11:42:14 +01:00
Claus 8cf3110708 fixing typo and missing file ref in csproj. 2017-02-10 11:41:46 +01:00
Mads Rasmussen 0dc0e68174 reset pagination when searching 2017-02-10 10:36:58 +01:00
Claus 5226762528 Merge branch 'temp-U4-9351' into dev-v7.6
Conflicts:
	src/Umbraco.Core/Events/ImportPackageEventArgs.cs
	src/Umbraco.Core/Umbraco.Core.csproj
	src/Umbraco.Web/Editors/PackageInstallController.cs
2017-02-10 10:08:31 +01:00
Claus 7889f82a9a added a check so the 'ensure' wont fail if the path is already as it should be.
added unit test for this method.
2017-02-10 09:25:16 +01:00
Emil Wangaa aaa9c8f194 Fixes delete of folders in partialviews,partialviewmacros and scripts 2017-02-10 09:24:14 +01:00
Sebastiaan Janssen 3d1a44b32c Merge branch 'temp-U4-8998' into dev-v7.6
# Conflicts:
#	src/Umbraco.Core/Umbraco.Core.csproj
2017-02-10 08:25:52 +01:00
Sebastiaan Janssen 724ec9ab73 Merge pull request #1748 from umbraco/temp-U4-8835
U4-8835 cmsMember.LoginName needs a DB index
2017-02-10 08:22:36 +01:00
Shannon aa0eaf590c adds indexes to relation type 2017-02-10 15:51:41 +11:00
Shannon 2b82520067 U4-8998 umbracoRelation table needs unique index on columns: parentId, childId, relType 2017-02-10 15:38:53 +11:00
Shannon 5aed6334c4 missing file 2017-02-10 14:24:33 +11:00
Shannon 91157caf0e U4-8835 cmsMember.LoginName needs a DB index 2017-02-10 14:23:46 +11:00
Shannon dbe489c0f2 U4-9513 Empty recycle bin SQL logic can SQL to timeout due to query inefficiencies 2017-02-10 12:27:50 +11:00
Shannon 2652a583e0 updates mediapicker.controller pre value to not make an uneeded request 2017-02-10 10:48:43 +11:00
Shannon bc1758f569 Updates the content picker to not make an unneeded request 2017-02-10 10:45:35 +11:00
Shannon a898c2d697 Fixes ParameterSwapControllerActionSelector when there is an empty parameter (not null but without a value) 2017-02-10 10:36:48 +11:00
Shannon e612bcae58 Merge branch 'refs/heads/dev-v7.6' into temp-U4-9310 2017-02-10 10:04:58 +11:00
Shannon d27fee8a5b Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-02-10 09:38:03 +11:00
Sebastiaan Janssen 7aef8cbb67 Merge branch 'temp-U4-9481' into dev-v7.6
# Conflicts:
#	src/Umbraco.Core/Services/FileService.cs
2017-02-09 21:55:17 +01:00
Sebastiaan Janssen a7e28a97d9 Merge pull request #1715 from umbraco/temp-U4-9450
U4-9450 Paged data queries return all property data in the entire dat…
2017-02-09 21:02:15 +01:00
Stephan 308a61895e deploy-219 - implement filesystem CanAddPhysical, AddFile from physical path 2017-02-09 15:58:44 +01:00
Stephan 8e5c57eb60 U4-9322 - rename kabum in Scope.RobustExit 2017-02-09 15:58:17 +01:00
Claus 9c5526f281 adding test for GetUrl on shadow. 2017-02-09 15:00:38 +01:00
Claus 9c803cc234 more test and comments to existing tests. 2017-02-09 15:00:37 +01:00
Claus f24fd42a69 GetFullPath now uses ShadowFileSystem. 2017-02-09 15:00:37 +01:00
Claus 9b7f459c44 added more checks to shadow tests to ensure correct behavior. 2017-02-09 15:00:36 +01:00
Claus 273a5cef28 fixed bug in GetFiles with filter param.
test for shadow filesystem GetFiles.
2017-02-09 15:00:35 +01:00
Claus 57945fcec6 fixing broken build - referencing files that aren't committed. 2017-02-09 14:41:22 +01:00
Sebastiaan Janssen ade3c4ee6c Merge pull request #1732 from rsoeteman/U4-9493
U4 9493
2017-02-09 14:26:44 +01:00
Arnold Visser 7da7c1e5a1 Addes all new/missing fields since last edit
Checked against the English version
2017-02-09 13:47:31 +01:00
Sebastiaan Janssen 8fe904d780 Merge pull request #1744 from umbraco/temp-U4-9433
U4-9433 Add index to path column on umbracoNode
2017-02-09 13:43:44 +01:00
Mads Rasmussen 1901fbb6ed add markup for member picker and content picker 2017-02-09 10:42:15 +01:00
Mads Rasmussen 1de52482e3 fix back arrow alignment 2017-02-09 09:23:30 +01:00
Shannon 1c0d4001ab U4-9433 Add index to path column on umbracoNode 2017-02-09 17:27:23 +11:00
Shannon f04d70f2d9 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-02-09 17:04:41 +11:00
Shannon Deminick 55098deac0 Merge pull request #1728 from umbraco/temp-u4-9487
U4-9487 - optimize initialization of xml nodes
2017-02-09 16:56:05 +11:00
Shannon 58c5618d30 Adds benchmarks for XML perf testing - had to make the init xml code static with out params to test but that's ok. 2017-02-09 16:42:59 +11:00
Shannon d0cbeb4a0a Better optimized initialization of xml nodes with less allocations 2017-02-09 15:29:38 +11:00
Shannon ce0821e2d6 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6
# Conflicts:
#	build/NuSpecs/UmbracoCms.Core.nuspec
#	src/Umbraco.Tests/Umbraco.Tests.csproj
2017-02-09 13:20:33 +11:00
Shannon Deminick b6e9db7363 Merge pull request #1726 from umbraco/temp-u4-9322
Scope Scope Scope!
2017-02-09 12:30:58 +11:00
Shannon 9f710a957d Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-u4-9322
# Conflicts:
#	src/Umbraco.Core/Services/FileService.cs
2017-02-09 12:30:01 +11:00
Shannon b7578e2b98 fixes tests 2017-02-09 12:07:16 +11:00
Shannon 97e8973cbd Ensures that the RelateOnTrashHandler doesn't attempt to create a relationship for an item that doesn't exist 2017-02-09 11:40:13 +11:00
Shannon 2dc45c3b9f Tons of code duplication removed, streamlines the content, media and member repositories to use the same paged methods and filtering mechanism (much bettter), adds some tests, creates a marker interface for IContentServiceBase so we can use extension methods for now to de-duplicate some of the code between media and content services 2017-02-09 10:34:40 +11:00
Mads Rasmussen 49c2ae3673 cleanup 2017-02-08 23:37:48 +01:00
Mads Rasmussen 5f22c81994 fixes: U4-9467 Mini list view: don’t animate list view if it is a start node 2017-02-08 23:37:33 +01:00
Mads Rasmussen f13427f5fb fixes to breadcrumb 2017-02-08 22:49:16 +01:00
Mads Rasmussen 2785eaeda5 only show unpublished state for content 2017-02-08 20:22:54 +01:00
Sebastiaan Janssen bb31eb7c35 Emit only relative paths for files in a package 2017-02-08 16:19:47 +01:00
Emil Wangaa a31cfb86f8 Moved reload to be last menu option and added a separator for delete option to keep consistency 2017-02-08 15:57:53 +01:00
Shannon 4feb876463 Fixes issues of deleting a content item and the trashing events raised for content/media that is going to be deleted anyways, adds tests to support. Fixes MediaService to not delete the xml directly and instead rely on it's repository to do that (which is the correct way), streamlines both content/media service logic to be the same (need to start sharing code!) 2017-02-09 01:47:04 +11:00
Emil Wangaa e4802b592f Centralized the tree menu logic for partialviews, partialviewmacros and scripts to the FileSystemTreeController and implemented logic to match what we do for Document Types 2017-02-08 15:43:31 +01:00
Mikkel Holck Madsen a8914dcfdb Merge pull request #1740 from umbraco/temp-U4-9458
Adds unit tests for U4-9458 UmbracoExamine performance optimizations
2017-02-08 15:12:07 +01:00
Mads Rasmussen 548f9fd01f open mini list view before children are loaded 2017-02-08 15:02:03 +01:00
Mads Rasmussen 843796c9a4 refactor move logic from tree controller into to mini-list-view component 2017-02-08 14:58:54 +01:00
Sebastiaan Janssen 7648c76f6f List full path of each file installed 2017-02-08 14:45:07 +01:00
Sebastiaan Janssen 308ed3bba7 Removed files that are not found on disk don't get updated to list their full path 2017-02-08 14:44:48 +01:00
Sebastiaan Janssen 7bcb2b11f6 Makes the (un)install summary accessible to events 2017-02-08 14:43:59 +01:00
Shannon e06cda98e9 fixes SQL IN expression 2017-02-08 22:25:07 +11:00
Shannon fb02a5b06d Fixes issue of removing content types in bulk (like when removing a package) and having the trashed event being raised for what will end up being a deleted node, Fixes a bug with the (very silly) extension methods for content types, removes singleton accessors from these (very silly) extension methods - which actually never worked for media types! 2017-02-08 21:59:16 +11:00
Mads Rasmussen c060856782 fix breadcrumb for pickers with a startNode 2017-02-08 11:09:09 +01:00
Sebastiaan Janssen 311edd3279 Adds missing dependency (it's in dev-v7, must have been a merge where it was forgotten to be merged into dev-v7.6) 2017-02-08 10:36:36 +01:00
Claus 1c89f8c8dd Merge branch 'temp-U4-1324' into dev-v7.6 2017-02-08 09:54:12 +01:00
Mads Rasmussen 857063ebd8 fixes: U4-9465 Mini list view: don’t show expand arrow on list views in trees not supporting mini list view 2017-02-08 09:53:52 +01:00
Claus 24063c403a Merge remote-tracking branch 'origin/dev-v7.6' into temp-U4-1324
Conflicts:
	src/Umbraco.Core/packages.config
	src/Umbraco.Tests/packages.config
2017-02-08 09:14:27 +01:00
Claus 0f930d7342 Merge pull request #1741 from umbraco/temp-U4-9499
U4-9499 Update to latest Json.Net
2017-02-08 08:58:22 +01:00
Emil Wangaa c36000c4dd Adds create container endpoint for creation folders for scripts, partialviews, partialviewmacros 2017-02-08 08:52:36 +01:00
Mads Rasmussen 999de5ae1d add client side logic for partial view macros folder creation 2017-02-08 08:52:36 +01:00
Mads Rasmussen 00982d4278 add client side logic for partial views folder creation 2017-02-08 08:46:10 +01:00
Mads Rasmussen cda47ed536 add client side logic for scripts folder creation 2017-02-08 08:45:23 +01:00
Shannon f4f1f6774d U4-9499 Update to latest Json.Net 2017-02-08 17:47:32 +11:00
Shannon a20cc60c10 Updates new UDI pickers that have start nodes for pre-values to also store UDIs for their prevalues, this has a knock on effect in that we need to be able to inject some server side config for pre-value editors (otherwise we'd have to make diff udi prevalue editors but that isn't very re-usable), so have implemented that and then updated all of the logic to deal with the udi idType. 2017-02-08 16:15:27 +11:00
Shannon 846ac573cc Fixes tests, ensures we don't install test data that doesn't exist 2017-02-08 14:18:37 +11:00
Warren Buckley 92acc3d331 Merge pull request #1736 from umbraco/temp-U4-9429
U4-9429 Make new create dialogs for code files (or rethink snippets)
2017-02-07 21:28:43 +00:00
Warren Buckley ed4db61288 Merge pull request #1738 from umbraco/temp-U4-9314
U4-9314 Update to .Net Framework 4.6.2
2017-02-07 17:49:17 +00:00
Warren Buckley ba6705a706 Merge branch 'dev-v7.6' into temp-U4-9314 2017-02-07 17:27:07 +00:00
Mads Rasmussen dc980bd78e remove null 2017-02-07 16:41:01 +01:00
Mads Rasmussen c9f99d7f42 localise create items 2017-02-07 16:35:33 +01:00
Sebastiaan Janssen 73e219b23c Fix unit tests 2017-02-07 16:24:34 +01:00
Sebastiaan Janssen 07e0de5824 Adds unit tests for U4-9458 UmbracoExamine performance optimizations 2017-02-07 16:20:40 +01:00
Mads Rasmussen 79a103662f remove alerts 2017-02-07 16:09:36 +01:00
Mads Rasmussen 2ba5627e2c fixes: U4-9471 Mini list view: show breadcrumb instead of back button 2017-02-07 15:57:53 +01:00
Warren Buckley 122295c89f Sets MacroPicker aka MacroContainer as deperecated 2017-02-07 13:55:49 +00:00
Mads Rasmussen 2669c68df0 fixes: U4-9468 Mini list view: add empty state for no children + no search result 2017-02-07 11:55:45 +01:00
Sebastiaan Janssen 389b29599b U4-9495 ImageProcessor high CPU usage when trimCache=true 2017-02-07 10:29:11 +01:00
Mads Rasmussen 912a6a52cc fixes: U4-9472 Mini list view: show published/unpublished state of node 2017-02-07 10:10:37 +01:00
Claus 925c343a30 U4-9351 Add events for package install/uninstall 2017-02-07 10:00:34 +01:00
Shannon 351796fd6b Created test to verify problem with deleting content of content type in a loop (i.e. on package uninstall) 2017-02-07 15:46:50 +11:00
Shannon e58d9a9535 Fixing tests, fixes PublishingStrategy to hvae the scope provider passed in 2017-02-07 14:40:45 +11:00
Shannon 3fa7c4d7ef Removes POC class, fixes content service trash/move events so there's not ambiguous 2017-02-07 14:08:55 +11:00
Shannon b6b2a53361 Fixes publishing strategy to use the normal event messages collection since we haven't actually wired those up to the scope for now. 2017-02-07 14:07:01 +11:00
Shannon 4647ed2551 Merge branch 'refs/heads/dev-v7.6' into temp-u4-9322
# Conflicts:
#	src/Umbraco.Core/DatabaseContext.cs
#	src/Umbraco.Core/UmbracoApplicationBase.cs
2017-02-07 13:44:17 +11:00
Shannon e7e6ad6d0b Some adjustments for U4-9477 2017-02-07 13:36:32 +11:00
Shannon 0e727f91da Merge branch 'refs/heads/dev-v7.6' into temp-U4-9310
# Conflicts:
#	src/UmbracoExamine/UmbracoMemberIndexer.cs
2017-02-07 13:21:02 +11:00
Shannon a71ec8dd81 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-02-07 12:50:44 +11:00
Shannon f816a63b54 Ok, reverting the correct commit this time: Revert "Fixes database context issue during startup when there is no db configured" 2017-02-07 12:49:26 +11:00
Shannon 138991d951 OMG Re-rever "DOH! Revert "Fixes database context issue during startup when there is no db configured", i reverted the wrong commit on the wrong branch 2017-02-07 12:43:06 +11:00
Shannon 92ce064d30 DOH! Revert "Fixes database context issue during startup when there is no db configured" pushed to the wrong branch 2017-02-07 12:40:28 +11:00
Shannon ab3bfa4e92 Fixes database context issue during startup when there is no db configured 2017-02-07 12:39:35 +11:00
Shannon fa8f3985b8 Fixes database context issue during startup when there is no db configured 2017-02-07 12:33:37 +11:00
Shannon 179523224a Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9310 2017-02-07 12:15:54 +11:00
Shannon 19e4bee34e fixes test 2017-02-07 12:02:38 +11:00
Shannon f1709f6066 Fixes identity seed for db 2017-02-07 11:58:10 +11:00
Shannon f2be235f85 Fixes the db data type for UDI media picker, fixes the initial db installation data to use the new pickers. 2017-02-07 11:44:04 +11:00
Mikkel Holck Madsen 175c785705 Merge pull request #1722 from umbraco/temp-U4-9458
Changes IndexFieldPolicies to be a StaticFieldCollection which is a k…
2017-02-06 21:45:54 +01:00
Mikkel Holck Madsen 72aebd3ecf Merge branch 'dev-v7' into temp-U4-9458 2017-02-06 21:44:26 +01:00
Warren Buckley c8408760df Merge pull request #1737 from umbraco/temp-U4-9474
Fixes: U4-9474 Update macro picker to follow the new picker UI
2017-02-06 16:03:25 +00:00
Warren Buckley 5834649abc Merge pull request #1733 from umbraco/temp-U4-9466
fixes: U4-9466 Duplicate reorder links for Umbraco grid
2017-02-06 15:36:04 +00:00
Mads Rasmussen 2eda70542f rename macro container to macro picker 2017-02-06 16:16:26 +01:00
Mads Rasmussen a2a17faca1 Fixes: U4-9474 Update macro picker to follow the new picker UI 2017-02-06 16:11:51 +01:00
Shannon a6c2844d12 updates nuspec with correctly targeted framework 2017-02-07 01:03:50 +11:00
Mikkel Holck Madsen 802cbb82c4 Merge pull request #1723 from umbraco/temp-U4-9448
U4-9448 Slave Front End server requires write access to database when…
2017-02-06 15:01:30 +01:00
Shannon 6f16b98b32 regression issue from refactoring how media works with Deploy 2017-02-07 00:57:44 +11:00
Mikkel Holck Madsen 42f5507fe8 Merge pull request #1734 from umbraco/temp-U4-9492
U4-9492 Update to latest ImageProcessor
2017-02-06 14:39:01 +01:00
Shannon 72910cb35e Updates everything to .Net 4.6.2, had to update the semver reference too - no breaking changes though 2017-02-07 00:22:34 +11:00
Shannon 7be30ad6ac Moves all binding redirects via code to one place 2017-02-06 23:46:44 +11:00
Sebastiaan Janssen 5a8e37f5b4 U4-9492 Update to latest ImageProcessor 2017-02-06 13:46:10 +01:00
Shannon f87ccc0a53 Updates nuspec 2017-02-06 23:36:56 +11:00
Shannon 40ed77103f Updates to latest 1.x version of log4net (before the real 2.x version) with binding redirects and codebase binding redirects to redirect from non-signed to signed version 2017-02-06 23:07:20 +11:00
Mads Rasmussen 483762a984 fixes: U4-9466 Duplicate reorder links for Umbraco grid 2017-02-06 12:50:34 +01:00
Richard Soeteman a3c7b1fcfe Fixed issue U4-9494 2017-02-06 11:51:44 +01:00
Stephan 145ca54dcf Merge origin/dev-v7.6 into temp-u4-9322 2017-02-06 11:29:04 +01:00
Richard Soeteman 02785eea42 Fixed issue U4-9493 2017-02-06 11:26:58 +01:00
Stephan 1aecb66167 U4-9322 - restore DatabaseContext ctors, see U4-9477 2017-02-06 11:17:24 +01:00
Stephan 96244f9f7b U4-9322 - pushed DEBUG_SCOPES by mistake 2017-02-06 10:43:39 +01:00
Stephan e0cc59d212 Merge branch 'temp-u4-9322' of https://github.com/umbraco/Umbraco-CMS into temp-u4-9322 2017-02-06 10:09:31 +01:00
Stephan dd2946419b U4-9322 - fix broken DEBUG_SCOPES 2017-02-06 10:08:29 +01:00
Shannon d0ea8e83ad Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-02-06 19:49:00 +11:00
Shannon Deminick 3c7d3b2f63 Merge pull request #1724 from umbraco/temp-installer-url-update
Update NewInstallStep.cs
2017-02-06 19:42:23 +11:00
Shannon a65ad3c72a Adds equality members for all event args, updates equality check for EventDefinitionBase to include the args (since that is quite important!), creates an OrderedHashSet class which can deduplicate lists for us based on member equality and supports first in or last in + tests. 2017-02-06 18:46:23 +11:00
Shannon f6a7b25e87 Updates CacheRefresherEventHandler to have consistent events, adds logic to find the event based on definitions, adds tests to test them all 2017-02-06 17:26:06 +11:00
aaron.morey d97cc36c53 u4-9491 Added an asterisk with appropriate css class to the property editor next to the label in the back office to indicate to the user that the field is mandatory before saving. This is more intuitive to the user to see what fields need filling in before submitting. This was implemented in our solution which is used by hundreds of back end users. 2017-02-06 17:24:53 +11:00
Shannon 0e06245177 Adds notes for stephen to look at 2017-02-06 14:46:02 +11:00
Stephan 5a81a9eed7 U4-9322 - various fixes 2017-02-04 15:44:56 +01:00
Stephan 38e7d7e697 Merge remote-tracking branch 'origin/temp-u4-9322' into temp-u4-9322 2017-02-03 21:54:55 +01:00
Stephan 820069d5d5 U4-9322 - filesystems & cleanup 2017-02-03 20:01:43 +01:00
Stephan 49f3979d18 U4-9487 - optimize initialization of xml nodes 2017-02-03 19:28:43 +01:00
Emil Wangaa 055e209e0b Fixed the path and virtualpath when creating and scaffolding codefiles
Ensuring that javascript files are created with the .js extension
2017-02-03 12:06:49 +01:00
Shannon 5579563105 Creates a test (which fails) so that stephen can have a look 2017-02-03 14:56:08 +11:00
Shannon cda9d0f9f2 pretty big perf boost so that we aren't going to the services user cache everytime we want to know the user's culture, this will already be set on the thread! 2017-02-03 14:42:06 +11:00
Shannon 49b7f15e3d fixes tests 2017-02-03 13:32:22 +11:00
Shannon 8ae700eedf code formatting and merge fixing 2017-02-03 12:23:32 +11:00
Shannon 411bbcc192 Merge branch 'refs/heads/dev-v7.6' into temp-u4-9322
# Conflicts:
#	build/UmbracoVersion.txt
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/ContentTypeService.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Core/Services/MacroService.cs
#	src/Umbraco.Core/Services/MediaService.cs
#	src/Umbraco.Core/Services/MemberService.cs
#	src/Umbraco.Core/Services/MemberTypeService.cs
#	src/Umbraco.Core/Services/UserService.cs
#	src/Umbraco.Web/Umbraco.Web.csproj
2017-02-03 12:14:38 +11:00
Shannon d598fdce54 Updates to latest Examine release 2017-02-03 12:03:56 +11:00
Shannon db86f6e1ee Fixes up issues reported on review and adds a null check 2017-02-03 11:49:22 +11:00
Shannon c16ce4ce1f Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6 2017-02-03 10:21:10 +11:00
Shannon 86021c5052 Adds remaining core methods to make 2FA providers work if you know how to wire it up 2017-02-03 00:47:28 +11:00
Mads Rasmussen de87701c95 remove option to create xml file 2017-02-02 14:46:23 +01:00
Shannon a03e0dfb53 Fixes tests 2017-02-02 22:21:36 +11:00
Shannon 5060e709d1 Fixed merge conflicts, adds required methods to auth controllers. 2017-02-02 22:11:34 +11:00
Emil Wangaa c073191f69 Fixes creation of codefiles in folders 2017-02-02 11:47:46 +01:00
Mads Rasmussen b4450ca7f2 add null check for startNode 2017-02-02 11:44:13 +01:00
Mads Rasmussen 7004765acf remove unused code 2017-02-02 11:40:53 +01:00
Mads Rasmussen 77a91bc017 fix entity look up 2017-02-02 11:28:56 +01:00
Mads Rasmussen 14b96da588 combine redundant resource code into one function 2017-02-02 11:19:56 +01:00
Emil Wangaa c21837e906 Merge remote-tracking branch 'origin/dev-v7.6' into temp-U4-9429
# Conflicts:
#	src/Umbraco.Web/Editors/CodeFileController.cs
2017-02-02 10:24:42 +01:00
Mads Rasmussen 99324035e5 clean up animation classes 2017-02-02 10:19:54 +01:00
Mads Rasmussen 8b9a5000be move back button styles to class 2017-02-02 10:09:31 +01:00
hartvig 32892cf5e0 Update NewInstallStep.cs 2017-02-02 10:05:14 +01:00
Mads Rasmussen c82bddb7dd remove fake list view search node 2017-02-02 09:51:13 +01:00
Stephan 478ca30948 U4-9322 fs - create scope option 2017-02-02 09:49:23 +01:00
Mads Rasmussen f2fd45576b speed up animations 2017-02-02 09:35:01 +01:00
Emil Wangaa 6bf5f4dbdf Fixed up tree menus for scripts, partialviews and partialviewmacros 2017-02-02 09:20:42 +01:00
Shannon 32d757b13c Updates the ContentRepository to not fetch the published version info in the same query when returning a collection of documents, instead we fetch the published version information in a separate query 2017-02-02 17:05:33 +11:00
Shannon 882d5ec7f5 missing null check 2017-02-02 16:02:29 +11:00
Shannon ce69497a68 Update code to have zero breaking changes for old public APIs 2017-02-02 14:16:39 +11:00
Shannon 1d43cf491b U4-9448 Slave Front End server requires write access to database when master performs unpublish 2017-02-02 14:09:49 +11:00
Mads Rasmussen d5a687cf3d start on code clean up - make ump-mini-list-view directive + move inline styles to classes 2017-02-01 23:12:49 +01:00
Emil Wangaa c9082ce511 Changed PostSave method in CodeFileController to create or update instead of only updating - this is for keeping consistency with how other new editors work 2017-02-01 15:46:22 +01:00
Claus 46c7737c17 Merge pull request #1714 from umbraco/temp-u4-9441
Fixes tree syncing issues
2017-02-01 14:04:18 +01:00
Claus 06c829eb27 initializing stringbuilder with text instead of appending after init.
trimming end instead of both beginning and end, since we know whats in the beginning.
2017-02-01 14:03:03 +01:00
Mads Rasmussen e439302b93 add support for getScaffold for scripts, partialViews and partialViewMacros editor 2017-02-01 13:54:16 +01:00
Emil Wangaa 6a1d7d2586 Adds GetScaffold in CodeFileController to simplify initial view in backoffice
Refactored the FileService a bit to be able to get content of the snippets without duplicate code
2017-02-01 12:33:20 +01:00
Shannon 27283754c0 Changes IndexFieldPolicies to be a StaticFieldCollection which is a keyed collection instead of using Linq and iterating to find the values in critical code 2017-02-01 16:48:09 +11:00
Shannon ff6ea0b42e Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9310
# Conflicts:
#	src/Umbraco.Core/Models/UmbracoObjectTypes.cs
2017-02-01 15:23:29 +11:00
Shannon 384a31e3c6 Gets member picker working with UDI, ensures that the GUID is indexed for all things - can't believe this wasn't being done, updates the search model mapper to return the UDI 2017-02-01 15:19:52 +11:00
Shannon 69b913c608 Gets MNTP working with UDI - updates EntityController to support all types of Ids for GetById 2017-02-01 14:07:13 +11:00
Shannon 83757c60b5 Adds UDI support for the content picker 2017-02-01 13:38:42 +11:00
Shannon 5b2212829c Small performance change which makes a fairly large impact when rebuilding very large indexes. 2017-02-01 13:02:22 +11:00
Mads Rasmussen 26acecb720 start on animation and nested list views 2017-02-01 00:28:40 +01:00
Stephan 4a6844b949 U4-9322 - repository caches, cleanup 2017-01-31 19:36:55 +01:00
Stephan ac9b484d3d U4-9322 - wire EventMessages, cleanup 2017-01-31 18:19:03 +01:00
Stephan 97a76d5ad4 U4-9322 - introduce ScopeContext that lives longer than Scope, now Xml does not multi-clone! 2017-01-31 16:42:01 +01:00
Mads Rasmussen d4fab66411 add UI for partial views create dialog 2017-01-31 15:00:37 +01:00
Mads Rasmussen 4cd287616e add UI for partial view macros create dialog 2017-01-31 14:44:52 +01:00
Mads Rasmussen d22afe07db add UI for scripts create dialog 2017-01-31 12:40:56 +01:00
Morten Christensen fa56f1a59d Merge branch 'dev-v7' into dev-v7.6 2017-01-31 12:27:40 +01:00
Morten Christensen 546209ddb5 Merge pull request #1716 from umbraco/temp-U4-9451
U4-9451 Package installation custom user control is not displayed aft…
2017-01-31 12:24:52 +01:00
Morten Christensen 1e7c44ead0 Merge remote-tracking branch 'origin/temp-U4-9451' into dev-v7.6 2017-01-31 11:38:41 +01:00
Per Ploug 90448f1c78 Added comments and made helper internal 2017-01-31 11:06:14 +01:00
Stephan 6dc34e1167 U4-9322 - cleanup EventExtensions 2017-01-31 10:37:37 +01:00
Warren Buckley 6956e01861 Merge pull request #1713 from umbraco/temp-U4-9413
U4-9413 moving links to document and media to top of generic properties.
2017-01-31 09:37:34 +00:00
Claus f3b364022a bumping version for deploy. 2017-01-31 10:33:57 +01:00
Claus 56ae2b709d adding deploy entity types for forms. 2017-01-31 10:31:45 +01:00
Mads Rasmussen 7c42cd26c2 clear minilistview data when leaving 2017-01-31 10:26:03 +01:00
Mads Rasmussen 13758418ac add better load indicators 2017-01-31 10:14:17 +01:00
Emil Wangaa 6bd1a77b96 Simple wiring up of the create menu for partialview, partialviewmacro and script 2017-01-31 10:10:05 +01:00
Mads Rasmussen 77b04d74d4 load mini list view for pickers with a start node 2017-01-31 10:00:44 +01:00
Shannon e95cb14d48 Gets FromJsonPath working for EntityController to have GetByIds with all types of Ids for both GET and POST 2017-01-31 19:11:05 +11:00
Shannon 86b2dac231 Needed to change the 2nd query to use a new PagingSqlQuery object due to the way that < SQL 2012 formats it's paging query which is just not compatible with how we were parsing the queries for properties... i don't actually think it was working for a long tme. 2017-01-31 17:20:44 +11:00
Shannon 54bda6f12a U4-9451 Package installation custom user control is not displayed after a package is installed 2017-01-31 15:40:02 +11:00
Shannon 2f67a485aa Ensures that the sqlIds query is used for paging when processing members/media 2017-01-31 14:52:48 +11:00
Shannon f192f241cf U4-9450 Paged data queries return all property data in the entire database, not just for the paged subset 2017-01-31 13:48:47 +11:00
Mads Rasmussen bf797bccc7 open list view on expand 2017-01-30 22:35:19 +01:00
Mads Rasmussen 4336f5201d show expand arrow for list views 2017-01-30 22:34:04 +01:00
Mads Rasmussen 0acc202740 Merge pull request #1712 from umbraco/temp-U4-9410
U4-9410 Hook up delete dialog for Code Files
2017-01-30 20:50:36 +01:00
Emil Wangaa 431f91b900 Adds an api endpoint for getting the available snippets in the Umbraco folder 2017-01-30 14:57:08 +01:00
Mads Rasmussen ed019a90e2 start on mini list view for pickers 2017-01-30 14:25:10 +01:00
Stephan d4acc2c79b U4-9322 - EventsDispatchMode, fix tests 2017-01-30 13:53:31 +01:00
Per Ploug b05c4711ce Fixes tree syncing issues 2017-01-30 13:33:05 +01:00
Claus 74c167ed03 U4-9413 moving links to document and media to top of generic properties. 2017-01-30 13:18:30 +01:00
Claus 4ad0c1bb89 cleaning usings. 2017-01-30 13:14:19 +01:00
Claus 67da15330e U4-9410 Hook up delete dialog for Code Files
delete dialogs for partialviews, partialviewmacros and scripts.
+ fixed codefileResource.
+ fixed comments in MemberTypesDeleteController.
2017-01-30 11:56:30 +01:00
Shannon 8d598cd37c Gets EntityController working with UDIs, INT and GUID for GetByIds 2017-01-30 20:40:45 +11:00
Sebastiaan Janssen 690af8e494 Merge pull request #1711 from umbraco/temp-U4-9444
U4-9444 SessionState is not available when rendering macro contents i…
2017-01-30 10:00:40 +01:00
Shannon 30c2f95844 Merge branch 'refs/heads/dev-v7.6' into temp-U4-9310 2017-01-30 16:55:38 +11:00
Shannon a458e7daf0 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.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web/Umbraco.Web.csproj
2017-01-30 16:55:12 +11:00
Shannon 0078a5d8cc Getting the media picker wired up for udi 2017-01-30 16:54:01 +11:00
Shannon 09085e3bcf Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9310 2017-01-30 16:52:42 +11:00
Shannon a31b03b3e2 Lazily loads all known UdiType's based on reading through the known constants 2017-01-30 15:59:42 +11:00
Shannon 9d06ce53a4 U4-9444 SessionState is not available when rendering macro contents in the Rich Text Editor 2017-01-30 13:22:47 +11:00
Stephan d0e8e77fc5 Fix FileSystemProviderManagerTests 2017-01-28 10:05:19 +01:00
Stephan d85cb9e15e Fix FileSystemProviderManagerTests 2017-01-28 10:04:43 +01:00
Stephan 798105998e U4-9322 - begin refactoring and fixing events 2017-01-27 18:17:21 +01:00
Shannon 9ef53536bf Updates the base editor models to include a readonly UDI, updates all model mappers to map the UDI, 2017-01-28 01:14:24 +11:00
Shannon 547351a719 Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9310 2017-01-28 00:25:25 +11:00
Shannon 371c4ae1a3 Starts creating new UDI picker property editors 2017-01-28 00:22:12 +11:00
Shannon 060137c798 Merge remote-tracking branch 'refs/remotes/origin/dev-v7.6' into temp-U4-9310 2017-01-27 23:07:48 +11:00
Stephan f4994a5133 Merge temp-u4-9322 (Shan Events) into temp-u4-9322a (Steph) - builds 2017-01-27 11:42:54 +01:00
Mads Rasmussen 19a4cf774b Merge pull request #1680 from umbraco/temp-U4-9352
Implements CodeFileController
2017-01-27 10:49:07 +01:00
Mads Rasmussen ab00ba8a12 Merge branch 'dev-v7.6' into temp-U4-9352
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
2017-01-27 10:39:31 +01:00
Claus 57e2a19023 changing parameter name for IGridCellValueConnector.IsConnector. 2017-01-27 10:16:01 +01:00
Claus daa80a7bf6 Merge pull request #1709 from umbraco/temp-U4-9435-2
U4-9435 Fix breaking change made in U4-9312
2017-01-27 09:05:47 +01:00
Shannon 8152e7cb92 Doh, forgot a file change for tests - fixes build 2017-01-27 16:55:29 +11:00
Shannon Deminick adccb4161e Merge pull request #1707 from umbraco/temp-u4-9438
U4-9438 - fix nasty issue with reading properties in VersionableRepos…
2017-01-27 16:52:10 +11:00
Shannon 72a0187295 Writes unit test to confirm the correct property data iteration in GetPropertyCollection 2017-01-27 16:50:44 +11:00
Shannon 24d6287918 Adds string overloads just in case 2017-01-27 16:21:01 +11:00
Shannon 55900a3464 Updates MediaController and MediaTypeController to have the same method signature supporting both INT and GUID with a custom action selector to handle the ambiguity 2017-01-27 16:09:35 +11:00
Sebastiaan Janssen a5a42854ef Bump version to alpha055 2017-01-26 22:02:18 +01:00
Warren Buckley 784c84a166 Merge pull request #1474 from umbraco/temp-U4-8963
U4-8963 Updates for ImageProcessor parameters to support background c…
2017-01-26 20:45:35 +00:00
Sebastiaan Janssen f5d78a4d04 Merge pull request #1708 from umbraco/temp-U4-9440
Fixes: U4-9440 Update the last few Danish translations for template e…
2017-01-26 19:51:54 +01:00
Mads Rasmussen b334e0ccb2 Fixes: U4-9440 Update the last few Danish translations for template editor 2017-01-26 19:45:05 +01:00
Stephan 6bbfb65100 Merge temp-u4-9322 (Shan Events) into temp-u4-9322a (Steph) 2017-01-26 18:30:00 +01:00
Sebastiaan Janssen 0a2e5badd0 Merge branch 'temp-template-editor' into dev-v7.6 2017-01-26 18:27:10 +01:00
Sebastiaan Janssen 90b0bf9d82 Merge branch 'dev-v7.6' into temp-template-editor 2017-01-26 18:26:32 +01:00
Sebastiaan Janssen 6bcd1e44f9 If translation is not done yet, better to leave it English so at least it kind of makes sense 2017-01-26 18:24:56 +01:00
Sebastiaan Janssen 36e9bb4d78 Merge pull request #1705 from umbraco/temp-v758-recyclebin-fix
Fixes U4-9437
2017-01-26 17:31:31 +01:00
Warren Buckley 4c06ead056 Merge pull request #1698 from umbraco/temp-U4-9419
fixes: U4-9419 The new content picker adds picked items in a random o…
2017-01-26 16:21:03 +00:00
Sebastiaan Janssen 639d04381e Bump version 2017-01-26 14:48:19 +01:00
mikkelhm 031340a2ac Adds case for IDictionaryItem when trying to get the Udi from an entity 2017-01-26 13:41:04 +01:00
Warren Buckley 2465eb233e Adds in same workaround as other trees like DataTypes & DocTypes where Folders/Containers set an inline piece of JS that does nothing & returns 2017-01-26 11:32:13 +00:00
Stephan 7f905bce0e U4-9438 - fix nasty issue with reading properties in VersionableRepositoryBase 2017-01-26 11:49:52 +01:00
Niels Hartvig 205ea22daa Fixes U4-9437 2017-01-25 17:34:34 +01:00
Stephan cca3b9032f U4-9322 - cleanup 2017-01-25 14:18:33 +01:00
Stephan 4fc3398e49 U4-9322 - refactor UnitOfWork pattern 2017-01-25 13:34:41 +01:00
Shannon 2d5254e169 Makes ScopedEventManager aware of it's outer manager (if any) so it knows when to raise events (if configured) 2017-01-25 20:17:39 +11:00
Shannon c5033710ca Updates all ambigous event raising when the event finder cannot determine the name based on the args, all tests pass apart from 3 now 2017-01-25 18:44:29 +11:00
Shannon c824d27728 Updates remaining services to use the event manager to emit events correctly 2017-01-25 16:52:32 +11:00
Shannon ac54affa57 Refactor IPublishingStrategy, create IPublishingStrategy2 as a work around, adds EventMessages to IScopeUnitOfWork, ensures all events raised with IPublishingStrategy are done with uow 2017-01-25 16:49:44 +11:00
Shannon f7d7a43720 Fixes BulkInsertRecords to not require a trans , removes inner trans from PermissionRepository, fixes up events in PermissionRepository and MemberGroupRepository, fixes up uow in UserService 2017-01-25 15:15:28 +11:00
Shannon 6028907a02 Fixes up relation service with correct even emitting and no nested uow 2017-01-25 14:45:49 +11:00
Shannon e14ca4f3d0 Fixes up memberservice service with correct even emitting and no nested uow and removes inner transactions in MemberGroupRepository 2017-01-25 14:40:24 +11:00
Stephan a97b566065 U4-9422 - complete implementing scoped xml cache 2017-01-24 07:59:46 +01:00
Stephan 26a95a8ca1 U4-9322 - cont. implementing scoped xml cache 2017-01-23 18:03:38 +01:00
Stephan e3308e86f0 U4-9322 - begin implementing scoped xml cache 2017-01-23 18:03:08 +01:00
Warren Buckley c1fcb37642 Adds keys for DA file but appends them with DA to try & make it clear they need some translation love as my Danish is to be desired :) 2017-01-23 16:08:38 +00:00
Warren Buckley 0bba68a7f5 Added keys needed in EN lang files 2017-01-23 16:06:37 +00:00
Warren Buckley 47e4c12395 Adds in translations into the JSON objects we send back from the API as the display name (not the aliases for querying) 2017-01-23 16:04:14 +00:00
Warren Buckley 25822a7564 Fix up orderby translation in view and use our new JSON properties for display the tranlsated value for asc & desc 2017-01-23 16:01:05 +00:00
Warren Buckley 072f0d1520 Adds in some extra propeties on JSON to store localization label for ascending & descending & use correct key for MyWebstie/WebSite Root that was already in lang file 2017-01-23 15:53:18 +00:00
Stephan 1d98507785 TEMP 2017-01-23 15:39:46 +01:00
Shannon 096c3aeec6 started fixing up MemberService but this one is odd.... 2017-01-23 23:56:39 +11:00
Shannon 7ca5c48ae7 Fixes up membergroup service with correct even emitting and no nested uow 2017-01-23 23:30:47 +11:00
Shannon 4a1a216b3c Fixes up macro service with correct even emitting and no nested uow 2017-01-23 23:28:50 +11:00
Shannon f96d6aed9d Fixes up localization service with correct even emitting and no nested uow 2017-01-23 23:25:39 +11:00
Shannon 192aae71a2 Fixes up file service with correct even emitting and no nested uow and fixes up strange thing with RepositoryFactory and stylesheets 2017-01-23 23:21:53 +11:00
Shannon bd8af539b4 Fixes up data type service with correct even emitting and no nested uow 2017-01-23 22:55:16 +11:00
Shannon 479d859a75 Fixes up member type service with correct even emitting and no nested uow 2017-01-23 22:48:52 +11:00
Shannon 1050af5376 Updates ContentTypeService with the correct event emitting and no nested uows 2017-01-23 22:45:45 +11:00
Shannon 82dbfb769e Updated media service with correct usage of emitting events and having non nested uow 2017-01-23 22:29:38 +11:00
Shannon 55eb996c19 Adds a couple needed hack methods, updates ContentService to have the proper event emmitting without any nested uow's and ensuring that readonly uow's are committed. 2017-01-23 22:16:27 +11:00
Shannon ac4de99f30 Initial commit of changing all IsRaisedEventCancelled to use the event manager and inside of a uow 2017-01-23 20:48:51 +11:00
Stephan a3150b7d4e U4-9322 - missing files 2017-01-20 18:33:21 +01:00
Stephan 1701eb2450 u4-9322 - events cleanup 2017-01-20 17:05:22 +01:00
Stephan 20ac21aef2 Merge origin/temp-U4-9322 into temp-u4-9322 2017-01-20 16:51:25 +01:00
Stephan 4ac20de1dd U4-9322 - complete scope repository caches 2017-01-20 16:29:13 +01:00
Stephan 848eaf5e27 U4-9322 - cont. implementing scoped repository caches 2017-01-20 12:08:55 +01:00
Warren Buckley f3e78e990f Fix up failing unit test for the number of Trees found - this has gone down due this test is for implementing interface ITree which is the legacy type of Trees, where the new PartialViews & PartialView Macros now use TreeController 2017-01-20 09:52:23 +00:00
Shannon a6996922b7 Adds more support for auto-finding event names, adds tests to support with examples of how to interrogate queued events 2017-01-20 17:45:46 +11:00
Stephan 434703f4ec U4-9322 - begin implementing scoped repository caches 2017-01-19 19:47:09 +01:00
Warren Buckley 2f7b532209 Adds in code summaries for C# doc generation. Removes unused references & some tidying up (mostly sensible R# suggestions) 2017-01-19 15:43:29 +00:00
Warren Buckley abebb40461 Update some copy/paste typos in code comments 2017-01-19 15:18:12 +00:00
Warren Buckley 3b54db9b49 Update main templat editor to use a localised notification 2017-01-19 15:14:46 +00:00
Warren Buckley 1defc1e0e4 Changed key for saving scripts - as it mentioned 'script view' Whats that?! So changed to more generic file 2017-01-19 15:14:14 +00:00
Warren Buckley a7e626f4a7 Localisation notification message for saving scripts 2017-01-19 15:05:05 +00:00
Warren Buckley 04f6a01196 Forgot to remove the old notification - as was display two 2017-01-19 15:04:36 +00:00
Warren Buckley ef64fbb839 Same change for the partialview editor - to display a localized success notifcation 2017-01-19 15:01:14 +00:00
Warren Buckley 2424a1c04b Adds in localised sucess notification when saving partial view macros 2017-01-19 14:57:23 +00:00
Warren Buckley c8c7de065d Forgot to update the var name in codeFileResource 2017-01-19 14:56:25 +00:00
Warren Buckley 61d71d0552 Update codeFileResource docs 2017-01-19 14:40:10 +00:00
Mads Rasmussen b8734e5eea fixes: U4-9419 The new content picker adds picked items in a random order 2017-01-19 15:11:37 +01:00
Per Ploug eefd13547c More localization of querybuilder 2017-01-19 12:53:39 +01:00
Mads Rasmussen a09755ef7f remove unused code in partial view editor 2017-01-19 11:19:34 +01:00
Niels Hartvig afae06a866 Adds support for icons and encoding of directories for Code files 2017-01-19 10:41:08 +01:00
Mads Rasmussen 86ffd66c8a update danish translations 2017-01-19 09:50:18 +01:00
Niels Hartvig 051af5c48e Wire up the editors and controllers 2017-01-19 09:49:27 +01:00
Niels Hartvig 1fb05fcca7 Merge remote-tracking branch 'refs/remotes/origin/temp-file-editors' into temp-U4-9352 2017-01-19 08:45:23 +01:00
Shannon b51e571803 Adds unit tests and fixes others 2017-01-19 18:25:45 +11:00
Shannon a275567dba Adds equality members to the EventDefinitionBase so they are tracked by their unique id, makes IEventManager disposable and disposes it on scope end. 2017-01-19 17:34:15 +11:00
Shannon 2a95ed3c7a no need for explicit implementation for this since we changed the old one 2017-01-19 17:29:36 +11:00
Shannon 9965aa461a Updates ContentService to raise events all with the EventManager 2017-01-19 17:18:06 +11:00
Shannon 8de8b53039 missing interface implementation 2017-01-19 16:58:10 +11:00
Shannon 27eeb383b4 Updates all repos to use IScopeUnitOfWork 2017-01-19 16:51:39 +11:00
Shannon 4f5347fa4d Creates IEventManager, IEventDefinition uses explicit implementation and 'new' keyword to force already existing uow providers to be IScopeUnitOfWork, creates extensions for the event manager so there's less work to do to wire it all up 2017-01-19 16:31:59 +11:00
Shannon 994f91e496 Creates IScopeUnitOfWork and IScopeUnitOfWorkProvider as internal along with ScopeRepositoryService which all services inherit from, this is maintaining backwards compat too 2017-01-19 15:37:17 +11:00
Stephan 4ab7f768fa U4-9322 - backport repository cache policy changes from v8 2017-01-18 18:48:13 +01:00
Stephan a020a02b26 U4-9322 - more fixes 2017-01-18 17:44:16 +01:00
Mads Rasmussen 49d24dada7 add partial views macros editor 2017-01-18 15:39:08 +01:00
Mads Rasmussen ef9dd6d803 add scripts editor 2017-01-18 15:38:40 +01:00
Stephan ca777b26de U4-9322 - manage isolation levels, cleanup tests 2017-01-18 14:53:24 +01:00
Stephan 1f636d05d1 U4-9322 - fix scope leaks 2017-01-18 10:36:11 +01:00
Stephan 7495cd3f2c U4-9322 - cleanup 2017-01-17 16:46:34 +01:00
Stephan 5f68f26d2f U4-9322 - scope and database, getting tests to run 2017-01-17 16:32:40 +01:00
Mads Rasmussen 01f50a243b translate master template and no macros 2017-01-17 14:13:20 +01:00
Shannon a5af5ba1a9 Adds new property to PropertyEditor's to mark them as deprecated so they don't show up in the data type list unless they are already selected 2017-01-17 18:54:50 +11:00
Stephan 1261f6b159 U4-9322 - getting tests to run 2017-01-16 19:54:09 +01:00
Niels Hartvig a162f21a70 Fixing missing mapping - let the green build lights appear 2017-01-16 19:49:57 +01:00
Niels Hartvig ace111aefb Adding support for get, save and rename to new Partial View editor 2017-01-16 16:50:22 +01:00
Per Ploug 7a0ac625ff Last remaining dk translation strings
This needs a review by the dynamic writing duo vera and martin.
2017-01-16 10:13:32 +01:00
Niels Hartvig dfe3798aab More merge 2017-01-16 09:59:00 +01:00
Niels Hartvig 975535a9e2 Merge of insert overlay view 2017-01-13 13:33:55 +01:00
Niels Hartvig e7f7631d1e Fixes merge conflicts (needs updated ng-if in insert overlay) 2017-01-13 13:22:43 +01:00
Per Ploug 99f66fe6a3 The danish language files - WIP
The danish language has such elements when used to discusssed
semi-technical-english terms
2017-01-13 13:21:37 +01:00
Per Ploug b413a6eeae English translations 2017-01-13 13:20:49 +01:00
Per Ploug 9b9db23461 Replaces the last static strings with language keys 2017-01-13 13:20:38 +01:00
Stephan 5446e4b0fc U4-9322 - IScopeProviderInternal 2017-01-12 19:32:44 +01:00
Stephan 79c2400d27 U4-9322 - scope 2017-01-12 18:28:25 +01:00
Mads Rasmussen 23304aca0b add unit tests for template helper 2017-01-10 15:16:16 +01:00
Mads Rasmussen 845dd4673c Add client side file for partial view editor 2017-01-10 15:15:56 +01:00
Niels Hartvig 14e402878a Merge conflict fixes 2017-01-10 14:49:19 +01:00
Niels Hartvig 5a2687d520 Merge of temp-template-editor 2017-01-10 14:47:33 +01:00
Niels Hartvig 4c330c8654 Implements CodeFileController 2017-01-09 22:54:28 +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
Claus b40a1fa613 U4-8963 Updates for ImageProcessor parameters to support background color 2016-09-12 12:47:12 +02:00
Arnold Visser ca1f43d048 Merge pull request #1 from ArnoldV/Dutch-Language-Update
Dutch Languagefile Update
2016-09-06 10:53:49 +02:00
Arnold Visser e962a48138 Dutch Languagefile Update
This updates the Dutch language file with new/missing translations and fixes some wrong translations used by the grid.
2016-09-06 10:53:09 +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
778 changed files with 30862 additions and 10946 deletions
+42 -42
View File
@@ -15,6 +15,8 @@
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--Must be this way because 2.0.5 is actually 1.2.15.0 and 2.0.6 is actually 2.0.6 !-->
<dependency id="log4net" version="[2.0.5,2.0.6)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.3,6.0.0)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.0.0)" />
@@ -22,58 +24,56 @@
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.9, 2.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.9.8, 7.0.0)" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
<!-- AutoMapper can not be updated due to: https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405 -->
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
<dependency id="Examine" version="[0.1.80, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.1, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.0, 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="Newtonsoft.Json" version="[9.0.1, 10.0.0)" />
<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="[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.4, 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>
<files>
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\SQLCE4Umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\net45\businesslogic.dll" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\net45\businesslogic.xml" />
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\net45\cms.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\net45\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\net45\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\net45\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\net45\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\net45\interfaces.xml" />
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\net45\log4net.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\net45\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\net45\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\net45\SQLCE4Umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\net45\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\net45\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\net45\TidyNet.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\net45\Umbraco.Core.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\net45\Umbraco.Core.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\net45\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\net45\umbraco.DataLayer.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\net45\umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\net45\umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\net45\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\net45\umbraco.editorControls.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\net45\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\net45\umbraco.MacroEngines.xml" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\net45\umbraco.providers.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\net45\umbraco.providers.xml" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net45\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net45\Umbraco.Web.UI.xml" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\net45\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\net45\UmbracoExamine.xml" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<!-- Added to be able to produce a symbols package -->
@@ -104,4 +104,4 @@
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
</files>
</package>
</package>
+3 -1
View File
@@ -16,9 +16,10 @@
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
<dependency id="Newtonsoft.Json" version="[9.0.1, 10.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.5, 4.0.0)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
</dependencies>
</metadata>
<files>
@@ -45,6 +46,7 @@
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
<file src="tools\processing.config.install.xdt" target="Content\Config\imageprocessor\processing.config.install.xdt" />
<file src="tools\cache.config.install.xdt" target="Content\Config\imageprocessor\cache.config.install.xdt" />
<file src="build\**" target="build" />
</files>
</package>
@@ -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>
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<caching xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<caches>
<cache name="DiskCache" trimCache="false" xdt:Transform="SetAttributes(trimCache)" xdt:Locator="Match(name)" />
</caches>
</caching>
-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
alpha054
beta
+3 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -49,9 +49,11 @@
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
+1 -1
View File
@@ -240,7 +240,7 @@ namespace SqlCE4Umbraco
{
var cmd = trx == null ? new SqlCeCommand(commandText, conn) : new SqlCeCommand(commandText, conn, trx);
AttachParameters(cmd, commandParameters);
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
return cmd.ExecuteReader();
}
catch
{
+2 -2
View File
@@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
@@ -32,4 +32,4 @@
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup></configuration>
+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-alpha054")]
[assembly: AssemblyInformationalVersion("7.6.0-beta")]
+14 -3
View File
@@ -1,12 +1,11 @@
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;
using Umbraco.Core.Profiling;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
@@ -162,6 +161,11 @@ namespace Umbraco.Core
/// </summary>
public static ApplicationContext Current { get; internal set; }
/// <summary>
/// Gets the scope provider.
/// </summary>
internal IScopeProvider ScopeProvider { get { return _databaseContext == null ? null : _databaseContext.ScopeProvider; } }
/// <summary>
/// Returns the application wide cache accessor
/// </summary>
@@ -418,10 +422,17 @@ namespace Umbraco.Core
this.ApplicationCache = null;
if (_databaseContext != null) //need to check the internal field here
{
if (_databaseContext.ScopeProvider.AmbientScope != null)
{
var scope = _databaseContext.ScopeProvider.AmbientScope;
scope.Dispose();
}
/*
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.Database != null)
{
DatabaseContext.Database.Dispose();
}
}
*/
}
this.DatabaseContext = null;
this.Services = null;
+48
View File
@@ -0,0 +1,48 @@
using System;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using Umbraco.Core;
namespace Umbraco.Core
{
/// <summary>
/// Manages any assembly binding redirects that cannot be done via config
/// </summary>
internal class BindingRedirects
{
public static void Initialize()
{
// this only gets called when an assembly can't be resolved
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=null", RegexOptions.Compiled);
private const string Log4NetReplacement = "log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
/// <summary>
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <returns></returns>
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//log4net:
// Use regex to match and replace
if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
{
return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
}
//AutoMapper:
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
return null;
}
}
}
@@ -1,268 +1,250 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
/// <summary>
/// The default cache policy for retrieving a single entity
/// Represents the default cache policy.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <typeparam name="TId">The type of the identifier.</typeparam>
/// <remarks>
/// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
/// default policy with no expiry.
/// <para>The default cache policy caches entities with a 5 minutes sliding expiration.</para>
/// <para>Each entity is cached individually.</para>
/// <para>If options.GetAllCacheAllowZeroCount then a 'zero-count' array is cached when GetAll finds nothing.</para>
/// <para>If options.GetAllCacheValidateCount then we check against the db when getting many entities.</para>
/// </remarks>
internal class DefaultRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
where TEntity : class, IAggregateRoot
{
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;
}
protected string GetCacheIdKey(object id)
public override IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
{
return new ScopedRepositoryCachePolicy<TEntity, TId>(this, runtimeCache, scope);
}
protected string GetEntityCacheKey(object id)
{
if (id == null) throw new ArgumentNullException("id");
return string.Format("{0}{1}", GetCacheTypeKey(), id);
return GetEntityTypeCacheKey() + id;
}
protected string GetCacheTypeKey()
protected string GetEntityTypeCacheKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
protected virtual void InsertEntity(string cacheKey, TEntity entity)
{
Cache.InsertCacheItem(cacheKey, () => entity, TimeSpan.FromMinutes(5), true);
}
protected virtual void InsertEntities(TId[] ids, TEntity[] entities)
{
if (ids.Length == 0 && entities.Length == 0 && _options.GetAllCacheAllowZeroCount)
{
// getting all of them, and finding nothing.
// if we can cache a zero count, cache an empty array,
// for as long as the cache is not cleared (no expiration)
Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => EmptyEntities);
}
else
{
// individually cache each item
foreach (var entity in entities)
{
var capture = entity;
Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true);
}
}
}
/// <inheritdoc />
public override void Create(TEntity entity, Action<TEntity> persistNew)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
persistNew(entity);
//set the disposal action
SetCacheAction(() =>
// just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
}
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetEntityTypeCacheKey());
}
catch
{
//set the disposal action
SetCacheAction(() =>
{
//if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
Cache.ClearCacheItem(GetCacheIdKey(entity.Id));
// if an exception is thrown we need to remove the entry from cache,
// this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
Cache.ClearCacheItem(GetEntityCacheKey(entity.Id));
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetEntityTypeCacheKey());
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
throw;
}
}
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
/// <inheritdoc />
public override void Update(TEntity entity, Action<TEntity> persistUpdated)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
}
finally
{
//set the disposal action
var cacheKey = GetCacheIdKey(entity.Id);
SetCacheAction(() =>
persistUpdated(entity);
// just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
Cache.ClearCacheItem(cacheKey);
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetCacheTypeKey());
});
Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
}
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetEntityTypeCacheKey());
}
catch
{
// if an exception is thrown we need to remove the entry from cache,
// this is ONLY a work around because of the way
// that we cache entities: http://issues.umbraco.org/issue/U4-4259
Cache.ClearCacheItem(GetEntityCacheKey(entity.Id));
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetEntityTypeCacheKey());
throw;
}
}
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
/// <inheritdoc />
public override void Delete(TEntity entity, Action<TEntity> persistDeleted)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
if (entity == null) throw new ArgumentNullException("entity");
var cacheKey = GetCacheIdKey(id);
try
{
persistDeleted(entity);
}
finally
{
// whatever happens, clear the cache
var cacheKey = GetEntityCacheKey(entity.Id);
Cache.ClearCacheItem(cacheKey);
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
Cache.ClearCacheItem(GetEntityTypeCacheKey());
}
}
/// <inheritdoc />
public override TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
var cacheKey = GetEntityCacheKey(id);
var fromCache = Cache.GetCacheItem<TEntity>(cacheKey);
// if found in cache then return else fetch and cache
if (fromCache != null)
return fromCache;
var entity = getFromRepo(id);
var entity = performGet(id);
//set the disposal action
SetCacheAction(cacheKey, entity);
if (entity != null && entity.HasIdentity)
InsertEntity(cacheKey, entity);
return entity;
}
public override TEntity Get(TId id)
/// <inheritdoc />
public override TEntity GetCached(TId id)
{
var cacheKey = GetCacheIdKey(id);
var cacheKey = GetEntityCacheKey(id);
return Cache.GetCacheItem<TEntity>(cacheKey);
}
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
/// <inheritdoc />
public override bool Exists(TId id, Func<TId, bool> performExists, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
var cacheKey = GetCacheIdKey(id);
// if found in cache the return else check
var cacheKey = GetEntityCacheKey(id);
var fromCache = Cache.GetCacheItem<TEntity>(cacheKey);
return fromCache != null || getFromRepo(id);
return fromCache != null || performExists(id);
}
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
/// <inheritdoc />
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
if (ids.Any())
if (ids.Length > 0)
{
var entities = ids.Select(Get).ToArray();
if (ids.Length.Equals(entities.Length) && entities.Any(x => x == null) == false)
return entities;
// try to get each entity from the cache
// if we can find all of them, return
var entities = ids.Select(GetCached).WhereNotNull().ToArray();
if (ids.Length.Equals(entities.Length))
return entities; // no need for null checks, we are not caching nulls
}
else
{
var allEntities = GetAllFromCache();
if (allEntities.Any())
// get everything we have
var entities = Cache.GetCacheItemsByKeySearch<TEntity>(GetEntityTypeCacheKey())
.ToArray(); // no need for null checks, we are not caching nulls
if (entities.Length > 0)
{
// if some of them were in the cache...
if (_options.GetAllCacheValidateCount)
{
//Get count of all entities of current type (TEntity) to ensure cached result is correct
// need to validate the count, get the actual count and return if ok
var totalCount = _options.PerformCount();
if (allEntities.Length == totalCount)
return allEntities;
if (entities.Length == totalCount)
return entities;
}
else
{
return allEntities;
// no need to validate, just return what we have and assume it's all there is
return entities;
}
}
else if (_options.GetAllCacheAllowZeroCount)
{
//if the repository allows caching a zero count, then check the zero count cache
if (HasZeroCountCache())
{
//there is a zero count cache so return an empty list
return new TEntity[] {};
}
// if none of them were in the cache
// and we allow zero count - check for the special (empty) entry
var empty = Cache.GetCacheItem<TEntity[]>(GetEntityTypeCacheKey());
if (empty != null) return empty;
}
}
//we need to do the lookup from the repo
var entityCollection = getFromRepo(ids)
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
// cache failed, get from repo and cache
var repoEntities = performGetAll(ids)
.WhereNotNull() // exclude nulls!
.Where(x => x.HasIdentity) // be safe, though would be weird...
.ToArray();
//set the disposal action
SetCacheAction(ids, entityCollection);
// note: if empty & allow zero count, will cache a special (empty) entry
InsertEntities(ids, repoEntities);
return entityCollection;
return repoEntities;
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected bool HasZeroCountCache()
/// <inheritdoc />
public override void ClearAll()
{
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
return (zeroCount != null && zeroCount.Any() == false);
Cache.ClearAllCache();
}
/// <summary>
/// Performs the lookup for all entities of this type from the cache
/// </summary>
/// <returns></returns>
protected TEntity[] GetAllFromCache()
{
var allEntities = Cache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey())
.WhereNotNull()
.ToArray();
return allEntities.Any() ? allEntities : new TEntity[] {};
}
/// <summary>
/// Sets the action to execute on disposal for a single entity
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="entity"></param>
protected virtual void SetCacheAction(string cacheKey, TEntity entity)
{
if (entity == null) return;
SetCacheAction(() =>
{
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
Cache.InsertCacheItem(cacheKey, () => entity,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
});
}
/// <summary>
/// Sets the action to execute on disposal for an entity collection
/// </summary>
/// <param name="ids"></param>
/// <param name="entityCollection"></param>
protected virtual void SetCacheAction(TId[] ids, TEntity[] entityCollection)
{
SetCacheAction(() =>
{
//This option cannot execute if we are looking up specific Ids
if (ids.Any() == false && entityCollection.Length == 0 && _options.GetAllCacheAllowZeroCount)
{
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
// to signify that there is a zero count cache
//NOTE: Don't set expiry/sliding for a zero count
Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
}
else
{
//This is the default behavior, we'll individually cache each item so that if/when these items are resolved
// by id, they are returned from the already existing cache.
foreach (var entity in entityCollection.WhereNotNull())
{
var localCopy = entity;
//just to be safe, we cannot cache an item without an identity
if (localCopy.HasIdentity)
{
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
}
}
});
}
}
}
@@ -1,27 +0,0 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class DefaultRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
{
_runtimeCache = runtimeCache;
_options = options;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new DefaultRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _options);
}
}
}
@@ -3,227 +3,178 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
/// <summary>
/// A caching policy that caches an entire dataset as a single collection
/// Represents a caching policy that caches the entire entities set as a single collection.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <typeparam name="TId">The type of the identifier.</typeparam>
/// <remarks>
/// <para>Caches the entire set of entities as a single collection.</para>
/// <para>Used by Content-, Media- and MemberTypeRepository, DataTypeRepository, DomainRepository,
/// LanguageRepository, PublicAccessRepository, TemplateRepository... things that make sense to
/// keep as a whole in memory.</para>
/// </remarks>
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly Func<TEntity, TId> _getEntityId;
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
private readonly Func<TEntity, TId> _entityGetId;
private readonly bool _expires;
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> entityGetId, bool expires)
: base(cache)
{
_getEntityId = getEntityId;
_getAllFromRepo = getAllFromRepo;
_entityGetId = entityGetId;
_expires = expires;
}
private bool? _hasZeroCountCache;
public override IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
{
return new ScopedRepositoryCachePolicy<TEntity, TId>(this, runtimeCache, scope);
}
protected static readonly TId[] EmptyIds = new TId[0]; // const
protected string GetCacheTypeKey()
protected string GetEntityTypeCacheKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
protected void InsertEntities(TEntity[] entities)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
// cache is expected to be a deep-cloning cache ie it deep-clones whatever is
// IDeepCloneable when it goes in, and out. it also resets dirty properties,
// making sure that no 'dirty' entity is cached.
//
// this policy is caching the entire list of entities. to ensure that entities
// are properly deep-clones when cached, it uses a DeepCloneableList. however,
// we don't want to deep-clone *each* entity in the list when fetching it from
// cache as that would not be efficient for Get(id). so the DeepCloneableList is
// set to ListCloneBehavior.CloneOnce ie it will clone *once* when inserting,
// and then will *not* clone when retrieving.
try
if (_expires)
{
persistMethod(entity);
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList<TEntity>(entities), TimeSpan.FromMinutes(5), true);
}
catch
else
{
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
throw;
Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList<TEntity>(entities));
}
}
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
/// <inheritdoc />
public override void Create(TEntity entity, Action<TEntity> persistNew)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
persistMethod(entity);
persistNew(entity);
}
finally
{
//set the disposal action
SetCacheAction(() =>
{
//Clear all
Cache.ClearCacheItem(GetCacheTypeKey());
});
ClearAll();
}
}
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
/// <inheritdoc />
public override void Update(TEntity entity, Action<TEntity> persistUpdated)
{
//Force get all with cache
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
if (entity == null) throw new ArgumentNullException("entity");
//we don't have anything in cache (this should never happen), just return from the repo
if (found == null) return getFromRepo(id);
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
if (entity == null) return null;
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
return (TEntity)entity.DeepClone();
}
public override TEntity Get(TId id)
{
//Force get all with cache
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
//we don't have anything in cache (this should never happen), just return null
if (found == null) return null;
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
if (entity == null) return null;
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
return (TEntity)entity.DeepClone();
}
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
{
//Force get all with cache
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
//we don't have anything in cache (this should never happen), just return from the repo
return found == null
? getFromRepo(id)
: found.Any(x => _getEntityId(x).Equals(id));
}
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
//process getting all including setting the cache callback
var result = PerformGetAll(getFromRepo);
//now that the base result has been calculated, they will all be cached.
// Now we can just filter by ids if they have been supplied
return (ids.Any()
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
: result)
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
.Select(x => (TEntity)x.DeepClone())
.ToArray();
}
private TEntity[] PerformGetAll(Func<TId[], IEnumerable<TEntity>> getFromRepo)
{
var allEntities = GetAllFromCache();
if (allEntities.Any())
try
{
return allEntities;
persistUpdated(entity);
}
//check the zero count cache
if (HasZeroCountCache())
finally
{
//there is a zero count cache so return an empty list
return new TEntity[] { };
ClearAll();
}
//we need to do the lookup from the repo
var entityCollection = getFromRepo(new TId[] { })
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
.ToArray();
//set the disposal action
SetCacheAction(entityCollection);
return entityCollection;
}
/// <summary>
/// For this type of caching policy, we don't cache individual items
/// </summary>
/// <param name="cacheKey"></param>
/// <param name="entity"></param>
protected void SetCacheAction(string cacheKey, TEntity entity)
/// <inheritdoc />
public override void Delete(TEntity entity, Action<TEntity> persistDeleted)
{
//No-op
}
if (entity == null) throw new ArgumentNullException("entity");
/// <summary>
/// Sets the action to execute on disposal for an entity collection
/// </summary>
/// <param name="entityCollection"></param>
protected void SetCacheAction(TEntity[] entityCollection)
{
//set the disposal action
SetCacheAction(() =>
try
{
//We want to cache the result as a single collection
if (_expires)
{
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection),
timeout: TimeSpan.FromMinutes(5),
isSliding: true);
}
else
{
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
}
});
persistDeleted(entity);
}
finally
{
ClearAll();
}
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected bool HasZeroCountCache()
/// <inheritdoc />
public override TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
if (_hasZeroCountCache.HasValue)
return _hasZeroCountCache.Value;
// get all from the cache, then look for the entity
var all = GetAllCached(performGetAll);
var entity = all.FirstOrDefault(x => _entityGetId(x).Equals(id));
_hasZeroCountCache = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey()) != null;
return _hasZeroCountCache.Value;
// see note in InsertEntities - what we get here is the original
// cached entity, not a clone, so we need to manually ensure it is deep-cloned.
return entity == null ? null : (TEntity) entity.DeepClone();
}
/// <summary>
/// This policy will cache the full data set as a single collection
/// </summary>
/// <returns></returns>
protected TEntity[] GetAllFromCache()
/// <inheritdoc />
public override TEntity GetCached(TId id)
{
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
// get all from the cache -- and only the cache, then look for the entity
var all = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetEntityTypeCacheKey());
var entity = all == null ? null : all.FirstOrDefault(x => _entityGetId(x).Equals(id));
//This method will get called before checking for zero count cache, so we'll just set the flag here
_hasZeroCountCache = found != null;
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
// see note in InsertEntities - what we get here is the original
// cached entity, not a clone, so we need to manually ensure it is deep-cloned.
return entity == null ? null : (TEntity)entity.DeepClone();
}
/// <inheritdoc />
public override bool Exists(TId id, Func<TId, bool> performExits, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// get all as one set, then look for the entity
var all = GetAllCached(performGetAll);
return all.Any(x => _entityGetId(x).Equals(id));
}
/// <inheritdoc />
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// get all as one set, from cache if possible, else repo
var all = GetAllCached(performGetAll);
// if ids have been specified, filter
if (ids.Length > 0) all = all.Where(x => ids.Contains(_entityGetId(x)));
// and return
// see note in SetCacheActionToInsertEntities - what we get here is the original
// cached entities, not clones, so we need to manually ensure they are deep-cloned.
return all.Select(x => (TEntity) x.DeepClone()).ToArray();
}
// does NOT clone anything, so be nice with the returned values
private IEnumerable<TEntity> GetAllCached(Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// try the cache first
var all = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetEntityTypeCacheKey());
if (all != null) return all.ToArray();
// else get from repo and cache
var entities = performGetAll(EmptyIds).WhereNotNull().ToArray();
InsertEntities(entities); // may be an empty array...
return entities;
}
/// <inheritdoc />
public override void ClearAll()
{
Cache.ClearCacheItem(GetEntityTypeCacheKey());
}
}
}
@@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class FullDataSetRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly Func<TEntity, TId> _getEntityId;
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
private readonly bool _expires;
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
{
_runtimeCache = runtimeCache;
_getEntityId = getEntityId;
_getAllFromRepo = getAllFromRepo;
_expires = expires;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
}
}
}
@@ -1,18 +1,97 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
internal interface IRepositoryCachePolicy<TEntity, TId> : IDisposable
internal interface IRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
TEntity Get(TId id);
bool Exists(TId id, Func<TId, bool> getFromRepo);
void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
void Remove(TEntity entity, Action<TEntity> persistMethod);
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
// note:
// at the moment each repository instance creates its corresponding cache policy instance
// we could reduce allocations by using static cache policy instances but then we would need
// to modify all methods here to pass the repository and cache eg:
//
// TEntity Get(TRepository repository, IRuntimeCacheProvider cache, TId id);
//
// 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.
/// <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>
/// Gets an entity from the cache, else from the repository.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="performGet">The repository PerformGet method.</param>
/// <param name="performGetAll">The repository PerformGetAll method.</param>
/// <returns>The entity with the specified identifier, if it exits, else null.</returns>
/// <remarks>First considers the cache then the repository.</remarks>
TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <summary>
/// Gets an entity from the cache.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The entity with the specified identifier, if it is in the cache already, else null.</returns>
/// <remarks>Does not consider the repository at all.</remarks>
TEntity GetCached(TId id);
/// <summary>
/// Gets a value indicating whether an entity with a specified identifier exists.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="performExists">The repository PerformExists method.</param>
/// <param name="performGetAll">The repository PerformGetAll method.</param>
/// <returns>A value indicating whether an entity with the specified identifier exists.</returns>
/// <remarks>First considers the cache then the repository.</remarks>
bool Exists(TId id, Func<TId, bool> performExists, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <summary>
/// Creates an entity.
/// </summary>
/// <param name="entity">The entity.</param>
/// <param name="persistNew">The repository PersistNewItem method.</param>
/// <remarks>Creates the entity in the repository, and updates the cache accordingly.</remarks>
void Create(TEntity entity, Action<TEntity> persistNew);
/// <summary>
/// Updates an entity.
/// </summary>
/// <param name="entity">The entity.</param>
/// <param name="persistUpdated">The reopsitory PersistUpdatedItem method.</param>
/// <remarks>Updates the entity in the repository, and updates the cache accordingly.</remarks>
void Update(TEntity entity, Action<TEntity> persistUpdated);
/// <summary>
/// Removes an entity.
/// </summary>
/// <param name="entity">The entity.</param>
/// <param name="persistDeleted">The repository PersistDeletedItem method.</param>
/// <remarks>Removes the entity from the repository and clears the cache.</remarks>
void Delete(TEntity entity, Action<TEntity> persistDeleted);
/// <summary>
/// Gets entities.
/// </summary>
/// <param name="ids">The identifiers.</param>
/// <param name="performGetAll">The repository PerformGetAll method.</param>
/// <returns>If <paramref name="ids"/> is empty, all entities, else the entities with the specified identifiers.</returns>
/// <remarks>Get all the entities. Either from the cache or the repository depending on the implementation.</remarks>
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <summary>
/// Clears the entire cache.
/// </summary>
void ClearAll();
}
}
@@ -1,9 +0,0 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
internal interface IRepositoryCachePolicyFactory<TEntity, TId> where TEntity : class, IAggregateRoot
{
IRepositoryCachePolicy<TEntity, TId> CreatePolicy();
}
}
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
internal class NoRepositoryCachePolicy<TEntity, TId> : IRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private static readonly NoRepositoryCachePolicy<TEntity, TId> StaticInstance = new NoRepositoryCachePolicy<TEntity, TId>();
private NoRepositoryCachePolicy()
{ }
public static NoRepositoryCachePolicy<TEntity, TId> Instance { get { return StaticInstance; } }
public IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
{
throw new NotImplementedException();
}
public TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
return performGet(id);
}
public TEntity GetCached(TId id)
{
return null;
}
public bool Exists(TId id, Func<TId, bool> performExists, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
return performExists(id);
}
public void Create(TEntity entity, Action<TEntity> persistNew)
{
persistNew(entity);
}
public void Update(TEntity entity, Action<TEntity> persistUpdated)
{
persistUpdated(entity);
}
public void Delete(TEntity entity, Action<TEntity> persistDeleted)
{
persistDeleted(entity);
}
public TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
return performGetAll(ids).ToArray();
}
public void ClearAll()
{ }
}
}
@@ -1,27 +0,0 @@
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Creates cache policies
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
internal class OnlySingleItemsRepositoryCachePolicyFactory<TEntity, TId> : IRepositoryCachePolicyFactory<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly RepositoryCachePolicyOptions _options;
public OnlySingleItemsRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
{
_runtimeCache = runtimeCache;
_options = options;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
{
return new SingleItemsOnlyRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _options);
}
}
}
@@ -1,48 +1,51 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
/// <summary>
/// A base class for repository cache policies.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <typeparam name="TId">The type of the identifier.</typeparam>
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : IRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private Action _action;
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
{
if (cache == null) throw new ArgumentNullException("cache");
if (cache == null) throw new ArgumentNullException("cache");
Cache = cache;
}
public abstract IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope);
protected IRuntimeCacheProvider Cache { get; private set; }
/// <summary>
/// The disposal performs the caching
/// </summary>
protected override void DisposeResources()
{
if (_action != null)
{
_action();
}
}
/// <inheritdoc />
public abstract TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <summary>
/// Sets the action to execute on disposal
/// </summary>
/// <param name="action"></param>
protected void SetCacheAction(Action action)
{
_action = action;
}
/// <inheritdoc />
public abstract TEntity GetCached(TId id);
/// <inheritdoc />
public abstract bool Exists(TId id, Func<TId, bool> performExists, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <inheritdoc />
public abstract void Create(TEntity entity, Action<TEntity> persistNew);
/// <inheritdoc />
public abstract void Update(TEntity entity, Action<TEntity> persistUpdated);
/// <inheritdoc />
public abstract void Delete(TEntity entity, Action<TEntity> persistDeleted);
/// <inheritdoc />
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll);
/// <inheritdoc />
public abstract void ClearAll();
public abstract TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
public abstract TEntity Get(TId id);
public abstract bool Exists(TId id, Func<TId, bool> getFromRepo);
public abstract void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
public abstract void Remove(TEntity entity, Action<TEntity> persistMethod);
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
}
}
@@ -2,6 +2,9 @@ using System;
namespace Umbraco.Core.Cache
{
/// <summary>
/// Specifies how a repository cache policy should cache entities.
/// </summary>
internal class RepositoryCachePolicyOptions
{
/// <summary>
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
internal class ScopedRepositoryCachePolicy<TEntity, TId> : IRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
private readonly IRepositoryCachePolicy<TEntity, TId> _cachePolicy;
private readonly IRuntimeCacheProvider _globalIsolatedCache;
private readonly IScope _scope;
public ScopedRepositoryCachePolicy(IRepositoryCachePolicy<TEntity, TId> cachePolicy, IRuntimeCacheProvider globalIsolatedCache, IScope scope)
{
_cachePolicy = cachePolicy;
_globalIsolatedCache = globalIsolatedCache;
_scope = scope;
}
public IRepositoryCachePolicy<TEntity, TId> Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
{
throw new InvalidOperationException(); // obviously
}
public TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// loads into the local cache only, ok for now
return _cachePolicy.Get(id, performGet, performGetAll);
}
public TEntity GetCached(TId id)
{
// loads into the local cache only, ok for now
return _cachePolicy.GetCached(id);
}
public bool Exists(TId id, Func<TId, bool> performExists, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// loads into the local cache only, ok for now
return _cachePolicy.Exists(id, performExists, performGetAll);
}
public void Create(TEntity entity, Action<TEntity> persistNew)
{
// writes into the local cache
_cachePolicy.Create(entity, persistNew);
}
public void Update(TEntity entity, Action<TEntity> persistUpdated)
{
// writes into the local cache
_cachePolicy.Update(entity, persistUpdated);
}
public void Delete(TEntity entity, Action<TEntity> persistDeleted)
{
// deletes the local cache
_cachePolicy.Delete(entity, persistDeleted);
}
public TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// loads into the local cache only, ok for now
return _cachePolicy.GetAll(ids, performGetAll);
}
public void ClearAll()
{
// clears the local cache
_cachePolicy.ClearAll();
}
}
}
@@ -1,24 +1,27 @@
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
/// <summary>
/// A caching policy that ignores all caches for GetAll - it will only cache calls for individual items
/// Represents a special policy that does not cache the result of GetAll.
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TId"></typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <typeparam name="TId">The type of the identifier.</typeparam>
/// <remarks>
/// <para>Overrides the default repository cache policy and does not writes the result of GetAll
/// to cache, but only the result of individual Gets. It does read the cache for GetAll, though.</para>
/// <para>Used by DictionaryRepository.</para>
/// </remarks>
internal class SingleItemsOnlyRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options) : base(cache, options)
public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
: base(cache, options)
{ }
protected override void InsertEntities(TId[] ids, TEntity[] entities)
{
}
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
{
//no-op
// nop
}
}
}
+8 -1
View File
@@ -21,6 +21,10 @@ namespace Umbraco.Core
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
private static readonly IsolatedRuntimeCache NullIsolatedCache = new IsolatedRuntimeCache(_ => NullRuntimeCache);
private static readonly CacheHelper NullCache = new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache);
public static CacheHelper NoCache { get { return NullCache; } }
/// <summary>
/// Creates a cache helper with disabled caches
@@ -31,7 +35,10 @@ namespace Umbraco.Core
/// </remarks>
public static CacheHelper CreateDisabledCacheHelper()
{
return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache));
// do *not* return NoCache
// NoCache is a special instance that is detected by RepositoryBase and disables all cache policies
// CreateDisabledCacheHelper is used in tests to use no cache, *but* keep all cache policies
return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache);
}
/// <summary>
@@ -0,0 +1,15 @@
using System;
namespace Umbraco.Core.CodeAnnotations
{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
internal class UmbracoUdiTypeAttribute : Attribute
{
public string UdiType { get; private set; }
public UmbracoUdiTypeAttribute(string udiType)
{
UdiType = udiType;
}
}
}
@@ -0,0 +1,9 @@
namespace Umbraco.Core.Configuration
{
internal enum ContentXmlStorage
{
Default,
AspNetTemp,
EnvironmentTemp
}
}
@@ -0,0 +1,27 @@
using System;
namespace Umbraco.Core.Configuration
{
internal static class CoreDebugExtensions
{
private static CoreDebug _coreDebug;
public static CoreDebug CoreDebug(this UmbracoConfig config)
{
return _coreDebug ?? (_coreDebug = new CoreDebug());
}
}
internal class CoreDebug
{
public CoreDebug()
{
var appSettings = System.Configuration.ConfigurationManager.AppSettings;
LogUncompletedScopes = string.Equals("true", appSettings["Umbraco.CoreDebug.LogUncompletedScopes"], StringComparison.OrdinalIgnoreCase);
}
// when true, Scope logs the stack trace for any scope that gets disposed without being completed.
// this helps troubleshooting rogue scopes that we forget to complete
public bool LogUncompletedScopes { get; private set; }
}
}
@@ -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;
}
}
@@ -159,6 +159,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring"); }
}
[ConfigurationProperty("showDeprecatedPropertyEditors")]
internal InnerTextConfigurationElement<bool> ShowDeprecatedPropertyEditors
{
get { return GetOptionalTextElement("showDeprecatedPropertyEditors", false); }
}
[ConfigurationProperty("EnableInheritedDocumentTypes")]
internal InnerTextConfigurationElement<bool> EnableInheritedDocumentTypes
{
@@ -171,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; }
@@ -306,6 +318,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return DefaultDocumentTypeProperty; }
}
bool IContentSection.ShowDeprecatedPropertyEditors
{
get { return ShowDeprecatedPropertyEditors; }
}
bool IContentSection.EnableInheritedDocumentTypes
{
get { return EnableInheritedDocumentTypes; }
@@ -315,5 +332,9 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
get { return EnableInheritedMediaTypes; }
}
bool IContentSection.EnablePropertyValueConverters
{
get { return EnablePropertyValueConverters; }
}
}
}
@@ -60,8 +60,17 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string DefaultDocumentTypeProperty { get; }
/// <summary>
/// The default for this is false but if you would like deprecated property editors displayed
/// in the data type editor you can enable this
/// </summary>
bool ShowDeprecatedPropertyEditors { get; }
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 "alpha054"; } }
public static string CurrentComment { get { return "beta"; } }
// 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
+7 -1
View File
@@ -112,9 +112,15 @@
public const string Languages = "languages";
public const string PartialViews = "partialViews";
public const string PartialViewMacros = "partialViewMacros";
public const string Scripts = "scripts";
//TODO: Fill in the rest!
}
}
}
}
+45
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>
@@ -109,6 +114,11 @@ namespace Umbraco.Core
/// </summary>
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
/// <summary>
/// Guid for a Media Type object.
/// </summary>
public static readonly Guid MemberGuid = new Guid(Member);
/// <summary>
/// Guid for a Member Group object.
/// </summary>
@@ -143,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>
@@ -162,6 +177,36 @@ namespace Umbraco.Core
/// Guid for a relation type.
/// </summary>
public static readonly Guid RelationTypeGuid = new Guid(RelationType);
/// <summary>
/// Guid for a Forms Form.
/// </summary>
public const string FormsForm = "F5A9F787-6593-46F0-B8FF-BFD9BCA9F6BB";
/// <summary>
/// Guid for a Forms Form.
/// </summary>
public static readonly Guid FormsFormGuid = new Guid(FormsForm);
/// <summary>
/// Guid for a Forms PreValue Source.
/// </summary>
public const string FormsPreValue = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
/// <summary>
/// Guid for a Forms PreValue Source.
/// </summary>
public static readonly Guid FormsPreValueGuid = new Guid(FormsPreValue);
/// <summary>
/// Guid for a Forms DataSource.
/// </summary>
public const string FormsDataSource = "CFED6CE4-9359-443E-9977-9956FEB1D867";
/// <summary>
/// Guid for a Forms DataSource.
/// </summary>
public static readonly Guid FormsDataSourceGuid = new Guid(FormsDataSource);
}
}
}
+24 -7
View File
@@ -42,10 +42,14 @@ namespace Umbraco.Core
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string ContentPicker = "158AA029-24ED-4948-939E-C3DA209E5FBA";
[Obsolete("This is an obsoleted content picker, use ContentPicker2Alias instead")]
public const string ContentPickerAlias = "Umbraco.ContentPickerAlias";
/// <summary>
/// Alias for the Content Picker datatype.
/// </summary>
public const string ContentPickerAlias = "Umbraco.ContentPickerAlias";
public const string ContentPicker2Alias = "Umbraco.ContentPicker2";
/// <summary>
/// Guid for the Date datatype.
@@ -192,11 +196,15 @@ namespace Umbraco.Core
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string MediaPicker = "EAD69342-F06D-4253-83AC-28000225583B";
[Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")]
public const string MediaPickerAlias = "Umbraco.MediaPicker";
/// <summary>
/// Alias for the Media Picker datatype.
/// </summary>
public const string MediaPickerAlias = "Umbraco.MediaPicker";
public const string MediaPicker2Alias = "Umbraco.MediaPicker2";
[Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")]
public const string MultipleMediaPickerAlias = "Umbraco.MultipleMediaPicker";
/// <summary>
@@ -205,26 +213,32 @@ namespace Umbraco.Core
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string MemberPicker = "39F533E4-0551-4505-A64B-E0425C5CE775";
[Obsolete("This is an obsoleted picker, use MemberPicker2Alias instead")]
public const string MemberPickerAlias = "Umbraco.MemberPicker";
/// <summary>
/// Alias for the Member Picker datatype.
/// </summary>
public const string MemberPickerAlias = "Umbraco.MemberPicker";
public const string MemberPicker2Alias = "Umbraco.MemberPicker2";
/// <summary>
/// Alias for the Member Group Picker datatype.
/// </summary>
public const string MemberGroupPickerAlias = "Umbraco.MemberGroupPicker";
/// <summary>
/// Guid for the Multi-Node Tree Picker datatype
/// </summary>
[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 MultiNodeTreePicker = "7E062C13-7C41-4AD9-B389-41D88AEEF87C";
[Obsolete("This is an obsoleted picker, use MultiNodeTreePicker2Alias instead")]
public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker";
/// <summary>
/// Alias for the Multi-Node Tree Picker datatype
/// </summary>
public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker";
public const string MultiNodeTreePicker2Alias = "Umbraco.MultiNodeTreePicker2";
/// <summary>
/// Guid for the Multiple Textstring datatype.
@@ -275,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.
+9 -7
View File
@@ -28,6 +28,7 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Publishing;
using Umbraco.Core.Macros;
using Umbraco.Core.Manifest;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Core.Strings;
@@ -108,8 +109,11 @@ namespace Umbraco.Core
var dbFactory = new DefaultDatabaseFactory(Constants.System.UmbracoConnectionName, ProfilingLogger.Logger);
Database.Mapper = new PetaPocoMapper();
var scopeProvider = new ScopeProvider(dbFactory);
dbFactory.ScopeProvider = scopeProvider;
var dbContext = new DatabaseContext(
dbFactory,
scopeProvider,
ProfilingLogger.Logger,
SqlSyntaxProviders.CreateDefault(ProfilingLogger.Logger));
@@ -117,7 +121,7 @@ namespace Umbraco.Core
dbContext.Initialize();
//get the service context
var serviceContext = CreateServiceContext(dbContext, dbFactory);
var serviceContext = CreateServiceContext(dbContext, scopeProvider);
//set property and singleton from response
ApplicationContext.Current = ApplicationContext = CreateApplicationContext(dbContext, serviceContext);
@@ -160,17 +164,15 @@ namespace Umbraco.Core
/// Creates and returns the service context for the app
/// </summary>
/// <param name="dbContext"></param>
/// <param name="dbFactory"></param>
/// <param name="scopeProvider"></param>
/// <returns></returns>
protected virtual ServiceContext CreateServiceContext(DatabaseContext dbContext, IDatabaseFactory dbFactory)
protected virtual ServiceContext CreateServiceContext(DatabaseContext dbContext, IScopeProvider scopeProvider)
{
//default transient factory
var msgFactory = new TransientMessagesFactory();
return new ServiceContext(
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
new PetaPocoUnitOfWorkProvider(dbFactory),
new FileUnitOfWorkProvider(),
new PublishingStrategy(msgFactory, ProfilingLogger.Logger),
new PetaPocoUnitOfWorkProvider(scopeProvider),
ApplicationCache,
ProfilingLogger.Logger,
msgFactory);
+107 -41
View File
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlServerCe;
using System.IO;
@@ -14,6 +13,7 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Initial;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
namespace Umbraco.Core
@@ -26,20 +26,33 @@ namespace Umbraco.Core
/// </remarks>
public class DatabaseContext
{
private readonly IDatabaseFactory _factory;
internal readonly IScopeProviderInternal ScopeProvider;
private readonly ILogger _logger;
private readonly SqlSyntaxProviders _syntaxProviders;
private bool _configured;
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
/// </summary>
private const int ConnectionCheckMinutes = 1;
#region Compatibility with 7.5
// note: the ctors accepting IDatabaseFactory are here only for backward compatibility purpose
//
// problem: IDatabaseFactory2 adds the CreateNewDatabase() method which creates a new database
// 'cos IDatabaseFactory CreateDatabase() is supposed to also manage the ambient thing. We
// want to keep these ctors for backward compatibility reasons (in case ppl use them in tests)
// so we need to create a scope provider (else nothing would work) and so we need a IDatabaseFactory2,
// so...?
// solution: wrap IDatabaseFactory and pretend we have a IDatabaseFactory2, it *should* work in most
// cases but really, it depends on what ppl are doing in their tests... yet, cannot really see any
// other way to do it?
[Obsolete("Use the constructor specifying all dependencies instead")]
public DatabaseContext(IDatabaseFactory factory)
: this(factory, LoggerResolver.Current.Logger, new SqlSyntaxProviders(new ISqlSyntaxProvider[]
@@ -48,8 +61,7 @@ namespace Umbraco.Core
new SqlCeSyntaxProvider(),
new SqlServerSyntaxProvider()
}))
{
}
{ }
/// <summary>
/// Default constructor
@@ -63,7 +75,11 @@ namespace Umbraco.Core
if (logger == null) throw new ArgumentNullException("logger");
if (syntaxProviders == null) throw new ArgumentNullException("syntaxProviders");
_factory = factory;
var asDbFactory2 = factory as IDatabaseFactory2;
ScopeProvider = asDbFactory2 == null
? new ScopeProvider(new DatabaseFactoryWrapper(factory))
: new ScopeProvider(asDbFactory2);
_logger = logger;
_syntaxProviders = syntaxProviders;
}
@@ -80,22 +96,86 @@ namespace Umbraco.Core
_providerName = providerName;
SqlSyntax = sqlSyntax;
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
_factory = factory;
var asDbFactory2 = factory as IDatabaseFactory2;
ScopeProvider = asDbFactory2 == null
? new ScopeProvider(new DatabaseFactoryWrapper(factory))
: new ScopeProvider(asDbFactory2);
_logger = logger;
_configured = true;
}
#if DEBUG_DATABASES
public List<UmbracoDatabase> Databases
private class DatabaseFactoryWrapper : IDatabaseFactory2
{
get
private readonly IDatabaseFactory _factory;
public DatabaseFactoryWrapper(IDatabaseFactory factory)
{
var factory = _factory as DefaultDatabaseFactory;
if (factory == null) throw new NotSupportedException();
return factory.Databases;
_factory = factory;
}
public UmbracoDatabase CreateDatabase()
{
return _factory.CreateDatabase();
}
public UmbracoDatabase CreateNewDatabase()
{
return CreateDatabase();
}
public void Dispose()
{
_factory.Dispose();
}
}
#endif
#endregion
[Obsolete("Use the constructor specifying all dependencies instead")]
internal DatabaseContext(IScopeProviderInternal scopeProvider)
: this(scopeProvider, LoggerResolver.Current.Logger, new SqlSyntaxProviders(new ISqlSyntaxProvider[]
{
new MySqlSyntaxProvider(LoggerResolver.Current.Logger),
new SqlCeSyntaxProvider(),
new SqlServerSyntaxProvider()
}))
{ }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="scopeProvider"></param>
/// <param name="logger"></param>
/// <param name="syntaxProviders"></param>
internal DatabaseContext(IScopeProviderInternal scopeProvider, ILogger logger, SqlSyntaxProviders syntaxProviders)
{
if (scopeProvider == null) throw new ArgumentNullException("scopeProvider");
if (logger == null) throw new ArgumentNullException("logger");
if (syntaxProviders == null) throw new ArgumentNullException("syntaxProviders");
ScopeProvider = scopeProvider;
_logger = logger;
_syntaxProviders = syntaxProviders;
}
/// <summary>
/// Create a configured DatabaseContext
/// </summary>
/// <param name="scopeProvider"></param>
/// <param name="logger"></param>
/// <param name="sqlSyntax"></param>
/// <param name="providerName"></param>
internal DatabaseContext(IScopeProviderInternal scopeProvider, ILogger logger, ISqlSyntaxProvider sqlSyntax, string providerName)
{
_providerName = providerName;
SqlSyntax = sqlSyntax;
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
ScopeProvider = scopeProvider;
_logger = logger;
_configured = true;
}
public ISqlSyntaxProvider SqlSyntax { get; private set; }
@@ -110,33 +190,17 @@ namespace Umbraco.Core
/// </remarks>
public virtual UmbracoDatabase Database
{
get { return _factory.CreateDatabase(); }
}
/// <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>
public virtual IDisposable UseSafeDatabase(bool force = false)
{
var factory = _factory as DefaultDatabaseFactory;
if (factory == null) throw new NotSupportedException();
if (DefaultDatabaseFactory.HasAmbientDatabase)
get
{
return force
? new UsingDatabase(DefaultDatabaseFactory.DetachAmbientDatabase(), factory.CreateDatabase())
: new UsingDatabase(null, null);
}
if (IsDatabaseConfigured == false)
{
throw new InvalidOperationException("Cannot create a database instance, there is no available connection string");
}
// create a new, temp, database (will be disposed with UsingDatabase)
return new UsingDatabase(null, factory.CreateDatabase());
return ScopeProvider.GetAmbientOrNoScope().Database;
//var scope = ScopeProvider.AmbientScope;
//return scope != null ? scope.Database : ScopeProvider.CreateNoScope().Database;
}
}
/// <summary>
@@ -159,7 +223,7 @@ namespace Umbraco.Core
//Don't check again if the timeout period hasn't elapsed
//this ensures we don't keep checking the connection too many times in a row like during startup.
//Do check if the _connectionLastChecked is null which means we're just initializing or it could
//Do check if the _connectionLastChecked is null which means we're just initializing or it could
//not connect last time it was checked.
if ((_connectionLastChecked.HasValue && (DateTime.Now - _connectionLastChecked.Value).TotalMinutes > ConnectionCheckMinutes)
|| _connectionLastChecked.HasValue == false)
@@ -202,7 +266,7 @@ namespace Umbraco.Core
}
else
{
throw new InvalidOperationException("Can't find a connection string with the name '" + Constants.System.UmbracoConnectionName + "'");
throw new NullReferenceException("Can't find a connection string with the name '" + Constants.System.UmbracoConnectionName + "'");
}
return _providerName;
}
@@ -809,6 +873,7 @@ namespace Umbraco.Core
return true;
}
/*
private class UsingDatabase : IDisposable
{
private readonly UmbracoDatabase _orig;
@@ -831,5 +896,6 @@ namespace Umbraco.Core
GC.SuppressFinalize(this);
}
}
*/
}
}
+4
View File
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Deploy
if (udi == null)
throw new ArgumentNullException("udi");
Udi = udi;
Name = Udi.ToString();
Dependencies = dependencies ?? Enumerable.Empty<ArtifactDependency>();
_checksum = new Lazy<string>(GetChecksum);
@@ -48,5 +49,8 @@ namespace Umbraco.Core.Deploy
}
#endregion
public string Name { get; set; }
public string Alias { get; set; }
}
}
+4 -1
View File
@@ -4,5 +4,8 @@ namespace Umbraco.Core.Deploy
/// Represents an artifact ie an object that can be transfered between environments.
/// </summary>
public interface IArtifact : IArtifactSignature
{ }
{
string Name { get; }
string Alias { get; }
}
}
+13 -3
View File
@@ -66,10 +66,20 @@ namespace Umbraco.Core.Deploy
/// <returns>The length of the file, or -1 if the file does not exist.</returns>
Task<long> GetFileLengthAsync(StringUdi udi, CancellationToken token);
// fixme - doc
void GetFiles(IEnumerable<StringUdi> udis, IFileStore fileStore);
/// <summary>
/// Gets files and store them using a file store.
/// </summary>
/// <param name="udis">The udis of the files to get.</param>
/// <param name="fileTypes">A collection of file types which can store the files.</param>
void GetFiles(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes);
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileStore fileStore, CancellationToken token);
/// <summary>
/// Gets files and store them using a file store.
/// </summary>
/// <param name="udis">The udis of the files to get.</param>
/// <param name="fileTypes">A collection of file types which can store the files.</param>
/// <param name="token">A cancellation token.</param>
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes, CancellationToken token);
///// <summary>
///// Gets the content of a file as a bytes array.
-9
View File
@@ -1,9 +0,0 @@
using System.IO;
namespace Umbraco.Core.Deploy
{
public interface IFileStore
{
void SaveStream(StringUdi udi, Stream stream);
}
}
+32
View File
@@ -0,0 +1,32 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Umbraco.Core.Deploy
{
public interface IFileType
{
Stream GetStream(StringUdi udi);
Task<Stream> GetStreamAsync(StringUdi udi, CancellationToken token);
Stream GetChecksumStream(StringUdi udi);
long GetLength(StringUdi udi);
void SetStream(StringUdi udi, Stream stream);
Task SetStreamAsync(StringUdi udi, Stream stream, CancellationToken token);
bool CanSetPhysical { get; }
void Set(StringUdi udi, string physicalPath, bool copy = false);
// this is not pretty as *everywhere* in Deploy we take care of ignoring
// the physical path and always rely on Core's virtual IFileSystem but
// Cloud wants to add some of these files to Git and needs the path...
string GetPhysicalPath(StringUdi udi);
string GetVirtualPath(StringUdi udi);
}
}
@@ -0,0 +1,9 @@
namespace Umbraco.Core.Deploy
{
public interface IFileTypeCollection
{
IFileType this[string entityType] { get; }
bool Contains(string entityType);
}
}
@@ -11,12 +11,12 @@ namespace Umbraco.Core.Deploy
public interface IGridCellValueConnector
{
/// <summary>
/// Gets a value indicating whether the connector supports a specified grid editor alias.
/// Gets a value indicating whether the connector supports a specified grid editor view.
/// </summary>
/// <param name="alias">The grid editor alias.</param>
/// <remarks>A value indicating whether the connector supports the grid editor alias.</remarks>
/// <remarks>Note that <paramref name="alias" /> can be string.Empty to indicate the "default" connector.</remarks>
bool IsConnector(string alias);
/// <param name="view">The grid editor view. It needs to be the view instead of the alias as the view is really what identifies what kind of connector should be used. Alias can be anything and you can have multiple different aliases using the same kind of view.</param>
/// <remarks>A value indicating whether the connector supports the grid editor view.</remarks>
/// <remarks>Note that <paramref name="view" /> can be string.Empty to indicate the "default" connector.</remarks>
bool IsConnector(string view);
/// <summary>
/// Gets the value to be deployed from the control value as a string.
@@ -1,8 +0,0 @@
namespace Umbraco.Core.Deploy
{
public interface IPrettyArtifact
{
string Name { get; }
string Alias { get; }
}
}
+22 -11
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
@@ -67,22 +68,15 @@ namespace Umbraco.Core
}
}
/// <summary>The for each.</summary>
/// <param name="items">The items.</param>
/// <param name="func">The func.</param>
/// <typeparam name="TItem">item type</typeparam>
/// <typeparam name="TResult">Result type</typeparam>
/// <returns>the Results</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
public static TResult[] ForEach<TItem, TResult>(this IEnumerable<TItem> items, Func<TItem, TResult> func)
{
return items.Select(func).ToArray();
}
/// <summary>The for each.</summary>
/// <param name="items">The items.</param>
/// <param name="action">The action.</param>
/// <typeparam name="TItem">Item type</typeparam>
/// <returns>list of TItem</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
public static IEnumerable<TItem> ForEach<TItem>(this IEnumerable<TItem> items, Action<TItem> action)
{
if (items != null)
@@ -101,6 +95,7 @@ namespace Umbraco.Core
/// <param name="f">The select child.</param>
/// <typeparam name="T">Item type</typeparam>
/// <returns>list of TItem</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
{
@@ -301,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;
}
}
}
}
@@ -10,8 +10,8 @@ namespace Umbraco.Core.Events
/// Event args for that can support cancellation
/// </summary>
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class CancellableEventArgs : EventArgs
{
public class CancellableEventArgs : EventArgs, IEquatable<CancellableEventArgs>
{
private bool _cancel;
public CancellableEventArgs(bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
@@ -98,6 +98,36 @@ namespace Umbraco.Core.Events
/// This allows for a bit of flexibility in our event raising - it's not pretty but we need to maintain backwards compatibility
/// so we cannot change the strongly typed nature for some events.
/// </remarks>
public ReadOnlyDictionary<string, object> AdditionalData { get; private set; }
}
public ReadOnlyDictionary<string, object> AdditionalData { get; private set; }
public bool Equals(CancellableEventArgs other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(AdditionalData, other.AdditionalData);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((CancellableEventArgs) obj);
}
public override int GetHashCode()
{
return (AdditionalData != null ? AdditionalData.GetHashCode() : 0);
}
public static bool operator ==(CancellableEventArgs left, CancellableEventArgs right)
{
return Equals(left, right);
}
public static bool operator !=(CancellableEventArgs left, CancellableEventArgs right)
{
return !Equals(left, right);
}
}
}
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Security.Permissions;
using Umbraco.Core.Models;
@@ -10,7 +11,7 @@ namespace Umbraco.Core.Events
/// </summary>
/// <typeparam name="T"></typeparam>
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class CancellableObjectEventArgs<T> : CancellableEventArgs
public class CancellableObjectEventArgs<T> : CancellableEventArgs, IEquatable<CancellableObjectEventArgs<T>>
{
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
: base(canCancel, messages, additionalData)
@@ -48,5 +49,37 @@ namespace Umbraco.Core.Events
/// </remarks>
protected T EventObject { get; set; }
public bool Equals(CancellableObjectEventArgs<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && EqualityComparer<T>.Default.Equals(EventObject, other.EventObject);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((CancellableObjectEventArgs<T>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ EqualityComparer<T>.Default.GetHashCode(EventObject);
}
}
public static bool operator ==(CancellableObjectEventArgs<T> left, CancellableObjectEventArgs<T> right)
{
return Equals(left, right);
}
public static bool operator !=(CancellableObjectEventArgs<T> left, CancellableObjectEventArgs<T> right)
{
return !Equals(left, right);
}
}
}
+41 -1
View File
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
public class CopyEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
public class CopyEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>, IEquatable<CopyEventArgs<TEntity>>
{
public CopyEventArgs(TEntity original, TEntity copy, bool canCancel, int parentId)
: base(original, canCancel)
@@ -43,5 +46,42 @@ namespace Umbraco.Core.Events
public int ParentId { get; private set; }
public bool RelateToOriginal { get; set; }
public bool Equals(CopyEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && EqualityComparer<TEntity>.Default.Equals(Copy, other.Copy) && ParentId == other.ParentId && RelateToOriginal == other.RelateToOriginal;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((CopyEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ EqualityComparer<TEntity>.Default.GetHashCode(Copy);
hashCode = (hashCode * 397) ^ ParentId;
hashCode = (hashCode * 397) ^ RelateToOriginal.GetHashCode();
return hashCode;
}
}
public static bool operator ==(CopyEventArgs<TEntity> left, CopyEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(CopyEventArgs<TEntity> left, CopyEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
+70 -3
View File
@@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<DeleteEventArgs<TEntity>>, IDeletingMediaFilesEventArgs
{
/// <summary>
/// Constructor accepting multiple entities that are used in the delete operation
@@ -99,10 +100,43 @@ namespace Umbraco.Core.Events
/// <summary>
/// A list of media files that can be added to during a deleted operation for which Umbraco will ensure are removed
/// </summary>
public List<string> MediaFilesToDelete { get; private set; }
public List<string> MediaFilesToDelete { get; private set; }
public bool Equals(DeleteEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && MediaFilesToDelete.Equals(other.MediaFilesToDelete);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((DeleteEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ MediaFilesToDelete.GetHashCode();
}
}
public static bool operator ==(DeleteEventArgs<TEntity> left, DeleteEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(DeleteEventArgs<TEntity> left, DeleteEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
public class DeleteEventArgs : CancellableEventArgs
public class DeleteEventArgs : CancellableEventArgs, IEquatable<DeleteEventArgs>
{
public DeleteEventArgs(int id, bool canCancel, EventMessages eventMessages)
: base(canCancel, eventMessages)
@@ -125,5 +159,38 @@ namespace Umbraco.Core.Events
/// Gets the Id of the object being deleted.
/// </summary>
public int Id { get; private set; }
public bool Equals(DeleteEventArgs other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((DeleteEventArgs) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ Id;
}
}
public static bool operator ==(DeleteEventArgs left, DeleteEventArgs right)
{
return Equals(left, right);
}
public static bool operator !=(DeleteEventArgs left, DeleteEventArgs right)
{
return !Equals(left, right);
}
}
}
@@ -2,7 +2,7 @@ using System;
namespace Umbraco.Core.Events
{
public class DeleteRevisionsEventArgs : DeleteEventArgs
public class DeleteRevisionsEventArgs : DeleteEventArgs, IEquatable<DeleteRevisionsEventArgs>
{
public DeleteRevisionsEventArgs(int id, bool canCancel, Guid specificVersion = default(Guid), bool deletePriorVersions = false, DateTime dateToRetain = default(DateTime))
: base(id, canCancel)
@@ -31,5 +31,42 @@ namespace Umbraco.Core.Events
{
get { return SpecificVersion != default(Guid); }
}
public bool Equals(DeleteRevisionsEventArgs other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && DateToRetain.Equals(other.DateToRetain) && DeletePriorVersions == other.DeletePriorVersions && SpecificVersion.Equals(other.SpecificVersion);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((DeleteRevisionsEventArgs) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ DateToRetain.GetHashCode();
hashCode = (hashCode * 397) ^ DeletePriorVersions.GetHashCode();
hashCode = (hashCode * 397) ^ SpecificVersion.GetHashCode();
return hashCode;
}
}
public static bool operator ==(DeleteRevisionsEventArgs left, DeleteRevisionsEventArgs right)
{
return Equals(left, right);
}
public static bool operator !=(DeleteRevisionsEventArgs left, DeleteRevisionsEventArgs right)
{
return !Equals(left, right);
}
}
}
@@ -0,0 +1,73 @@
using System;
namespace Umbraco.Core.Events
{
internal class EventDefinition : EventDefinitionBase
{
private readonly EventHandler _trackedEvent;
private readonly object _sender;
private readonly EventArgs _args;
public EventDefinition(EventHandler trackedEvent, object sender, EventArgs args, string eventName = null)
: base(sender, args, eventName)
{
_trackedEvent = trackedEvent;
_sender = sender;
_args = args;
}
public override void RaiseEvent()
{
if (_trackedEvent != null)
{
_trackedEvent(_sender, _args);
}
}
}
internal class EventDefinition<TEventArgs> : EventDefinitionBase
{
private readonly EventHandler<TEventArgs> _trackedEvent;
private readonly object _sender;
private readonly TEventArgs _args;
public EventDefinition(EventHandler<TEventArgs> trackedEvent, object sender, TEventArgs args, string eventName = null)
: base(sender, args, eventName)
{
_trackedEvent = trackedEvent;
_sender = sender;
_args = args;
}
public override void RaiseEvent()
{
if (_trackedEvent != null)
{
_trackedEvent(_sender, _args);
}
}
}
internal class EventDefinition<TSender, TEventArgs> : EventDefinitionBase
{
private readonly TypedEventHandler<TSender, TEventArgs> _trackedEvent;
private readonly TSender _sender;
private readonly TEventArgs _args;
public EventDefinition(TypedEventHandler<TSender, TEventArgs> trackedEvent, TSender sender, TEventArgs args, string eventName = null)
: base(sender, args, eventName)
{
_trackedEvent = trackedEvent;
_sender = sender;
_args = args;
}
public override void RaiseEvent()
{
if (_trackedEvent != null)
{
_trackedEvent(_sender, _args);
}
}
}
}
@@ -0,0 +1,70 @@
using System;
using System.Reflection;
namespace Umbraco.Core.Events
{
public abstract class EventDefinitionBase : IEventDefinition, IEquatable<EventDefinitionBase>
{
protected EventDefinitionBase(object sender, object args, string eventName = null)
{
if (sender == null) throw new ArgumentNullException("sender");
if (args == null) throw new ArgumentNullException("args");
Sender = sender;
Args = args;
EventName = eventName;
if (EventName.IsNullOrWhiteSpace())
{
var findResult = EventNameExtractor.FindEvent(sender, args,
//don't match "Ing" suffixed names
exclude:EventNameExtractor.MatchIngNames);
if (findResult.Success == false)
throw new AmbiguousMatchException("Could not automatically find the event name, the event name will need to be explicitly registered for this event definition. Error: " + findResult.Result.Error);
EventName = findResult.Result.Name;
}
}
public object Sender { get; private set; }
public object Args { get; private set; }
public string EventName { get; private set; }
public abstract void RaiseEvent();
public bool Equals(EventDefinitionBase other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Args.Equals(other.Args) && string.Equals(EventName, other.EventName) && Sender.Equals(other.Sender);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((EventDefinitionBase) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = Args.GetHashCode();
hashCode = (hashCode * 397) ^ EventName.GetHashCode();
hashCode = (hashCode * 397) ^ Sender.GetHashCode();
return hashCode;
}
}
public static bool operator ==(EventDefinitionBase left, EventDefinitionBase right)
{
return Equals(left, right);
}
public static bool operator !=(EventDefinitionBase left, EventDefinitionBase right)
{
return Equals(left, right) == false;
}
}
}
@@ -0,0 +1,24 @@
namespace Umbraco.Core.Events
{
/// <summary>
/// The filter used in the <see cref="IEventDispatcher"/> GetEvents method which determines
/// how the result list is filtered
/// </summary>
public enum EventDefinitionFilter
{
/// <summary>
/// Returns all events tracked
/// </summary>
All,
/// <summary>
/// Deduplicates events and only returns the first duplicate instance tracked
/// </summary>
FirstIn,
/// <summary>
/// Deduplicates events and only returns the last duplicate instance tracked
/// </summary>
LastIn
}
}
+30 -61
View File
@@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Events
{
@@ -10,73 +12,40 @@ namespace Umbraco.Core.Events
/// </summary>
public static class EventExtensions
{
/// <summary>
/// Raises the event and returns a boolean value indicating if the event was cancelled
/// </summary>
/// <typeparam name="TSender"></typeparam>
/// <typeparam name="TArgs"></typeparam>
/// <param name="eventHandler"></param>
/// <param name="args"></param>
/// <param name="sender"></param>
/// <returns></returns>
public static bool IsRaisedEventCancelled<TSender, TArgs>(
this TypedEventHandler<TSender, TArgs> eventHandler,
TArgs args,
TSender sender)
where TArgs : CancellableEventArgs
{
if (eventHandler != null)
eventHandler(sender, args);
// keep these two for backward compatibility reasons but understand that
// they are *not* part of any scope / event dispatcher / anything...
/// <summary>
/// Raises a cancelable event and returns a value indicating whether the event should be cancelled.
/// </summary>
/// <typeparam name="TSender">The type of the event source.</typeparam>
/// <typeparam name="TArgs">The type of the event data.</typeparam>
/// <param name="eventHandler">The event handler.</param>
/// <param name="args">The event source.</param>
/// <param name="sender">The event data.</param>
/// <returns>A value indicating whether the cancelable event should be cancelled</returns>
/// <remarks>A cancelable event is raised by a component when it is about to perform an action that can be canceled.</remarks>
public static bool IsRaisedEventCancelled<TSender, TArgs>(this TypedEventHandler<TSender, TArgs> eventHandler, TArgs args, TSender sender)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
/// <summary>
/// Raises the event
/// Raises an event.
/// </summary>
/// <typeparam name="TSender"></typeparam>
/// <typeparam name="TArgs"></typeparam>
/// <param name="eventHandler"></param>
/// <param name="args"></param>
/// <param name="sender"></param>
public static void RaiseEvent<TSender, TArgs>(
this TypedEventHandler<TSender, TArgs> eventHandler,
TArgs args,
TSender sender)
where TArgs : EventArgs
{
if (eventHandler != null)
eventHandler(sender, args);
}
// moves the last handler that was added to an instance event, to first position
public static void PromoteLastHandler(object sender, string eventName)
{
var fieldInfo = sender.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
if (fieldInfo == null) throw new InvalidOperationException("No event named " + eventName + ".");
PromoteLastHandler(sender, fieldInfo);
}
// moves the last handler that was added to a static event, to first position
public static void PromoteLastHandler<TSender>(string eventName)
/// <typeparam name="TSender">The type of the event source.</typeparam>
/// <typeparam name="TArgs">The type of the event data.</typeparam>
/// <param name="eventHandler">The event handler.</param>
/// <param name="args">The event source.</param>
/// <param name="sender">The event data.</param>
public static void RaiseEvent<TSender, TArgs>(this TypedEventHandler<TSender, TArgs> eventHandler, TArgs args, TSender sender)
where TArgs : EventArgs
{
var fieldInfo = typeof(TSender).GetField(eventName, BindingFlags.Static | BindingFlags.NonPublic);
if (fieldInfo == null) throw new InvalidOperationException("No event named " + eventName + ".");
PromoteLastHandler(null, fieldInfo);
}
private static void PromoteLastHandler(object sender, FieldInfo fieldInfo)
{
var d = fieldInfo.GetValue(sender) as Delegate;
if (d == null) return;
var l = d.GetInvocationList();
var x = l[l.Length - 1];
for (var i = l.Length - 1; i > 0; i--)
l[i] = l[i - 1];
l[0] = x;
fieldInfo.SetValue(sender, Delegate.Combine(l));
if (eventHandler == null) return;
eventHandler(sender, args);
}
}
}
@@ -0,0 +1,159 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Umbraco.Core.Events
{
/// <summary>
/// There is actually no way to discover an event name in c# at the time of raising the event. It is possible
/// to get the event name from the handler that is being executed based on the event being raised, however that is not
/// what we want in this case. We need to find the event name before it is being raised - you would think that it's possible
/// with reflection or anything but that is not the case, the delegate that defines an event has no info attached to it, it
/// is literally just an event.
///
/// So what this does is take the sender and event args objects, looks up all public/static events on the sender that have
/// a generic event handler with generic arguments (but only) one, then we match the type of event arguments with the ones
/// being passed in. As it turns out, in our services this will work for the majority of our events! In some cases it may not
/// work and we'll have to supply a string but hopefully this saves a bit of magic strings.
///
/// We can also write tests to validate these are all working correctly for all services.
/// </summary>
internal class EventNameExtractor
{
/// <summary>
/// Finds the event name on the sender that matches the args type
/// </summary>
/// <param name="senderType"></param>
/// <param name="argsType"></param>
/// <param name="exclude">
/// A filter to exclude matched event names, this filter should return true to exclude the event name from being matched
/// </param>
/// <returns>
/// null if not found or an ambiguous match
/// </returns>
public static Attempt<EventNameExtractorResult> FindEvent(Type senderType, Type argsType, Func<string, bool> exclude)
{
var found = MatchedEventNames.GetOrAdd(new Tuple<Type, Type>(senderType, argsType), tuple =>
{
var events = CandidateEvents.GetOrAdd(senderType, t =>
{
return t.GetEvents(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
//we can only look for events handlers with generic types because that is the only
// way that we can try to find a matching event based on the arg type passed in
.Where(x => x.EventHandlerType.IsGenericType)
.Select(x => new EventInfoArgs(x, x.EventHandlerType.GetGenericArguments()))
//we are only looking for event handlers that have more than one generic argument
.Where(x =>
{
if (x.GenericArgs.Length == 1) return true;
//special case for our own TypedEventHandler
if (x.EventInfo.EventHandlerType.GetGenericTypeDefinition() == typeof(TypedEventHandler<,>) && x.GenericArgs.Length == 2)
{
return true;
}
return false;
})
.ToArray();
});
return events.Where(x =>
{
if (x.GenericArgs.Length == 1 && x.GenericArgs[0] == tuple.Item2)
return true;
//special case for our own TypedEventHandler
if (x.EventInfo.EventHandlerType.GetGenericTypeDefinition() == typeof(TypedEventHandler<,>)
&& x.GenericArgs.Length == 2
&& x.GenericArgs[1] == tuple.Item2)
{
return true;
}
return false;
}).Select(x => x.EventInfo.Name).ToArray();
});
var filtered = found.Where(x => exclude(x) == false).ToArray();
if (filtered.Length == 0)
return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.NoneFound));
if (filtered.Length == 1)
return Attempt.Succeed(new EventNameExtractorResult(filtered[0]));
//there's more than one left so it's ambiguous!
return Attempt.Fail(new EventNameExtractorResult(EventNameExtractorError.Ambiguous));
}
/// <summary>
/// Finds the event name on the sender that matches the args type
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <param name="exclude">
/// A filter to exclude matched event names, this filter should return true to exclude the event name from being matched
/// </param>
/// <returns>
/// null if not found or an ambiguous match
/// </returns>
public static Attempt<EventNameExtractorResult> FindEvent(object sender, object args, Func<string, bool> exclude)
{
return FindEvent(sender.GetType(), args.GetType(), exclude);
}
/// <summary>
/// Return true if the event is named with an ING name such as "Saving" or "RollingBack"
/// </summary>
/// <param name="eventName"></param>
/// <returns></returns>
internal static bool MatchIngNames(string eventName)
{
var splitter = new Regex(@"(?<!^)(?=[A-Z])");
var words = splitter.Split(eventName);
if (words.Length == 0)
return false;
return words[0].EndsWith("ing");
}
/// <summary>
/// Return true if the event is not named with an ING name such as "Saving" or "RollingBack"
/// </summary>
/// <param name="eventName"></param>
/// <returns></returns>
internal static bool MatchNonIngNames(string eventName)
{
var splitter = new Regex(@"(?<!^)(?=[A-Z])");
var words = splitter.Split(eventName);
if (words.Length == 0)
return false;
return words[0].EndsWith("ing") == false;
}
private class EventInfoArgs
{
public EventInfo EventInfo { get; private set; }
public Type[] GenericArgs { get; private set; }
public EventInfoArgs(EventInfo eventInfo, Type[] genericArgs)
{
EventInfo = eventInfo;
GenericArgs = genericArgs;
}
}
/// <summary>
/// Used to cache all candidate events for a given type so we don't re-look them up
/// </summary>
private static readonly ConcurrentDictionary<Type, EventInfoArgs[]> CandidateEvents = new ConcurrentDictionary<Type, EventInfoArgs[]>();
/// <summary>
/// Used to cache all matched event names by (sender type + arg type) so we don't re-look them up
/// </summary>
private static readonly ConcurrentDictionary<Tuple<Type, Type>, string[]> MatchedEventNames = new ConcurrentDictionary<Tuple<Type, Type>, string[]>();
}
}
@@ -0,0 +1,8 @@
namespace Umbraco.Core.Events
{
internal enum EventNameExtractorError
{
NoneFound,
Ambiguous
}
}
@@ -0,0 +1,18 @@
namespace Umbraco.Core.Events
{
internal class EventNameExtractorResult
{
public EventNameExtractorError? Error { get; private set; }
public string Name { get; private set; }
public EventNameExtractorResult(string name)
{
Name = name;
}
public EventNameExtractorResult(EventNameExtractorError error)
{
Error = error;
}
}
}
+36 -2
View File
@@ -1,9 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Umbraco.Core.Events
{
public class ExportEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
public class ExportEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<ExportEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting a single entity instance
@@ -48,5 +49,38 @@ namespace Umbraco.Core.Events
/// Returns the xml relating to the export event
/// </summary>
public XElement Xml { get; private set; }
public bool Equals(ExportEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && Equals(Xml, other.Xml);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ExportEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ (Xml != null ? Xml.GetHashCode() : 0);
}
}
public static bool operator ==(ExportEventArgs<TEntity> left, ExportEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(ExportEventArgs<TEntity> left, ExportEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
internal interface IDeletingMediaFilesEventArgs
{
List<string> MediaFilesToDelete { get; }
}
}
@@ -0,0 +1,13 @@
using System;
namespace Umbraco.Core.Events
{
public interface IEventDefinition
{
object Sender { get; }
object Args { get; }
string EventName { get; }
void RaiseEvent();
}
}
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
/// <summary>
/// Dispatches events from within a scope.
/// </summary>
/// <remarks>
/// <para>The name of the event is auto-magically discovered by matching the sender type, args type, and
/// eventHandler type. If the match is not unique, then the name parameter must be used to specify the
/// name in an explicit way.</para>
/// <para>What happens when an event is dispatched depends on the scope settings. It can be anything from
/// "trigger immediately" to "just ignore". Refer to the scope documentation for more details.</para>
/// </remarks>
public interface IEventDispatcher
{
// not sure about the Dispatch & DispatchCancelable signatures at all for now
// nor about the event name thing, etc - but let's keep it like this
/// <summary>
/// Dispatches a cancelable event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string name = null);
/// <summary>
/// Dispatches a cancelable event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string name = null)
where TArgs : CancellableEventArgs;
/// <summary>
/// Dispatches a cancelable event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <returns>A value indicating whether the cancelable event was cancelled.</returns>
/// <remarks>See general remarks on the interface.</remarks>
bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string name = null)
where TArgs : CancellableEventArgs;
/// <summary>
/// Dispatches an event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string name = null);
/// <summary>
/// Dispatches an event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string name = null);
/// <summary>
/// Dispatches an event.
/// </summary>
/// <param name="eventHandler">The event handler.</param>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The event data.</param>
/// <param name="name">The optional name of the event.</param>
/// <remarks>See general remarks on the interface.</remarks>
void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string name = null);
/// <summary>
/// Notifies the dispatcher that the scope is exiting.
/// </summary>
/// <param name="completed">A value indicating whether the scope completed.</param>
void ScopeExit(bool completed);
/// <summary>
/// Gets the collected events.
/// </summary>
/// <returns>The collected events.</returns>
IEnumerable<IEventDefinition> GetEvents(EventDefinitionFilter filter);
}
}
+36 -2
View File
@@ -1,9 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Umbraco.Core.Events
{
public class ImportEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
public class ImportEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<ImportEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting an XElement with the xml being imported
@@ -46,5 +47,38 @@ namespace Umbraco.Core.Events
/// Returns the xml relating to the import event
/// </summary>
public XElement Xml { get; private set; }
public bool Equals(ImportEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && Equals(Xml, other.Xml);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ImportEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ (Xml != null ? Xml.GetHashCode() : 0);
}
}
public static bool operator ==(ImportEventArgs<TEntity> left, ImportEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(ImportEventArgs<TEntity> left, ImportEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
@@ -1,9 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Events
{
internal class ImportPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
internal class ImportPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<ImportPackageEventArgs<TEntity>>
{
private readonly MetaData _packageMetaData;
@@ -21,6 +22,44 @@ namespace Umbraco.Core.Events
public MetaData PackageMetaData
{
get { return _packageMetaData; }
}
public IEnumerable<TEntity> InstallationSummary
{
get { return EventObject; }
}
public bool Equals(ImportPackageEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && _packageMetaData.Equals(other._packageMetaData);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ImportPackageEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ _packageMetaData.GetHashCode();
}
}
public static bool operator ==(ImportPackageEventArgs<TEntity> left, ImportPackageEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(ImportPackageEventArgs<TEntity> left, ImportPackageEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
+39 -1
View File
@@ -7,7 +7,7 @@ using Umbraco.Core.Persistence.Migrations;
namespace Umbraco.Core.Events
{
public class MigrationEventArgs : CancellableObjectEventArgs<IList<IMigration>>
public class MigrationEventArgs : CancellableObjectEventArgs<IList<IMigration>>, IEquatable<MigrationEventArgs>
{
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
@@ -141,5 +141,43 @@ namespace Umbraco.Core.Events
public string ProductName { get; private set; }
internal MigrationContext MigrationContext { get; private set; }
public bool Equals(MigrationEventArgs other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && ConfiguredSemVersion.Equals(other.ConfiguredSemVersion) && MigrationContext.Equals(other.MigrationContext) && string.Equals(ProductName, other.ProductName) && TargetSemVersion.Equals(other.TargetSemVersion);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MigrationEventArgs) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ ConfiguredSemVersion.GetHashCode();
hashCode = (hashCode * 397) ^ MigrationContext.GetHashCode();
hashCode = (hashCode * 397) ^ ProductName.GetHashCode();
hashCode = (hashCode * 397) ^ TargetSemVersion.GetHashCode();
return hashCode;
}
}
public static bool operator ==(MigrationEventArgs left, MigrationEventArgs right)
{
return Equals(left, right);
}
public static bool operator !=(MigrationEventArgs left, MigrationEventArgs right)
{
return !Equals(left, right);
}
}
}
+34 -1
View File
@@ -4,7 +4,7 @@ using System.Linq;
namespace Umbraco.Core.Events
{
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>, IEquatable<MoveEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting a collection of MoveEventInfo objects
@@ -123,5 +123,38 @@ namespace Umbraco.Core.Events
/// </summary>
[Obsolete("Retrieve the ParentId from the MoveInfoCollection property instead")]
public int ParentId { get; private set; }
public bool Equals(MoveEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && MoveInfoCollection.Equals(other.MoveInfoCollection);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MoveEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ MoveInfoCollection.GetHashCode();
}
}
public static bool operator ==(MoveEventArgs<TEntity> left, MoveEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(MoveEventArgs<TEntity> left, MoveEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
+40 -1
View File
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
public class MoveEventInfo<TEntity>
public class MoveEventInfo<TEntity> : IEquatable<MoveEventInfo<TEntity>>
{
public MoveEventInfo(TEntity entity, string originalPath, int newParentId)
{
@@ -12,5 +15,41 @@ namespace Umbraco.Core.Events
public TEntity Entity { get; set; }
public string OriginalPath { get; set; }
public int NewParentId { get; set; }
public bool Equals(MoveEventInfo<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EqualityComparer<TEntity>.Default.Equals(Entity, other.Entity) && NewParentId == other.NewParentId && string.Equals(OriginalPath, other.OriginalPath);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MoveEventInfo<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = EqualityComparer<TEntity>.Default.GetHashCode(Entity);
hashCode = (hashCode * 397) ^ NewParentId;
hashCode = (hashCode * 397) ^ OriginalPath.GetHashCode();
return hashCode;
}
}
public static bool operator ==(MoveEventInfo<TEntity> left, MoveEventInfo<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(MoveEventInfo<TEntity> left, MoveEventInfo<TEntity> right)
{
return !Equals(left, right);
}
}
}
+40 -1
View File
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Events
{
public class NewEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
public class NewEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>, IEquatable<NewEventArgs<TEntity>>
{
@@ -84,5 +86,42 @@ namespace Umbraco.Core.Events
/// Gets or Sets the parent IContent object.
/// </summary>
public TEntity Parent { get; private set; }
public bool Equals(NewEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && string.Equals(Alias, other.Alias) && EqualityComparer<TEntity>.Default.Equals(Parent, other.Parent) && ParentId == other.ParentId;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((NewEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ Alias.GetHashCode();
hashCode = (hashCode * 397) ^ EqualityComparer<TEntity>.Default.GetHashCode(Parent);
hashCode = (hashCode * 397) ^ ParentId;
return hashCode;
}
}
public static bool operator ==(NewEventArgs<TEntity> left, NewEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(NewEventArgs<TEntity> left, NewEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Events
{
/// <summary>
/// This event manager supports event cancellation and will raise the events as soon as they are tracked, it does not store tracked events
/// </summary>
internal class PassThroughEventDispatcher : IEventDispatcher
{
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
{
if (eventHandler == null) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
{
if (eventHandler == null) return;
eventHandler(sender, args);
}
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
{
if (eventHandler == null) return;
eventHandler(sender, args);
}
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
{
if (eventHandler == null) return;
eventHandler(sender, args);
}
public IEnumerable<IEventDefinition> GetEvents(EventDefinitionFilter filter)
{
return Enumerable.Empty<IEventDefinition>();
}
public void ScopeExit(bool completed)
{ }
}
}
+36 -2
View File
@@ -1,8 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Events
{
public class PublishEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
public class PublishEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<PublishEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting multiple entities that are used in the publish operation
@@ -101,5 +102,38 @@ namespace Umbraco.Core.Events
}
public bool IsAllRepublished { get; private set; }
public bool Equals(PublishEventArgs<TEntity> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && IsAllRepublished == other.IsAllRepublished;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((PublishEventArgs<TEntity>) obj);
}
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ IsAllRepublished.GetHashCode();
}
}
public static bool operator ==(PublishEventArgs<TEntity> left, PublishEventArgs<TEntity> right)
{
return Equals(left, right);
}
public static bool operator !=(PublishEventArgs<TEntity> left, PublishEventArgs<TEntity> right)
{
return !Equals(left, right);
}
}
}
+42 -1
View File
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Events
{
public class RecycleBinEventArgs : CancellableEventArgs
public class RecycleBinEventArgs : CancellableEventArgs, IEquatable<RecycleBinEventArgs>, IDeletingMediaFilesEventArgs
{
public RecycleBinEventArgs(Guid nodeObjectType, Dictionary<int, IEnumerable<Property>> allPropertyData, bool emptiedSuccessfully)
: base(false)
@@ -97,6 +97,8 @@ namespace Umbraco.Core.Events
/// </remarks>
public List<string> Files { get; private set; }
public List<string> MediaFilesToDelete { get { return Files; } }
/// <summary>
/// Gets the list of all property data associated with a content id
/// </summary>
@@ -122,5 +124,44 @@ namespace Umbraco.Core.Events
{
get { return NodeObjectType == new Guid(Constants.ObjectTypes.Media); }
}
public bool Equals(RecycleBinEventArgs other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && AllPropertyData.Equals(other.AllPropertyData) && Files.Equals(other.Files) && Ids.Equals(other.Ids) && NodeObjectType.Equals(other.NodeObjectType) && RecycleBinEmptiedSuccessfully == other.RecycleBinEmptiedSuccessfully;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((RecycleBinEventArgs) obj);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = base.GetHashCode();
hashCode = (hashCode * 397) ^ AllPropertyData.GetHashCode();
hashCode = (hashCode * 397) ^ Files.GetHashCode();
hashCode = (hashCode * 397) ^ Ids.GetHashCode();
hashCode = (hashCode * 397) ^ NodeObjectType.GetHashCode();
hashCode = (hashCode * 397) ^ RecycleBinEmptiedSuccessfully.GetHashCode();
return hashCode;
}
}
public static bool operator ==(RecycleBinEventArgs left, RecycleBinEventArgs right)
{
return Equals(left, right);
}
public static bool operator !=(RecycleBinEventArgs left, RecycleBinEventArgs right)
{
return !Equals(left, right);
}
}
}
@@ -17,5 +17,7 @@ namespace Umbraco.Core.Events
{
get { return EventObject; }
}
}
}
+2
View File
@@ -116,5 +116,7 @@ namespace Umbraco.Core.Events
{
get { return EventObject; }
}
}
}
@@ -0,0 +1,46 @@
using Umbraco.Core.IO;
namespace Umbraco.Core.Events
{
/// <summary>
/// This event manager is created for each scope and is aware of if it is nested in an outer scope
/// </summary>
/// <remarks>
/// The outer scope is the only scope that can raise events, the inner scope's will defer to the outer scope
/// </remarks>
internal class ScopeEventDispatcher : ScopeEventDispatcherBase
{
public ScopeEventDispatcher()
: base(true)
{ }
protected override void ScopeExitCompleted()
{
// 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.LastIn))
{
e.RaiseEvent();
// 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);
}
}
private MediaFileSystem _mediaFileSystem;
private MediaFileSystem MediaFileSystem
{
get
{
return _mediaFileSystem ?? (_mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem);
}
}
}
}
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Events
{
public abstract class ScopeEventDispatcherBase : IEventDispatcher
{
private List<IEventDefinition> _events;
private readonly bool _raiseCancelable;
protected ScopeEventDispatcherBase(bool raiseCancelable)
{
_raiseCancelable = raiseCancelable;
}
private List<IEventDefinition> Events { get { return _events ?? (_events = new List<IEventDefinition>()); } }
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
{
if (eventHandler == null) return args.Cancel;
if (_raiseCancelable == false) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
if (_raiseCancelable == false) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
where TArgs : CancellableEventArgs
{
if (eventHandler == null) return args.Cancel;
if (_raiseCancelable == false) return args.Cancel;
eventHandler(sender, args);
return args.Cancel;
}
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition(eventHandler, sender, args, eventName));
}
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition<TArgs>(eventHandler, sender, args, eventName));
}
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
{
if (eventHandler == null) return;
Events.Add(new EventDefinition<TSender, TArgs>(eventHandler, sender, args, eventName));
}
public IEnumerable<IEventDefinition> GetEvents(EventDefinitionFilter filter)
{
if (_events == null)
return Enumerable.Empty<IEventDefinition>();
switch (filter)
{
case EventDefinitionFilter.All:
return _events;
case EventDefinitionFilter.FirstIn:
var l1 = new OrderedHashSet<IEventDefinition>();
foreach (var e in _events)
{
l1.Add(e);
}
return l1;
case EventDefinitionFilter.LastIn:
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
foreach (var e in _events)
{
l2.Add(e);
}
return l2;
default:
throw new ArgumentOutOfRangeException("filter", filter, null);
}
}
public void ScopeExit(bool completed)
{
if (_events == null) return;
if (completed)
ScopeExitCompleted();
_events.Clear();
}
protected abstract void ScopeExitCompleted();
}
}
@@ -0,0 +1,58 @@
using System;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Events
{
/// <summary>
/// Stores the instance of EventMessages in the current scope.
/// </summary>
internal class ScopeLifespanMessagesFactory : IEventMessagesFactory
{
public const string ContextKey = "Umbraco.Core.Events.ScopeLifespanMessagesFactory";
private readonly IHttpContextAccessor _contextAccessor;
private readonly IScopeProviderInternal _scopeProvider;
public static ScopeLifespanMessagesFactory Current { get; private set; }
public ScopeLifespanMessagesFactory(IHttpContextAccessor contextAccesor, IScopeProvider scopeProvider)
{
if (contextAccesor == null) throw new ArgumentNullException("contextAccesor");
if (scopeProvider == null) throw new ArgumentNullException("scopeProvider");
if (scopeProvider is IScopeProviderInternal == false) throw new ArgumentException("Not IScopeProviderInternal.", "scopeProvider");
_contextAccessor = contextAccesor;
_scopeProvider = (IScopeProviderInternal) scopeProvider;
Current = this;
}
public EventMessages Get()
{
var messages = GetFromHttpContext();
if (messages != null) return messages;
var scope = _scopeProvider.GetAmbientOrNoScope();
return scope.Messages;
}
public EventMessages GetFromHttpContext()
{
if (_contextAccessor == null || _contextAccessor.Value == null) return null;
return (EventMessages)_contextAccessor.Value.Items[ContextKey];
}
public EventMessages TryGet()
{
var messages = GetFromHttpContext();
if (messages != null) return messages;
var scope = _scopeProvider.AmbientScope;
return scope == null ? null : scope.MessagesOrNull;
}
public void Set(EventMessages messages)
{
if (_contextAccessor.Value == null) return;
_contextAccessor.Value.Items[ContextKey] = messages;
}
}
}
+1 -1
View File
@@ -2,6 +2,6 @@ using System;
namespace Umbraco.Core.Events
{
[Serializable]
[Serializable]
public delegate void TypedEventHandler<in TSender, in TEventArgs>(TSender sender, TEventArgs e);
}
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Events
{
internal class UninstallPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
{
private readonly MetaData _packageMetaData;
public UninstallPackageEventArgs(TEntity eventObject, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
}
public UninstallPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: base(new[] { eventObject })
{
_packageMetaData = packageMetaData;
}
public MetaData PackageMetaData
{
get { return _packageMetaData; }
}
public IEnumerable<TEntity> UninstallationSummary
{
get { return EventObject; }
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.0
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
+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>
+9
View File
@@ -0,0 +1,9 @@
using System.Web;
namespace Umbraco.Core
{
public interface IHttpContextAccessor
{
HttpContextBase Value { get; }
}
}
+179 -141
View File
@@ -5,31 +5,25 @@ using System.Configuration;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Configuration;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.IO
{
{
public class FileSystemProviderManager
{
private readonly FileSystemProvidersSection _config;
private readonly WeakSet<ShadowWrapper> _wrappers = new WeakSet<ShadowWrapper>();
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
// actual well-known filesystems returned by properties
private readonly IFileSystem2 _macroPartialFileSystem;
private readonly IFileSystem2 _partialViewsFileSystem;
private readonly IFileSystem2 _stylesheetsFileSystem;
private readonly IFileSystem2 _scriptsFileSystem;
private readonly IFileSystem2 _xsltFileSystem;
private readonly IFileSystem2 _masterPagesFileSystem;
private readonly IFileSystem2 _mvcViewsFileSystem;
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
private readonly ConcurrentDictionary<string, IFileSystem2> _filesystems = new ConcurrentDictionary<string, IFileSystem2>();
// when shadowing is enabled, above filesystems, as wrappers
private readonly ShadowWrapper _macroPartialFileSystemWrapper;
private readonly ShadowWrapper _partialViewsFileSystemWrapper;
private readonly ShadowWrapper _stylesheetsFileSystemWrapper;
private readonly ShadowWrapper _scriptsFileSystemWrapper;
private readonly ShadowWrapper _xsltFileSystemWrapper;
private readonly ShadowWrapper _masterPagesFileSystemWrapper;
private readonly ShadowWrapper _mvcViewsFileSystemWrapper;
private ShadowWrapper _macroPartialFileSystem;
private ShadowWrapper _partialViewsFileSystem;
private ShadowWrapper _stylesheetsFileSystem;
private ShadowWrapper _scriptsFileSystem;
private ShadowWrapper _xsltFileSystem;
private ShadowWrapper _masterPagesFileSystem;
private ShadowWrapper _mvcViewsFileSystem;
#region Singleton & Constructor
@@ -40,25 +34,46 @@ namespace Umbraco.Core.IO
get { return Instance; }
}
// for tests only, totally unsafe
internal void Reset()
{
_wrappers.Clear();
_providerLookup.Clear();
_filesystems.Clear();
CreateWellKnownFileSystems();
}
private IScopeProviderInternal ScopeProvider
{
// 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; }
}
internal FileSystemProviderManager()
{
_config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
CreateWellKnownFileSystems();
}
_macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials);
_partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews);
_stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css);
_scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts);
_xsltFileSystem = new PhysicalFileSystem(SystemDirectories.Xslt);
_masterPagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
_mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
private void CreateWellKnownFileSystems()
{
var macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials);
var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews);
var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css);
var scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts);
var xsltFileSystem = new PhysicalFileSystem(SystemDirectories.Xslt);
var masterPagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
var mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
_macroPartialFileSystem = _macroPartialFileSystemWrapper = new ShadowWrapper(_macroPartialFileSystem, "Views/MacroPartials");
_partialViewsFileSystem = _partialViewsFileSystemWrapper = new ShadowWrapper(_partialViewsFileSystem, "Views/Partials");
_stylesheetsFileSystem = _stylesheetsFileSystemWrapper = new ShadowWrapper(_stylesheetsFileSystem, "css");
_scriptsFileSystem = _scriptsFileSystemWrapper = new ShadowWrapper(_scriptsFileSystem, "scripts");
_xsltFileSystem = _xsltFileSystemWrapper = new ShadowWrapper(_xsltFileSystem, "xslt");
_masterPagesFileSystem = _masterPagesFileSystemWrapper = new ShadowWrapper(_masterPagesFileSystem, "masterpages");
_mvcViewsFileSystem = _mvcViewsFileSystemWrapper = new ShadowWrapper(_mvcViewsFileSystem, "Views");
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", ScopeProvider);
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", ScopeProvider);
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", ScopeProvider);
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", ScopeProvider);
_xsltFileSystem = new ShadowWrapper(xsltFileSystem, "xslt", ScopeProvider);
_masterPagesFileSystem = new ShadowWrapper(masterPagesFileSystem, "masterpages", ScopeProvider);
_mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", ScopeProvider);
// filesystems obtained from GetFileSystemProvider are already wrapped and do not need to be wrapped again
MediaFileSystem = GetFileSystemProvider<MediaFileSystem>();
@@ -73,7 +88,7 @@ namespace Umbraco.Core.IO
public IFileSystem2 StylesheetsFileSystem { get { return _stylesheetsFileSystem; } }
public IFileSystem2 ScriptsFileSystem { get { return _scriptsFileSystem; } }
public IFileSystem2 XsltFileSystem { get { return _xsltFileSystem; } }
public IFileSystem2 MasterPagesFileSystem { get { return _masterPagesFileSystem; } }
public IFileSystem2 MasterPagesFileSystem { get { return _mvcViewsFileSystem; } }
public IFileSystem2 MvcViewsFileSystem { get { return _mvcViewsFileSystem; } }
public MediaFileSystem MediaFileSystem { get; private set; }
@@ -91,56 +106,74 @@ namespace Umbraco.Core.IO
//public string ProviderAlias { get; set; }
}
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
private readonly ConcurrentDictionary<Type, string> _aliases = new ConcurrentDictionary<Type, string>();
/// <summary>
/// Gets an underlying (non-typed) filesystem supporting a strongly-typed filesystem.
/// </summary>
/// <param name="alias">The alias of the strongly-typed filesystem.</param>
/// <returns>The non-typed filesystem supporting the strongly-typed filesystem with the specified alias.</returns>
/// <remarks>This method should not be used directly, used <see cref="GetFileSystemProvider{TFileSystem}"/> instead.</remarks>
/// <remarks>This method should not be used directly, used <see cref="GetFileSystemProvider{TFileSystem}()"/> instead.</remarks>
public IFileSystem GetUnderlyingFileSystemProvider(string alias)
{
return GetUnderlyingFileSystemProvider(alias, null);
}
/// <summary>
/// Gets an underlying (non-typed) filesystem supporting a strongly-typed filesystem.
/// </summary>
/// <param name="alias">The alias of the strongly-typed filesystem.</param>
/// /// <param name="fallback">A fallback creator for the filesystem.</param>
/// <returns>The non-typed filesystem supporting the strongly-typed filesystem with the specified alias.</returns>
/// <remarks>This method should not be used directly, used <see cref="GetFileSystemProvider{TFileSystem}()"/> instead.</remarks>
private IFileSystem GetUnderlyingFileSystemProvider(string alias, Func<IFileSystem> fallback)
{
// either get the constructor info from cache or create it and add to cache
var ctorInfo = _providerLookup.GetOrAdd(alias, s =>
{
// get config
var providerConfig = _config.Providers[s];
if (providerConfig == null)
throw new ArgumentException(string.Format("No provider found with alias {0}.", s));
var ctorInfo = _providerLookup.GetOrAdd(alias, _ => GetUnderlyingFileSystemCtor(alias, fallback));
return ctorInfo == null ? fallback() : (IFileSystem) ctorInfo.Constructor.Invoke(ctorInfo.Parameters);
}
// get the filesystem type
var providerType = Type.GetType(providerConfig.Type);
if (providerType == null)
throw new InvalidOperationException(string.Format("Could not find type {0}.", providerConfig.Type));
private IFileSystem GetUnderlyingFileSystemNoCache(string alias, Func<IFileSystem> fallback)
{
var ctorInfo = GetUnderlyingFileSystemCtor(alias, fallback);
return ctorInfo == null ? fallback() : (IFileSystem) ctorInfo.Constructor.Invoke(ctorInfo.Parameters);
}
// ensure it implements IFileSystem
if (providerType.IsAssignableFrom(typeof (IFileSystem)))
throw new InvalidOperationException(string.Format("Type {0} does not implement IFileSystem.", providerType.FullName));
private ProviderConstructionInfo GetUnderlyingFileSystemCtor(string alias, Func<IFileSystem> fallback)
{
// get config
var providerConfig = _config.Providers[alias];
if (providerConfig == null)
{
if (fallback != null) return null;
throw new ArgumentException(string.Format("No provider found with alias {0}.", alias));
}
// find a ctor matching the config parameters
var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
var constructor = providerType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
if (constructor == null)
throw new InvalidOperationException(string.Format("Type {0} has no ctor matching the {1} configuration parameter(s).", providerType.FullName, paramCount));
// get the filesystem type
var providerType = Type.GetType(providerConfig.Type);
if (providerType == null)
throw new InvalidOperationException(string.Format("Could not find type {0}.", providerConfig.Type));
var parameters = new object[paramCount];
if (providerConfig.Parameters != null) // keeps ReSharper happy
for (var i = 0; i < paramCount; i++)
parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
// ensure it implements IFileSystem
if (providerType.IsAssignableFrom(typeof(IFileSystem)))
throw new InvalidOperationException(string.Format("Type {0} does not implement IFileSystem.", providerType.FullName));
return new ProviderConstructionInfo
{
Constructor = constructor,
Parameters = parameters,
//ProviderAlias = s
};
});
// find a ctor matching the config parameters
var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
var constructor = providerType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
if (constructor == null)
throw new InvalidOperationException(string.Format("Type {0} has no ctor matching the {1} configuration parameter(s).", providerType.FullName, paramCount));
// create the fs and return
return (IFileSystem) ctorInfo.Constructor.Invoke(ctorInfo.Parameters);
var parameters = new object[paramCount];
if (providerConfig.Parameters != null) // keeps ReSharper happy
for (var i = 0; i < paramCount; i++)
parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
return new ProviderConstructionInfo
{
Constructor = constructor,
Parameters = parameters,
//ProviderAlias = s
};
}
/// <summary>
@@ -148,92 +181,111 @@ namespace Umbraco.Core.IO
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <returns>A strongly-typed filesystem of the specified type.</returns>
/// <remarks>
/// <para>Ideally, this should cache the instances, but that would break backward compatibility, so we
/// only do it for our own MediaFileSystem - for everything else, it's the responsibility of the caller
/// to ensure that they maintain singletons. This is important for singletons, as each filesystem maintains
/// its own shadow and having multiple instances would lead to inconsistencies.</para>
/// <para>Note that any filesystem created by this method *after* shadowing begins, will *not* be
/// shadowing (and an exception will be thrown by the ShadowWrapper).</para>
/// </remarks>
public TFileSystem GetFileSystemProvider<TFileSystem>()
where TFileSystem : FileSystemWrapper
where TFileSystem : FileSystemWrapper
{
// deal with known types - avoid infinite loops!
if (typeof(TFileSystem) == typeof(MediaFileSystem) && MediaFileSystem != null)
return MediaFileSystem as TFileSystem; // else create and return
return GetFileSystemProvider<TFileSystem>(null);
}
// get/cache the alias for the filesystem type
var alias = _aliases.GetOrAdd(typeof (TFileSystem), fsType =>
{
// validate the ctor
var constructor = fsType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == 1 && TypeHelper.IsTypeAssignableFrom<IFileSystem>(x.GetParameters().Single().ParameterType));
if (constructor == null)
throw new InvalidOperationException("Type " + fsType.FullName + " must inherit from FileSystemWrapper and have a constructor that accepts one parameter of type " + typeof(IFileSystem).FullName + ".");
/// <summary>
/// Gets a strongly-typed filesystem.
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <param name="fallback">A fallback creator for the inner filesystem.</param>
/// <returns>A strongly-typed filesystem of the specified type.</returns>
/// <remarks>
/// <para>The fallback creator is used only if nothing is configured.</para>
/// <para>Ideally, this should cache the instances, but that would break backward compatibility, so we
/// only do it for our own MediaFileSystem - for everything else, it's the responsibility of the caller
/// to ensure that they maintain singletons. This is important for singletons, as each filesystem maintains
/// its own shadow and having multiple instances would lead to inconsistencies.</para>
/// <para>Note that any filesystem created by this method *after* shadowing begins, will *not* be
/// shadowing (and an exception will be thrown by the ShadowWrapper).</para>
/// </remarks>
public TFileSystem GetFileSystemProvider<TFileSystem>(Func<IFileSystem> fallback)
where TFileSystem : FileSystemWrapper
{
var alias = GetFileSystemAlias<TFileSystem>();
return (TFileSystem) _filesystems.GetOrAdd(alias, _ =>
{
// gets the inner fs, create the strongly-typed fs wrapping the inner fs, register & return
// so we are double-wrapping here
// could be optimized by having FileSystemWrapper inherit from ShadowWrapper, maybe
var innerFs = GetUnderlyingFileSystemNoCache(alias, fallback);
var shadowWrapper = new ShadowWrapper(innerFs, "typed/" + alias, ScopeProvider);
var fs = (IFileSystem2) Activator.CreateInstance(typeof (TFileSystem), shadowWrapper);
_wrappers.Add(shadowWrapper); // keeping a reference to the wrapper
return fs;
});
}
// find the attribute and get the alias
var attr = (FileSystemProviderAttribute) fsType.GetCustomAttributes(typeof(FileSystemProviderAttribute), false).SingleOrDefault();
if (attr == null)
throw new InvalidOperationException("Type " + fsType.FullName + "is missing the required FileSystemProviderAttribute.");
private string GetFileSystemAlias<TFileSystem>()
{
var fsType = typeof(TFileSystem);
return attr.Alias;
});
// validate the ctor
var constructor = fsType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == 1 && TypeHelper.IsTypeAssignableFrom<IFileSystem>(x.GetParameters().Single().ParameterType));
if (constructor == null)
throw new InvalidOperationException("Type " + fsType.FullName + " must inherit from FileSystemWrapper and have a constructor that accepts one parameter of type " + typeof(IFileSystem).FullName + ".");
// gets the inner fs, create the strongly-typed fs wrapping the inner fs, register & return
// so we are double-wrapping here
// could be optimized by having FileSystemWrapper inherit from ShadowWrapper, maybe
var innerFs = GetUnderlyingFileSystemProvider(alias);
var shadowWrapper = new ShadowWrapper(innerFs, "typed/" + alias);
var fs = (TFileSystem) Activator.CreateInstance(typeof (TFileSystem), innerFs);
_wrappers.Add(shadowWrapper); // keeping a weak reference to the wrapper
return fs;
// find the attribute and get the alias
var attr = (FileSystemProviderAttribute)fsType.GetCustomAttributes(typeof(FileSystemProviderAttribute), false).SingleOrDefault();
if (attr == null)
throw new InvalidOperationException("Type " + fsType.FullName + "is missing the required FileSystemProviderAttribute.");
return attr.Alias;
}
#endregion
#region Shadow
// note
// shadowing is thread-safe, but entering and exiting shadow mode is not, and there is only one
// global shadow for the entire application, so great care should be taken to ensure that the
// application is *not* doing anything else when using a shadow.
// shadow applies to well-known filesystems *only* - at the moment, any other filesystem that would
// be created directly (via ctor) or via GetFileSystemProvider<T> is *not* shadowed.
// shadow must be enabled in an app event handler before anything else ie before any filesystem
// is actually created and used - after, it is too late - enabling shadow has a neglictible perfs
// impact.
// NO! by the time an app event handler is instanciated it is already too late, see note in ctor.
//internal void EnableShadow()
//{
// if (_mvcViewsFileSystem != null) // test one of the fs...
// throw new InvalidOperationException("Cannot enable shadow once filesystems have been created.");
// _shadowEnabled = true;
//}
public ICompletable Shadow(Guid id)
internal ICompletable Shadow(Guid id)
{
var typed = _wrappers.ToArray();
var wrappers = new ShadowWrapper[typed.Length + 7];
var i = 0;
while (i < typed.Length) wrappers[i] = typed[i++];
wrappers[i++] = _macroPartialFileSystemWrapper;
wrappers[i++] = _partialViewsFileSystemWrapper;
wrappers[i++] = _stylesheetsFileSystemWrapper;
wrappers[i++] = _scriptsFileSystemWrapper;
wrappers[i++] = _xsltFileSystemWrapper;
wrappers[i++] = _masterPagesFileSystemWrapper;
wrappers[i] = _mvcViewsFileSystemWrapper;
wrappers[i++] = _macroPartialFileSystem;
wrappers[i++] = _partialViewsFileSystem;
wrappers[i++] = _stylesheetsFileSystem;
wrappers[i++] = _scriptsFileSystem;
wrappers[i++] = _xsltFileSystem;
wrappers[i++] = _masterPagesFileSystem;
wrappers[i] = _mvcViewsFileSystem;
return ShadowFileSystemsScope.CreateScope(id, wrappers);
return new ShadowFileSystems(id, wrappers);
}
#endregion
private class WeakSet<T>
private class ConcurrentSet<T>
where T : class
{
private readonly HashSet<WeakReference<T>> _set = new HashSet<WeakReference<T>>();
private readonly HashSet<T> _set = new HashSet<T>();
public void Add(T item)
{
lock (_set)
{
_set.Add(new WeakReference<T>(item));
CollectLocked();
_set.Add(item);
}
}
public void Clear()
{
lock (_set)
{
_set.Clear();
}
}
@@ -241,23 +293,9 @@ namespace Umbraco.Core.IO
{
lock (_set)
{
CollectLocked();
return _set.Select(x =>
{
T target;
return x.TryGetTarget(out target) ? target : null;
}).WhereNotNull().ToArray();
return _set.ToArray();
}
}
private void CollectLocked()
{
_set.RemoveWhere(x =>
{
T target;
return x.TryGetTarget(out target) == false;
});
}
}
}
}
+19
View File
@@ -109,5 +109,24 @@ namespace Umbraco.Core.IO
var wrapped2 = Wrapped as IFileSystem2;
return wrapped2 == null ? Wrapped.GetSize(path) : wrapped2.GetSize(path);
}
// explicitely implementing - not breaking
bool IFileSystem2.CanAddPhysical
{
get
{
var wrapped2 = Wrapped as IFileSystem2;
return wrapped2 != null && wrapped2.CanAddPhysical;
}
}
// explicitely implementing - not breaking
void IFileSystem2.AddFile(string path, string physicalPath, bool overrideIfExists, bool copy)
{
var wrapped2 = Wrapped as IFileSystem2;
if (wrapped2 == null)
throw new NotSupportedException();
wrapped2.AddFile(path, physicalPath, overrideIfExists, copy);
}
}
}
+4
View File
@@ -44,6 +44,10 @@ namespace Umbraco.Core.IO
{
long GetSize(string path);
bool CanAddPhysical { get; }
void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false);
// TODO: implement these
//
//void CreateDirectory(string path);
+50 -3
View File
@@ -4,11 +4,11 @@ using System.Globalization;
using System.Reflection;
using System.IO;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Text.RegularExpressions;
using System.Web.Hosting;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
namespace Umbraco.Core.IO
{
@@ -351,7 +351,54 @@ namespace Umbraco.Core.IO
writer.Write(contents);
}
}
}
}
/// <summary>
/// Checks if a given path is a full path including drive letter
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
// From: http://stackoverflow.com/a/35046453/5018
internal static bool IsFullPath(this string path)
{
return string.IsNullOrWhiteSpace(path) == false
&& path.IndexOfAny(Path.GetInvalidPathChars().ToArray()) == -1
&& Path.IsPathRooted(path)
&& Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) == false;
}
/// <summary>
/// Get properly formatted relative path from an existing absolute or relative path
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
internal static string GetRelativePath(this string path)
{
if (path.IsFullPath())
{
var rootDirectory = GetRootDirectorySafe();
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
path = relativePath;
}
return path.EnsurePathIsApplicationRootPrefixed();
}
/// <summary>
/// Ensures that a path has `~/` as prefix
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
internal static string EnsurePathIsApplicationRootPrefixed(this string path)
{
if (path.StartsWith("~/"))
return path;
if (path.StartsWith("/") == false && path.StartsWith("\\") == false)
path = string.Format("/{0}", path);
if (path.StartsWith("~") == false)
path = string.Format("~{0}", path);
return path;
}
}
}
+43 -6
View File
@@ -7,6 +7,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -24,6 +25,7 @@ namespace Umbraco.Core.IO
{
private readonly IContentSection _contentConfig;
private readonly UploadAutoFillProperties _uploadAutoFillProperties;
private readonly ILogger _logger;
private readonly object _folderCounterLock = new object();
private long _folderCounter;
@@ -42,6 +44,7 @@ namespace Umbraco.Core.IO
public MediaFileSystem(IFileSystem wrapped, IContentSection contentConfig, ILogger logger)
: base(wrapped)
{
_logger = logger;
_contentConfig = contentConfig;
_uploadAutoFillProperties = new UploadAutoFillProperties(this, logger, contentConfig);
}
@@ -99,7 +102,7 @@ namespace Umbraco.Core.IO
}
else
{
// new scheme: path is "<cuid>-<puid>/<filename>" OR "<cuid>-<puid>-<filename>"
// new scheme: path is "<xuid>/<filename>" where xuid is a combination of cuid and puid
// default media filesystem maps to "~/media/<filepath>"
// assumes that cuid and puid keys can be trusted - and that a single property type
// for a single content cannot store two different files with the same name
@@ -299,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);
@@ -435,6 +438,43 @@ namespace Umbraco.Core.IO
}
}
public void DeleteMediaFiles(IEnumerable<string> files)
{
files = files.Distinct();
Parallel.ForEach(files, file =>
{
try
{
if (file.IsNullOrWhiteSpace()) return;
if (FileExists(file) == false) return;
DeleteFile(file, true);
if (UseTheNewMediaPathScheme == false)
{
// old scheme: filepath is "<int>/<filename>" OR "<int>-<filename>"
// remove the directory if any
var dir = Path.GetDirectoryName(file);
if (string.IsNullOrWhiteSpace(dir) == false)
DeleteDirectory(dir, true);
}
else
{
// new scheme: path is "<xuid>/<filename>" where xuid is a combination of cuid and puid
// remove the directory
var dir = Path.GetDirectoryName(file);
DeleteDirectory(dir, true);
}
}
catch (Exception e)
{
_logger.Error<MediaFileSystem>("Failed to delete attached file \"" + file + "\".", e);
}
});
}
#endregion
#region GenerateThumbnails
@@ -488,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);
@@ -597,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();
+29 -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?
@@ -364,6 +368,29 @@ namespace Umbraco.Core.IO
return file.Exists ? file.Length : -1;
}
public bool CanAddPhysical { get { return true; } }
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
{
var fullPath = GetFullPath(path);
if (File.Exists(fullPath))
{
if (overrideIfExists == false)
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
File.Delete(fullPath);
}
var directory = Path.GetDirectoryName(fullPath);
if (directory == null) throw new InvalidOperationException("Could not get directory.");
Directory.CreateDirectory(directory); // ensure it exists
if (copy)
File.Copy(physicalPath, fullPath);
else
File.Move(physicalPath, fullPath);
}
#region Helper Methods
protected virtual void EnsureDirectory(string path)
+82 -11
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Umbraco.Core.IO
{
@@ -33,8 +34,16 @@ namespace Umbraco.Core.IO
{
try
{
using (var stream = _sfs.OpenFile(kvp.Key))
_fs.AddFile(kvp.Key, stream, true);
var fs2 = _fs as IFileSystem2;
if (fs2 != null && fs2.CanAddPhysical)
{
fs2.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)); // overwrite, move
}
else
{
using (var stream = _sfs.OpenFile(kvp.Key))
_fs.AddFile(kvp.Key, stream, true);
}
}
catch (Exception e)
{
@@ -201,19 +210,20 @@ namespace Umbraco.Core.IO
public IEnumerable<string> GetFiles(string path)
{
var normPath = NormPath(path);
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
var files = _fs.GetFiles(path);
return files
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
.Select(kvp => kvp.Key))
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist).Select(kvp => kvp.Key))
.Distinct();
return GetFiles(path, null);
}
public IEnumerable<string> GetFiles(string path, string filter)
{
return _fs.GetFiles(path, filter);
var normPath = NormPath(path);
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
var files = filter != null ? _fs.GetFiles(path, filter) : _fs.GetFiles(path);
var regexFilter = FilterToRegex(filter);
return files
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
.Select(kvp => kvp.Key))
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist && FilterByRegex(kvp.Key, regexFilter)).Select(kvp => kvp.Key))
.Distinct();
}
public Stream OpenFile(string path)
@@ -245,6 +255,9 @@ namespace Umbraco.Core.IO
public string GetFullPath(string path)
{
ShadowNode sf;
if (Nodes.TryGetValue(NormPath(path), out sf))
return sf.IsDir || sf.IsDelete ? null : _sfs.GetFullPath(path);
return _fs.GetFullPath(path);
}
@@ -282,5 +295,63 @@ namespace Umbraco.Core.IO
if (sf.IsDelete || sf.IsDir) throw new InvalidOperationException("Invalid path.");
return _sfs.GetSize(path);
}
public bool CanAddPhysical { get { return true; } }
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
{
ShadowNode sf;
var normPath = NormPath(path);
if (Nodes.TryGetValue(normPath, out sf) && sf.IsExist && (sf.IsDir || overrideIfExists == false))
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
var parts = normPath.Split('/');
for (var i = 0; i < parts.Length - 1; i++)
{
var dirPath = string.Join("/", parts.Take(i + 1));
ShadowNode sd;
if (Nodes.TryGetValue(dirPath, out sd))
{
if (sd.IsFile) throw new InvalidOperationException("Invalid path.");
if (sd.IsDelete) Nodes[dirPath] = new ShadowNode(false, true);
}
else
{
if (_fs.DirectoryExists(dirPath)) continue;
if (_fs.FileExists(dirPath)) throw new InvalidOperationException("Invalid path.");
Nodes[dirPath] = new ShadowNode(false, true);
}
}
_sfs.AddFile(path, physicalPath, overrideIfExists, copy);
Nodes[normPath] = new ShadowNode(false, false);
}
/// <summary>
/// Helper function for filtering keys by Regex if a filter is specified.
/// </summary>
/// <param name="input"></param>
/// <param name="regexFilter"></param>
/// <returns></returns>
internal static bool FilterByRegex(string input, string regexFilter)
{
if (regexFilter == null) return true;
return regexFilter != string.Empty && Regex.IsMatch(input, regexFilter);
}
/// <summary>
/// Transforms a filter pattern into a Regex pattern
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
/// <remarks>
/// Appending '$' only if not containing wildcard is stupid and broken.
/// It is however what seems to be what they're doing in .NET so we need to match the functionality.
/// </remarks>
internal static string FilterToRegex(string pattern)
{
if (pattern == null) return null;
return "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + (pattern.Contains("*") ? string.Empty : "$");
}
}
}
+73
View File
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging;
namespace Umbraco.Core.IO
{
internal class ShadowFileSystems : ICompletable
{
// note: taking a reference to the _manager instead of using manager.Current
// to avoid using Current everywhere but really, we support only 1 scope at
// a time, not multiple scopes in case of multiple managers (not supported)
private static readonly object Locker = new object();
private static Guid _currentId = Guid.Empty;
private readonly Guid _id;
private readonly ShadowWrapper[] _wrappers;
private bool _completed;
public ShadowFileSystems(Guid id, ShadowWrapper[] wrappers)
{
lock (Locker)
{
if (_currentId != Guid.Empty)
throw new InvalidOperationException("Already shadowing.");
_currentId = id;
LogHelper.Debug<ShadowFileSystems>("Shadow " + id + ".");
_id = id;
_wrappers = wrappers;
foreach (var wrapper in _wrappers)
wrapper.Shadow(id);
}
}
public void Complete()
{
_completed = true;
}
public void Dispose()
{
lock (Locker)
{
LogHelper.Debug<ShadowFileSystems>("UnShadow " + _id + " (" + (_completed ? "complete" : "abort") + ").");
var exceptions = new List<Exception>();
foreach (var wrapper in _wrappers)
{
try
{
// this may throw an AggregateException if some of the changes could not be applied
wrapper.UnShadow(_completed);
}
catch (AggregateException ae)
{
exceptions.Add(ae);
}
}
_currentId = Guid.Empty;
if (exceptions.Count > 0)
throw new AggregateException(_completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions);
}
}
// for tests
internal static void ResetId()
{
_currentId = Guid.Empty;
}
}
}
@@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using Umbraco.Core.Logging;
namespace Umbraco.Core.IO
{
internal class ShadowFileSystemsScope : ICompletable
{
// note: taking a reference to the _manager instead of using manager.Current
// to avoid using Current everywhere but really, we support only 1 scope at
// a time, not multiple scopes in case of multiple managers (not supported)
private const string ItemKey = "Umbraco.Core.IO.ShadowFileSystemsScope";
private static readonly object Locker = new object();
private readonly Guid _id;
private readonly ShadowWrapper[] _wrappers;
static ShadowFileSystemsScope()
{
SafeCallContext.Register(
() =>
{
var scope = CallContext.LogicalGetData(ItemKey);
CallContext.FreeNamedDataSlot(ItemKey);
return scope;
},
o =>
{
if (CallContext.LogicalGetData(ItemKey) != null) throw new InvalidOperationException();
if (o != null) CallContext.LogicalSetData(ItemKey, o);
});
}
private ShadowFileSystemsScope(Guid id, ShadowWrapper[] wrappers)
{
LogHelper.Debug<ShadowFileSystemsScope>("Shadow " + id + ".");
_id = id;
_wrappers = wrappers;
foreach (var wrapper in _wrappers)
wrapper.Shadow(id);
}
// internal for tests + FileSystemProviderManager
// do NOT use otherwise
internal static ShadowFileSystemsScope CreateScope(Guid id, ShadowWrapper[] wrappers)
{
lock (Locker)
{
if (CallContext.LogicalGetData(ItemKey) != null) throw new InvalidOperationException("Already shadowing.");
CallContext.LogicalSetData(ItemKey, ItemKey); // value does not matter
}
return new ShadowFileSystemsScope(id, wrappers);
}
internal static bool InScope
{
get { return NoScope == false; }
}
internal static bool NoScope
{
get { return CallContext.LogicalGetData(ItemKey) == null; }
}
public void Complete()
{
lock (Locker)
{
LogHelper.Debug<ShadowFileSystemsScope>("UnShadow " + _id + " (complete).");
var exceptions = new List<Exception>();
foreach (var wrapper in _wrappers)
{
try
{
// this may throw an AggregateException if some of the changes could not be applied
wrapper.UnShadow(true);
}
catch (AggregateException ae)
{
exceptions.Add(ae);
}
}
if (exceptions.Count > 0)
throw new AggregateException("Failed to apply all changes (see exceptions).", exceptions);
// last, & *only* if successful (otherwise we'll unshadow & cleanup as best as we can)
CallContext.FreeNamedDataSlot(ItemKey);
}
}
public void Dispose()
{
lock (Locker)
{
if (CallContext.LogicalGetData(ItemKey) == null) return;
try
{
LogHelper.Debug<ShadowFileSystemsScope>("UnShadow " + _id + " (abort)");
foreach (var wrapper in _wrappers)
wrapper.UnShadow(false); // should not throw
}
finally
{
// last, & always
CallContext.FreeNamedDataSlot(ItemKey);
}
}
}
}
}
+35 -3
View File
@@ -2,20 +2,23 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.IO
{
internal class ShadowWrapper : IFileSystem2
{
private readonly IScopeProviderInternal _scopeProvider;
private readonly IFileSystem _innerFileSystem;
private readonly string _shadowPath;
private ShadowFileSystem _shadowFileSystem;
private string _shadowDir;
public ShadowWrapper(IFileSystem innerFileSystem, string shadowPath)
public ShadowWrapper(IFileSystem innerFileSystem, string shadowPath, IScopeProviderInternal scopeProvider)
{
_innerFileSystem = innerFileSystem;
_shadowPath = shadowPath;
_scopeProvider = scopeProvider;
}
internal void Shadow(Guid id)
@@ -24,7 +27,7 @@ namespace Umbraco.Core.IO
// on ShadowFileSystemsScope.None - and if None is false then we should be running
// in a single thread anyways
var virt = "~/App_Data/Shadow/" + id + "/" + _shadowPath;
var virt = "~/App_Data/TEMP/ShadowFs/" + id + "/" + _shadowPath;
_shadowDir = IOHelper.MapPath(virt);
Directory.CreateDirectory(_shadowDir);
var tempfs = new PhysicalFileSystem(virt);
@@ -62,7 +65,19 @@ namespace Umbraco.Core.IO
private IFileSystem FileSystem
{
get { return ShadowFileSystemsScope.NoScope ? _innerFileSystem : _shadowFileSystem; }
get
{
var isScoped = _scopeProvider != null && _scopeProvider.AmbientScope != null && _scopeProvider.AmbientScope.ScopedFileSystems;
// if the filesystem is created *after* shadowing starts, it won't be shadowing
// better not ignore that situation and raised a meaningful (?) exception
if (isScoped && _shadowFileSystem == null)
throw new Exception("The filesystems are shadowing, but this filesystem is not.");
return isScoped
? _shadowFileSystem
: _innerFileSystem;
}
}
public IEnumerable<string> GetDirectories(string path)
@@ -154,5 +169,22 @@ namespace Umbraco.Core.IO
var filesystem2 = filesystem as IFileSystem2;
return filesystem2 == null ? filesystem.GetSize(path) : filesystem2.GetSize(path);
}
public bool CanAddPhysical
{
get
{
var fileSystem2 = FileSystem as IFileSystem2;
return fileSystem2 != null && fileSystem2.CanAddPhysical;
}
}
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
{
var fileSystem2 = FileSystem as IFileSystem2;
if (fileSystem2 == null)
throw new NotSupportedException();
fileSystem2.AddFile(path, physicalPath, overrideIfExists, copy);
}
}
}
+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;
+13 -14
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>
@@ -400,7 +399,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Set property values by alias with an annonymous object
/// </summary>
public static void PropertyValues(this IContent content, object value)
public static void PropertyValues(this IContentBase content, object value)
{
if (value == null)
throw new Exception("No properties has been passed in");
@@ -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,44 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
internal static class ContentTypeExtensions
{
/// <summary>
/// Get all descendant content types
/// </summary>
/// <param name="contentType"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType)
{
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
.SelectRecursive(type => contentTypeService.GetContentTypeChildren(type.Id));
return descendants;
}
/// <summary>
/// Get all descendant and self content types
/// </summary>
/// <param name="contentType"></param>
/// <returns></returns>
public static IEnumerable<IContentTypeBase> DescendantsAndSelf(this IContentTypeBase contentType)
{
var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants());
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);
//}
}
}
@@ -13,6 +13,7 @@ namespace Umbraco.Core.Models.Identity
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
config.CreateMap<IUser, BackOfficeIdentityUser>()
.ForMember(user => user.LastLoginDateUtc, expression => expression.MapFrom(user => user.LastLoginDate.ToUniversalTime()))
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
.ForMember(user => user.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null))
@@ -24,12 +24,17 @@ namespace Umbraco.Core.Models.Identity
///
/// </summary>
public IdentityUser()
{
{
this.Claims = new List<TClaim>();
this.Roles = new List<TRole>();
this.Logins = new List<TLogin>();
}
/// <summary>
/// Last login date
/// </summary>
public virtual DateTime? LastLoginDateUtc { get; set; }
/// <summary>
/// Email
///
@@ -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
{

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