Compare commits

...

191 Commits

Author SHA1 Message Date
Warren Buckley 5218d31f23 Bumps version to alpha-072 2017-03-07 15:43:29 +00: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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Emil Wangaa d747cf69c3 Fixes typo in comment 2017-02-21 08:23:21 +01: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 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
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
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 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
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
Mads Rasmussen 7c049b55a8 media picker - search media library instead of filter current folder 2017-02-13 14:36:39 +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
Shannon d554417fde U4-9517 BackOfficeSignInManager doesn't automatically keep LastLoginDate set on users 2017-02-13 16:47:04 +11: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
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
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
Arnold Visser 7da7c1e5a1 Addes all new/missing fields since last edit
Checked against the English version
2017-02-09 13:47:31 +01: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 122295c89f Sets MacroPicker aka MacroContainer as deperecated 2017-02-07 13:55:49 +00: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 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
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 db86f6e1ee Fixes up issues reported on review and adds a null check 2017-02-03 11:49:22 +11:00
Shannon a03e0dfb53 Fixes tests 2017-02-02 22:21:36 +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 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 8d598cd37c Gets EntityController working with UDIs, INT and GUID for GetByIds 2017-01-30 20:40:45 +11:00
Shannon 30c2f95844 Merge branch 'refs/heads/dev-v7.6' into temp-U4-9310 2017-01-30 16:55:38 +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 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
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
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
261 changed files with 6171 additions and 2101 deletions
+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
alpha063
alpha072
+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-alpha063")]
[assembly: AssemblyInformationalVersion("7.6.0-alpha072")]
@@ -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;
}
}
}
@@ -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
{
@@ -306,6 +312,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return DefaultDocumentTypeProperty; }
}
bool IContentSection.ShowDeprecatedPropertyEditors
{
get { return ShowDeprecatedPropertyEditors; }
}
bool IContentSection.EnableInheritedDocumentTypes
{
get { return EnableInheritedDocumentTypes; }
@@ -60,6 +60,12 @@ 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; }
@@ -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 "alpha063"; } }
public static string CurrentComment { get { return "alpha072"; } }
// 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
@@ -109,6 +109,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>
+19 -5
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.
+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);
}
}
@@ -1,8 +0,0 @@
namespace Umbraco.Core.Deploy
{
public interface IPrettyArtifact
{
string Name { get; }
string Alias { get; }
}
}
+6 -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)
{
@@ -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;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
using System.Web;
namespace Umbraco.Core
{
public interface IHttpContextAccessor
{
HttpContextBase Value { get; }
}
}
+41 -9
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Umbraco.Core.IO
{
@@ -209,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)
@@ -253,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);
}
@@ -321,5 +326,32 @@ namespace Umbraco.Core.IO
_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 : "$");
}
}
}
+1 -1
View File
@@ -27,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);
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Models
return descendants;
}
throw new NotSupportedException("The content type must be " + typeof(IContentType) + " or " + typeof(IMediaType));
//No other content types have children (i.e. member types)
return Enumerable.Empty<IContentTypeBase>();
}
/// <summary>
@@ -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
///
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Rdbms
internal class DataTypePreValueDto
{
[Column("id")]
[PrimaryKeyColumn(IdentitySeed = 6)]
[PrimaryKeyColumn(IdentitySeed = 10)]
public int Id { get; set; }
[Column("datatypeNodeId")]
@@ -15,6 +15,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("nodeId")]
[ForeignKey(typeof(NodeDto))]
[Index(IndexTypes.NonClustered, Name = "IX_umbracoUser2NodePermission_nodeId")]
public int NodeId { get; set; }
[Column("permission")]
@@ -113,6 +113,11 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// When resolved from EntityService this checks if the entity has the HasChildren flag
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public static bool HasChildren(this IUmbracoEntity entity)
{
if (entity.AdditionalData.ContainsKey("HasChildren"))
@@ -133,6 +138,11 @@ namespace Umbraco.Core.Models
return entity.AdditionalData.GetValueIgnoreCase(key, defaultVal);
}
/// <summary>
/// When resolved from EntityService this checks if the entity has the IsContainer flag
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public static bool IsContainer(this IUmbracoEntity entity)
{
if (entity.AdditionalData.ContainsKeyIgnoreCase("IsContainer") == false) return false;
+16 -2
View File
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Root
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.SystemRoot)]
[UmbracoObjectType(Constants.ObjectTypes.SystemRoot)]
[FriendlyName("Root")]
ROOT,
@@ -35,6 +35,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.Document, typeof(IContent))]
[FriendlyName("Document")]
[UmbracoUdiType(Constants.UdiEntityType.Document)]
Document,
/// <summary>
@@ -42,6 +43,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.Media, typeof(IMedia))]
[FriendlyName("Media")]
[UmbracoUdiType(Constants.UdiEntityType.Media)]
Media,
/// <summary>
@@ -49,6 +51,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.MemberType, typeof(IMemberType))]
[FriendlyName("Member Type")]
[UmbracoUdiType(Constants.UdiEntityType.MemberType)]
MemberType,
/// <summary>
@@ -56,6 +59,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.Template, typeof(ITemplate))]
[FriendlyName("Template")]
[UmbracoUdiType(Constants.UdiEntityType.Template)]
Template,
/// <summary>
@@ -63,6 +67,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.MemberGroup)]
[FriendlyName("Member Group")]
[UmbracoUdiType(Constants.UdiEntityType.MemberGroup)]
MemberGroup,
//TODO: What is a 'Content Item' supposed to be???
@@ -80,6 +85,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.MediaType, typeof(IMediaType))]
[FriendlyName("Media Type")]
[UmbracoUdiType(Constants.UdiEntityType.MediaType)]
MediaType,
/// <summary>
@@ -87,13 +93,14 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DocumentType, typeof(IContentType))]
[FriendlyName("Document Type")]
[UmbracoUdiType(Constants.UdiEntityType.DocumentType)]
DocumentType,
/// <summary>
/// Recycle Bin
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.ContentRecycleBin)]
[FriendlyName("Recycle Bin")]
[FriendlyName("Recycle Bin")]
RecycleBin,
/// <summary>
@@ -101,6 +108,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.Stylesheet)]
[FriendlyName("Stylesheet")]
[UmbracoUdiType(Constants.UdiEntityType.Stylesheet)]
Stylesheet,
/// <summary>
@@ -108,6 +116,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.Member, typeof(IMember))]
[FriendlyName("Member")]
[UmbracoUdiType(Constants.UdiEntityType.Member)]
Member,
/// <summary>
@@ -115,6 +124,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))]
[FriendlyName("Data Type")]
[UmbracoUdiType(Constants.UdiEntityType.DataType)]
DataType,
/// <summary>
@@ -122,6 +132,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DocumentTypeContainer)]
[FriendlyName("Document Type Container")]
[UmbracoUdiType(Constants.UdiEntityType.DocumentTypeContainer)]
DocumentTypeContainer,
/// <summary>
@@ -129,6 +140,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.MediaTypeContainer)]
[FriendlyName("Media Type Container")]
[UmbracoUdiType(Constants.UdiEntityType.MediaTypeContainer)]
MediaTypeContainer,
/// <summary>
@@ -136,6 +148,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DataTypeContainer)]
[FriendlyName("Data Type Container")]
[UmbracoUdiType(Constants.UdiEntityType.DataTypeContainer)]
DataTypeContainer,
/// <summary>
@@ -143,6 +156,7 @@ namespace Umbraco.Core.Models
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.RelationType)]
[FriendlyName("Relation Type")]
[UmbracoUdiType(Constants.UdiEntityType.RelationType)]
RelationType,
/// <summary>
@@ -12,6 +12,7 @@ namespace Umbraco.Core.Models
{
//MUST be concurrent to avoid thread collisions!
private static readonly ConcurrentDictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new ConcurrentDictionary<UmbracoObjectTypes, Guid>();
private static readonly ConcurrentDictionary<UmbracoObjectTypes, string> UmbracoObjectTypeUdiCache = new ConcurrentDictionary<UmbracoObjectTypes, string>();
/// <summary>
/// Get an UmbracoObjectTypes value from it's name
@@ -43,6 +44,21 @@ namespace Umbraco.Core.Models
return umbracoObjectType;
}
public static string GetUdiType(Guid guid)
{
var umbracoObjectType = Constants.UdiEntityType.Unknown;
foreach (var name in Enum.GetNames(typeof(UmbracoObjectTypes)))
{
var objType = GetUmbracoObjectType(name);
if (objType.GetGuid() == guid)
{
umbracoObjectType = GetUdiType(objType);
}
}
return umbracoObjectType;
}
/// <summary>
/// Extension method for the UmbracoObjectTypes enum to return the enum GUID
/// </summary>
@@ -68,6 +84,26 @@ namespace Umbraco.Core.Models
});
}
public static string GetUdiType(this UmbracoObjectTypes umbracoObjectType)
{
return UmbracoObjectTypeUdiCache.GetOrAdd(umbracoObjectType, types =>
{
var type = typeof(UmbracoObjectTypes);
var memInfo = type.GetMember(umbracoObjectType.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoUdiTypeAttribute),
false);
if (attributes.Length == 0)
return Constants.UdiEntityType.Unknown;
var attribute = ((UmbracoUdiTypeAttribute)attributes[0]);
if (attribute == null)
return Constants.UdiEntityType.Unknown;
return attribute.UdiType;
});
}
/// <summary>
/// Extension method for the UmbracoObjectTypes enum to return the enum name
/// </summary>
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Factories
entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty;
var publishedVersion = default(Guid);
//some content items don't have a published version
//some content items don't have a published/newest version
if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null)
{
Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion);
@@ -130,21 +130,21 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1034, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1034", SortOrder = 2, UniqueId = new Guid("a6857c73-d6e9-480c-b6e6-f15f6ad11125"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1035, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1035", SortOrder = 2, UniqueId = new Guid("93929b9a-93a2-4e2a-b239-d99334440a59"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1036, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1036", SortOrder = 2, UniqueId = new Guid("2b24165f-9782-4aa3-b459-1de4a4d21f60"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1040, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1040", SortOrder = 2, UniqueId = new Guid("21e798da-e06e-4eda-a511-ed257f78d4fa"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1045, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1045", SortOrder = 2, UniqueId = new Guid("7E3962CC-CE20-4FFC-B661-5897A894BA7E"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//New UDI pickers with newer Ids
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//TODO: We're not creating these for 7.0
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
}
@@ -246,17 +246,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 16, DataTypeId = 1034, PropertyEditorAlias = Constants.PropertyEditors.ContentPickerAlias, DbType = "Integer" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 18, DataTypeId = 1036, PropertyEditorAlias = Constants.PropertyEditors.MemberPickerAlias, DbType = "Integer" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 25, DataTypeId = 1045, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -26, DataTypeId = Constants.System.DefaultContentListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -27, DataTypeId = Constants.System.DefaultMediaListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
//New UDI pickers with newer Ids
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 26, DataTypeId = 1046, PropertyEditorAlias = Constants.PropertyEditors.ContentPicker2Alias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 27, DataTypeId = 1047, PropertyEditorAlias = Constants.PropertyEditors.MemberPicker2Alias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 28, DataTypeId = 1048, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 29, DataTypeId = 1049, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
//TODO: We're not creating these for 7.0
//_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 19, DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" });
@@ -268,10 +270,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
{
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 3, Alias = "", SortOrder = 0, DataTypeNodeId = -87, Value = ",code,undo,redo,cut,copy,mcepasteword,stylepicker,bold,italic,bullist,numlist,outdent,indent,mcelink,unlink,mceinsertanchor,mceimage,umbracomacro,mceinserttable,umbracoembed,mcecharmap,|1|1,2,3,|0|500,400|1049,|true|" });
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 4, Alias = "group", SortOrder = 0, DataTypeNodeId = 1041, Value = "default" });
//default's for MultipleMediaPickerAlias picker
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 5, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1045, Value = "1" });
//defaults for the member list
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -1, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "10" });
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "username" });
@@ -288,6 +287,9 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -7, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "desc" });
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -8, Alias = "layouts", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[" + cardLayout + "," + listLayout + "]" });
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" });
//default's for MultipleMediaPickerAlias picker
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 6, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1049, Value = "1" });
}
private void CreateUmbracoRelationTypeData()
@@ -14,14 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
public override void Up()
{
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
.Select(x => new DbIndexDefinition()
{
TableName = x.Item1,
IndexName = x.Item2,
ColumnName = x.Item3,
IsUnique = x.Item4
}).ToArray();
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
@@ -0,0 +1,34 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
{
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
public class AddIndexToUser2NodePermission : MigrationBase
{
public AddIndexToUser2NodePermission(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{ }
public override void Up()
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoUser2NodePermission_nodeId")) == false)
{
Create.Index("IX_umbracoUser2NodePermission_nodeId").OnTable("umbracoUser2NodePermission")
.OnColumn("nodeId")
.Ascending()
.WithOptions()
.NonClustered();
}
}
public override void Down()
{
Delete.Index("IX_umbracoUser2NodePermission_nodeId").OnTable("cmsMember");
}
}
}
+6 -8
View File
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Persistence
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{
sqlSelectRemoved = null;
@@ -723,10 +723,9 @@ namespace Umbraco.Core.Persistence
sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
else
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
// Look for an "ORDER BY <whatever>" clause
m = rxOrderBy.Match(sqlCount);
// Look for an "ORDER BY <whatever>" clause
m = rxOrderBy.Match(sqlCount);
if (!m.Success)
{
sqlOrderBy = null;
@@ -737,8 +736,7 @@ namespace Umbraco.Core.Persistence
sqlOrderBy = g.ToString();
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
}
return true;
return true;
}
/// <summary>
@@ -820,7 +818,7 @@ namespace Umbraco.Core.Persistence
result.CurrentPage = page;
result.ItemsPerPage = itemsPerPage;
result.TotalItems = ExecuteScalar<long>(sqlCount, args);
result.TotalPages = result.TotalItems / itemsPerPage;
result.TotalPages = result.TotalItems / itemsPerPage;
if ((result.TotalItems % itemsPerPage) != 0)
result.TotalPages++;
@@ -785,13 +785,8 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
public void ClearPublished(IContent content)
{
// race cond!
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId=@id AND published=@published", new { id = content.Id, published = true });
foreach (var documentDto in documentDtos)
{
documentDto.Published = false;
Database.Update(documentDto);
}
var sql = "UPDATE cmsDocument SET published=0 WHERE nodeId=@id AND published=1";
Database.Execute(sql, new {id = content.Id});
}
/// <summary>
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
using Umbraco.Core;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -49,6 +50,124 @@ namespace Umbraco.Core.Persistence.Repositories
#region Query Methods
public IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null)
{
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
var factory = new UmbracoEntityFactory();
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, sql =>
{
if (filter != null)
{
foreach (var filterClaus in filter.GetWhereClauses())
{
sql.Where(filterClaus.Item1, filterClaus.Item2);
}
}
}, objectTypeId);
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
var entitySql = translator.Translate();
var pagedSql = entitySql.Append(GetGroupBy(isContent, isMedia, false)).OrderBy("umbracoNode.id");
IEnumerable<IUmbracoEntity> result;
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
var ids = pagedResult.Items.Select(x => (int) x.id).InGroupsOf(2000);
var entities = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
//Now we need to merge in the property data since we need paging and we can't do this the way that the big media query was working before
foreach (var idGroup in ids)
{
var propSql = GetPropertySql(Constants.ObjectTypes.Media)
.Where("contentNodeId IN (@ids)", new {ids = idGroup})
.OrderBy("contentNodeId");
//This does NOT fetch all data into memory in a list, this will read
// over the records as a data reader, this is much better for performance and memory,
// but it means that during the reading of this data set, nothing else can be read
// from SQL server otherwise we'll get an exception.
var allPropertyData = _work.Database.Query<dynamic>(propSql);
//keep track of the current property data item being enumerated
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
var hasCurrent = false; // initially there is no enumerator.Current
try
{
//This must be sorted by node id (which is done by SQL) because this is how we are sorting the query to lookup property types above,
// which allows us to more efficiently iterate over the large data set of property values.
foreach (var entity in entities)
{
// assemble the dtos for this def
// use the available enumerator.Current if any else move to next
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
{
if (propertyDataSetEnumerator.Current.contentNodeId == entity.Id)
{
hasCurrent = false; // enumerator.Current is not available
//the property data goes into the additional data
entity.AdditionalData[propertyDataSetEnumerator.Current.propertyTypeAlias] = new UmbracoEntity.EntityProperty
{
PropertyEditorAlias = propertyDataSetEnumerator.Current.propertyEditorAlias,
Value = StringExtensions.IsNullOrWhiteSpace(propertyDataSetEnumerator.Current.dataNtext)
? propertyDataSetEnumerator.Current.dataNvarchar
: StringExtensions.ConvertToJsonIfPossible(propertyDataSetEnumerator.Current.dataNtext)
};
}
else
{
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
}
}
}
}
finally
{
propertyDataSetEnumerator.Dispose();
}
}
result = entities;
}
else
{
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
result = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
}
//The total items from the PetaPoco page query will be wrong due to the Outer join used on parent, depending on the search this will
//return duplicate results when the COUNT is used in conjuction with it, so we need to get the total on our own.
//generate a query that does not contain the LEFT Join for parent, this would cause
//the COUNT(*) query to return the wrong
var sqlCountClause = GetBaseWhere(
(isC, isM, f) => GetBase(isC, isM, f, true), //true == is a count query
isContent, isMedia, sql =>
{
if (filter != null)
{
foreach (var filterClaus in filter.GetWhereClauses())
{
sql.Where(filterClaus.Item1, filterClaus.Item2);
}
}
}, objectTypeId);
var translatorCount = new SqlTranslator<IUmbracoEntity>(sqlCountClause, query);
var countSql = translatorCount.Translate();
totalRecords = _work.Database.ExecuteScalar<int>(countSql);
return result;
}
public IUmbracoEntity GetByKey(Guid key)
{
var sql = GetBaseWhere(GetBase, false, false, key);
@@ -71,8 +190,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
//for now treat media differently
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
@@ -115,8 +233,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
//for now treat media differently
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
@@ -171,8 +288,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
//for now treat media differently
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
foreach (var entity in entities)
@@ -231,8 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
});
//treat media differently for now
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, mediaSql);
return entities;
@@ -278,11 +393,9 @@ namespace Umbraco.Core.Persistence.Repositories
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
}
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
private Sql GetPropertySql(string nodeObjectType)
{
//this will add any dataNvarchar property to the output which can be added to the additional properties
var joinSql = new Sql()
var sql = new Sql()
.Select("contentNodeId, versionId, dataNvarchar, dataNtext, propertyEditorAlias, alias as propertyTypeAlias")
.From<PropertyDataDto>()
.InnerJoin<NodeDto>()
@@ -291,7 +404,16 @@ namespace Umbraco.Core.Persistence.Repositories
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new {nodeObjectType = Constants.ObjectTypes.Media});
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new { nodeObjectType = nodeObjectType });
return sql;
}
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
{
//this will add any dataNvarchar property to the output which can be added to the additional properties
var joinSql = GetPropertySql(Constants.ObjectTypes.Media);
if (filter != null)
{
@@ -310,34 +432,52 @@ namespace Umbraco.Core.Persistence.Repositories
.OrderBy("sortOrder, id");
return wrappedSql;
}
}
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
{
var columns = new List<object>
{
"umbracoNode.id",
"umbracoNode.trashed",
"umbracoNode.parentID",
"umbracoNode.nodeUser",
"umbracoNode.level",
"umbracoNode.path",
"umbracoNode.sortOrder",
"umbracoNode.uniqueID",
"umbracoNode.text",
"umbracoNode.nodeObjectType",
"umbracoNode.createDate",
"COUNT(parent.parentID) as children"
};
return GetBase(isContent, isMedia, customFilter, false);
}
if (isContent || isMedia)
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter, bool isCount)
{
var columns = new List<object>();
if (isCount)
{
columns.Add("published.versionId as publishedVersion");
columns.Add("latest.versionId as newestVersion");
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
columns.Add("contenttype.isContainer");
columns.Add("COUNT(*)");
}
else
{
columns.AddRange(new List<object>
{
"umbracoNode.id",
"umbracoNode.trashed",
"umbracoNode.parentID",
"umbracoNode.nodeUser",
"umbracoNode.level",
"umbracoNode.path",
"umbracoNode.sortOrder",
"umbracoNode.uniqueID",
"umbracoNode.text",
"umbracoNode.nodeObjectType",
"umbracoNode.createDate",
"COUNT(parent.parentID) as children"
});
if (isContent || isMedia)
{
if (isContent)
{
//only content has this info
columns.Add("published.versionId as publishedVersion");
columns.Add("document.versionId as newestVersion");
}
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
columns.Add("contenttype.isContainer");
}
}
//Creates an SQL query to return a single row for the entity
@@ -348,17 +488,24 @@ namespace Umbraco.Core.Persistence.Repositories
if (isContent || isMedia)
{
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType")
.LeftJoin(
"(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published")
.On("umbracoNode.id = published.nodeId")
.LeftJoin(
"(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest")
.On("umbracoNode.id = latest.nodeId");
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
if (isContent)
{
//only content has this info
entitySql
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1) as published")
.On("umbracoNode.id = published.nodeId");
}
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
}
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
if (isCount == false)
{
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
}
if (customFilter != null)
{
@@ -372,22 +519,42 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = baseQuery(isContent, isMedia, filter)
.Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = nodeObjectType });
if (isContent)
{
sql.Where("document.newest = 1");
}
return sql;
}
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, int id)
{
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.id = @Id", new { Id = id })
.Append(GetGroupBy(isContent, isMedia));
.Where("umbracoNode.id = @Id", new { Id = id });
if (isContent)
{
sql.Where("document.newest = 1");
}
sql.Append(GetGroupBy(isContent, isMedia));
return sql;
}
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
{
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key })
.Append(GetGroupBy(isContent, isMedia));
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
if (isContent)
{
sql.Where("document.newest = 1");
}
sql.Append(GetGroupBy(isContent, isMedia));
return sql;
}
@@ -396,6 +563,12 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType",
new {Id = id, NodeObjectType = nodeObjectType});
if (isContent)
{
sql.Where("document.newest = 1");
}
return sql;
}
@@ -404,30 +577,39 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.uniqueID = @UniqueID AND umbracoNode.nodeObjectType = @NodeObjectType",
new { UniqueID = key, NodeObjectType = nodeObjectType });
if (isContent)
{
sql.Where("document.newest = 1");
}
return sql;
}
protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true)
{
var columns = new List<object>
{
"umbracoNode.id",
"umbracoNode.trashed",
"umbracoNode.parentID",
"umbracoNode.nodeUser",
"umbracoNode.level",
"umbracoNode.path",
"umbracoNode.sortOrder",
"umbracoNode.uniqueID",
"umbracoNode.text",
"umbracoNode.nodeObjectType",
"umbracoNode.createDate"
};
{
"umbracoNode.id",
"umbracoNode.trashed",
"umbracoNode.parentID",
"umbracoNode.nodeUser",
"umbracoNode.level",
"umbracoNode.path",
"umbracoNode.sortOrder",
"umbracoNode.uniqueID",
"umbracoNode.text",
"umbracoNode.nodeObjectType",
"umbracoNode.createDate"
};
if (isContent || isMedia)
{
columns.Add("published.versionId");
columns.Add("latest.versionId");
if (isContent)
{
columns.Add("published.versionId");
columns.Add("document.versionId");
}
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
@@ -16,6 +17,21 @@ namespace Umbraco.Core.Persistence.Repositories
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query);
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId);
/// <summary>
/// Gets paged results
/// </summary>
/// <param name="query">Query to excute</param>
/// <param name="objectTypeId"></param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter"></param>
/// <returns>An Enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null);
/// <summary>
/// Returns true if the entity exists
/// </summary>
@@ -63,6 +63,7 @@ namespace Umbraco.Core.Persistence.Repositories
FormatDeleteStatement("cmsContentVersion", "ContentId"),
FormatDeleteStatement("cmsContentXml", "nodeId"),
FormatDeleteStatement("cmsContent", "nodeId"),
//TODO: Why is this being done? We just delete this exact data in the next line
"UPDATE umbracoNode SET parentID = '" + RecycleBinId + "' WHERE trashed = '1' AND nodeObjectType = @NodeObjectType",
"DELETE FROM umbracoNode WHERE trashed = '1' AND nodeObjectType = @NodeObjectType"
};
@@ -91,14 +92,18 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
/// <summary>
/// A delete statement that will delete anything in the table specified where its PK (keyName) is found in the
/// list of umbracoNode.id that have trashed flag set
/// </summary>
/// <param name="tableName"></param>
/// <param name="keyName"></param>
/// <returns></returns>
private string FormatDeleteStatement(string tableName, string keyName)
{
//This query works with sql ce and sql server:
//DELETE FROM umbracoUser2NodeNotify WHERE umbracoUser2NodeNotify.nodeId IN
//(SELECT nodeId FROM umbracoUser2NodeNotify as TB1 INNER JOIN umbracoNode as TB2 ON TB1.nodeId = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972')
return
string.Format(
"DELETE FROM {0} WHERE {0}.{1} IN (SELECT TB1.{1} FROM {0} as TB1 INNER JOIN umbracoNode as TB2 ON TB1.{1} = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
"DELETE FROM {0} WHERE {0}.{1} IN (SELECT id FROM umbracoNode WHERE trashed = '1' AND nodeObjectType = @NodeObjectType)",
tableName, keyName);
}
@@ -73,12 +73,16 @@ namespace Umbraco.Core.Persistence.Repositories
RelationFactory factory = null;
var relationTypeId = -1;
// the ToList() here is important because we are using _relationTypeRepository and we
// cannot wait until the result is actually enumerated to do so, because that would
// mean we kinda capture the current unit of work and reuse it after it's been disposed
return dtos.Select(x =>
{
if (relationTypeId != x.RelationType)
factory = new RelationFactory(_relationTypeRepository.Get(relationTypeId = x.RelationType));
return DtoToEntity(x, factory);
});
}).ToList();
}
private static IRelation DtoToEntity(RelationDto dto, RelationFactory factory)
@@ -270,12 +270,11 @@ namespace Umbraco.Core.Persistence.Repositories
// once content has been set, "template on disk" are not "on disk" anymore
template.Content = content;
SetVirtualPath(template);
if (dto.Design == content) return;
dto.Design = content;
Database.Update(dto); // though... we don't care about the db value really??!!
SetVirtualPath(template);
}
protected override void PersistDeletedItem(ITemplate entity)
@@ -15,6 +15,7 @@ namespace Umbraco.Core.PropertyEditors
public PreValueField()
{
Validators = new List<IPropertyValidator>();
Config = new Dictionary<string, object>();
//check for an attribute and fill the values
var att = GetType().GetCustomAttribute<PreValueFieldAttribute>(false);
@@ -79,5 +80,11 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
[JsonProperty("validation", ItemConverterType = typeof(ManifestValidatorConverter))]
public List<IPropertyValidator> Validators { get; private set; }
/// <summary>
/// This allows for custom configuration to be injected into the pre-value editor
/// </summary>
[JsonProperty("config")]
public IDictionary<string, object> Config { get; set; }
}
}
@@ -38,6 +38,7 @@ namespace Umbraco.Core.PropertyEditors
IsParameterEditor = _attribute.IsParameterEditor;
Icon = _attribute.Icon;
Group = _attribute.Group;
IsDeprecated = _attribute.IsDeprecated;
}
}
@@ -90,6 +91,9 @@ namespace Umbraco.Core.PropertyEditors
get { return CreateValueEditor(); }
}
[JsonIgnore]
public bool IsDeprecated { get; internal set; }
[JsonIgnore]
IValueEditor IParameterEditor.ValueEditor
{
@@ -60,6 +60,12 @@ namespace Umbraco.Core.PropertyEditors
public string ValueType { get; set; }
public bool IsParameterEditor { get; set; }
/// <summary>
/// If set to true, this property editor will not show up in the DataType's drop down list
/// if there is not already one of them chosen for a DataType
/// </summary>
public bool IsDeprecated { get; set; }
/// <summary>
/// If this is is true than the editor will be displayed full width without a label
/// </summary>
+33 -2
View File
@@ -15,6 +15,7 @@ namespace Umbraco.Core.Scoping
private bool _disposed;
private UmbracoDatabase _database;
private EventMessages _messages;
public NoScope(ScopeProvider scopeProvider)
{
@@ -61,12 +62,42 @@ namespace Umbraco.Core.Scoping
/// <inheritdoc />
public EventMessages Messages
{
get { throw new NotSupportedException(); }
get
{
EnsureNotDisposed();
if (_messages != null) return _messages;
// see comments in Scope
var factory = ScopeLifespanMessagesFactory.Current;
if (factory == null)
{
_messages = new EventMessages();
}
else
{
_messages = factory.GetFromHttpContext();
if (_messages == null)
factory.Set(_messages = new EventMessages());
}
return _messages;
}
}
public EventMessages MessagesOrNull
{
get { throw new NotSupportedException(); }
get
{
EnsureNotDisposed();
// see comments in Scope
if (_messages != null) return _messages;
var factory = ScopeLifespanMessagesFactory.Current;
return factory == null ? null : factory.GetFromHttpContext();
}
}
/// <inheritdoc />
+33 -8
View File
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Scoping
private IsolatedRuntimeCache _isolatedRuntimeCache;
private UmbracoDatabase _database;
private EventMessages _messages;
private ICompletable _fscope;
private IEventDispatcher _eventDispatcher;
@@ -127,6 +128,7 @@ namespace Umbraco.Core.Scoping
{
// steal everything from NoScope
_database = noScope.DatabaseOrNull;
_messages = noScope.MessagesOrNull;
// make sure the NoScope can be replaced ie not in a transaction
if (_database != null && _database.InTransaction)
@@ -271,11 +273,27 @@ namespace Umbraco.Core.Scoping
{
EnsureNotDisposed();
if (ParentScope != null) return ParentScope.Messages;
//return _messages ?? (_messages = new EventMessages());
// ok, this isn't pretty, but it works
// TODO kill the message factory and let the scope manage it all
return ApplicationContext.Current.Services.EventMessagesFactory.Get();
if (_messages != null) return _messages;
// this is ugly - in v7 for backward compatibility reasons, EventMessages need
// to survive way longer that the scopes, and kinda resides on its own in http
// context, but must also be in scopes for when we do async and lose http context
// TODO refactor in v8
var factory = ScopeLifespanMessagesFactory.Current;
if (factory == null)
{
_messages = new EventMessages();
}
else
{
_messages = factory.GetFromHttpContext();
if (_messages == null)
factory.Set(_messages = new EventMessages());
}
return _messages;
}
}
@@ -284,7 +302,14 @@ namespace Umbraco.Core.Scoping
get
{
EnsureNotDisposed();
return ParentScope == null ? null : ParentScope.MessagesOrNull;
if (ParentScope != null) return ParentScope.MessagesOrNull;
// see comments in Messages
if (_messages != null) return _messages;
var factory = ScopeLifespanMessagesFactory.Current;
return factory == null ? null : factory.GetFromHttpContext();
}
}
@@ -343,13 +368,13 @@ namespace Umbraco.Core.Scoping
#endif
}
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
#if DEBUG_SCOPES
_scopeProvider.Disposed(this);
#endif
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
if (parent != null)
parent.ChildCompleted(_completed);
else
+38 -9
View File
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Events;
using Umbraco.Core.Persistence;
@@ -99,18 +100,23 @@ namespace Umbraco.Core.Scoping
where T : class
{
var objectKey = CallContext.LogicalGetData(key).AsGuid();
if (objectKey == Guid.Empty) return null;
lock (StaticCallContextObjectsLock)
{
object callContextObject;
if (StaticCallContextObjects.TryGetValue(objectKey, out callContextObject))
{
#if DEBUG_SCOPES
//Logging.LogHelper.Debug<ScopeProvider>("GotObject " + objectKey.ToString("N").Substring(0, 8));
Logging.LogHelper.Debug<ScopeProvider>("Got " + typeof(T).Name + " Object " + objectKey.ToString("N").Substring(0, 8));
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
return (T) callContextObject;
}
Logging.LogHelper.Warn<ScopeProvider>("Missed " + typeof(T).Name + " Object " + objectKey.ToString("N").Substring(0, 8));
#if DEBUG_SCOPES
//Logging.LogHelper.Debug<ScopeProvider>("MissedObject " + objectKey.ToString("N").Substring(0, 8));
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
return null;
}
@@ -146,7 +152,8 @@ namespace Umbraco.Core.Scoping
lock (StaticCallContextObjectsLock)
{
#if DEBUG_SCOPES
//Logging.LogHelper.Debug<ScopeProvider>("RemoveObject " + objectKey.ToString("N").Substring(0, 8));
Logging.LogHelper.Debug<ScopeProvider>("Remove Object " + objectKey.ToString("N").Substring(0, 8));
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Remove(objectKey);
}
@@ -160,7 +167,8 @@ namespace Umbraco.Core.Scoping
lock (StaticCallContextObjectsLock)
{
#if DEBUG_SCOPES
//Logging.LogHelper.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
Logging.LogHelper.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Add(objectKey, value);
}
@@ -506,7 +514,7 @@ namespace Umbraco.Core.Scoping
lock (StaticScopeInfosLock)
{
if (StaticScopeInfos.ContainsKey(scope)) throw new Exception("oops: already registered.");
//Logging.LogHelper.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
Logging.LogHelper.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
StaticScopeInfos[scope] = new ScopeInfo(scope, Environment.StackTrace);
}
}
@@ -524,14 +532,35 @@ namespace Umbraco.Core.Scoping
if (context == null) return;
throw new Exception("oops: unregistered scope.");
}
//Logging.LogHelper.Debug<ScopeProvider>("Register context " + (context ?? "null") + " for " + scope.InstanceId.ToString("N").Substring(0, 8));
var sb = new StringBuilder();
var s = scope;
while (s != null)
{
if (sb.Length > 0) sb.Append(" < ");
sb.Append(s.InstanceId.ToString("N").Substring(0, 8));
var ss = s as IScopeInternal;
s = ss == null ? null : ss.ParentScope;
}
Logging.LogHelper.Debug<ScopeProvider>("Register " + (context ?? "null") + " context " + sb);
if (context == null) info.NullStack = Environment.StackTrace;
//if (context == null)
// Logging.LogHelper.Debug<ScopeProvider>("STACK\r\n" + info.NullStack);
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 16));
info.Context = context;
}
}
private static string Head(string s, int count)
{
var pos = 0;
var i = 0;
while (i < count && pos >= 0)
{
pos = s.IndexOf("\r\n", pos + 1, StringComparison.OrdinalIgnoreCase);
i++;
}
if (pos < 0) return s;
return s.Substring(0, pos);
}
public void Disposed(IScope scope)
{
lock (StaticScopeInfosLock)
@@ -541,7 +570,7 @@ namespace Umbraco.Core.Scoping
// enable this by default
//Console.WriteLine("unregister " + scope.InstanceId.ToString("N").Substring(0, 8));
StaticScopeInfos.Remove(scope);
//Logging.LogHelper.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));
Logging.LogHelper.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));
// instead, enable this to keep *all* scopes
// beware, there can be a lot of scopes!
@@ -176,7 +176,7 @@ namespace Umbraco.Core.Security
AllowRefresh = true,
IssuedUtc = nowUtc,
ExpiresUtc = nowUtc.AddMinutes(GlobalSettings.TimeOutInMinutes)
}, userIdentity, rememberBrowserIdentity);
}, userIdentity, rememberBrowserIdentity);
}
else
{
@@ -189,6 +189,10 @@ namespace Umbraco.Core.Security
}, userIdentity);
}
//track the last login date
user.LastLoginDateUtc = DateTime.UtcNow;
await UserManager.UpdateAsync(user);
_logger.WriteCore(TraceEventType.Information, 0,
string.Format(
"Login attempt succeeded for username {0} from IP address {1}",
@@ -625,6 +625,12 @@ namespace Umbraco.Core.Security
var anythingChanged = false;
//don't assign anything if nothing has changed as this will trigger
//the track changes of the model
if ((user.LastLoginDate != default(DateTime) && identityUser.LastLoginDateUtc.HasValue == false)
|| identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)
{
anythingChanged = true;
user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime();
}
if (user.Name != identityUser.Name && identityUser.Name.IsNullOrWhiteSpace() == false)
{
anythingChanged = true;
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Services
repo.AddOrUpdate(container);
uow.Commit();
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedContentTypeContainer");
//TODO: Audit trail ?
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
@@ -106,7 +106,7 @@ namespace Umbraco.Core.Services
repo.AddOrUpdate(container);
uow.Commit();
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedMediaTypeContainer");
//TODO: Audit trail ?
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
@@ -122,14 +122,16 @@ namespace Umbraco.Core.Services
{
return SaveContainer(
SavingContentTypeContainer, SavedContentTypeContainer,
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type",
"SavedContentTypeContainer", userId);
}
public Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0)
{
return SaveContainer(
SavingMediaTypeContainer, SavedMediaTypeContainer,
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type",
"SavedMediaTypeContainer", userId);
}
private Attempt<OperationStatus> SaveContainer(
@@ -137,7 +139,9 @@ namespace Umbraco.Core.Services
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
EntityContainer container,
Guid containerObjectType,
string objectTypeName, int userId)
string objectTypeName,
string savedEventName,
int userId)
{
var evtMsgs = EventMessagesFactory.Get();
@@ -165,7 +169,7 @@ namespace Umbraco.Core.Services
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType);
repo.AddOrUpdate(container);
uow.Commit();
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), savedEventName);
}
//TODO: Audit trail ?
+112
View File
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -91,6 +92,7 @@ namespace Umbraco.Core.Services
case UmbracoObjectTypes.Member:
case UmbracoObjectTypes.DataType:
case UmbracoObjectTypes.DocumentTypeContainer:
uow.Commit();
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
case UmbracoObjectTypes.RecycleBin:
case UmbracoObjectTypes.Stylesheet:
@@ -129,6 +131,7 @@ namespace Umbraco.Core.Services
case UmbracoObjectTypes.DocumentType:
case UmbracoObjectTypes.Member:
case UmbracoObjectTypes.DataType:
uow.Commit();
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
case UmbracoObjectTypes.RecycleBin:
case UmbracoObjectTypes.Stylesheet:
@@ -374,6 +377,115 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Returns a paged collection of children
/// </summary>
/// <param name="parentId">The parent id to return children for</param>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <returns></returns>
public IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
{
var objectTypeId = umbracoObjectType.GetGuid();
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateEntityRepository(uow);
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId && x.Trashed == false);
IQuery<IUmbracoEntity> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
}
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
uow.Commit();
return contents;
}
}
/// <summary>
/// Returns a paged collection of descendants
/// </summary>
/// <param name="id"></param>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <returns></returns>
public IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
{
var objectTypeId = umbracoObjectType.GetGuid();
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateEntityRepository(uow);
var query = Query<IUmbracoEntity>.Builder;
//if the id is System Root, then just get all
if (id != Constants.System.Root)
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
IQuery<IUmbracoEntity> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
}
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
uow.Commit();
return contents;
}
}
/// <summary>
/// Returns a paged collection of descendants from the root
/// </summary>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <param name="includeTrashed">true/false to include trashed objects</param>
/// <returns></returns>
public IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
{
var objectTypeId = umbracoObjectType.GetGuid();
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateEntityRepository(uow);
var query = Query<IUmbracoEntity>.Builder;
//don't include trashed if specfied
if (includeTrashed == false)
{
query.Where(x => x.Trashed == false);
}
IQuery<IUmbracoEntity> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
}
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
uow.Commit();
return contents;
}
}
/// <summary>
/// Gets a collection of descendents by the parents Id
/// </summary>
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Services
{
@@ -137,6 +138,51 @@ namespace Umbraco.Core.Services
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
IEnumerable<IUmbracoEntity> GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType);
/// <summary>
/// Returns a paged collection of children
/// </summary>
/// <param name="parentId">The parent id to return children for</param>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <returns></returns>
IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Returns a paged collection of descendants
/// </summary>
/// <param name="id"></param>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <returns></returns>
IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Returns a paged collection of descendants from the root
/// </summary>
/// <param name="umbracoObjectType"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="filter"></param>
/// <param name="includeTrashed">true/false to include trashed objects</param>
/// <returns></returns>
IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true);
/// <summary>
/// Gets a collection of descendents by the parents Id
/// </summary>
+21
View File
@@ -425,7 +425,28 @@ namespace Umbraco.Core
assemblyName.FullName.StartsWith("App_Code.") ? "App_Code" : assemblyName.Name);
}
/// <summary>
/// If the given <paramref name="type"/> is an array or some other collection
/// comprised of 0 or more instances of a "subtype", get that type
/// </summary>
/// <param name="type">the source type</param>
/// <returns></returns>
internal static Type GetEnumeratedType(this Type type)
{
if (typeof(IEnumerable).IsAssignableFrom(type) == false)
return null;
// provided by Array
var elType = type.GetElementType();
if (null != elType) return elType;
// otherwise provided by collection
var elTypes = type.GetGenericArguments();
if (elTypes.Length > 0) return elTypes[0];
// otherwise is not an 'enumerated' type
return null;
}
}
}
+55 -34
View File
@@ -1,7 +1,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Deploy;
namespace Umbraco.Core
@@ -10,9 +12,10 @@ namespace Umbraco.Core
/// Represents an entity identifier.
/// </summary>
/// <remarks>An Udi can be fully qualified or "closed" eg umb://document/{guid} or "open" eg umb://document.</remarks>
[TypeConverter(typeof(UdiTypeConverter))]
public abstract class Udi : IComparable<Udi>
{
private static readonly Dictionary<string, UdiType> UdiTypes = new Dictionary<string, UdiType>();
private static readonly Lazy<Dictionary<string, UdiType>> UdiTypes;
private static readonly ConcurrentDictionary<string, Udi> RootUdis = new ConcurrentDictionary<string, Udi>();
internal readonly Uri UriValue; // internal for UdiRange
@@ -39,32 +42,50 @@ namespace Umbraco.Core
static Udi()
{
// for tests etc.
UdiTypes[Constants.DeployEntityType.AnyGuid] = UdiType.GuidUdi;
UdiTypes[Constants.DeployEntityType.AnyString] = UdiType.StringUdi;
// we don't have connectors for these...
UdiTypes[Constants.DeployEntityType.Member] = UdiType.GuidUdi;
UdiTypes[Constants.DeployEntityType.MemberGroup] = UdiType.GuidUdi;
// fixme - or inject from...?
// there is no way we can get the "registered" service connectors, as registration
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
// just pick every service connectors - just making sure that not two of them
// would register the same entity type, with different udi types (would not make
// much sense anyways).
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
foreach (var connector in connectors)
UdiTypes = new Lazy<Dictionary<string, UdiType>>(() =>
{
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
foreach (var attr in attrs)
var result = new Dictionary<string, UdiType>();
// known types:
foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static))
{
UdiType udiType;
if (UdiTypes.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
UdiTypes[attr.EntityType] = attr.UdiType;
// IsLiteral determines if its value is written at
// compile time and not changeable
// IsInitOnly determine if the field can be set
// in the body of the constructor
// for C# a field which is readonly keyword would have both true
// but a const field would have only IsLiteral equal to true
if (fi.IsLiteral && fi.IsInitOnly == false)
{
var udiType = fi.GetCustomAttribute<Constants.UdiTypeAttribute>();
if (udiType == null)
throw new InvalidOperationException("All Constants listed in UdiEntityType must be attributed with " + typeof(Constants.UdiTypeAttribute));
result[fi.GetValue(null).ToString()] = udiType.UdiType;
}
}
}
// Scan for unknown UDI types
// there is no way we can get the "registered" service connectors, as registration
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
// just pick every service connectors - just making sure that not two of them
// would register the same entity type, with different udi types (would not make
// much sense anyways).
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
foreach (var connector in connectors)
{
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
foreach (var attr in attrs)
{
UdiType udiType;
if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
result[attr.EntityType] = attr.UdiType;
}
}
return result;
});
}
/// <summary>
@@ -105,8 +126,8 @@ namespace Umbraco.Core
udi = null;
Uri uri;
if (!Uri.IsWellFormedUriString(s, UriKind.Absolute)
|| !Uri.TryCreate(s, UriKind.Absolute, out uri))
if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false
|| Uri.TryCreate(s, UriKind.Absolute, out uri) == false)
{
if (tryParse) return false;
throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s));
@@ -114,7 +135,7 @@ namespace Umbraco.Core
var entityType = uri.Host;
UdiType udiType;
if (!UdiTypes.TryGetValue(entityType, out udiType))
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
{
if (tryParse) return false;
throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType));
@@ -128,7 +149,7 @@ namespace Umbraco.Core
return true;
}
Guid guid;
if (!Guid.TryParse(path, out guid))
if (Guid.TryParse(path, out guid) == false)
{
if (tryParse) return false;
throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s));
@@ -150,7 +171,7 @@ namespace Umbraco.Core
return RootUdis.GetOrAdd(entityType, x =>
{
UdiType udiType;
if (!UdiTypes.TryGetValue(x, out udiType))
if (UdiTypes.Value.TryGetValue(x, out udiType) == false)
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType));
return udiType == UdiType.StringUdi
? (Udi)new StringUdi(entityType, string.Empty)
@@ -177,7 +198,7 @@ namespace Umbraco.Core
public static Udi Create(string entityType, string id)
{
UdiType udiType;
if (!UdiTypes.TryGetValue(entityType, out udiType))
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentException("Value cannot be null or whitespace.", "id");
@@ -196,7 +217,7 @@ namespace Umbraco.Core
public static Udi Create(string entityType, Guid id)
{
UdiType udiType;
if (!UdiTypes.TryGetValue(entityType, out udiType))
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
if (udiType != UdiType.GuidUdi)
throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have guid udis.", entityType));
@@ -208,7 +229,7 @@ namespace Umbraco.Core
internal static Udi Create(Uri uri)
{
UdiType udiType;
if (!UdiTypes.TryGetValue(uri.Host, out udiType))
if (UdiTypes.Value.TryGetValue(uri.Host, out udiType) == false)
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", uri.Host), "uri");
if (udiType == UdiType.GuidUdi)
return new GuidUdi(uri);
@@ -219,7 +240,7 @@ namespace Umbraco.Core
public void EnsureType(params string[] validTypes)
{
if (!validTypes.Contains(EntityType))
if (validTypes.Contains(EntityType) == false)
throw new Exception(string.Format("Unexpected entity type \"{0}\".", EntityType));
}
@@ -260,7 +281,7 @@ namespace Umbraco.Core
public static bool operator !=(Udi udi1, Udi udi2)
{
return !(udi1 == udi2);
return (udi1 == udi2) == false;
}
}
@@ -7,52 +7,82 @@ namespace Umbraco.Core
public static partial class Constants
{
/// <summary>
/// Defines well-known entity types.
/// </summary>
/// <remarks>Well-known entity types are those that Deploy already knows about,
/// but entity types are strings and so can be extended beyond what is defined here.</remarks>
public static class DeployEntityType
public static class UdiEntityType
{
[UdiType(UdiType.Unknown)]
public const string Unknown = "unknown";
// guid entity types
[UdiType(UdiType.GuidUdi)]
public const string AnyGuid = "any-guid"; // that one is for tests
[UdiType(UdiType.GuidUdi)]
public const string Document = "document";
[UdiType(UdiType.GuidUdi)]
public const string Media = "media";
[UdiType(UdiType.GuidUdi)]
public const string Member = "member";
[UdiType(UdiType.GuidUdi)]
public const string DictionaryItem = "dictionary-item";
[UdiType(UdiType.GuidUdi)]
public const string Macro = "macro";
[UdiType(UdiType.GuidUdi)]
public const string Template = "template";
[UdiType(UdiType.GuidUdi)]
public const string DocumentType = "document-type";
[UdiType(UdiType.GuidUdi)]
public const string DocumentTypeContainer = "document-type-container";
[UdiType(UdiType.GuidUdi)]
public const string MediaType = "media-type";
[UdiType(UdiType.GuidUdi)]
public const string MediaTypeContainer = "media-type-container";
[UdiType(UdiType.GuidUdi)]
public const string DataType = "data-type";
[UdiType(UdiType.GuidUdi)]
public const string DataTypeContainer = "data-type-container";
[UdiType(UdiType.GuidUdi)]
public const string MemberType = "member-type";
[UdiType(UdiType.GuidUdi)]
public const string MemberGroup = "member-group";
[UdiType(UdiType.GuidUdi)]
public const string RelationType = "relation-type";
// forms
[UdiType(UdiType.GuidUdi)]
public const string FormsForm = "forms-form";
[UdiType(UdiType.GuidUdi)]
public const string FormsPreValue = "forms-prevalue";
[UdiType(UdiType.GuidUdi)]
public const string FormsDataSource = "forms-datasource";
// string entity types
[UdiType(UdiType.StringUdi)]
public const string AnyString = "any-string"; // that one is for tests
[UdiType(UdiType.StringUdi)]
public const string MediaFile = "media-file";
[UdiType(UdiType.StringUdi)]
public const string TemplateFile = "template-file";
[UdiType(UdiType.StringUdi)]
public const string Script = "script";
[UdiType(UdiType.StringUdi)]
public const string Stylesheet = "stylesheet";
[UdiType(UdiType.StringUdi)]
public const string PartialView = "partial-view";
[UdiType(UdiType.StringUdi)]
public const string PartialViewMacro = "partial-view-macro";
[UdiType(UdiType.StringUdi)]
public const string Xslt = "xslt";
public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType)
@@ -141,6 +171,15 @@ namespace Umbraco.Core
}
}
[AttributeUsage(AttributeTargets.Field)]
internal class UdiTypeAttribute : Attribute
{
public UdiType UdiType { get; private set; }
public UdiTypeAttribute(UdiType udiType)
{
UdiType = udiType;
}
}
}
}
+25 -25
View File
@@ -17,7 +17,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this ITemplate entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.Template, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.Template, entity.Key).EnsureClosed();
}
/// <summary>
@@ -28,7 +28,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IContentType entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.DocumentType, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.DocumentType, entity.Key).EnsureClosed();
}
/// <summary>
@@ -39,7 +39,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMediaType entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.MediaType, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.MediaType, entity.Key).EnsureClosed();
}
/// <summary>
@@ -50,7 +50,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMemberType entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.MemberType, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.MemberType, entity.Key).EnsureClosed();
}
/// <summary>
@@ -61,7 +61,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMemberGroup entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.MemberGroup, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.MemberGroup, entity.Key).EnsureClosed();
}
/// <summary>
@@ -74,9 +74,9 @@ namespace Umbraco.Core
if (entity == null) throw new ArgumentNullException("entity");
string type;
if (entity is IContentType) type = Constants.DeployEntityType.DocumentType;
else if (entity is IMediaType) type = Constants.DeployEntityType.MediaType;
else if (entity is IMemberType) type = Constants.DeployEntityType.MemberType;
if (entity is IContentType) type = Constants.UdiEntityType.DocumentType;
else if (entity is IMediaType) type = Constants.UdiEntityType.MediaType;
else if (entity is IMemberType) type = Constants.UdiEntityType.MemberType;
else throw new NotSupportedException(string.Format("Composition type {0} is not supported.", entity.GetType().FullName));
return new GuidUdi(type, entity.Key).EnsureClosed();
}
@@ -89,7 +89,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IDataTypeDefinition entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.DataType, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.DataType, entity.Key).EnsureClosed();
}
/// <summary>
@@ -103,11 +103,11 @@ namespace Umbraco.Core
string entityType;
if (entity.ContainedObjectType == Constants.ObjectTypes.DataTypeGuid)
entityType = Constants.DeployEntityType.DataTypeContainer;
entityType = Constants.UdiEntityType.DataTypeContainer;
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentTypeGuid)
entityType = Constants.DeployEntityType.DocumentTypeContainer;
entityType = Constants.UdiEntityType.DocumentTypeContainer;
else if (entity.ContainedObjectType == Constants.ObjectTypes.MediaTypeGuid)
entityType = Constants.DeployEntityType.MediaTypeContainer;
entityType = Constants.UdiEntityType.MediaTypeContainer;
else
throw new NotSupportedException(string.Format("Contained object type {0} is not supported.", entity.ContainedObjectType));
return new GuidUdi(entityType, entity.Key).EnsureClosed();
@@ -121,7 +121,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMedia entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.Media, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.Media, entity.Key).EnsureClosed();
}
/// <summary>
@@ -132,7 +132,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IContent entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.Document, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.Document, entity.Key).EnsureClosed();
}
/// <summary>
@@ -143,7 +143,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMember entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.Member, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.Member, entity.Key).EnsureClosed();
}
/// <summary>
@@ -154,7 +154,7 @@ namespace Umbraco.Core
public static StringUdi GetUdi(this Stylesheet entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new StringUdi(Constants.DeployEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed();
return new StringUdi(Constants.UdiEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed();
}
/// <summary>
@@ -165,7 +165,7 @@ namespace Umbraco.Core
public static StringUdi GetUdi(this Script entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new StringUdi(Constants.DeployEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed();
return new StringUdi(Constants.UdiEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed();
}
/// <summary>
@@ -176,7 +176,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IDictionaryItem entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.DictionaryItem, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.DictionaryItem, entity.Key).EnsureClosed();
}
/// <summary>
@@ -187,7 +187,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IMacro entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.Macro, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.Macro, entity.Key).EnsureClosed();
}
/// <summary>
@@ -198,7 +198,7 @@ namespace Umbraco.Core
public static StringUdi GetUdi(this IPartialView entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new StringUdi(Constants.DeployEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed();
return new StringUdi(Constants.UdiEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed();
}
/// <summary>
@@ -209,7 +209,7 @@ namespace Umbraco.Core
public static StringUdi GetUdi(this IXsltFile entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new StringUdi(Constants.DeployEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed();
return new StringUdi(Constants.UdiEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed();
}
/// <summary>
@@ -222,9 +222,9 @@ namespace Umbraco.Core
if (entity == null) throw new ArgumentNullException("entity");
string type;
if (entity is IContent) type = Constants.DeployEntityType.Document;
else if (entity is IMedia) type = Constants.DeployEntityType.Media;
else if (entity is IMember) type = Constants.DeployEntityType.Member;
if (entity is IContent) type = Constants.UdiEntityType.Document;
else if (entity is IMedia) type = Constants.UdiEntityType.Media;
else if (entity is IMember) type = Constants.UdiEntityType.Member;
else throw new NotSupportedException(string.Format("ContentBase type {0} is not supported.", entity.GetType().FullName));
return new GuidUdi(type, entity.Key).EnsureClosed();
}
@@ -237,7 +237,7 @@ namespace Umbraco.Core
public static GuidUdi GetUdi(this IRelationType entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new GuidUdi(Constants.DeployEntityType.RelationType, entity.Key).EnsureClosed();
return new GuidUdi(Constants.UdiEntityType.RelationType, entity.Key).EnsureClosed();
}
/// <summary>
+37
View File
@@ -0,0 +1,37 @@
using System;
using System.ComponentModel;
using System.Globalization;
namespace Umbraco.Core
{
/// <summary>
/// A custom type converter for UDI
/// </summary>
/// <remarks>
/// Primarily this is used so that WebApi can auto-bind a string parameter to a UDI instance
/// </remarks>
internal class UdiTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
Udi udi;
if (Udi.TryParse((string)value, out udi))
{
return udi;
}
}
return base.ConvertFrom(context, culture, value);
}
}
}
+8 -3
View File
@@ -163,6 +163,7 @@
<Compile Include="Cache\DeepCloneRuntimeCacheProvider.cs" />
<Compile Include="CodeAnnotations\FriendlyNameAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoObjectTypeAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoUdiTypeAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoWillObsoleteAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
@@ -289,7 +290,6 @@
<Compile Include="Configuration\UmbracoSettings\WebRoutingElement.cs" />
<Compile Include="Configuration\UmbracoVersion.cs" />
<Compile Include="Attempt.cs" />
<Compile Include="Constants-DeployEntityType.cs" />
<Compile Include="Constants-DeploySelector.cs" />
<Compile Include="Constants-Examine.cs" />
<Compile Include="Constants-Icons.cs" />
@@ -311,10 +311,13 @@
<Compile Include="Deploy\ArtifactSignature.cs" />
<Compile Include="Deploy\Difference.cs" />
<Compile Include="Deploy\Direction.cs" />
<Compile Include="Deploy\IFileStore.cs" />
<Compile Include="Deploy\IFileType.cs" />
<Compile Include="Deploy\IFileTypeCollection.cs" />
<Compile Include="Events\EventDefinitionFilter.cs" />
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
<Compile Include="Events\ScopeLifespanMessagesFactory.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="OrderedHashSet.cs" />
<Compile Include="Events\UninstallPackageEventArgs.cs" />
<Compile Include="Models\GridValue.cs" />
@@ -326,7 +329,6 @@
<Compile Include="Deploy\IImageSourceParser.cs" />
<Compile Include="Deploy\ILocalLinkParser.cs" />
<Compile Include="Deploy\IMacroParser.cs" />
<Compile Include="Deploy\IPrettyArtifact.cs" />
<Compile Include="Deploy\IPreValueConnector.cs" />
<Compile Include="Deploy\IServiceConnector.cs" />
<Compile Include="Deploy\IValueConnector.cs" />
@@ -485,6 +487,7 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToCmsMemberLoginName.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexesToUmbracoRelationTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUmbracoNodePath.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUser2NodePermission.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddRelationTypeUniqueIdColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddMacroUniqueIdColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\RemovePropertyDataIdIndex.cs" />
@@ -1440,9 +1443,11 @@
<Compile Include="TypeHelper.cs" />
<Compile Include="Udi.cs" />
<Compile Include="UdiDefinitionAttribute.cs" />
<Compile Include="UdiEntityType.cs" />
<Compile Include="UdiGetterExtensions.cs" />
<Compile Include="UdiRange.cs" />
<Compile Include="UdiType.cs" />
<Compile Include="UdiTypeConverter.cs" />
<Compile Include="UmbracoApplicationBase.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Constants-Applications.cs">
+398 -16
View File
@@ -336,8 +336,9 @@ namespace Umbraco.Tests.IO
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("path/to/some/dir/f1.txt", ms);
// file is only written to the shadow fs
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt"));
Assert.IsFalse(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
// let the shadow fs die
}
@@ -376,6 +377,7 @@ namespace Umbraco.Tests.IO
var path = IOHelper.MapPath("FileSysTests");
var appdata = IOHelper.MapPath("App_Data");
Directory.CreateDirectory(path);
Directory.CreateDirectory(appdata);
var scopedFileSystems = false;
var scopeProvider = MockScopeProvider(() => scopedFileSystems);
@@ -392,47 +394,47 @@ namespace Umbraco.Tests.IO
// explicit shadow without scope does not work
sw.Shadow(id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
sw.UnShadow(true);
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
Assert.IsFalse(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
// shadow with scope but no complete does not complete
scopedFileSystems = true; // pretend we have a scope
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f3.txt", ms);
Assert.IsFalse(fs.FileExists("sub/f3.txt"));
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/Shadow").Length);
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
scope.Dispose();
scopedFileSystems = false;
Assert.IsFalse(fs.FileExists("sub/f3.txt"));
Assert.IsFalse(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
// shadow with scope and complete does complete
scopedFileSystems = true; // pretend we have a scope
scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f4.txt", ms);
Assert.IsFalse(fs.FileExists("sub/f4.txt"));
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/Shadow").Length);
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
scope.Complete();
scope.Dispose();
scopedFileSystems = false;
TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(appdata + "/Shadow").Length));
TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length));
Assert.IsTrue(fs.FileExists("sub/f4.txt"));
Assert.IsFalse(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
// test scope for "another thread"
scopedFileSystems = true; // pretend we have a scope
scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f5.txt", ms);
Assert.IsFalse(fs.FileExists("sub/f5.txt"));
@@ -448,7 +450,7 @@ namespace Umbraco.Tests.IO
scope.Dispose();
scopedFileSystems = false;
Assert.IsTrue(fs.FileExists("sub/f5.txt"));
Assert.IsFalse(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
}
[Test]
@@ -473,7 +475,7 @@ namespace Umbraco.Tests.IO
scopedFileSystems = true; // pretend we have a scope
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
Assert.IsFalse(fs.FileExists("sub/f2.txt"));
@@ -489,7 +491,7 @@ namespace Umbraco.Tests.IO
scope.Dispose();
scopedFileSystems = false;
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/Shadow/" + id)));
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)));
string text;
using (var s = fs.OpenFile("sub/f2.txt"))
@@ -522,7 +524,7 @@ namespace Umbraco.Tests.IO
scopedFileSystems = true; // pretend we have a scope
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);
Assert.IsTrue(Directory.Exists(appdata + "/Shadow/" + id));
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
Assert.IsFalse(fs.FileExists("sub/f2.txt"));
@@ -554,7 +556,7 @@ namespace Umbraco.Tests.IO
var e = ae.InnerExceptions[0];
Assert.IsNotNull(e.InnerException);
Assert.IsInstanceOf<AggregateException>(e);
ae = (AggregateException) e;
ae = (AggregateException)e;
Assert.AreEqual(1, ae.InnerExceptions.Count);
e = ae.InnerExceptions[0];
@@ -623,5 +625,385 @@ namespace Umbraco.Tests.IO
providerMock.Setup(x => x.AmbientScope).Returns(scopeMock.Object);
return providerMock.Object;
}
/// <summary>
/// Check that GetFiles will return all files on the shadow, while returning
/// just one on each of the filesystems used by the shadow.
/// </summary>
[Test]
public void ShadowGetFiles()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
/// <summary>
/// Check that GetFiles using the filter function with empty string will return expected results
/// </summary>
[Test]
public void ShadowGetFilesUsingEmptyFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
// ensure we get 0 files when using a empty filter
var getFilesWithEmptyFilter = ss.GetFiles(string.Empty, "");
Assert.AreEqual(0, getFilesWithEmptyFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
/// <summary>
/// Check that GetFiles using the filter function with null will return expected results
/// </summary>
[Test]
public void ShadowGetFilesUsingNullFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
// ensure we get 2 files when using null in filter parameter
var getFilesWithNullFilter = ss.GetFiles(string.Empty, null);
Assert.AreEqual(2, getFilesWithNullFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
[Test]
public void ShadowGetFilesUsingWildcardFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.doc", ms);
// Assert
// ensure we get 4 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(4, getFiles.Count());
// ensure we get only 2 of 4 files from the shadow when using filter
var getFilesWithWildcardFilter = ss.GetFiles(string.Empty, "*.doc");
Assert.AreEqual(2, getFilesWithWildcardFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(2, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(2, sfsFiles.Length);
}
[Test]
public void ShadowGetFilesUsingSingleCharacterFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.doc", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.docx", ms);
// Assert
// ensure we get 6 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(6, getFiles.Count());
// ensure we get only 2 of 6 files from the shadow when using filter on shadow
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "f1.d?c");
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter.Count());
// ensure we get only 2 of 6 files from the shadow when using filter on disk
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "f2.d?c");
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter2.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, sfsFiles.Length);
}
[Test]
public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.doc", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.docx", ms);
// Assert
// ensure we get 6 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(6, getFiles.Count());
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "*.d?c");
Assert.AreEqual(4, getFilesWithWildcardSinglecharFilter.Count());
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "*.d?cx");
Assert.AreEqual(2, getFilesWithWildcardSinglecharFilter2.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, sfsFiles.Length);
}
[Test]
public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/filter");
// create files on disk and create a "fake" list of files to verify filters against
File.WriteAllText(path + "/filter/f1.txt", "foo");
File.WriteAllText(path + "/filter/f1.doc", "foo");
File.WriteAllText(path + "/filter/f1.docx", "foo");
var files = new string[]
{
"f1.txt",
"f1.doc",
"f1.docx",
};
var filter1 = "";
var filter2 = "*";
var filter3 = "*.doc";
var filter4 = "*.d?c";
var filter5 = "f1.doc";
var filter6 = "f1.d?c";
var filter7 = "**.d?c";
var filter8 = "f*.doc";
// Act & Assert
var result1Disk = Directory.GetFiles(path + "/filter/", filter1).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result1Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter1))).OrderBy(x => x).ToArray();
Assert.AreEqual(result1Disk, result1Fake);
var result2Disk = Directory.GetFiles(path + "/filter/", filter2).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result2Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter2))).OrderBy(x => x).ToArray();
Assert.AreEqual(result2Disk, result2Fake);
var result3Disk = Directory.GetFiles(path + "/filter/", filter3).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result3Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter3))).OrderBy(x => x).ToArray();
Assert.AreEqual(result3Disk, result3Fake);
var result4Disk = Directory.GetFiles(path + "/filter/", filter4).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result4Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter4))).OrderBy(x => x).ToArray();
Assert.AreEqual(result4Disk, result4Fake);
var result5Disk = Directory.GetFiles(path + "/filter/", filter5).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result5Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter5))).OrderBy(x => x).ToArray();
Assert.AreEqual(result5Disk, result5Fake);
var result6Disk = Directory.GetFiles(path + "/filter/", filter6).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result6Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter6))).OrderBy(x => x).ToArray();
Assert.AreEqual(result6Disk, result6Fake);
var result7Disk = Directory.GetFiles(path + "/filter/", filter7).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result7Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter7))).OrderBy(x => x).ToArray();
Assert.AreEqual(result7Disk, result7Fake);
var result8Disk = Directory.GetFiles(path + "/filter/", filter8).Select(Path.GetFileName).OrderBy(x => x).ToArray();
var result8Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter8))).OrderBy(x => x).ToArray();
Assert.AreEqual(result8Disk, result8Fake);
}
/// <summary>
/// Returns the full paths of the files on the disk.
/// Note that this will be the *actual* path of the file, meaning a file existing on the initialized FS
/// will be in one location, while a file written after initializing the shadow, will exist at the
/// shadow location directory.
/// </summary>
[Test]
public void ShadowGetFullPath()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1FullPath = ss.GetFullPath("f1.txt");
var f2FullPath = ss.GetFullPath("f2.txt");
Assert.AreEqual(Path.Combine(path, "ShadowTests", "f1.txt"), f1FullPath);
Assert.AreEqual(Path.Combine(path, "ShadowSystem", "f2.txt"), f2FullPath);
}
/// <summary>
/// Returns the path relative to the filesystem root
/// </summary>
/// <remarks>
/// This file stuff in this test is kinda irrelevant with the current implementation.
/// We do tests that the files are written to the correct places and the relative path is returned correct,
/// but GetRelativePath is currently really just string manipulation so files are not actually hit by the code.
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
/// </remarks>
[Test]
public void ShadowGetRelativePath()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1RelativePath = ss.GetRelativePath("f1.txt");
var f2RelativePath = ss.GetRelativePath("f2.txt");
Assert.AreEqual("f1.txt", f1RelativePath);
Assert.AreEqual("f2.txt", f2RelativePath);
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
}
/// <summary>
/// Ensure the url returned contains the path relative to the FS root,
/// but including the rootUrl the FS was initialized with.
/// </summary>
/// <remarks>
/// This file stuff in this test is kinda irrelevant with the current implementation.
/// We do tests that the files are written to the correct places and the url is returned correct,
/// but GetUrl is currently really just string manipulation so files are not actually hit by the code.
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
/// </remarks>
[Test]
public void ShadowGetUrl()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "rootUrl");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "rootUrl");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1Url = ss.GetUrl("f1.txt");
var f2Url = ss.GetUrl("f2.txt");
Assert.AreEqual("rootUrl/f1.txt", f1Url);
Assert.AreEqual("rootUrl/f2.txt", f2Url);
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
}
}
}
@@ -441,7 +441,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
// Act
var exists = repository.Exists(1034); //Content picker
var exists = repository.Exists(1046); //Content picker
var doesntExist = repository.Exists(-80);
// Assert
@@ -0,0 +1,177 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Umbraco.Tests.Logging;
using Umbraco.Web.Scheduling;
namespace Umbraco.Tests.Scheduling
{
[TestFixture]
[Timeout(60000)]
public class BackgroundTaskRunnerTests2
{
// this tests was used to debug a background task runner issue that was unearthed by Deploy,
// where work items would never complete under certain circumstances, due to threading issues.
// (fixed now)
//
[Test]
[Timeout(4000)]
public async Task ThreadResumeIssue()
{
var logger = new ConsoleLogger();
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
var work = new ThreadResumeIssueWorkItem();
runner.Add(work);
Console.WriteLine("running");
await Task.Delay(1000); // don't complete too soon
Console.WriteLine("completing");
// this never returned, never reached "completed" because the same thread
// resumed executing the waiting on queue operation in the runner
work.Complete();
Console.WriteLine("completed");
Console.WriteLine("done");
}
public class ThreadResumeIssueWorkItem : IBackgroundTask
{
private TaskCompletionSource<int> _completionSource;
public async Task RunAsync(CancellationToken token)
{
_completionSource = new TaskCompletionSource<int>();
token.Register(() => _completionSource.TrySetCanceled()); // propagate
Console.WriteLine("item running...");
await _completionSource.Task.ConfigureAwait(false);
Console.WriteLine("item returning");
}
public bool Complete(bool success = true)
{
Console.WriteLine("item completing");
// this never returned, see test
_completionSource.SetResult(0);
Console.WriteLine("item returning from completing");
return true;
}
public void Run()
{
throw new NotImplementedException();
}
public bool IsAsync { get { return true; } }
public void Dispose()
{}
}
[Test]
[Ignore("Only runs in the debugger.")]
public async Task DebuggerInterferenceIssue()
{
var logger = new ConsoleLogger();
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
var taskCompleted = false;
runner.TaskCompleted += (sender, args) =>
{
Console.WriteLine("runner task completed");
taskCompleted = true;
};
var work = new DebuggerInterferenceIssueWorkitem();
// add the workitem to the runner and wait until it is running
runner.Add(work);
work.Running.Wait();
// then wait a little bit more to ensure that the WhenAny has been entered
await Task.Delay(500);
// then break
// when the timeout triggers, we cannot handle it
// taskCompleted value does *not* change & nothing happens
Debugger.Break();
// release after 15s
// WhenAny should return the timeout task
// and then taskCompleted should turn to true
// = debugging does not prevent task completion
Console.WriteLine("*");
Assert.IsFalse(taskCompleted);
await Task.Delay(1000);
Console.WriteLine("*");
Assert.IsTrue(taskCompleted);
}
public class DebuggerInterferenceIssueWorkitem : IBackgroundTask
{
private readonly SemaphoreSlim _timeout = new SemaphoreSlim(0, 1);
private readonly ManualResetEventSlim _running = new ManualResetEventSlim(false);
private Timer _timer;
public ManualResetEventSlim Running { get { return _running; } }
public async Task RunAsync(CancellationToken token)
{
// timeout timer
_timer = new Timer(_ => { _timeout.Release(); });
_timer.Change(1000, 0);
var timeout = _timeout.WaitAsync(token);
var source = CancellationTokenSource.CreateLinkedTokenSource(token); // cancels when token cancels
_running.Set();
var task = WorkExecuteAsync(source.Token);
Console.WriteLine("execute");
var anyTask = await Task.WhenAny(task, timeout).ConfigureAwait(false);
Console.Write("anyTask: ");
Console.WriteLine(anyTask == timeout ? "timeout" : "task");
Console.WriteLine("return");
}
private async Task WorkExecuteAsync(CancellationToken token)
{
await Task.Delay(30000);
}
public void Run()
{
throw new NotImplementedException();
}
public bool IsAsync { get { return true; } }
public void Dispose()
{ }
}
[Test]
[Ignore("Only runs in the debugger.")]
public void TimerDebuggerTest()
{
var triggered = false;
var timer = new Timer(_ => { triggered = true; });
timer.Change(1000, 0);
Debugger.Break();
// pause in debugger for 10s
// means the timer triggers while execution is suspended
// 'triggered' remains false all along
// then resume execution
// and 'triggered' becomes true, so the trigger "catches up"
// = debugging should not prevent triggered code from executing
Thread.Sleep(200);
Assert.IsTrue(triggered);
}
}
}
@@ -1,73 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Umbraco.Tests.Logging;
using Umbraco.Web.Scheduling;
namespace Umbraco.Tests.Scheduling
{
// THIS REPRODUCES THE DEPLOY ISSUE IN CORE
//
// the exact same thing also reproduces in playground
// so it's not a framework version issue - but something we're doing here
[TestFixture]
[Timeout(4000)]
public class Repro
{
[Test]
public async Task ReproduceDeployIssue()
{
var logger = new ConsoleLogger();
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
var work = new SimpleWorkItem();
runner.Add(work);
Console.WriteLine("running");
await Task.Delay(1000); // don't complete too soon
Console.WriteLine("completing");
// this never returns, never reached "completed" because the same thread
// resumes executing the waiting on queue operation in the runner
work.Complete();
Console.WriteLine("completed");
Console.WriteLine("done");
}
public class SimpleWorkItem : IBackgroundTask
{
private TaskCompletionSource<int> _completionSource;
public async Task RunAsync(CancellationToken token)
{
_completionSource = new TaskCompletionSource<int>();
token.Register(() => _completionSource.TrySetCanceled()); // propagate
Console.WriteLine("item running...");
await _completionSource.Task.ConfigureAwait(false);
Console.WriteLine("item returning");
}
public bool Complete(bool success = true)
{
Console.WriteLine("item completing");
// this never returns, see test
_completionSource.SetResult(0);
Console.WriteLine("item returning from completing");
return true;
}
public void Run()
{
throw new NotImplementedException();
}
public bool IsAsync { get { return true; } }
public void Dispose()
{}
}
}
}
@@ -1343,6 +1343,69 @@ namespace Umbraco.Tests.Services
Assert.That(contents.Any(), Is.False);
}
[Test]
public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data()
{
// Arrange
//need to:
// * add relations
// * add permissions
// * add notifications
// * public access
// * tags
// * domain
// * published & preview data
// * multiple versions
var contentType = MockedContentTypes.CreateAllTypesContentType("test", "test");
ServiceContext.ContentTypeService.Save(contentType, 0);
object obj =
new
{
tags = "Hello,World"
};
var content1 = MockedContent.CreateBasicContent(contentType);
content1.PropertyValues(obj);
content1.ResetDirtyProperties(false);
ServiceContext.ContentService.Save(content1, 0);
Assert.IsTrue(ServiceContext.ContentService.PublishWithStatus(content1, 0).Success);
var content2 = MockedContent.CreateBasicContent(contentType);
content2.PropertyValues(obj);
content2.ResetDirtyProperties(false);
ServiceContext.ContentService.Save(content2, 0);
Assert.IsTrue(ServiceContext.ContentService.PublishWithStatus(content2, 0).Success);
ServiceContext.RelationService.Save(new RelationType(Constants.ObjectTypes.DocumentGuid, Constants.ObjectTypes.DocumentGuid, "test"));
Assert.IsNotNull(ServiceContext.RelationService.Relate(content1, content2, "test"));
ServiceContext.PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List<PublicAccessRule>
{
new PublicAccessRule
{
RuleType = "test",
RuleValue = "test"
}
}));
Assert.IsTrue(ServiceContext.PublicAccessService.AddRule(content1, "test2", "test2").Success);
Assert.IsNotNull(ServiceContext.NotificationService.CreateNotification(ServiceContext.UserService.GetUserById(0), content1, "test"));
ServiceContext.ContentService.AssignContentPermission(content1, 'A', new[] {0});
Assert.IsTrue(ServiceContext.DomainService.Save(new UmbracoDomain("www.test.com", "en-AU")
{
RootContentId = content1.Id
}).Success);
// Act
ServiceContext.ContentService.EmptyRecycleBin();
var contents = ServiceContext.ContentService.GetContentInRecycleBin();
// Assert
Assert.That(contents.Any(), Is.False);
}
[Test]
public void Can_Move_Content()
{
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
@@ -25,8 +26,368 @@ namespace Umbraco.Tests.Services
public override void TearDown()
{
base.TearDown();
}
[Test]
public void EntityService_Can_Get_Paged_Content_Children()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
}
[Test]
public void EntityService_Can_Get_Paged_Content_Descendants()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
var count = 0;
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
count++;
for (int j = 0; j < 5; j++)
{
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
ServiceContext.ContentService.Save(c2);
count++;
}
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(31));
Assert.That(total, Is.EqualTo(60));
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(29));
Assert.That(total, Is.EqualTo(60));
}
[Test]
public void EntityService_Can_Get_Paged_Content_Descendants_Including_Recycled()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
var toDelete = new List<IContent>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
if (i % 2 == 0)
{
toDelete.Add(c1);
}
for (int j = 0; j < 5; j++)
{
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
ServiceContext.ContentService.Save(c2);
}
}
foreach (var content in toDelete)
{
ServiceContext.ContentService.MoveToRecycleBin(content);
}
var service = ServiceContext.EntityService;
long total;
//search at root to see if it returns recycled
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total)
.Select(x => x.Id)
.ToArray();
foreach (var c in toDelete)
{
Assert.True(entities.Contains(c.Id));
}
}
[Test]
public void EntityService_Can_Get_Paged_Content_Descendants_Without_Recycled()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
var toDelete = new List<IContent>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
ServiceContext.ContentService.Save(c1);
if (i % 2 == 0)
{
toDelete.Add(c1);
}
for (int j = 0; j < 5; j++)
{
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
ServiceContext.ContentService.Save(c2);
}
}
foreach (var content in toDelete)
{
ServiceContext.ContentService.MoveToRecycleBin(content);
}
var service = ServiceContext.EntityService;
long total;
//search at root to see if it returns recycled
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed:false)
.Select(x => x.Id)
.ToArray();
foreach (var c in toDelete)
{
Assert.IsFalse(entities.Contains(c.Id));
}
}
[Test]
public void EntityService_Can_Get_Paged_Content_Descendants_With_Search()
{
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
var root = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root);
ServiceContext.ContentService.Save(c1);
for (int j = 0; j < 5; j++)
{
var c2 = MockedContent.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1);
ServiceContext.ContentService.Save(c2);
}
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: "ssss").ToArray();
Assert.That(entities.Length, Is.EqualTo(10));
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, filter: "tttt").ToArray();
Assert.That(entities.Length, Is.EqualTo(50));
Assert.That(total, Is.EqualTo(50));
}
[Test]
public void EntityService_Can_Get_Paged_Media_Children()
{
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
ServiceContext.MediaService.Save(c1);
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(6));
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(4));
Assert.That(total, Is.EqualTo(10));
}
[Test]
public void EntityService_Can_Get_Paged_Media_Descendants()
{
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
var count = 0;
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
ServiceContext.MediaService.Save(c1);
count++;
for (int j = 0; j < 5; j++)
{
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
ServiceContext.MediaService.Save(c2);
count++;
}
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(31));
Assert.That(total, Is.EqualTo(60));
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray();
Assert.That(entities.Length, Is.EqualTo(29));
Assert.That(total, Is.EqualTo(60));
}
[Test]
public void EntityService_Can_Get_Paged_Media_Descendants_Including_Recycled()
{
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
var toDelete = new List<IMedia>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
ServiceContext.MediaService.Save(c1);
if (i % 2 == 0)
{
toDelete.Add(c1);
}
for (int j = 0; j < 5; j++)
{
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
ServiceContext.MediaService.Save(c2);
}
}
foreach (var content in toDelete)
{
ServiceContext.MediaService.MoveToRecycleBin(content);
}
var service = ServiceContext.EntityService;
long total;
//search at root to see if it returns recycled
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total)
.Select(x => x.Id)
.ToArray();
foreach (var media in toDelete)
{
Assert.IsTrue(entities.Contains(media.Id));
}
}
[Test]
public void EntityService_Can_Get_Paged_Media_Descendants_Without_Recycled()
{
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
var toDelete = new List<IMedia>();
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
ServiceContext.MediaService.Save(c1);
if (i % 2 == 0)
{
toDelete.Add(c1);
}
for (int j = 0; j < 5; j++)
{
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
ServiceContext.MediaService.Save(c2);
}
}
foreach (var content in toDelete)
{
ServiceContext.MediaService.MoveToRecycleBin(content);
}
var service = ServiceContext.EntityService;
long total;
//search at root to see if it returns recycled
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed:false)
.Select(x => x.Id)
.ToArray();
foreach (var media in toDelete)
{
Assert.IsFalse(entities.Contains(media.Id));
}
}
[Test]
public void EntityService_Can_Get_Paged_Media_Descendants_With_Search()
{
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
var root = MockedMedia.CreateMediaFolder(folderType, -1);
ServiceContext.MediaService.Save(root);
for (int i = 0; i < 10; i++)
{
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
c1.Name = "ssss" + Guid.NewGuid();
ServiceContext.MediaService.Save(c1);
for (int j = 0; j < 5; j++)
{
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
c2.Name = "tttt" + Guid.NewGuid();
ServiceContext.MediaService.Save(c2);
}
}
var service = ServiceContext.EntityService;
long total;
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: "ssss").ToArray();
Assert.That(entities.Length, Is.EqualTo(10));
Assert.That(total, Is.EqualTo(10));
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, filter: "tttt").ToArray();
Assert.That(entities.Length, Is.EqualTo(50));
Assert.That(total, Is.EqualTo(50));
}
[Test]
public void EntityService_Can_Find_All_Content_By_UmbracoObjectTypes()
{
@@ -358,9 +358,9 @@ namespace Umbraco.Tests.TestHelpers.Entities
contentCollection.Add(new PropertyType(Constants.PropertyEditors.DateAlias, DataTypeDatabaseType.Date) { Alias = "date", Name = "Date", Mandatory = false, SortOrder = 13, DataTypeDefinitionId = -41 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.DropDownListAlias, DataTypeDatabaseType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeDefinitionId = -42 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.CheckBoxListAlias, DataTypeDatabaseType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeDefinitionId = -43 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPickerAlias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1034 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPickerAlias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1035 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPickerAlias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1036 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1046 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1048 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1047 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.RelatedLinksAlias, DataTypeDatabaseType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeDefinitionId = 1040 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TagsAlias, DataTypeDatabaseType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeDefinitionId = 1041 });
+22 -22
View File
@@ -13,41 +13,41 @@ namespace Umbraco.Tests
[Test]
public void StringEntityCtorTest()
{
var udi = new StringUdi(Constants.DeployEntityType.AnyString, "test-id");
Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType);
var udi = new StringUdi(Constants.UdiEntityType.AnyString, "test-id");
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
Assert.AreEqual("test-id", udi.Id);
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString());
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
}
[Test]
public void StringEntityParseTest()
{
var udi = Udi.Parse("umb://" + Constants.DeployEntityType.AnyString + "/test-id");
Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType);
var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id");
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
Assert.IsInstanceOf<StringUdi>(udi);
var stringEntityId = udi as StringUdi;
Assert.IsNotNull(stringEntityId);
Assert.AreEqual("test-id", stringEntityId.Id);
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString());
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
}
[Test]
public void GuidEntityCtorTest()
{
var guid = Guid.NewGuid();
var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid);
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid);
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
Assert.AreEqual(guid, udi.Guid);
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString());
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString());
}
[Test]
public void GuidEntityParseTest()
{
var guid = Guid.NewGuid();
var s = "umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N");
var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N");
var udi = Udi.Parse(s);
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
Assert.IsInstanceOf<GuidUdi>(udi);
var gudi = udi as GuidUdi;
Assert.IsNotNull(gudi);
@@ -82,9 +82,9 @@ namespace Umbraco.Tests
var guid1 = Guid.NewGuid();
var entities = new[]
{
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
};
Assert.AreEqual(1, entities.Distinct().Count());
}
@@ -93,12 +93,12 @@ namespace Umbraco.Tests
public void CreateTest()
{
var guid = Guid.NewGuid();
var udi = Udi.Create(Constants.DeployEntityType.AnyGuid, guid);
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, guid);
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
Assert.AreEqual(guid, ((GuidUdi)udi).Guid);
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.DeployEntityType.AnyString, guid));
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.DeployEntityType.AnyGuid, "foo"));
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyString, guid));
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyGuid, "foo"));
Assert.Throws<ArgumentException>(() => Udi.Create("barf", "foo"));
}
@@ -106,13 +106,13 @@ namespace Umbraco.Tests
public void RangeTest()
{
// can parse open string udi
var stringUdiString = "umb://" + Constants.DeployEntityType.AnyString;
var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString;
Udi stringUdi;
Assert.IsTrue(Udi.TryParse(stringUdiString, out stringUdi));
Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id);
// can parse open guid udi
var guidUdiString = "umb://" + Constants.DeployEntityType.AnyGuid;
var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid;
Udi guidUdi;
Assert.IsTrue(Udi.TryParse(guidUdiString, out guidUdi));
Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid);
@@ -134,12 +134,12 @@ namespace Umbraco.Tests
var guid = Guid.NewGuid();
var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid);
var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid);
var json = JsonConvert.SerializeObject(udi, settings);
Assert.AreEqual(string.Format("\"umb://any-guid/{0:N}\"", guid), json);
var dudi = JsonConvert.DeserializeObject<Udi>(json, settings);
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, dudi.EntityType);
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, dudi.EntityType);
Assert.AreEqual(guid, ((GuidUdi)dudi).Guid);
var range = new UdiRange(udi, Constants.DeploySelector.ChildrenOfThis);
+1 -1
View File
@@ -169,7 +169,7 @@
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
<Compile Include="Persistence\Repositories\LockedRepositoryTests.cs" />
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
<Compile Include="Scheduling\DeployTest.cs" />
<Compile Include="Scheduling\BackgroundTaskRunnerTests2.cs" />
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
<Compile Include="Scoping\EventNameExtractorTests.cs" />
<Compile Include="Scoping\LeakTests.cs" />
+1 -1
View File
@@ -25,7 +25,7 @@
"jquery-migrate": "1.4.0",
"angular-dynamic-locale": "0.1.28",
"ng-file-upload": "~7.3.8",
"tinymce": "~4.1.10",
"tinymce": "~4.5.3",
"codemirror": "~5.3.0",
"angular-local-storage": "~0.2.3",
"moment": "~2.10.3",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

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