Compare commits

...

217 Commits

Author SHA1 Message Date
Niels Lyngsø a91d82b864 latest test version 2019-06-25 15:26:28 +02:00
Niels Lyngsø 6868581770 removed id 2019-06-25 15:26:06 +02:00
Niels Lyngsø 90e0fcb299 outcomment apporach on how to get media info to store in RTE content. 2019-06-13 08:27:39 +02:00
Niels Lyngsø 21abe5ff81 upload files to media library 2019-06-13 08:26:50 +02:00
Niels Lyngsø d0129caea4 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/5577-trix-property-editor 2019-06-11 14:58:12 +02:00
Sebastiaan Janssen 39d93a7ace Spelling mistake IContentFinder function (#5616)
Spelling mistake IContentFinder function
2019-06-11 13:00:27 +02:00
Niels Lyngsø 66eac81fe8 AngularJS requires ngModel to be the fourth attribute... 2019-06-11 08:44:06 +02:00
Patrick de Mooij e59d75f4f9 Spelling mistake IContentFinder function 2019-06-07 16:42:53 +02:00
Sebastiaan Janssen e3b2d427a4 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1
#	build/Modules/Umbraco.Build/Umbraco.Build.psm1
#	build/NuSpecs/UmbracoCms.Core.nuspec
#	build/NuSpecs/UmbracoCms.nuspec
#	src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
#	src/SQLCE4Umbraco/app.config
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Core/app.config
#	src/Umbraco.Core/packages.config
#	src/Umbraco.Tests.Benchmarks/app.config
#	src/Umbraco.Tests.Benchmarks/packages.config
#	src/Umbraco.Tests/App.config
#	src/Umbraco.Tests/Migrations/SqlScripts/SqlResources.Designer.cs
#	src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs
#	src/Umbraco.Tests/TreesAndSections/ResourceFiles.Designer.cs
#	src/Umbraco.Tests/packages.config
#	src/Umbraco.Web.UI.Client/bower.json
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI/Properties/Settings.Designer.cs
#	src/Umbraco.Web.UI/config/imageprocessor/cache.config
#	src/Umbraco.Web.UI/config/imageprocessor/processing.config
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web.UI/web.Template.Debug.config
#	src/Umbraco.Web.UI/web.Template.config
#	src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/Mvc/Strings.Designer.cs
#	src/Umbraco.Web/Properties/Settings1.Designer.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/UI/JavaScript/Resources.Designer.cs
#	src/Umbraco.Web/Web References/org.umbraco.our/Reference.cs
#	src/Umbraco.Web/Web References/org.umbraco.update/Reference.cs
#	src/Umbraco.Web/app.config
#	src/Umbraco.Web/packages.config
#	src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Resources.Designer.cs
#	src/UmbracoExamine/UmbracoExamine.csproj
#	src/UmbracoExamine/app.config
#	src/UmbracoExamine/packages.config
#	src/umbraco.MacroEngines/Resources/Strings.Designer.cs
#	src/umbraco.MacroEngines/app.config
#	src/umbraco.MacroEngines/packages.config
#	src/umbraco.MacroEngines/umbraco.MacroEngines.csproj
#	src/umbraco.businesslogic/app.config
#	src/umbraco.businesslogic/packages.config
#	src/umbraco.businesslogic/umbraco.businesslogic.csproj
#	src/umbraco.cms/app.config
#	src/umbraco.cms/businesslogic/Packager/FileResources/PackageFiles.Designer.cs
#	src/umbraco.cms/packages.config
#	src/umbraco.cms/umbraco.cms.csproj
#	src/umbraco.controls/TreePicker/BaseTreePickerScripts.Designer.cs
#	src/umbraco.controls/app.config
#	src/umbraco.controls/umbraco.controls.csproj
#	src/umbraco.datalayer/app.config
#	src/umbraco.datalayer/umbraco.datalayer.csproj
#	src/umbraco.editorControls/app.config
#	src/umbraco.editorControls/mediapicker/MediaChooserScripts.Designer.cs
#	src/umbraco.editorControls/umbraco.editorControls.csproj
#	src/umbraco.interfaces/umbraco.interfaces.csproj
#	src/umbraco.providers/app.config
#	src/umbraco.providers/umbraco.providers.csproj
2019-06-07 16:05:44 +02:00
Sebastiaan Janssen 22f54394fb Fix method signatures to prevent breaking changes (just like what I'd already done in v8) 2019-06-07 16:02:03 +02:00
Sebastiaan Janssen 57c368f70d Bumps version to 7.15.0 2019-06-07 14:32:02 +02:00
Bjarke Berg 0120dc6ea3 https://github.com/umbraco/Umbraco-CMS/issues/5574 - Fixes issue when… (#5575) 2019-06-07 09:01:15 +02:00
Shannon 9f346e6ee2 fixes valServer directive so that JS errors dont' occur on the content tyep editor 2019-06-07 13:01:58 +10:00
Shannon 3ea9504620 Revert "Don't show multiple open menus"
This reverts commit 661246b5f5.
2019-06-07 13:01:13 +10:00
Shannon Deminick 86db972188 Merge pull request #5208 from umbraco/v8/bugfix/5190-invariant-property-validation
Fix for server side validation fails invariant-properties on non-default languages.
2019-06-07 12:16:57 +10:00
Shannon 6d12eea789 Adds unit tests for serverValidationManager and fixes it up to ensure that the correct culture callbacks are called. 2019-06-07 12:16:00 +10:00
Shannon 68174bc7df Merge branch 'v8/dev' into v8/bugfix/5190-invariant-property-validation 2019-06-07 11:21:36 +10:00
Shannon 5ca9600c98 adds comments 2019-06-07 11:01:30 +10:00
Shannon 87b3fb5539 Fixes BulkInsertRecordsSqlServer 2019-06-07 10:18:45 +10:00
Sébastien Sougnez 4be6a48fb2 Update tinymce version to 4.9.4 in v7 (#4703) 2019-06-06 17:42:12 +02:00
Sebastiaan Janssen 53731049de Updates .NET Framework to 4.5.2 and updates dependencies (#3064)
Updates .NET Framework to 4.5.2 and updates dependencies
2019-06-06 17:27:53 +02:00
Sebastiaan Janssen 4b2ce522fe Update nuspecs 2019-06-06 15:55:38 +02:00
Sebastiaan Janssen d0eddbb9a2 Update SignalR 2019-06-06 15:38:37 +02:00
Sebastiaan Janssen 938abab9d6 Update assembly redirects 2019-06-06 15:29:32 +02:00
Sebastiaan Janssen 5faa71187d More Owin updates 2019-06-06 15:21:05 +02:00
Sebastiaan Janssen c069f262dc Update MVC, Razor, WebApi and Owin 2019-06-06 14:50:01 +02:00
Shannon Deminick ac79fe7a77 Merge pull request #5576 from umbraco/v8/bugfix/database-factory-fix
Fix UmbracoDatabaseFactory SqlServer detection
2019-06-06 22:46:37 +10:00
Sebastiaan Janssen 9f42e6a607 Update ImageProcessor and Newtonsoft.Json dependencies to the latest version 2019-06-06 14:37:57 +02:00
Shannon 3f8fe334b2 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-06-06 22:35:15 +10:00
Shannon 096004db13 fixes infinite loop issue 2019-06-06 22:34:57 +10:00
Sebastiaan Janssen 202f2d2e27 Fix build for VS2019 (not complete yet) 2019-06-06 13:53:42 +02:00
Sebastiaan Janssen aaab14be3e fix csproj file 2019-06-06 13:48:48 +02:00
Sebastiaan Janssen 1c87176d80 Merge branch 'v7/dev' into pr/3064
# Conflicts:
#	build/NuSpecs/UmbracoCms.Core.nuspec
#	src/Umbraco.Tests/packages.config
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web/packages.config
#	src/umbraco.MacroEngines/packages.config
2019-06-06 12:50:48 +02:00
Shannon Deminick 04967143d8 Merge pull request #5598 from kjac/v8-fix-content-type-culture-variance
V8: Fix broken culture variance toggle on content type properties
2019-06-06 17:33:17 +10:00
Kenn Jacobsen 70fb48d94a Fix broken culture variance toggle on content type properties 2019-06-06 08:39:21 +02:00
Shannon 760d1d7daa Merge branch 'v8/dev' into v8/bugfix/database-factory-fix 2019-06-06 16:32:24 +10:00
Shannon Deminick 3135353a1a Merge pull request #5597 from kjac/v8-fix-rte-unconfigured-dimensions
V8: Fix JS error when the RTE has unconfigured dimensions
2019-06-06 16:16:07 +10:00
Kenn Jacobsen 1565ff1661 Fix JS error when the RTE has unconfigured dimensions 2019-06-06 08:04:06 +02:00
Sebastiaan Janssen bc55d96cde Merge pull request #5589 from MvdDonk/v8/dev
5588 - Correct location for Visual Studio xml documentation files
2019-06-05 16:17:44 +02:00
Maarten v.d. Donk 3d2379d582 Correct location for Visual Studio xml documentation files (5588) 2019-06-05 11:34:42 +02:00
Shannon Deminick 73e907291b Merge pull request #5568 from umbraco/v8/bugfix/5565-rte-sizing
5565 fix for configuration of TineMCE size
2019-06-05 16:07:55 +10:00
Shannon 49c76c744e Fixes width/height for when in distraction free mode 2019-06-05 16:06:55 +10:00
Shannon 8967061758 fixes semi colons 2019-06-05 15:21:00 +10:00
Niels Lyngsø eff8075102 Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/5190-invariant-property-validation
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
2019-06-04 14:49:23 +02:00
Niels Lyngsø ae5122f4bb adding localization for notification when uploading a disallowed file type 2019-06-04 14:39:54 +02:00
Niels Lyngsø 6085d659e2 adding localizationService dependency 2019-06-04 14:39:18 +02:00
Niels Lyngsø 3675b3f40c First implementation of Trix 2019-06-04 14:23:40 +02:00
Niels Lyngsø e9eb1e9b45 Enable tokens in TranslateMeny 2019-06-04 14:23:19 +02:00
Niels Lyngsø 156fd1b4e6 Gulp tasks that enables working with the property-editor as App_Plugin from UI.Client 2019-06-04 14:22:58 +02:00
Stephan 849feb0683 Fix UmbracoDatabaseFactory SqlServer detection 2019-06-04 13:15:25 +02:00
Sebastiaan Janssen a182c9b1ee Updates to latest Examine (#4851)
Updates to latest Examine
2019-06-04 13:06:35 +02:00
Poornima Nayar 17675d389e Toggle color picker labels squeeze spectrum color picker (#5391) 2019-06-03 12:41:27 +02:00
Niels Lyngsø f30aefb614 parse dimensions to configuration of TinyMCE + remove autoresize if height is set. 2019-06-03 12:04:14 +02:00
Sebastiaan Janssen a1722f268c Merge pull request #5400 from poornimanayar/temp-5326
Search shadow-layer should be on top of the user-dialog
2019-06-03 12:00:41 +02:00
Poornima Nayar 864d83f8f7 Introduce a maxlength on the name of the node (#5374) 2019-06-03 11:41:58 +02:00
Bjarke Berg 2f978e96d4 Merge pull request #5467 from umbraco/v8/bugfix/805-migrate-from-7
Tested starterkit both using SqlCE and SqlServer and reviewed the code. Merging in..
2019-06-03 10:59:57 +02:00
Sebastiaan Janssen dccc6238e0 Merge pull request #5558 from FransdeJong/DeleteDictionaryChildren
Added a check for and delete descendants when deleting a dictionary item
2019-06-03 10:21:45 +02:00
Sebastiaan Janssen 0687125343 Merge pull request #5563 from kjac/v8-fix-multiple-open-menus
V8: Don't show multiple open menus
2019-06-03 10:16:02 +02:00
Sebastiaan Janssen de36edfd58 Merge pull request #5566 from bjarnef/dev-v8-rte-startnodes-description
v8: Remove HTML characters in RTE prevalue description
2019-06-03 10:14:35 +02:00
Bjarne Fyrstenborg 2842a56356 Remove html characters in description 2019-06-02 23:03:20 +02:00
Kenn Jacobsen 661246b5f5 Don't show multiple open menus 2019-06-01 21:11:59 +02:00
Frans de Jong 457474ecf9 Added a check for and delete descendants when deleting a dictionary item 2019-06-01 13:07:16 +02:00
Sebastiaan Janssen 5f67b3a9c1 Merge pull request #5458 from tiffy74/issue#5277_13
Issue#5277 13
2019-05-31 20:52:16 +02:00
Sebastiaan Janssen a3547a79e8 Merge pull request #5460 from kjac/v8-fix-rte-load-indicator
V8: Use umb-load-indicator when loading the RTE
2019-05-31 20:49:22 +02:00
Sebastiaan Janssen c6467b355d Merge pull request #5491 from kjac/v8-feature-mntp-single-mode-improvements
V8: MNTP improvements when configured to select only one item
2019-05-31 20:47:41 +02:00
Sebastiaan Janssen e2ef186dd1 Merge pull request #5519 from FransdeJong/Umb-Sections
Updated allowed width for Umb-Section directive
2019-05-31 20:41:39 +02:00
Sebastiaan Janssen 0ccc40bf52 Merge pull request #5522 from kjac/v8-feature-content-type-editor-without-live-editing
V8: Don't apply changes instantly when editing content type properties
2019-05-31 20:39:22 +02:00
Sebastiaan Janssen ebc21a1cc7 V8: Apply nicer log message wrapping (#5274)
V8: Apply nicer log message wrapping
2019-05-31 20:36:00 +02:00
Kenn Jacobsen 30067d92ae V8: Always show content and media search results first (#5309) 2019-05-31 20:29:00 +02:00
Kenn Jacobsen 342f924e8f V8: Fix the link picker anchor list (#5379) 2019-05-31 20:27:15 +02:00
Sebastiaan Janssen ba12efd285 Merge pull request #5358 from kjac/v8-feature-backoffice-localize
V8: Allow localizing content types and properties using language files
2019-05-31 20:15:22 +02:00
Sebastiaan Janssen ed3efe9bee V8: Default nested content item names to the item type name (#5369)
V8: Default nested content item names to the item type name
2019-05-31 20:11:56 +02:00
Sebastiaan Janssen 47a7c08686 Merge pull request #5407 from kjac/v8-fix-users-search-empty-state
V8: Add/fix empty state in users and groups search
2019-05-31 20:08:57 +02:00
Sebastiaan Janssen 5191dbf011 Case insensitive section comparison (#5540)
Case insensitive section comparison
2019-05-31 20:07:26 +02:00
Sebastiaan Janssen 8d9ae085aa Fix bug with multi url picker. (#5408)
Fix bug with multi url picker.
2019-05-31 19:59:30 +02:00
Sebastiaan Janssen 161d6505eb Merge pull request #5414 from electricsheep/v8/bugfix/5404-avatar-cursor
V8: Fix the avatar cursor
2019-05-31 19:42:12 +02:00
Sebastiaan Janssen c292f7ff03 Merge pull request #5424 from electricsheep/v8/bugfix/5292-remove-hsts-preload
V8: Remove preload from HSTS healthcheck
2019-05-31 19:31:19 +02:00
Sebastiaan Janssen 17860fb8c7 Merge pull request #5432 from leekelleher/v8/bugfix/entitycontroller-convert-membertype
Corrected `EntityController.ConvertToObjectType` return type for MemberType
2019-05-31 19:28:01 +02:00
Sebastiaan Janssen eb642dc611 Merge pull request #5434 from bjarnef/patch-2
Fix noPasswordManager name for docs
2019-05-31 19:27:07 +02:00
Sebastiaan Janssen bc99d074a9 Merge pull request #5435 from ArnoldV/temp-5420
5420: v8 Invited user keeps showing as "has not logged in yet"
2019-05-31 19:25:56 +02:00
Kenn Jacobsen d536bebdbe V8: Show loading indicator while the Nested Content editor is loading (#5446) 2019-05-31 19:22:23 +02:00
Sebastiaan Janssen 3639d952d5 Merge pull request #5447 from kjac/v8-fix-nested-content-set-dirty-on-paste
V8: Prompt to save changes after pasting items into Nested Content
2019-05-31 19:19:41 +02:00
Sebastiaan Janssen 7c79cf318e Merge pull request #5450 from Matthew-Wise/5277-27
Login errors are not identified for screen reader users
2019-05-31 19:17:45 +02:00
Sebastiaan Janssen 6ad1607685 Merge pull request #5456 from electricsheep/v8/feature/5443-add-publish-menu-hotkeys
V8/feature/5443 add publish menu hotkeys
2019-05-31 19:15:41 +02:00
Sebastiaan Janssen c1ed2b9f45 Merge pull request #5523 from kjac/v8-fix-tree-node-flickering
V8: Fix the flickering when browsing up and down already loaded trees
2019-05-31 16:42:56 +02:00
Sebastiaan Janssen 2c5eeaeac8 V8: Don't load the breadcrumb twice when editing content (#5454)
V8: Don't load the breadcrumb twice when editing content
2019-05-31 16:41:43 +02:00
Sebastiaan Janssen a74a0c343e Merge pull request #5465 from kjac/v8-feature-content-sort-ux
V8: UX update for content/media sort dialog
2019-05-31 16:40:17 +02:00
Sebastiaan Janssen 4eb897ccff Merge pull request #5477 from electricsheep/v8/bugfix/5443-save-options-not-tabbable
V8: Enable tabbing for save options dropdown
2019-05-31 16:37:58 +02:00
Sebastiaan Janssen 20dc77c330 Merge pull request #5480 from electricsheep/v8/bugfix/4657-fix-view-source-animation
V8: Fix TinyMCE source overlay animation
2019-05-31 16:36:04 +02:00
Sebastiaan Janssen 4c79863130 Merge pull request #5521 from FransdeJong/Issue5038
Fixed form controls being pushed off screen.
2019-05-31 16:25:19 +02:00
Sebastiaan Janssen 9ec95c7aa2 Merge pull request #5520 from kjac/v8-fix-macro-tree-sorting
V8: Sort macros alphabetically
2019-05-31 16:21:29 +02:00
Sebastiaan Janssen 38bfd07883 Merge pull request #5535 from AndyButland/defect/5534-user-no-group-save-notification
V8: Fixes #5534 (saving a user with no groups fails validation, but no message is displayed)
2019-05-31 16:19:01 +02:00
Sebastiaan Janssen ce15b7c7c4 Merge pull request #5548 from kjac/v8-feature-reload-close-context-menu
V8: Automatically hide the context menu after reloading a node
2019-05-31 16:17:41 +02:00
Sebastiaan Janssen b090de3cde Merge pull request #5549 from kjac/v8-fix-remove-reload-for-container-nodes
V8: Don't show "Reload" for list view nodes
2019-05-31 16:16:42 +02:00
Bjarne Fyrstenborg dbd74f5273 v8: Fix listview layout icons (#5405) 2019-05-31 16:15:20 +02:00
Ollie P e87f8b14be Removed reference to adding languages from dictionary item description (#5457) 2019-05-31 16:14:10 +02:00
Sebastiaan Janssen fb14a4987c Merge pull request #5494 from kjac/v8-fix-umbconfirm-cursor
V8: umb-confirm button cursor should be "pointer"
2019-05-31 16:12:14 +02:00
Sebastiaan Janssen a471e7d25e Merge pull request #5553 from kjac/v8-fix-pointer-cursor-for-ng-links
V8: Ensure "pointer" cursor for all links with ng-click
2019-05-31 16:11:23 +02:00
Sebastiaan Janssen fef9248b51 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/macropicker.html
#	src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-05-31 11:36:29 +02:00
Kenn Jacobsen a8e2798add Ensure "pointer" cursor for all links with ng-click (even if they have no href) 2019-05-30 21:39:52 +02:00
Sebastiaan Janssen 6af1057ad7 Merge pull request #5508 from Geckex/v7/temp-5507
MemberModelMapper to return member groups ordered alphabetically
2019-05-30 17:38:53 +02:00
Bjarke Berg b366c5da03 Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/805-migrate-from-7 2019-05-29 10:14:31 +02:00
Stephan 24998425fc Better handling of default constraints 2019-05-29 09:19:29 +02:00
Mario Lopez 1ad4414026 case insensitive section comparison 2019-05-29 11:39:10 +10:00
Stephan 70e4b7d931 Fix tests 2019-05-28 18:40:44 +02:00
Stephan 49d2a6dbf0 Fix migrations for SqlServer 2019-05-28 17:49:50 +02:00
Andy Butland 0dedd7b2d4 Show the notification when validation fails following saving a user with no groups assigned 2019-05-28 15:57:03 +02:00
Stephan 457427a5f4 Cleanup logging in DataTypeMigration 2019-05-28 10:58:47 +02:00
Stephan 5046bc019c Cleanup strings in UmbracoPlan 2019-05-28 10:52:04 +02:00
Stephan 187ab9ba46 Better exceptions in MigrationPlan 2019-05-28 10:46:26 +02:00
Stephan 3a813d2d77 Cleanup unknown user for audit events 2019-05-28 10:26:30 +02:00
Kenn Jacobsen 460653d078 Don't show "Reload" for container nodes 2019-05-26 19:06:24 +02:00
Kenn Jacobsen beb9068805 Automatically hide the context menu after reloading a node 2019-05-26 19:05:19 +02:00
Kenn Jacobsen f5a00cc3bd Fix the tree node flickering when browsing up and down already loaded trees. 2019-05-26 13:43:30 +02:00
Frans de Jong 86aef126fd Added float none for viewport up to 768 Larger viewports are not affected 2019-05-25 22:17:19 +02:00
Kenn Jacobsen 0e9d0a5a10 Don't live edit content type properties 2019-05-25 19:08:46 +02:00
Kenn Jacobsen a4f1b433eb Sort macros alphabetically 2019-05-25 10:34:03 +02:00
Frans de Jong 08b386e180 Finetuned Umb-Sections directive to use full space 2019-05-25 10:19:08 +02:00
Sebastiaan Janssen 97ae6165e4 Merge pull request #5511 from ReVoid/patch-1
ng-switch-default directive typo in macropicker.html
2019-05-23 11:19:47 +02:00
Sebastiaan Janssen c4ba0454fc Merge pull request #5488 from bjarnef/dev-v8-fix-overlay-drawer
v8: Fix overlay drawer
2019-05-22 23:02:13 +02:00
Sebastiaan Janssen cf1351b50f v8: Show box shadow when hover user avatar (#5490)
v8: Show box shadow when hover user avatar
2019-05-22 21:02:43 +02:00
Dmitriy 8cdb61195d ng-switch-default typo in macropicker.html
looks like it is just a typo :) fixed
2019-05-22 19:49:07 +03:00
Thomas Poulsen 50c2d574f1 Change MemberModelMapper GetMemberGroupValue to return member groups ordered alphabetically.
- This is used in ContentPropertyDisplay class - for UI purposes only.
2019-05-22 14:13:46 +01:00
Sebastiaan Janssen e3de3f98fd Merge pull request #5396 from kjac/v8-fix-color-picker-label-enabled
V8: Make sure that the color picker labels are always shown
2019-05-22 14:43:17 +02:00
Kenn Jacobsen 7a8a1a3705 Add a bit of a wait to the toggle initialization 2019-05-21 11:48:02 +02:00
Kenn Jacobsen 7707839968 Merge branch 'v8/dev' into v8-fix-color-picker-label-enabled 2019-05-21 11:36:18 +02:00
Sebastiaan Janssen b270db791b Merge pull request #5398 from kjac/v8-fix-rte-codeview-autofocus
V8: Support auto focus on ACE editor and use it for RTE source view
2019-05-21 10:40:04 +02:00
Kenn Jacobsen c6cabf1239 Make sense of the umb-confirm button cursor 2019-05-20 08:11:00 +02:00
Sebastiaan Janssen 0ea4864f24 Merge pull request #5461 from kjac/v8-fix-confirm-discard-esc-key
V8: Disable the escape key in the "unsaved changes" dialog
2019-05-19 10:01:14 +02:00
Kenn Jacobsen f07fcac13d If MNTP is configured to pick max 1 item, don't allow multiselect in the content picker dialog 2019-05-19 08:38:03 +02:00
Kenn Jacobsen e2746604a1 If MNTP is configured to pick max 1 item, convert the value into IPublishedContent instead of IEnumerable<IPublishedContent> 2019-05-19 08:37:33 +02:00
Bjarne Fyrstenborg 21e8a6faf4 Cleanup styles 2019-05-18 14:40:35 +02:00
Bjarne Fyrstenborg 65d8be45a1 Show box shadow when hover user avatar 2019-05-18 14:27:51 +02:00
Bjarne Fyrstenborg 00768fdfa7 Remove empty style 2019-05-18 13:33:43 +02:00
Bjarne Fyrstenborg ee3105009b Add back 100% height to make drawer positioned at bottom in overlays. 2019-05-18 13:33:16 +02:00
Ollie Philpott e9b5225676 Updated view source callback to execute correctly 2019-05-16 15:38:56 +01:00
Stephan 5dbc95a604 Fix StandaloneTests 2019-05-16 14:48:04 +02:00
Bjarke Berg 206f47bf52 Added missing nuget dependencies to the nuspec-file of UmbracoCms.Core 2019-05-16 14:24:09 +02:00
Stephan ea4f1a0f56 Merge branch v8/dev into v8/bugfix/805-migrate-from-7 2019-05-16 13:58:32 +02:00
Ollie Philpott c2046ad173 Fixed formatting 2019-05-16 10:53:03 +01:00
Ollie Philpott f080260396 Enabled tabbing for save options dropdown 2019-05-16 10:42:37 +01:00
Niels Lyngsø 9fac00d91b Fixed documentation mistake 2019-05-16 10:50:24 +02:00
Niels Lyngsø 4456a202e4 Merge remote-tracking branch 'origin/pr_5448' into v8/dev 2019-05-16 10:36:57 +02:00
Niels Lyngsø b503becaf3 Only show if we do have pasteable items. 2019-05-16 10:27:00 +02:00
Niels Lyngsø 5d1da3ada1 normalizing non-existing-culture to "invariant", cause the server sends invariant errors as invariant-culture. 2019-05-16 09:15:57 +02:00
Stephan d5e63c0e62 Fix ContentNu cascade rules 2019-05-15 18:27:34 +02:00
Stephan 066a860c1d Fix more PreValues migration + better error reporting 2019-05-15 17:00:05 +02:00
Niels Lyngsø 225688facf fix comment 2019-05-15 16:23:23 +02:00
Niels Lyngsø 8bc28a4d81 clean up 2019-05-15 16:21:38 +02:00
Stephan c0f650436b Fix wording in DatabaseBuilder 2019-05-15 16:17:18 +02:00
Niels Lyngsø e7e74840bc indication if something is wrong in another variant than the current one. 2019-05-15 16:11:01 +02:00
Stephan d16002eb7c Fix KeyValueService to support re-running migrations 2019-05-15 15:34:37 +02:00
Stephan 1a54a24150 Fix DataType and PreValues migrations 2019-05-15 14:21:24 +02:00
Niels Lyngsø ceb1260509 current progress 2019-05-15 08:49:16 +02:00
Kenn Jacobsen 9706a0f76a Remove sort order and add item icons in content and media sort dialogs 2019-05-15 08:32:47 +02:00
Kenn Jacobsen 572dc11995 Disable the escape key in the "confirm discard" dialog 2019-05-14 18:43:57 +02:00
Kenn Jacobsen 12d79f2d08 Use umb-load-indicator when loading the RTE 2019-05-14 17:54:37 +02:00
Tiffany Prosser ef15c247c2 updated styles on focus state on section menu 2019-05-14 14:05:09 +01:00
Tiffany Prosser d255cd115b fixed sections.less focus states on top menu 2019-05-14 13:45:49 +01:00
Sebastiaan Janssen 1090d54763 Update to the latest caniuse-lite to fix the build
Fixes #5455
2019-05-14 13:32:28 +02:00
Ollie Philpott c0c9f4dfcc Changed publish submenu rendering to allow working hotkeys 2019-05-14 12:21:29 +01:00
Ollie Philpott 61ba78538a Added hotkeys for schedule and publish with descendants 2019-05-14 12:20:58 +01:00
Kenn Jacobsen cb76914a27 Don't load the breadcrumb twice when editing content 2019-05-14 09:09:18 +02:00
Matthew Wise 9b0d16f0ad Added aria label for validation messages on login 2019-05-11 17:31:37 +01:00
Kenn Jacobsen d9027e04f3 Hide "Create new" header in Nested Content create item dialog if all items are filtered out 2019-05-10 21:58:55 +02:00
Kenn Jacobsen 3377888219 Prompt to save changes after pasting items into Nested Content 2019-05-10 21:45:06 +02:00
Stephan 0b924f75d4 Fix migrations 2019-05-10 10:14:15 +02:00
Stephan 301b16a036 Fix user for v7 migration 2019-05-10 10:14:15 +02:00
Stephan 919fb79db9 Fix migrations 2019-05-10 10:14:15 +02:00
Stephan ba9aa49b91 Fix user for v7 migration 2019-05-10 10:14:14 +02:00
Stephan 7fed43cc68 Fix migration tooling 2019-05-10 10:14:14 +02:00
Stephan a1828fec51 Fix migrations 2019-05-10 10:14:09 +02:00
Arnold Visser 62a6a4ec92 5420: v8 Invited user keeps showing as "has not logged in yet" 2019-05-09 10:31:44 +02:00
Bjarne Fyrstenborg 943e050493 Fix noPasswordManager name for docs
Fix `noPasswordManager` for documentation.
https://our.umbraco.com/apidocs/v8/ui/#/api/umbraco.directives.directive:no-password-manager
2019-05-09 09:45:29 +02:00
leekelleher e958ca6f89 Fixed EntityController.ConvertToObjectType (for MemberType)
When the `entityType` was "MemberType", it would return the "MediaType" object-type.
2019-05-09 07:21:18 +01:00
Ollie Philpott 0a752c8985 Updated hsts description from days to weeks 2019-05-08 11:57:03 +01:00
Ollie Philpott b6ad19ccad Corrected hsts max age description 2019-05-08 11:12:09 +01:00
Ollie Philpott bea1d35ebf Updated hsts urls 2019-05-08 11:11:47 +01:00
Ollie Philpott dae8802c50 Removed preload from descriptions 2019-05-08 11:11:01 +01:00
Ollie Philpott 58cdff1d71 Removed preload from HSTS header 2019-05-08 11:09:45 +01:00
Shannon 93bc2dc95b fixes some null checks 2019-05-08 17:48:54 +10:00
Shannon 1bcf40402c Merge branch 'v8/dev' into v8/bugfix/5190-invariant-property-validation
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
2019-05-08 16:53:21 +10:00
Shannon 7b101f0b9e Fixes duplicate error messages per key in ModelState 2019-05-08 16:52:25 +10:00
Shannon dad3f31f86 merged 2019-05-08 16:51:23 +10:00
Stephan 7cd31ce970 Fix TourController during upgrade 2019-05-07 14:58:05 +02:00
Stephan 54a8796d51 Cleanup migration plan, supports 7.14.0 2019-05-07 14:58:05 +02:00
Ollie Philpott e091987f0f Added hash to user profile href and reordered attributes 2019-05-07 11:57:35 +01:00
Kenn Jacobsen f07b9da2ef Add line wrap to RTE code editor 2019-05-06 14:57:18 +02:00
Thomas Pralong 60a3cdc5ab Fix bug with multi url picker. Would display the wrong language tree in
the link picker dialog
2019-05-06 10:47:33 +02:00
Kenn Jacobsen 03006d7698 Add empty state to groups search result 2019-05-05 19:00:36 +02:00
Kenn Jacobsen 8344372ae2 Fix the empty state for User search 2019-05-05 18:40:10 +02:00
Poornima Nayar 4fa07389dd Search shadow-layer should be on top of the user-dialog 2019-05-03 13:07:05 +01:00
Kenn Jacobsen a056c273de Support auto focus on ACE editor and use it for RTE code view 2019-05-03 11:17:15 +02:00
Kenn Jacobsen a6136c18bb Make sure that the color picker labels are always shown 2019-05-03 09:01:41 +02:00
Kenn Jacobsen 2bdbd86787 Default nested content item names to the content type name if there are multiple content item types to choose from 2019-05-01 09:10:09 +02:00
Kenn Jacobsen 3d86b08e31 Send delete notifications when content is moved to trash 2019-04-30 22:19:38 +02:00
matthew-hair 5cef71e4e6 fixed typos in ClearLoginSessions queries 2019-04-30 22:11:07 +02:00
matthew-hair fe7b114083 fix for umbracoUserLogin not pruned
Signed-off-by: matthew-hair <matthew.hair@sedgwick.gov>
2019-04-30 22:11:07 +02:00
Kenn Jacobsen adc7201e86 Allow localizing content types and properties using language files 2019-04-29 08:24:34 +02:00
Kenn Jacobsen 2c436d5ae0 Apply nicer log message wrapping 2019-04-16 09:39:54 +02:00
Niels Lyngsø 92a0ec2964 take valserver and valpropertymsg out of business if we are dealing with invariant property on non-default-language 2019-04-11 13:03:28 +02:00
Niels Lyngsø 760b7ad0ce Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/5190-invariant-property-validation 2019-04-11 11:53:27 +02:00
Niels Lyngsø b6918253c0 if invariant property then only validate if we are working on the default language. 2019-04-09 15:07:31 +02:00
Shannon 34a3389c17 Updates to latest Examine 2019-03-05 12:50:51 +11:00
Shannon beb325eacf oops got a couple versions wrong 2018-09-28 15:01:47 +10:00
Shannon 8e45bcf23f changes targetFramework in web.config 2018-09-28 14:34:39 +10:00
Shannon 40dc49ed47 updates nuspecs 2018-09-28 14:27:03 +10:00
Shannon 4b07305dc5 Update HtmlAgilityPack 2018-09-28 14:10:45 +10:00
Shannon 2514a59e93 Latest MS libs for benchmark project 2018-09-28 14:00:03 +10:00
Shannon 6843da790c Latest MS libs for benchmark project 2018-09-28 13:57:48 +10:00
Shannon ba1a9c3758 Updates to latest compatible CodeAnalysis & DotNetCompilerPlatform libs 2018-09-28 13:54:20 +10:00
Shannon 332ad6349d Updates latest newtonsoft.json 2018-09-28 12:59:12 +10:00
Shannon 42e48426e4 Updates other MS libs: ValueTuple, Dataflow, Reflection.Metadata 2018-09-28 12:44:17 +10:00
Shannon a0cc788f27 Updates to latest Image Processor versions 2018-09-28 12:24:16 +10:00
Shannon aecf96d74d Updates to latest MVC, WebApi and Owin 2018-09-28 12:19:34 +10:00
Shannon c75938076e reinstalls all packages flagged as 'requiresReinstallation' 2018-09-28 11:54:05 +10:00
Shannon cebbcb711a csproj, etc... updates for 452 (and 462 for benchmark proj) 2018-09-28 11:29:56 +10:00
223 changed files with 3173 additions and 3099 deletions
+3 -1
View File
@@ -39,6 +39,8 @@
<dependency id="Serilog.Formatting.Compact.Reader" version="[1.0.3,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.2.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="Serilog.Sinks.Map" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Sinks.Async" version="[1.3.0,1.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</group>
@@ -50,7 +52,7 @@
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\net472\Umbraco.Core.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
+3 -3
View File
@@ -53,9 +53,9 @@
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\net472\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net472\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\net472\Umbraco.Examine.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
@@ -44,21 +44,22 @@ namespace Umbraco.Core.Compose
public void Terminate()
{ }
internal static IUser UnknownUser => new User { Id = Constants.Security.UnknownUserId, Name = Constants.Security.UnknownUserName, Email = "" };
private IUser CurrentPerformingUser
{
get
{
var identity = Thread.CurrentPrincipal?.GetUmbracoIdentity();
return identity == null
? new User { Id = 0, Name = "SYSTEM", Email = "" }
: _userService.GetUserById(Convert.ToInt32(identity.Id));
var user = identity == null ? null : _userService.GetUserById(Convert.ToInt32(identity.Id));
return user ?? UnknownUser;
}
}
private IUser GetPerformingUser(int userId)
{
var found = userId >= 0 ? _userService.GetUserById(userId) : null;
return found ?? new User {Id = 0, Name = "SYSTEM", Email = ""};
return found ?? UnknownUser;
}
private string PerformingIp
+6 -1
View File
@@ -15,13 +15,18 @@ namespace Umbraco.Core
public const int SuperUserId = -1;
/// <summary>
/// The id for the 'unknown' user
/// The id for the 'unknown' user.
/// </summary>
/// <remarks>
/// This is a user row that exists in the DB only for referential integrity but the user is never returned from any of the services
/// </remarks>
public const int UnknownUserId = 0;
/// <summary>
/// The name of the 'unknown' user.
/// </summary>
public const string UnknownUserName = "SYTEM";
public const string AdminGroupAlias = "admin";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
@@ -25,11 +25,25 @@ namespace Umbraco.Core.Migrations.Expressions.Create.KeysAndIndexes
var syntax = _context.SqlContext.SqlSyntax;
var tableDefinition = DefinitionFactory.GetTableDefinition(TypeOfDto, syntax);
// note: of course we are creating the keys and indexes as per the DTO, so
// changing the DTO may break old migrations - or, better, these migrations
// should capture a copy of the DTO class that will not change
ExecuteSql(syntax.FormatPrimaryKey(tableDefinition));
foreach (var sql in syntax.Format(tableDefinition.Indexes))
ExecuteSql(sql);
foreach (var sql in syntax.Format(tableDefinition.ForeignKeys))
ExecuteSql(sql);
// note: we do *not* create the DF_ default constraints
/*
foreach (var column in tableDefinition.Columns)
{
var sql = syntax.FormatDefaultConstraint(column);
if (!sql.IsNullOrWhiteSpace())
ExecuteSql(sql);
}
*/
}
private void ExecuteSql(string sql)
@@ -10,9 +10,13 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
IDeleteDefaultConstraintOnTableBuilder,
IDeleteDefaultConstraintOnColumnBuilder
{
public DeleteDefaultConstraintBuilder(DeleteDefaultConstraintExpression expression)
private readonly IMigrationContext _context;
public DeleteDefaultConstraintBuilder(IMigrationContext context, DeleteDefaultConstraintExpression expression)
: base(expression)
{ }
{
_context = context;
}
/// <inheritdoc />
public IDeleteDefaultConstraintOnColumnBuilder OnTable(string tableName)
@@ -25,6 +29,9 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
public IExecutableBuilder OnColumn(string columnName)
{
Expression.ColumnName = columnName;
Expression.HasDefaultConstraint = _context.SqlContext.SqlSyntax.TryGetDefaultConstraint(_context.Database, Expression.TableName, columnName, out var constraintName);
Expression.ConstraintName = constraintName ?? string.Empty;
return new ExecutableBuilder(Expression);
}
}
@@ -1,4 +1,4 @@
using NPoco;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Migrations.Expressions.Common;
using Umbraco.Core.Migrations.Expressions.Delete.Column;
using Umbraco.Core.Migrations.Expressions.Delete.Constraint;
@@ -29,9 +29,19 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
}
/// <inheritdoc />
public IExecutableBuilder KeysAndIndexes(string tableName = null)
public IExecutableBuilder KeysAndIndexes<TDto>(bool local = true, bool foreign = true)
{
return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName };
var syntax = _context.SqlContext.SqlSyntax;
var tableDefinition = DefinitionFactory.GetTableDefinition(typeof(TDto), syntax);
return KeysAndIndexes(tableDefinition.Name, local, foreign);
}
/// <inheritdoc />
public IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true)
{
if (tableName.IsNullOrWhiteSpace())
throw new ArgumentNullOrEmptyException(nameof(tableName));
return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName, DeleteLocal = local, DeleteForeign = foreign };
}
/// <inheritdoc />
@@ -100,7 +110,7 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
public IDeleteDefaultConstraintOnTableBuilder DefaultConstraint()
{
var expression = new DeleteDefaultConstraintExpression(_context);
return new DeleteDefaultConstraintBuilder(expression);
return new DeleteDefaultConstraintBuilder(_context, expression);
}
}
}
@@ -10,12 +10,17 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.Expressions
public virtual string TableName { get; set; }
public virtual string ColumnName { get; set; }
public virtual string ConstraintName { get; set; }
public virtual bool HasDefaultConstraint { get; set; }
protected override string GetSql()
{
return string.Format(SqlSyntax.DeleteDefaultConstraint,
SqlSyntax.GetQuotedTableName(TableName),
SqlSyntax.GetQuotedColumnName(ColumnName));
return HasDefaultConstraint
? string.Format(SqlSyntax.DeleteDefaultConstraint,
SqlSyntax.GetQuotedTableName(TableName),
SqlSyntax.GetQuotedColumnName(ColumnName),
SqlSyntax.GetQuotedName(ConstraintName))
: string.Empty;
}
}
}
@@ -19,9 +19,14 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
IExecutableBuilder Table(string tableName);
/// <summary>
/// Specifies the table to delete keys and indexes for.
/// Builds a Delete Keys and Indexes expression, and executes.
/// </summary>
IExecutableBuilder KeysAndIndexes(string tableName = null);
IExecutableBuilder KeysAndIndexes<TDto>(bool local = true, bool foreign = true);
/// <summary>
/// Builds a Delete Keys and Indexes expression, and executes.
/// </summary>
IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true);
/// <summary>
/// Specifies the column to delete.
@@ -18,34 +18,38 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.KeysAndIndexes
public string TableName { get; set; }
public bool DeleteLocal { get; set; }
public bool DeleteForeign { get; set; }
/// <inheritdoc />
public void Do()
{
if (TableName == null)
{
// drop keys
var keys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToArray();
foreach (var key in keys.Where(x => x.Item2.StartsWith("FK_")))
Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
foreach (var key in keys.Where(x => x.Item2.StartsWith("PK_")))
Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
_context.BuildingExpression = false;
// drop indexes
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToArray();
foreach (var index in indexes)
Delete.Index(index.IndexName).OnTable(index.TableName).Do();
// drop keys
if (DeleteLocal || DeleteForeign)
{
// table, constraint
var tableKeys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
if (DeleteForeign)
{
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
}
if (DeleteLocal)
{
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
// note: we do *not* delete the DEFAULT constraints
}
}
else
{
// drop keys
var keys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToArray();
foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
// drop indexes
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToArray();
// drop indexes
if (DeleteLocal)
{
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToList();
foreach (var index in indexes.Where(x => x.TableName == TableName))
Delete.Index(index.IndexName).OnTable(index.TableName).Do();
}
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Migrations
bool BuildingExpression { get; set; }
/// <summary>
/// Adds a post-migrations.
/// Adds a post-migration.
/// </summary>
void AddPostMigration<TMigration>()
where TMigration : IMigration;
@@ -389,7 +389,7 @@ namespace Umbraco.Core.Migrations.Install
private DatabaseSchemaResult ValidateSchema(IScope scope)
{
if (_databaseFactory.Configured == false)
if (_databaseFactory.Initialized == false)
return new DatabaseSchemaResult(_databaseFactory.SqlContext.SqlSyntax);
if (_databaseSchemaValidationResult != null)
@@ -513,7 +513,7 @@ namespace Umbraco.Core.Migrations.Install
private Attempt<Result> CheckReadyForInstall()
{
if (_databaseFactory.Configured == false)
if (_databaseFactory.CanConnect == false)
{
return Attempt.Fail(new Result
{
@@ -539,7 +539,7 @@ namespace Umbraco.Core.Migrations.Install
{
Message =
"The database configuration failed with the following message: " + ex.Message +
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
"\n Please check log file for additional information (can be found in '/App_Data/Logs/')",
Success = false,
Percentage = "90"
};
@@ -41,6 +41,7 @@ namespace Umbraco.Core.Migrations
public void AddPostMigration<TMigration>()
where TMigration : IMigration
{
// just adding - will be de-duplicated when executing
PostMigrations.Add(typeof(TMigration));
}
}
@@ -92,6 +92,7 @@ namespace Umbraco.Core.Migrations
if (_executed)
throw new InvalidOperationException("This expression has already been executed.");
_executed = true;
Context.BuildingExpression = false;
if (sql == null)
{
+19 -4
View File
@@ -240,7 +240,8 @@ namespace Umbraco.Core.Migrations
if (finalState == null)
finalState = kvp.Key;
else
throw new Exception("Multiple final states have been detected.");
throw new InvalidOperationException($"Multiple final states have been detected in the plan (\"{finalState}\", \"{kvp.Key}\")."
+ " Make sure the plan contains only one final state.");
}
// now check for loops
@@ -254,7 +255,8 @@ namespace Umbraco.Core.Migrations
while (nextTransition != null && !verified.Contains(nextTransition.SourceState))
{
if (visited.Contains(nextTransition.SourceState))
throw new Exception("A loop has been detected.");
throw new InvalidOperationException($"A loop has been detected in the plan around state \"{nextTransition.SourceState}\"."
+ " Make sure the plan does not contain circular transition paths.");
visited.Add(nextTransition.SourceState);
nextTransition = _transitions[nextTransition.TargetState];
}
@@ -264,6 +266,14 @@ namespace Umbraco.Core.Migrations
_finalState = finalState;
}
/// <summary>
/// Throws an exception when the initial state is unknown.
/// </summary>
protected virtual void ThrowOnUnknownInitialState(string state)
{
throw new InvalidOperationException($"The migration plan does not support migrating from state \"{state}\".");
}
/// <summary>
/// Executes the plan.
/// </summary>
@@ -287,13 +297,15 @@ namespace Umbraco.Core.Migrations
logger.Info<MigrationPlan>("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState);
if (!_transitions.TryGetValue(origState, out var transition))
throw new Exception($"Unknown state \"{origState}\".");
ThrowOnUnknownInitialState(origState);
var context = new MigrationContext(scope.Database, logger);
context.PostMigrations.AddRange(_postMigrationTypes);
while (transition != null)
{
logger.Info<MigrationPlan>("Execute {MigrationType}", transition.MigrationType.Name);
var migration = migrationBuilder.Build(transition.MigrationType, context);
migration.Migrate();
@@ -302,6 +314,8 @@ namespace Umbraco.Core.Migrations
logger.Info<MigrationPlan>("At {OrigState}", origState);
// throw a raw exception here: this should never happen as the plan has
// been validated - this is just a paranoid safety test
if (!_transitions.TryGetValue(origState, out transition))
throw new Exception($"Unknown state \"{origState}\".");
}
@@ -322,7 +336,8 @@ namespace Umbraco.Core.Migrations
logger.Info<MigrationPlan>("Done (pending scope completion).");
// safety check
// safety check - again, this should never happen as the plan has been validated,
// and this is just a paranoid safety test
if (origState != _finalState)
throw new Exception($"Internal error, reached state {origState} which is not final state {_finalState}");
@@ -0,0 +1,21 @@
using Umbraco.Core.Migrations.Install;
namespace Umbraco.Core.Migrations.Upgrade.Common
{
public class CreateKeysAndIndexes : MigrationBase
{
public CreateKeysAndIndexes(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// remove those that may already have keys
Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.KeyValue).Do();
// re-create *all* keys and indexes
foreach (var x in DatabaseSchemaCreator.OrderedTables)
Create.KeysAndIndexes(x).Do();
}
}
}
@@ -0,0 +1,75 @@
namespace Umbraco.Core.Migrations.Upgrade.Common
{
public class DeleteKeysAndIndexes : MigrationBase
{
public DeleteKeysAndIndexes(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// all v7.14 tables
var tables = new[]
{
"cmsContent",
"cmsContentType",
"cmsContentType2ContentType",
"cmsContentTypeAllowedContentType",
"cmsContentVersion",
"cmsContentXml",
"cmsDataType",
"cmsDataTypePreValues",
"cmsDictionary",
"cmsDocument",
"cmsDocumentType",
"cmsLanguageText",
"cmsMacro",
"cmsMacroProperty",
"cmsMedia",
"cmsMember",
"cmsMember2MemberGroup",
"cmsMemberType",
"cmsPreviewXml",
"cmsPropertyData",
"cmsPropertyType",
"cmsPropertyTypeGroup",
"cmsTagRelationship",
"cmsTags",
"cmsTask",
"cmsTaskType",
"cmsTemplate",
"umbracoAccess",
"umbracoAccessRule",
"umbracoAudit",
"umbracoCacheInstruction",
"umbracoConsent",
"umbracoDomains",
"umbracoExternalLogin",
"umbracoLanguage",
"umbracoLock",
"umbracoLog",
"umbracoMigration",
"umbracoNode",
"umbracoRedirectUrl",
"umbracoRelation",
"umbracoRelationType",
"umbracoServer",
"umbracoUser",
"umbracoUser2NodeNotify",
"umbracoUser2UserGroup",
"umbracoUserGroup",
"umbracoUserGroup2App",
"umbracoUserGroup2NodePermission",
"umbracoUserLogin",
"umbracoUserStartNode",
};
// delete *all* keys and indexes - because of FKs
// on known v7 tables only
foreach (var table in tables)
Delete.KeysAndIndexes(table, false, true).Do();
foreach (var table in tables)
Delete.KeysAndIndexes(table, true, false).Do();
}
}
}
@@ -2,8 +2,7 @@
using System.Configuration;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
using Umbraco.Core.Migrations.Upgrade.Common;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
@@ -15,6 +14,9 @@ namespace Umbraco.Core.Migrations.Upgrade
/// </summary>
public class UmbracoPlan : MigrationPlan
{
private const string InitPrefix = "{init-";
private const string InitSuffix = "}";
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoPlan"/> class.
/// </summary>
@@ -24,6 +26,27 @@ namespace Umbraco.Core.Migrations.Upgrade
DefinePlan();
}
/// <summary>
/// Gets the initial state corresponding to a version.
/// </summary>
private static string GetInitState(SemVersion version)
=> InitPrefix + version + InitSuffix;
/// <summary>
/// Tries to extract a version from an initial state.
/// </summary>
private static bool TryGetInitStateVersion(string state, out string version)
{
if (state.StartsWith(InitPrefix) && state.EndsWith(InitSuffix))
{
version = state.TrimStart(InitPrefix).TrimEnd(InitSuffix);
return true;
}
version = null;
return false;
}
/// <inheritdoc />
/// <remarks>
/// <para>The default initial state in plans is string.Empty.</para>
@@ -41,23 +64,32 @@ namespace Umbraco.Core.Migrations.Upgrade
if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var currentVersion))
throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting.");
// we currently support upgrading from 7.10.0 and later
if (currentVersion < new SemVersion(7, 10))
throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}.");
// cannot go back in time
if (currentVersion > UmbracoVersion.SemanticVersion)
throw new InvalidOperationException($"Version {currentVersion} cannot be downgraded to {UmbracoVersion.SemanticVersion}.");
// upgrading from version 7 => initial state is eg "{init-7.10.0}"
// anything else is not supported - ie if 8 and above, we should have an initial state already
if (currentVersion.Major != 7)
throw new InvalidOperationException($"Version {currentVersion} is not supported by the migration plan.");
// only from 7.14.0 and above
var minVersion = new SemVersion(7, 14);
if (currentVersion < minVersion)
throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}."
+ $" Please upgrade first to at least {minVersion}.");
return "{init-" + currentVersion + "}";
// initial state is eg "{init-7.14.0}"
return GetInitState(currentVersion);
}
}
protected override void ThrowOnUnknownInitialState(string state)
{
if (TryGetInitStateVersion(state, out var initVersion))
{
throw new InvalidOperationException($"Version {UmbracoVersion.SemanticVersion} does not support migrating from {initVersion}."
+ $" Please verify which versions support migrating from {initVersion}.");
}
base.ThrowOnUnknownInitialState(state);
}
// define the plan
protected void DefinePlan()
{
@@ -70,21 +102,23 @@ namespace Umbraco.Core.Migrations.Upgrade
//
// If the new migration causes a merge conflict, because someone else also added another
// new migration, you NEED to fix the conflict by providing one default path, and paths
// out of the conflict states (see example below).
// out of the conflict states (see examples below).
//
// * Porting from version 7:
// Append the ported migration to the main chain, using a new guid (same as above).
// Create a new special chain from the {init-...} state to the main chain (see example
// below).
// Create a new special chain from the {init-...} state to the main chain.
// plan starts at 7.10.0 (anything before 7.10.0 is not supported)
// upgrades from 7 to 8, and then takes care of all eventual upgrades
// plan starts at 7.14.0 (anything before 7.14.0 is not supported)
//
From("{init-7.10.0}");
From(GetInitState(new SemVersion(7, 14, 0)));
// begin migrating from v7 - remove all keys and indexes
To<DeleteKeysAndIndexes>("{B36B9ABD-374E-465B-9C5F-26AB0D39326F}");
To<AddLockObjects>("{7C447271-CA3F-4A6A-A913-5D77015655CB}");
To<AddContentNuTable>("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}");
To<RefactorXmlColumns>("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}");
To<RenameMediaVersionTable>("{5CB66059-45F4-48BA-BCBD-C5035D79206B}");
To<VariantsMigration>("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}");
To<DropMigrationsTable>("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}");
To<DataTypeMigration>("{8640C9E4-A1C0-4C59-99BB-609B4E604981}");
@@ -95,91 +129,55 @@ namespace Umbraco.Core.Migrations.Upgrade
ToWithReplace<AddVariationTables2, AddVariationTables1A>("{941B2ABA-2D06-4E04-81F5-74224F1DB037}", "{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); // kill AddVariationTable1
To<RefactorMacroColumns>("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}");
Merge().To<UserForeignKeys>("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}") // shannon added that one
.With().To<AddTypedLabels>("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}") // stephan added that one
Merge()
.To<UserForeignKeys>("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}")
.With()
.To<AddTypedLabels>("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}")
.As("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}");
To<ContentVariationMigration>("{1350617A-4930-4D61-852F-E3AA9E692173}");
To<UpdateUmbracoConsent>("{39E5B1F7-A50B-437E-B768-1723AEC45B65}"); // from 7.12.0
Merge()
.To<AddRelationTypeForMediaFolderOnDelete>("{0541A62B-EF87-4CA2-8225-F0EB98ECCC9F}") // from 7.12.0
.To<IncreaseLanguageIsoCodeColumnLength>("{EB34B5DC-BB87-4005-985E-D983EA496C38}") // from 7.12.0
.To<RenameTrueFalseField>("{517CE9EA-36D7-472A-BF4B-A0D6FB1B8F89}") // from 7.12.0
.To<SetDefaultTagsStorageType>("{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}") // from 7.12.0
.With()
.To<FallbackLanguage>("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}") // andy added that one
.As("{8B14CEBD-EE47-4AAD-A841-93551D917F11}");
ToWithReplace<UpdateDefaultMandatoryLanguage>("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}", "{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // merge
ToWithReplace<RefactorVariantsModel>("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}", "{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); // merge
To<FallbackLanguage>("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}");
To<UpdateDefaultMandatoryLanguage>("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}");
To<RefactorVariantsModel>("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}");
To<DropTaskTables>("{6A2C7C1B-A9DB-4EA9-B6AB-78E7D5B722A7}");
To<FixLockTablePrimaryKey>("{77874C77-93E5-4488-A404-A630907CEEF0}");
To<AddLogTableColumns>("{8804D8E8-FE62-4E3A-B8A2-C047C2118C38}");
To<DropPreValueTable>("{23275462-446E-44C7-8C2C-3B8C1127B07D}");
To<DropDownPropertyEditorsMigration>("{6B251841-3069-4AD5-8AE9-861F9523E8DA}");
To<TagsMigrationFix>("{EE429F1B-9B26-43CA-89F8-A86017C809A3}");
To<DropTemplateDesignColumn>("{08919C4B-B431-449C-90EC-2B8445B5C6B1}");
To<TablesForScheduledPublishing>("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}");
To<DropTaskTables>("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version
To<MakeTagsVariant>("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
To<MakeRedirectUrlVariant>("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
To<AddContentTypeIsElementColumn>("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}");
To<UpdateMemberGroupPickerData>("{8A027815-D5CD-4872-8B88-9A51AB5986A6}"); // from 7.14.0
To<ConvertRelatedLinksToMultiUrlPicker>("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}");
To<UpdatePickerIntegerValuesToUdi>("{38C809D5-6C34-426B-9BEA-EFD39162595C}");
To<RenameUmbracoDomainsTable>("{6017F044-8E70-4E10-B2A3-336949692ADD}");
To<AddUserLoginDtoDateIndex>("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}");
Merge()
.To<DropXmlTables>("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}")
.With()
.To<RadioAndCheckboxAndDropdownPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}")
.To<RadioAndCheckboxPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}")
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
To<FixLanguageIsoCodeLength>("{48AD6CCD-C7A4-4305-A8AB-38728AD23FC5}");
// finish migrating from v7 - recreate all keys and indexes
To<CreateKeysAndIndexes>("{3F9764F5-73D0-4D45-8804-1240A66E43A2}");
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
// release-8.0.0
// to 8.0.1...
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
// release-8.0.1
// to 8.1.0...
To<ConvertTinyMceAndGridMediaUrlsToLocalLink>("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
To<RenameUserLoginDtoDateIndex>("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
To<FixContentNuCascade>("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
//FINAL
// and then, need to support upgrading from more recent 7.x
//
From("{init-7.10.1}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.10.2}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.10.3}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.10.4}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.10.5}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.11.0}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.11.1}").To("{init-7.10.0}"); // same as 7.10.0
From("{init-7.11.2}").To("{init-7.10.0}"); // same as 7.10.0
// 7.12.0 has migrations, define a custom chain which copies the chain
// going from {init-7.10.0} to former final (1350617A) , and then goes straight to
// main chain, skipping the migrations
//
From("{init-7.12.0}");
// clone start / clone stop / target
ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}");
From("{init-7.12.1}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.12.2}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.12.3}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
// 7.14.0 has migrations, handle it...
// clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
// clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),
// ending in 8A027815 (after 7.14 migrations)
From("{init-7.14.0}")
.ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{9109B8AF-6B34-46EE-9484-7434196D0C79}")
.ToWithClone("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}", "{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}", "{8A027815-D5CD-4872-8B88-9A51AB5986A6}");
}
}
}
@@ -1,36 +0,0 @@
using System.IO;
using Umbraco.Core.IO;
using File = System.IO.File;
namespace Umbraco.Core.Migrations.Upgrade.V_7_10_0
{
/// <summary>
/// Renames the preview folder containing static HTML files to ensure it does not interfere with the MVC route
/// that is now supposed to render these views dynamically. We don't want to delete as people may have made
/// customizations to these files that would need to be migrated to the new .cshtml view files.
/// </summary>
public class RenamePreviewFolder : MigrationBase
{
public RenamePreviewFolder(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var previewFolderPath = IOHelper.MapPath(SystemDirectories.Umbraco + "/preview");
if (Directory.Exists(previewFolderPath))
{
var newPath = previewFolderPath.Replace("preview", "preview.old");
if (Directory.Exists(newPath) == false)
{
Directory.Move(previewFolderPath, newPath);
var readmeText =
$"Static HTML files used for preview and canvas editing functionality no longer live in this directory.\r\n" +
$"Instead they have been recreated as MVC views and can now be found in '~/Umbraco/Views/Preview'.\r\n" +
$"See issue: http://issues.umbraco.org/issue/U4-11090";
File.WriteAllText(Path.Combine(newPath, "readme.txt"), readmeText);
}
}
}
}
}
@@ -1,33 +0,0 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
public class AddRelationTypeForMediaFolderOnDelete : MigrationBase
{
public AddRelationTypeForMediaFolderOnDelete(IMigrationContext context) : base(context)
{
}
public override void Migrate()
{
var relationTypeCount = Context.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoRelationType WHERE alias=@alias",
new { alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias });
if (relationTypeCount > 0)
return;
var uniqueId = (Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias + "____" + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName).ToGuid();
Insert.IntoTable("umbracoRelationType").Row(new
{
typeUniqueId = uniqueId,
alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias,
name = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName,
childObjectType = Constants.ObjectTypes.MediaType,
parentObjectType = Constants.ObjectTypes.MediaType,
dual = false
}).Do();
}
}
}
@@ -1,46 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
public class IncreaseLanguageIsoCodeColumnLength : MigrationBase
{
public IncreaseLanguageIsoCodeColumnLength(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// Some people seem to have a constraint in their DB instead of an index, we'd need to drop that one
// See: https://our.umbraco.com/forum/using-umbraco-and-getting-started/93282-upgrade-from-711-to-712-fails
var constraints = SqlSyntax.GetConstraintsPerTable(Context.Database).Distinct().ToArray();
if (constraints.Any(x => x.Item2.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
{
Delete.UniqueConstraint("IX_umbracoLanguage_languageISOCode").FromTable("umbracoLanguage").Do();
}
//Now check for indexes of that name and drop that if it exists
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
{
Delete.Index("IX_umbracoLanguage_languageISOCode").OnTable("umbracoLanguage").Do();
}
Alter.Table("umbracoLanguage")
.AlterColumn("languageISOCode")
.AsString(14)
.Nullable()
.Do();
Create.Index("IX_umbracoLanguage_languageISOCode")
.OnTable("umbracoLanguage")
.OnColumn("languageISOCode")
.Ascending()
.WithOptions()
.Unique()
.Do();
}
}
}
@@ -1,19 +0,0 @@
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
public class RenameTrueFalseField : MigrationBase
{
public RenameTrueFalseField(IMigrationContext context) : base(context)
{
}
public override void Migrate()
{
//rename the existing true/false field
Update.Table(NodeDto.TableName).Set(new { text = "Checkbox" }).Where(new { id = Constants.DataTypes.Boolean }).Do();
}
}
}
@@ -1,51 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
/// <summary>
/// Set the default storageType for the tags datatype to "CSV" to ensure backwards compatibility since the default is going to be JSON in new versions.
/// </summary>
public class SetDefaultTagsStorageType : MigrationBase
{
public SetDefaultTagsStorageType(IMigrationContext context)
: base(context)
{ }
// dummy editor for deserialization
private class TagConfigurationEditor : ConfigurationEditor<TagConfiguration>
{ }
public override void Migrate()
{
// get all Umbraco.Tags datatypes
var dataTypeDtos = Database.Fetch<DataTypeDto>(Context.SqlContext.Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Aliases.Tags));
// get a dummy editor for deserialization
var editor = new TagConfigurationEditor();
foreach (var dataTypeDto in dataTypeDtos)
{
// need to check storageType on raw dictionary, as TagConfiguration would have a default value
var dictionary = JsonConvert.DeserializeObject<JObject>(dataTypeDto.Configuration);
// if missing, use TagConfiguration to properly update the configuration
// due to ... reasons ... the key can start with a lower or upper 'S'
if (!dictionary.ContainsKey("storageType") && !dictionary.ContainsKey("StorageType"))
{
var configuration = (TagConfiguration)editor.FromDatabase(dataTypeDto.Configuration);
configuration.StorageType = TagsStorageType.Csv;
dataTypeDto.Configuration = ConfigurationEditor.ToDatabase(configuration);
Database.Update(dataTypeDto);
}
}
}
}
}
@@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{ public class UpdateUmbracoConsent : MigrationBase {
public UpdateUmbracoConsent(IMigrationContext context)
: base(context)
{ }
public override void Migrate() { Alter.Table(Constants.DatabaseSchema.Tables.Consent).AlterColumn("comment").AsString().Nullable().Do(); }
}
}
@@ -1,29 +0,0 @@
namespace Umbraco.Core.Migrations.Upgrade.V_7_14_0
{
/// <summary>
/// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
/// </summary>
public class UpdateMemberGroupPickerData : MigrationBase
{
/// <summary>
/// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
/// </summary>
public UpdateMemberGroupPickerData(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
Database.Execute($@"UPDATE umbracoPropertyData SET textValue = varcharValue, varcharValue = NULL
WHERE textValue IS NULL AND id IN (
SELECT id FROM umbracoPropertyData WHERE propertyTypeId in (
SELECT id from cmsPropertyType where dataTypeId IN (
SELECT nodeId FROM umbracoDataType WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'
)
)
)");
Database.Execute($"UPDATE umbracoDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'");
}
}
}
@@ -1,50 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
{
public class AddRedirectUrlTable : MigrationBase
{
public AddRedirectUrlTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var database = Database;
var umbracoRedirectUrlTableName = "umbracoRedirectUrl";
var tables = SqlSyntax.GetTablesInSchema(database).ToArray();
if (tables.InvariantContains(umbracoRedirectUrlTableName))
{
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals(umbracoRedirectUrlTableName) && x.ColumnName.InvariantEquals("id") && x.DataType == "uniqueidentifier"))
return;
Delete.Table(umbracoRedirectUrlTableName).Do();
}
Create.Table(umbracoRedirectUrlTableName)
.WithColumn("id").AsGuid().NotNullable().PrimaryKey("PK_" + umbracoRedirectUrlTableName)
.WithColumn("createDateUtc").AsDateTime().NotNullable()
.WithColumn("url").AsString(2048).NotNullable()
.WithColumn("contentKey").AsGuid().NotNullable()
.WithColumn("urlHash").AsString(40).NotNullable()
.Do();
Create.Index("IX_" + umbracoRedirectUrlTableName).OnTable(umbracoRedirectUrlTableName)
.OnColumn("urlHash")
.Ascending()
.OnColumn("contentKey")
.Ascending()
.OnColumn("createDateUtc")
.Descending()
.WithOptions().NonClustered()
.Do();
Create.ForeignKey("FK_" + umbracoRedirectUrlTableName)
.FromTable(umbracoRedirectUrlTableName).ForeignColumn("contentKey")
.ToTable("umbracoNode").PrimaryColumn("uniqueID")
.Do();
}
}
}
@@ -1,40 +0,0 @@
using System;
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
{
/// <summary>
/// This is here to re-remove these tables, we dropped them in 7.3 but new installs created them again so we're going to re-drop them
/// </summary>
public class RemoveStylesheetDataAndTablesAgain : MigrationBase
{
public RemoveStylesheetDataAndTablesAgain(IMigrationContext context)
: base(context)
{
}
public override void Migrate()
{
// these have been obsoleted, need to copy the values here
var stylesheetPropertyObjectType = new Guid("5555da4f-a123-42b2-4488-dcdfb25e4111");
var stylesheetObjectType = new Guid("9F68DA4F-A3A8-44C2-8226-DCBD125E4840");
//Clear all stylesheet data if the tables exist
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("cmsStylesheetProperty"))
{
Delete.FromTable("cmsStylesheetProperty").AllRows().Do();
Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetPropertyObjectType }).Do();
Delete.Table("cmsStylesheetProperty").Do();
}
if (tables.InvariantContains("cmsStylesheet"))
{
Delete.FromTable("cmsStylesheet").AllRows().Do();
Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetObjectType }).Do();
Delete.Table("cmsStylesheet").Do();
}
}
}
}
@@ -1,44 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
{
/// <summary>
/// See: http://issues.umbraco.org/issue/U4-8522
/// </summary>
public class UpdateUniqueIndexOnPropertyData : MigrationBase
{
public UpdateUniqueIndexOnPropertyData(IMigrationContext context)
: base(context)
{
}
public override void Migrate()
{
//Clear all stylesheet data if the tables exist
//tuple = tablename, indexname, columnname, unique
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
var found = indexes.FirstOrDefault(
x => x.Item1.InvariantEquals("cmsPropertyData")
&& x.Item2.InvariantEquals("IX_cmsPropertyData_1")
//we're searching for the old index which is not unique
&& x.Item4 == false);
if (found != null)
{
Database.Execute("DELETE FROM cmsPropertyData WHERE id NOT IN (SELECT MIN(id) FROM cmsPropertyData GROUP BY nodeId, versionId, propertytypeid HAVING MIN(id) IS NOT NULL)");
//we need to re create this index
Delete.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData").Do();
Create.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData")
.OnColumn("nodeId").Ascending()
.OnColumn("versionId").Ascending()
.OnColumn("propertytypeid").Ascending()
.WithOptions().NonClustered()
.WithOptions().Unique()
.Do();
}
}
}
}
@@ -1,17 +0,0 @@
namespace Umbraco.Core.Migrations.Upgrade.V_7_5_5
{
/// <summary>
/// See: http://issues.umbraco.org/issue/U4-4196
/// </summary>
public class UpdateAllowedMediaTypesAtRoot : MigrationBase
{
public UpdateAllowedMediaTypesAtRoot(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
Database.Execute("UPDATE cmsContentType SET allowAtRoot = 1 WHERE nodeId = 1032 OR nodeId = 1033");
}
}
}
@@ -1,41 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddIndexToCmsMemberLoginName : MigrationBase
{
public AddIndexToCmsMemberLoginName(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var database = Database;
//Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
//http://issues.umbraco.org/issue/U4-9758
var colLen = database.ExecuteScalar<int?>("select max(datalength(LoginName)) from cmsMember");
if (colLen < 900 == false && colLen != null)
{
return;
}
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
{
//we can apply the index
Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
.OnColumn("LoginName")
.Ascending()
.WithOptions()
.NonClustered()
.Do();
}
}
}
}
@@ -1,28 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddIndexToUmbracoNodePath : MigrationBase
{
public AddIndexToUmbracoNodePath(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodePath")) == false)
{
Create.Index("IX_umbracoNodePath").OnTable("umbracoNode")
.OnColumn("path")
.Ascending()
.WithOptions()
.NonClustered()
.Do();
}
}
}
}
@@ -1,28 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddIndexToUser2NodePermission : MigrationBase
{
public AddIndexToUser2NodePermission(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
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()
.Do();
}
}
}
}
@@ -1,85 +0,0 @@
using System;
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddIndexesToUmbracoRelationTables : MigrationBase
{
public AddIndexesToUmbracoRelationTables(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database).ToArray();
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelation_parentChildType")) == false)
{
//This will remove any corrupt/duplicate data in the relation table before the index is applied
//Ensure this executes in a deferred block which will be done inside of the migration transaction
var database = Database;
//We need to check if this index has corrupted data and then clear that data
var duplicates = database.Fetch<dynamic>("SELECT parentId,childId,relType FROM umbracoRelation GROUP BY parentId,childId,relType HAVING COUNT(*) > 1");
if (duplicates.Count > 0)
{
//need to fix this there cannot be duplicates so we'll take the latest entries, it's really not going to matter though
foreach (var duplicate in duplicates)
{
var ids = database.Fetch<int>("SELECT id FROM umbracoRelation WHERE parentId=@parentId AND childId=@childId AND relType=@relType ORDER BY datetime DESC",
new { parentId = duplicate.parentId, childId = duplicate.childId, relType = duplicate.relType });
if (ids.Count == 1)
{
//this is just a safety check, this should absolutely never happen
throw new InvalidOperationException("Duplicates were detected but could not be discovered");
}
//delete the others
ids = ids.Skip(0).ToList();
//iterate in groups of 2000 to avoid the max sql parameter limit
foreach (var idGroup in ids.InGroupsOf(2000))
{
database.Execute("DELETE FROM umbracoRelation WHERE id IN (@ids)", new { ids = idGroup });
}
}
}
//unique index to prevent duplicates - and for better perf
Create.Index("IX_umbracoRelation_parentChildType").OnTable("umbracoRelation")
.OnColumn("parentId").Ascending()
.OnColumn("childId").Ascending()
.OnColumn("relType").Ascending()
.WithOptions()
.Unique()
.Do();
}
//need indexes on alias and name for relation type since these are queried against
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_alias")) == false)
{
Create.Index("IX_umbracoRelationType_alias").OnTable("umbracoRelationType")
.OnColumn("alias")
.Ascending()
.WithOptions()
.NonClustered()
.Do();
}
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_name")) == false)
{
Create.Index("IX_umbracoRelationType_name").OnTable("umbracoRelationType")
.OnColumn("name")
.Ascending()
.WithOptions()
.NonClustered()
.Do();
}
}
}
}
@@ -1,27 +0,0 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddLockObjects : MigrationBase
{
public AddLockObjects(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
EnsureLockObject(Constants.Locks.Servers, "Servers");
}
private void EnsureLockObject(int id, string name)
{
var db = Database;
var exists = db.Exists<LockDto>(id);
if (exists) return;
// be safe: delete old umbracoNode lock objects if any
db.Execute("DELETE FROM umbracoNode WHERE id=@id;", new { id });
// then create umbracoLock object
db.Execute("INSERT umbracoLock (id, name, value) VALUES (@id, @name, 1);", new { id, name });
}
}
}
@@ -1,24 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddLockTable : MigrationBase
{
public AddLockTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("umbracoLock") == false)
{
Create.Table("umbracoLock")
.WithColumn("id").AsInt32().PrimaryKey("PK_umbracoLock")
.WithColumn("value").AsInt32().NotNullable()
.WithColumn("name").AsString(64).NotNullable()
.Do();
}
}
}
}
@@ -1,68 +0,0 @@
using System;
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddMacroUniqueIdColumn : MigrationBase
{
public AddMacroUniqueIdColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("cmsMacro") && x.ColumnName.InvariantEquals("uniqueId")) == false)
{
Create.Column("uniqueId").OnTable("cmsMacro").AsGuid().Nullable().Do();
UpdateMacroGuids();
Alter.Table("cmsMacro").AlterColumn("uniqueId").AsGuid().NotNullable().Do();
Create.Index("IX_cmsMacro_UniqueId").OnTable("cmsMacro").OnColumn("uniqueId")
.Ascending()
.WithOptions().NonClustered()
.WithOptions().Unique()
.Do();
}
if (columns.Any(x => x.TableName.InvariantEquals("cmsMacroProperty") && x.ColumnName.InvariantEquals("uniquePropertyId")) == false)
{
Create.Column("uniquePropertyId").OnTable("cmsMacroProperty").AsGuid().Nullable().Do();
UpdateMacroPropertyGuids();
Alter.Table("cmsMacroProperty").AlterColumn("uniquePropertyId").AsGuid().NotNullable().Do();
Create.Index("IX_cmsMacroProperty_UniquePropertyId").OnTable("cmsMacroProperty").OnColumn("uniquePropertyId")
.Ascending()
.WithOptions().NonClustered()
.WithOptions().Unique()
.Do();
}
}
private void UpdateMacroGuids()
{
var database = Database;
var updates = database.Query<dynamic>("SELECT id, macroAlias FROM cmsMacro")
.Select(macro => Tuple.Create((int) macro.id, ("macro____" + (string) macro.macroAlias).ToGuid()))
.ToList();
foreach (var update in updates)
database.Execute("UPDATE cmsMacro set uniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
}
private void UpdateMacroPropertyGuids()
{
var database = Database;
var updates = database.Query<dynamic>(@"SELECT cmsMacroProperty.id id, macroPropertyAlias propertyAlias, cmsMacro.macroAlias macroAlias
FROM cmsMacroProperty
JOIN cmsMacro ON cmsMacroProperty.macro=cmsMacro.id")
.Select(prop => Tuple.Create((int) prop.id, ("macro____" + (string) prop.macroAlias + "____" + (string) prop.propertyAlias).ToGuid()))
.ToList();
foreach (var update in updates)
database.Execute("UPDATE cmsMacroProperty set uniquePropertyId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
}
}
}
@@ -1,40 +0,0 @@
using System;
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class AddRelationTypeUniqueIdColumn : MigrationBase
{
public AddRelationTypeUniqueIdColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRelationType") && x.ColumnName.InvariantEquals("typeUniqueId")) == false)
{
Create.Column("typeUniqueId").OnTable("umbracoRelationType").AsGuid().Nullable().Do();
UpdateRelationTypeGuids();
Alter.Table("umbracoRelationType").AlterColumn("typeUniqueId").AsGuid().NotNullable().Do();
Create.Index("IX_umbracoRelationType_UniqueId").OnTable("umbracoRelationType").OnColumn("typeUniqueId")
.Ascending()
.WithOptions().NonClustered()
.WithOptions().Unique()
.Do();
}
}
private void UpdateRelationTypeGuids()
{
var database = Database;
var updates = database.Query<dynamic>("SELECT id, alias, name FROM umbracoRelationType")
.Select(relationType => Tuple.Create((int) relationType.id, ("relationType____" + (string) relationType.alias + "____" + (string) relationType.name).ToGuid()))
.ToList();
foreach (var update in updates)
database.Execute("UPDATE umbracoRelationType set typeUniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
}
}
}
@@ -1,37 +0,0 @@
using System;
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class NormalizeTemplateGuids : MigrationBase
{
public NormalizeTemplateGuids(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var database = Database;
// we need this migration because ppl running pre-7.6 on Cloud and Courier have templates in different
// environments having different GUIDs (Courier does not sync template GUIDs) and we need to normalize
// these GUIDs so templates with the same alias on different environments have the same GUID.
// however, if already running a prerelease version of 7.6, we do NOT want to normalize the GUIDs as quite
// probably, we are already running Deploy and the GUIDs are OK. assuming noone is running a prerelease
// of 7.6 on Courier.
// so... testing if we already have a 7.6.0 version installed. not pretty but...?
//
var version = database.FirstOrDefault<string>("SELECT version FROM umbracoMigration WHERE name=@name ORDER BY version DESC", new { name = Constants.System.UmbracoUpgradePlanName });
if (version != null && version.StartsWith("7.6.0")) return;
var updates = database.Query<dynamic>(@"SELECT umbracoNode.id, cmsTemplate.alias FROM umbracoNode
JOIN cmsTemplate ON umbracoNode.id=cmsTemplate.nodeId
WHERE nodeObjectType = @guid", new { guid = Constants.ObjectTypes.TemplateType })
.Select(template => Tuple.Create((int) template.id, ("template____" + (string) template.alias).ToGuid()))
.ToList();
foreach (var update in updates)
database.Execute("UPDATE umbracoNode set uniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
}
}
}
@@ -1,41 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class ReduceLoginNameColumnsSize : MigrationBase
{
public ReduceLoginNameColumnsSize(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
//Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
//http://issues.umbraco.org/issue/U4-9758
var database = Database;
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
var colLen = database.ExecuteScalar<int?>("select max(datalength(LoginName)) from cmsMember");
if (colLen < 900 == false) return;
//if an index exists on this table we need to drop it. Normally we'd check via index name but in some odd cases (i.e. Our)
//the index name is something odd (starts with "mi_"). In any case, the index cannot exist if we want to alter the column
//so we'll drop whatever index is there and add one with the correct name after.
var loginNameIndex = dbIndexes.FirstOrDefault(x => x.TableName.InvariantEquals("cmsMember") && x.ColumnName.InvariantEquals("LoginName"));
if (loginNameIndex != null)
{
Delete.Index(loginNameIndex.IndexName).OnTable("cmsMember").Do();
}
//we can apply the col length change
Alter.Table("cmsMember")
.AlterColumn("LoginName")
.AsString(225)
.NotNullable()
.Do();
}
}
}
@@ -1,29 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
/// <summary>
/// See: http://issues.umbraco.org/issue/U4-9188
/// </summary>
public class UpdateUniqueIndexOnPropertyData : MigrationBase
{
public UpdateUniqueIndexOnPropertyData(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
//tuple = tablename, indexname, columnname, unique
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
var found = indexes.FirstOrDefault(
x => x.Item1.InvariantEquals("cmsPropertyData")
&& x.Item2.InvariantEquals("IX_cmsPropertyData"));
if (found != null)
{
//drop the index
Delete.Index("IX_cmsPropertyData").OnTable("cmsPropertyData").Do();
}
}
}
}
@@ -1,30 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
{
public class RemoveUmbracoDeployTables : MigrationBase
{
public RemoveUmbracoDeployTables(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
// there are two versions of umbracoDeployDependency,
// 1. one created by 7.4 and never used, we need to remove it (has a sourceId column)
// 2. one created by Deploy itself, we need to keep it (has a sourceUdi column)
if (tables.InvariantContains("umbracoDeployDependency"))
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoDeployDependency") && x.ColumnName.InvariantEquals("sourceId")))
Delete.Table("umbracoDeployDependency").Do();
}
// always remove umbracoDeployChecksum
if (tables.InvariantContains("umbracoDeployChecksum"))
Delete.Table("umbracoDeployChecksum").Do();
}
}
}
@@ -1,38 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
public class AddIndexToDictionaryKeyColumn : MigrationBase
{
public AddIndexToDictionaryKeyColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var database = Database;
//Now we need to check if we can actually do this because we won't be able to if there's data in there that is too long
var colLen = database.ExecuteScalar<int?>(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key")));
if (colLen < 900 == false && colLen != null)
{
return;
}
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key")) == false)
{
//we can apply the index
Create.Index("IX_cmsDictionary_key").OnTable("cmsDictionary")
.OnColumn("key")
.Ascending()
.WithOptions()
.NonClustered()
.Do();
}
}
}
}
@@ -1,357 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using ColumnInfo = Umbraco.Core.Persistence.SqlSyntax.ColumnInfo;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
public class AddUserGroupTables : MigrationBase
{
private readonly string _collateSyntax;
public AddUserGroupTables(IMigrationContext context)
: base(context)
{
//For some of the migration data inserts we require to use a special MSSQL collate expression since
//some databases may have a custom collation specified and if that is the case, when we compare strings
//in dynamic SQL it will try to compare strings in different collations and this will yield errors.
_collateSyntax = "COLLATE DATABASE_DEFAULT";
}
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToList();
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
//In some very rare cases, there might already be user group tables that we'll need to remove first
//but of course we don't want to remove the tables we will be creating below if they already exist so
//need to do some checks first since these old rare tables have a different schema
RemoveOldTablesIfExist(tables, columns);
if (AddNewTables(tables))
{
MigrateUserPermissions();
MigrateUserTypesToGroups();
DeleteOldTables(tables, constraints);
SetDefaultIcons();
}
else
{
//if we aren't adding the tables, make sure that the umbracoUserGroup table has the correct FKs - these
//were added after the beta release so we need to do some cleanup
//if the FK doesn't exist
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
&& x.Item2.InvariantEquals("startContentId")
&& x.Item3.InvariantEquals("FK_startContentId_umbracoNode_id")) == false)
{
//before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
//release if a start node was assigned and then that start node was deleted.
Database.Execute(@"UPDATE umbracoUserGroup SET startContentId = NULL WHERE startContentId NOT IN (SELECT id FROM umbracoNode)");
Create.ForeignKey("FK_startContentId_umbracoNode_id")
.FromTable("umbracoUserGroup")
.ForeignColumn("startContentId")
.ToTable("umbracoNode")
.PrimaryColumn("id")
.OnDelete(Rule.None)
.OnUpdate(Rule.None)
.Do();
}
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
&& x.Item2.InvariantEquals("startMediaId")
&& x.Item3.InvariantEquals("FK_startMediaId_umbracoNode_id")) == false)
{
//before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
//release if a start node was assigned and then that start node was deleted.
Database.Execute(@"UPDATE umbracoUserGroup SET startMediaId = NULL WHERE startMediaId NOT IN (SELECT id FROM umbracoNode)");
Create.ForeignKey("FK_startMediaId_umbracoNode_id")
.FromTable("umbracoUserGroup")
.ForeignColumn("startMediaId")
.ToTable("umbracoNode")
.PrimaryColumn("id")
.OnDelete(Rule.None)
.OnUpdate(Rule.None)
.Do();
}
}
}
/// <summary>
/// In some very rare cases, there might already be user group tables that we'll need to remove first
/// but of course we don't want to remove the tables we will be creating below if they already exist so
/// need to do some checks first since these old rare tables have a different schema
/// </summary>
/// <param name="tables"></param>
/// <param name="columns"></param>
private void RemoveOldTablesIfExist(List<string> tables, ColumnInfo[] columns)
{
if (tables.Contains("umbracoUser2userGroup", StringComparer.InvariantCultureIgnoreCase))
{
//this column doesn't exist in the 7.7 schema, so if it's there, then this is a super old table
var foundOldColumn = columns
.FirstOrDefault(x =>
x.ColumnName.Equals("user", StringComparison.InvariantCultureIgnoreCase)
&& x.TableName.Equals("umbracoUser2userGroup", StringComparison.InvariantCultureIgnoreCase));
if (foundOldColumn != null)
{
Delete.Table("umbracoUser2userGroup").Do();
//remove from the tables list since this will be re-checked in further logic
tables.Remove("umbracoUser2userGroup");
}
}
if (tables.Contains("umbracoUserGroup", StringComparer.InvariantCultureIgnoreCase))
{
//The new schema has several columns, the super old one for this table only had 2 so if it's 2 get rid of it
var countOfCols = columns
.Count(x => x.TableName.Equals("umbracoUserGroup", StringComparison.InvariantCultureIgnoreCase));
if (countOfCols == 2)
{
Delete.Table("umbracoUserGroup").Do();
//remove from the tables list since this will be re-checked in further logic
tables.Remove("umbracoUserGroup");
}
}
}
private void SetDefaultIcons()
{
Database.Execute($"UPDATE umbracoUserGroup SET icon = \'\' WHERE userGroupAlias = \'{Constants.Security.AdminGroupAlias}\'");
Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-edit\' WHERE userGroupAlias = \'writer\'");
Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-tools\' WHERE userGroupAlias = \'editor\'");
Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-globe\' WHERE userGroupAlias = \'translator\'");
}
private bool AddNewTables(List<string> tables)
{
var updated = false;
if (tables.InvariantContains("umbracoUserGroup") == false)
{
Create.Table<UserGroupDto>().Do();
updated = true;
}
if (tables.InvariantContains("umbracoUser2UserGroup") == false)
{
Create.Table<User2UserGroupDto>().Do();
updated = true;
}
if (tables.InvariantContains("umbracoUserGroup2App") == false)
{
Create.Table<UserGroup2AppDto>().Do();
updated = true;
}
if (tables.InvariantContains("umbracoUserGroup2NodePermission") == false)
{
Create.Table<UserGroup2NodePermissionDto>().Do();
updated = true;
}
return updated;
}
private void MigrateUserTypesToGroups()
{
// Create a user group for each user type
Database.Execute(@"INSERT INTO umbracoUserGroup (userGroupAlias, userGroupName, userGroupDefaultPermissions)
SELECT userTypeAlias, userTypeName, userTypeDefaultPermissions
FROM umbracoUserType");
// Add each user to the group created from their type
Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
SELECT u.id, ug.id
FROM umbracoUser u
INNER JOIN umbracoUserType ut ON ut.id = u.userType
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = ut.userTypeAlias {0}", _collateSyntax));
// Add the built-in administrator account to all apps
// this will lookup all of the apps that the admin currently has access to in order to assign the sections
// instead of use statically assigning since there could be extra sections we don't know about.
Database.Execute(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
SELECT ug.id, app
FROM umbracoUserGroup ug
INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
INNER JOIN umbracoUser u ON u.id = u2ug.userId
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
WHERE u.id = 0");
// Add the default section access to the other built-in accounts
// writer:
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
SELECT ug.id, 'content' as app
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = 'writer' {0}", _collateSyntax));
// editor
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
SELECT ug.id, 'content' as app
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
SELECT ug.id, 'media' as app
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
// translator
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
SELECT ug.id, 'translation' as app
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = 'translator' {0}", _collateSyntax));
//We need to lookup all distinct combinations of section access and create a group for each distinct collection
//and assign groups accordingly. We'll perform the lookup 'now' to then create the queued SQL migrations.
var userAppsData = Context.Database.Query<dynamic>(@"SELECT u.id, u2a.app FROM umbracoUser u
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
ORDER BY u.id, u2a.app");
var usersWithApps = new Dictionary<int, List<string>>();
foreach (var userApps in userAppsData)
{
if (usersWithApps.TryGetValue(userApps.id, out List<string> apps) == false)
{
apps = new List<string> {userApps.app};
usersWithApps.Add(userApps.id, apps);
}
else
{
apps.Add(userApps.app);
}
}
//At this stage we have a dictionary of users with a collection of their apps which are sorted
//and we need to determine the unique/distinct app collections for each user to create groups with.
//We can do this by creating a hash value of all of the app values and since they are already sorted we can get a distinct
//collection by this hash.
var distinctApps = usersWithApps
.Select(x => new {appCollection = x.Value, appsHash = string.Join("", x.Value).GenerateHash()})
.DistinctBy(x => x.appsHash)
.ToArray();
//Now we need to create user groups for each of these distinct app collections, and then assign the corresponding users to those groups
for (var i = 0; i < distinctApps.Length; i++)
{
//create the group
var alias = "MigratedSectionAccessGroup_" + (i + 1);
Insert.IntoTable("umbracoUserGroup").Row(new
{
userGroupAlias = "MigratedSectionAccessGroup_" + (i + 1),
userGroupName = "Migrated Section Access Group " + (i + 1)
}).Do();
//now assign the apps
var distinctApp = distinctApps[i];
foreach (var app in distinctApp.appCollection)
{
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
SELECT ug.id, '" + app + @"' as app
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
}
//now assign the corresponding users to this group
foreach (var userWithApps in usersWithApps)
{
//check if this user's groups hash matches the current groups hash
var hash = string.Join("", userWithApps.Value).GenerateHash();
if (hash == distinctApp.appsHash)
{
//it matches so assign the user to this group
Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
SELECT " + userWithApps.Key + @", ug.id
FROM umbracoUserGroup ug
WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
}
}
}
// Rename some groups for consistency (plural form)
Database.Execute("UPDATE umbracoUserGroup SET userGroupName = 'Writers' WHERE userGroupAlias = 'writer'");
Database.Execute("UPDATE umbracoUserGroup SET userGroupName = 'Translators' WHERE userGroupAlias = 'translator'");
//Ensure all built in groups have a start node of -1
Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'editor'");
Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'editor'");
Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'writer'");
Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'writer'");
Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'translator'");
Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'translator'");
Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'admin'");
Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'admin'");
}
private void MigrateUserPermissions()
{
// Create user group records for all non-admin users that have specific permissions set
Database.Execute(@"INSERT INTO umbracoUserGroup(userGroupAlias, userGroupName)
SELECT 'permissionGroupFor' + userLogin, 'Migrated Permission Group for ' + userLogin
FROM umbracoUser
WHERE (id IN (
SELECT userid
FROM umbracoUser2NodePermission
))
AND id > 0");
// Associate those groups with the users
Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
SELECT u.id, ug.id
FROM umbracoUser u
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = 'permissionGroupFor' + userLogin {0}", _collateSyntax));
// Create node permissions on the groups
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2NodePermission (userGroupId,nodeId,permission)
SELECT ug.id, nodeId, permission
FROM umbracoUserGroup ug
INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
INNER JOIN umbracoUser u ON u.id = u2ug.userId
INNER JOIN umbracoUser2NodePermission u2np ON u2np.userId = u.id
WHERE ug.userGroupAlias {0} NOT IN (
SELECT userTypeAlias {0}
FROM umbracoUserType
)", _collateSyntax));
// Create app permissions on the groups
Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
SELECT ug.id, app
FROM umbracoUserGroup ug
INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
INNER JOIN umbracoUser u ON u.id = u2ug.userId
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
WHERE ug.userGroupAlias {0} NOT IN (
SELECT userTypeAlias {0}
FROM umbracoUserType
)", _collateSyntax));
}
private void DeleteOldTables(List<string> tables, Tuple<string, string, string>[] constraints)
{
if (tables.InvariantContains("umbracoUser2App"))
{
Delete.Table("umbracoUser2App").Do();
}
if (tables.InvariantContains("umbracoUser2NodePermission"))
{
Delete.Table("umbracoUser2NodePermission").Do();
}
if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser"))
{
//Delete the FK if it exists before dropping the column
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
{
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser").Do();
}
//This is the super old constraint name of the FK for user type so check this one too
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
{
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser").Do();
}
Delete.Column("userType").FromTable("umbracoUser").Do();
Delete.Table("umbracoUserType").Do();
}
}
}
}
@@ -1,41 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
public class AddUserStartNodeTable : MigrationBase
{
public AddUserStartNodeTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("umbracoUserStartNode")) return;
Create.Table<UserStartNodeDto>().Do();
MigrateUserStartNodes();
//now remove the old columns
Delete.Column("startStructureID").FromTable("umbracoUser").Do();
Delete.Column("startMediaID").FromTable("umbracoUser").Do();
}
private void MigrateUserStartNodes()
{
Database.Execute(@"INSERT INTO umbracoUserStartNode (userId, startNode, startNodeType)
SELECT id, startStructureID, 1
FROM umbracoUser
WHERE startStructureID IS NOT NULL AND startStructureID > 0 AND startStructureID IN (SELECT id FROM umbracoNode WHERE nodeObjectType='" + Constants.ObjectTypes.Document + "')");
Database.Execute(@"INSERT INTO umbracoUserStartNode (userId, startNode, startNodeType)
SELECT id, startMediaID, 2
FROM umbracoUser
WHERE startMediaID IS NOT NULL AND startMediaID > 0 AND startMediaID IN (SELECT id FROM umbracoNode WHERE nodeObjectType='" + Constants.ObjectTypes.Media + "')");
}
}
}
@@ -1,37 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
/// <summary>
/// Ensures the built-in user groups have the blueprint permission by default on upgrade
/// </summary>
public class EnsureContentTemplatePermissions : MigrationBase
{
public EnsureContentTemplatePermissions(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var database = Database;
var userGroups = database.Fetch<UserGroupDto>(
Context.SqlContext.Sql().Select("*")
.From<UserGroupDto>()
.Where<UserGroupDto>(x => x.Alias == "admin" || x.Alias == "editor"));
foreach (var userGroup in userGroups)
{
if (userGroup.DefaultPermissions.Contains('') == false)
{
userGroup.DefaultPermissions += "";
Update.Table("umbracoUserGroup")
.Set(new { userGroupDefaultPermissions = userGroup.DefaultPermissions })
.Where(new { id = userGroup.Id })
.Do();
}
}
}
}
}
@@ -1,37 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
public class ReduceDictionaryKeyColumnsSize : MigrationBase
{
public ReduceDictionaryKeyColumnsSize(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
//Now we need to check if we can actually do this because we won't be able to if there's data in there that is too long
var database = Database;
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
var colLen = database.ExecuteScalar<int?>(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key")));
if (colLen < 900 == false) return;
//if it exists we need to drop it first
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key")))
{
Delete.Index("IX_cmsDictionary_key").OnTable("cmsDictionary").Do();
}
//we can apply the col length change
Alter.Table("cmsDictionary")
.AlterColumn("key")
.AsString(450)
.NotNullable()
.Do();
}
}
}
@@ -1,48 +0,0 @@
using System.Linq;
using System.Web.Security;
using Newtonsoft.Json;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Security;
namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
{
public class UpdateUserTables : MigrationBase
{
public UpdateUserTables(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
//Don't execute if the column is already there
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("createDate")) == false)
Create.Column("createDate").OnTable("umbracoUser").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime).Do();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("updateDate")) == false)
Create.Column("updateDate").OnTable("umbracoUser").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime).Do();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("emailConfirmedDate")) == false)
Create.Column("emailConfirmedDate").OnTable("umbracoUser").AsDateTime().Nullable().Do();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("invitedDate")) == false)
Create.Column("invitedDate").OnTable("umbracoUser").AsDateTime().Nullable().Do();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("avatar")) == false)
Create.Column("avatar").OnTable("umbracoUser").AsString(500).Nullable().Do();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("passwordConfig")) == false)
{
Create.Column("passwordConfig").OnTable("umbracoUser").AsString(500).Nullable().Do();
//Check if we have a known config, we only want to store config for hashing
var membershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider();
if (membershipProvider.PasswordFormat == MembershipPasswordFormat.Hashed)
{
var json = JsonConvert.SerializeObject(new { hashAlgorithm = Membership.HashAlgorithmType });
Database.Execute("UPDATE umbracoUser SET passwordConfig = '" + json + "'");
}
}
}
}
}
@@ -1,27 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
{
internal class AddIndexToPropertyTypeAliasColumn : MigrationBase
{
public AddIndexToPropertyTypeAliasColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsPropertyTypeAlias")) == false)
{
//we can apply the index
Create.Index("IX_cmsPropertyTypeAlias").OnTable(Constants.DatabaseSchema.Tables.PropertyType)
.OnColumn("Alias")
.Ascending().WithOptions().NonClustered()
.Do();
}
}
}
}
@@ -1,20 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
{
internal class AddInstructionCountColumn : MigrationBase
{
public AddInstructionCountColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.CacheInstruction) && x.ColumnName.InvariantEquals("instructionCount")) == false)
AddColumn<CacheInstructionDto>("instructionCount");
}
}
}
@@ -1,65 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
{
internal class AddMediaVersionTable : MigrationBase
{
public AddMediaVersionTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(Constants.DatabaseSchema.Tables.MediaVersion)) return;
Create.Table<MediaVersionDto>().Do();
MigrateMediaPaths();
}
private void MigrateMediaPaths()
{
// this may not be the most efficient way to do it, compared to how it's done in v7, but this
// migration should only run for v8 sites that are being developed, before v8 is released, so
// no big sites and performances don't matter here - keep it simple
var sql = Sql()
.Select<PropertyDataDto>(x => x.VarcharValue, x => x.TextValue)
.AndSelect<ContentVersionDto>(x => Alias(x.Id, "versionId"))
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
.InnerJoin<ContentVersionDto>().On<PropertyDataDto, ContentVersionDto>((left, right) => left.VersionId == right.Id)
.InnerJoin<NodeDto>().On<ContentVersionDto, NodeDto>((left, right) => left.NodeId == right.NodeId)
.Where<PropertyTypeDto>(x => x.Alias == "umbracoFile")
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media);
var paths = new List<MediaVersionDto>();
//using QUERY = a db cursor, we won't load this all into memory first, just row by row
foreach (var row in Database.Query<dynamic>(sql))
{
// if there's values then ensure there's a media path match and extract it
string mediaPath = null;
if (
(row.varcharValue != null && ContentBaseFactory.TryMatch((string) row.varcharValue, out mediaPath))
|| (row.textValue != null && ContentBaseFactory.TryMatch((string) row.textValue, out mediaPath)))
{
paths.Add(new MediaVersionDto
{
Id = (int) row.versionId,
Path = mediaPath
});
}
}
// bulk insert
Database.BulkInsertRecords(paths);
}
}
}
@@ -1,21 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
{
internal class AddTourDataUserColumn : MigrationBase
{
public AddTourDataUserColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.User) && x.ColumnName.InvariantEquals("tourData")) == false)
AddColumn<UserDto>("tourData");
}
}
}
@@ -1,22 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
{
internal class AddUserLoginTable : MigrationBase
{
public AddUserLoginTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(Constants.DatabaseSchema.Tables.UserLogin) == false)
{
Create.Table<UserLoginDto>().Do();
}
}
}
}
@@ -1,20 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
{
internal class AddIsSensitiveMemberTypeColumn : MigrationBase
{
public AddIsSensitiveMemberTypeColumn(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.MemberPropertyType) && x.ColumnName.InvariantEquals("isSensitive")) == false)
AddColumn<MemberPropertyTypeDto>("isSensitive");
}
}
}
@@ -1,22 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
{
internal class AddUmbracoAuditTable : MigrationBase
{
public AddUmbracoAuditTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(Constants.DatabaseSchema.Tables.AuditEntry))
return;
Create.Table<AuditEntryDto>().Do();
}
}
}
@@ -1,22 +0,0 @@
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
{
internal class AddUmbracoConsentTable : MigrationBase
{
public AddUmbracoConsentTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(Constants.DatabaseSchema.Tables.Consent))
return;
Create.Table<ConsentDto>().Do();
}
}
}
@@ -1,27 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
{
internal class CreateSensitiveDataUserGroup : MigrationBase
{
public CreateSensitiveDataUserGroup(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var sql = Sql()
.SelectCount()
.From<UserGroupDto>()
.Where<UserGroupDto>(x => x.Alias == Constants.Security.SensitiveDataGroupAlias);
var exists = Database.ExecuteScalar<int>(sql) > 0;
if (exists) return;
var groupId = Database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", new UserGroupDto { StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.SensitiveDataGroupAlias, Name = "Sensitive data", DefaultPermissions = "", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-lock" });
Database.Insert(new User2UserGroupDto { UserGroupId = Convert.ToInt32(groupId), UserId = Constants.Security.SuperUserId }); // add super to sensitive data
}
}
}
@@ -1,6 +1,7 @@
using System.Data;
using System.Linq;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -12,31 +13,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
var tables = SqlSyntax.GetTablesInSchema(Context.Database);
if (tables.InvariantContains("cmsContentNu")) return;
var textType = SqlSyntax.GetSpecialDbType(SpecialDbTypes.NTEXT);
Create.Table("cmsContentNu")
.WithColumn("nodeId").AsInt32().NotNullable()
.WithColumn("published").AsBoolean().NotNullable()
.WithColumn("data").AsCustom(textType).NotNullable()
.WithColumn("rv").AsInt64().NotNullable().WithDefaultValue(0)
.Do();
Create.PrimaryKey("PK_cmsContentNu")
.OnTable("cmsContentNu")
.Columns(new[] { "nodeId", "published" })
.Do();
Create.ForeignKey("FK_cmsContentNu_umbracoNode_id")
.FromTable("cmsContentNu")
.ForeignColumn("nodeId")
.ToTable("umbracoNode")
.PrimaryColumn("id")
.OnDelete(Rule.Cascade)
.OnUpdate(Rule.None)
.Do();
Create.Table<ContentNuDto>(true).Do();
}
}
}
@@ -1,24 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class AddLockTable : MigrationBase
{
public AddLockTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("umbracoLock") == false)
{
Create.Table("umbracoLock")
.WithColumn("id").AsInt32().PrimaryKey("PK_umbracoLock")
.WithColumn("value").AsInt32().NotNullable()
.WithColumn("name").AsString(64).NotNullable()
.Do();
}
}
}
}
@@ -1,22 +0,0 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class AddUserLoginDtoDateIndex : MigrationBase
{
public AddUserLoginDtoDateIndex(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
if (!IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
Create.Index("IX_umbracoUserLogin_lastValidatedUtc")
.OnTable(UserLoginDto.TableName)
.OnColumn("lastValidatedUtc")
.Ascending()
.WithOptions().NonClustered()
.Do();
}
}
}
@@ -11,8 +11,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
Create.Table<ContentVersionCultureVariationDto>().Do();
Create.Table<DocumentCultureVariationDto>().Do();
Create.Table<ContentVersionCultureVariationDto>(true).Do();
Create.Table<DocumentCultureVariationDto>(true).Do();
}
}
}
@@ -1,28 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using NPoco;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class DataTypeMigration : MigrationBase
{
public DataTypeMigration(IMigrationContext context)
private readonly PreValueMigratorCollection _preValueMigrators;
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger)
: base(context)
{ }
{
_preValueMigrators = preValueMigrators;
_propertyEditors = propertyEditors;
_logger = logger;
}
public override void Migrate()
{
// delete *all* keys and indexes - because of FKs
Delete.KeysAndIndexes().Do();
// drop and create columns
Delete.Column("pk").FromTable("cmsDataType").Do();
@@ -31,21 +36,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
// create column
AddColumn<DataTypeDto>(Constants.DatabaseSchema.Tables.DataType, "config");
Execute.Sql(Sql().Update<DataTypeDto>(u => u.Set(x => x.Configuration, string.Empty)).SQL).Do();
// re-create *all* keys and indexes
foreach (var x in DatabaseSchemaCreator.OrderedTables)
Create.KeysAndIndexes(x).Do();
Execute.Sql(Sql().Update<DataTypeDto>(u => u.Set(x => x.Configuration, string.Empty))).Do();
// renames
Execute.Sql(Sql()
.Update<DataTypeDto>(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker"))
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.ColorPickerAlias").SQL).Do();
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.ColorPickerAlias")).Do();
// from preValues to configuration...
var sql = Sql()
.Select<DataTypeDto>()
.AndSelect<PreValueDto>(x => x.Alias, x => x.SortOrder, x => x.Value)
.AndSelect<PreValueDto>(x => x.Id, x => x.Alias, x => x.SortOrder, x => x.Value)
.From<DataTypeDto>()
.InnerJoin<PreValueDto>().On<DataTypeDto, PreValueDto>((left, right) => left.NodeId == right.NodeId)
.OrderBy<DataTypeDto>(x => x.NodeId)
@@ -60,43 +61,45 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.NodeId == group.Key)).First();
var aliases = group.Select(x => x.Alias).Distinct().ToArray();
if (aliases.Length == 1 && string.IsNullOrWhiteSpace(aliases[0]))
// migrate the preValues to configuration
var migrator = _preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator();
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, group.ToDictionary(x => x.Alias, x => x));
var json = JsonConvert.SerializeObject(config);
// validate - and kill the migration if it fails
var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
if (newAlias == null)
{
// array-based prevalues
var values = new Dictionary<string, object> { ["values"] = group.OrderBy(x => x.SortOrder).Select(x => x.Value).ToArray() };
dataType.Configuration = JsonConvert.SerializeObject(values);
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
}
else if (!_propertyEditors.TryGet(newAlias, out var propertyEditor))
{
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
else
{
// assuming we don't want to fall back to array
if (aliases.Length != group.Count() || aliases.Any(string.IsNullOrWhiteSpace))
throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataType.NodeId} preValues: duplicate or null/empty alias.");
// dictionary-base prevalues
var values = group.ToDictionary(x => x.Alias, x => x.Value);
dataType.Configuration = JsonConvert.SerializeObject(values);
var configEditor = propertyEditor.GetConfigurationEditor();
try
{
var _ = configEditor.FromDatabase(json);
}
catch (Exception e)
{
_logger.Warn<DataTypeMigration>(e, "Failed to validate configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})."
+ " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
}
// update
dataType.Configuration = JsonConvert.SerializeObject(config);
Database.Update(dataType);
}
}
[TableName("cmsDataTypePreValues")]
[ExplicitColumns]
public class PreValueDto
{
[Column("datatypeNodeId")]
public int NodeId { get; set; }
[Column("alias")]
public string Alias { get; set; }
[Column("sortorder")]
public int SortOrder { get; set; }
[Column("value")]
public string Value { get; set; }
}
}
}
@@ -0,0 +1,20 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class ContentPickerPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.ContentPicker2";
public override string GetNewAlias(string editorAlias)
=> null;
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "showOpenButton" ||
preValue.Alias == "ignoreUserStartNodes")
return preValue.Value == "1";
return base.GetPreValueValue(preValue);
}
}
}
@@ -0,0 +1,20 @@
using Newtonsoft.Json;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class DecimalPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.Decimal";
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "min" ||
preValue.Alias == "step" ||
preValue.Alias == "max")
return decimal.TryParse(preValue.Value, out var d) ? (decimal?) d : null;
return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class DefaultPreValueMigrator : IPreValueMigrator
{
public virtual bool CanMigrate(string editorAlias)
=> true;
public virtual string GetNewAlias(string editorAlias)
=> editorAlias;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var preValuesA = preValues.Values.ToList();
var aliases = preValuesA.Select(x => x.Alias).Distinct().ToArray();
if (aliases.Length == 1 && string.IsNullOrWhiteSpace(aliases[0]))
{
// array-based prevalues
return new Dictionary<string, object> { ["values"] = preValuesA.OrderBy(x => x.SortOrder).Select(x => x.Value).ToArray() };
}
// assuming we don't want to fall back to array
if (aliases.Length != preValuesA.Count || aliases.Any(string.IsNullOrWhiteSpace))
throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataTypeId} preValues: duplicate or null/empty alias.");
// dictionary-base prevalues
return GetPreValues(preValuesA).ToDictionary(x => x.Alias, GetPreValueValue);
}
protected virtual IEnumerable<PreValueDto> GetPreValues(IEnumerable<PreValueDto> preValues)
=> preValues;
protected virtual object GetPreValueValue(PreValueDto preValue)
{
return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}
}
@@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
/// <summary>
/// Defines a service migrating preValues.
/// </summary>
public interface IPreValueMigrator
{
/// <summary>
/// Determines whether this migrator can migrate a data type.
/// </summary>
/// <param name="editorAlias">The data type editor alias.</param>
bool CanMigrate(string editorAlias);
/// <summary>
/// Gets the v8 codebase data type editor alias.
/// </summary>
/// <param name="editorAlias">The original v7 codebase editor alias.</param>
/// <remarks>
/// <para>This is used to validate that the migrated configuration can be parsed
/// by the new property editor. Return <c>null</c> to bypass this validation,
/// when for instance we know it will fail, and another, later migration will
/// deal with it.</para>
/// </remarks>
string GetNewAlias(string editorAlias);
/// <summary>
/// Gets the configuration object corresponding to preValue.
/// </summary>
/// <param name="dataTypeId">The data type identifier.</param>
/// <param name="editorAlias">The data type editor alias.</param>
/// <param name="preValues">PreValues.</param>
object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues);
}
}
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class ListViewPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.ListView";
protected override IEnumerable<PreValueDto> GetPreValues(IEnumerable<PreValueDto> preValues)
{
return preValues.Where(preValue => preValue.Alias != "displayAtTabNumber");
}
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "pageSize")
return int.TryParse(preValue.Value, out var i) ? (int?)i : null;
return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}
}
@@ -0,0 +1,37 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class MediaPickerPreValueMigrator : DefaultPreValueMigrator //PreValueMigratorBase
{
private readonly string[] _editors =
{
"Umbraco.MediaPicker2",
"Umbraco.MediaPicker"
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
=> "Umbraco.MediaPicker";
// you wish - but MediaPickerConfiguration lives in Umbraco.Web
/*
public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
return new MediaPickerConfiguration { ... };
}
*/
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "multiPicker" ||
preValue.Alias == "onlyImages" ||
preValue.Alias == "disableFolderSelect")
return preValue.Value == "1";
return base.GetPreValueValue(preValue);
}
}
}
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class NestedContentPreValueMigrator : DefaultPreValueMigrator //PreValueMigratorBase
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.NestedContent";
// you wish - but NestedContentConfiguration lives in Umbraco.Web
/*
public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
return new NestedContentConfiguration { ... };
}
*/
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "confirmDeletes" ||
preValue.Alias == "showIcons" ||
preValue.Alias == "hideLabel")
return preValue.Value == "1";
if (preValue.Alias == "minItems" ||
preValue.Alias == "maxItems")
return int.TryParse(preValue.Value, out var i) ? (int?)i : null;
return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}
}
@@ -0,0 +1,24 @@
using NPoco;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
[TableName("cmsDataTypePreValues")]
[ExplicitColumns]
public class PreValueDto
{
[Column("id")]
public int Id { get; set; }
[Column("datatypeNodeId")]
public int NodeId { get; set; }
[Column("alias")]
public string Alias { get; set; }
[Column("sortorder")]
public int SortOrder { get; set; }
[Column("value")]
public string Value { get; set; }
}
}
@@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
public abstract class PreValueMigratorBase : IPreValueMigrator
{
public abstract bool CanMigrate(string editorAlias);
public virtual string GetNewAlias(string editorAlias)
=> editorAlias;
public abstract object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues);
protected bool GetBoolValue(Dictionary<string, PreValueDto> preValues, string alias, bool defaultValue = false)
=> preValues.TryGetValue(alias, out var preValue) ? preValue.Value == "1" : defaultValue;
protected decimal GetDecimalValue(Dictionary<string, PreValueDto> preValues, string alias, decimal defaultValue = 0)
=> preValues.TryGetValue(alias, out var preValue) && decimal.TryParse(preValue.Value, out var value) ? value : defaultValue;
}
}
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
public class PreValueMigratorCollection : BuilderCollectionBase<IPreValueMigrator>
{
private readonly ILogger _logger;
public PreValueMigratorCollection(IEnumerable<IPreValueMigrator> items, ILogger logger)
: base(items)
{
_logger = logger;
_logger.Debug(GetType(), "Migrators: " + string.Join(", ", items.Select(x => x.GetType().Name)));
}
public IPreValueMigrator GetMigrator(string editorAlias)
{
var migrator = this.FirstOrDefault(x => x.CanMigrate(editorAlias));
_logger.Debug(GetType(), "Getting migrator for \"{EditorAlias}\" = {MigratorType}", editorAlias, migrator == null ? "<null>" : migrator.GetType().Name);
return migrator;
}
}
}
@@ -0,0 +1,9 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
public class PreValueMigratorCollectionBuilder : OrderedCollectionBuilderBase<PreValueMigratorCollectionBuilder, PreValueMigratorCollection, IPreValueMigrator>
{
protected override PreValueMigratorCollectionBuilder This => this;
}
}
@@ -0,0 +1,25 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
public class PreValueMigratorComposer : ICoreComposer
{
public void Compose(Composition composition)
{
// do NOT add DefaultPreValueMigrator to this list!
// it will be automatically used if nothing matches
composition.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
.Append<RenamingPreValueMigrator>()
.Append<RichTextPreValueMigrator>()
.Append<UmbracoSliderPreValueMigrator>()
.Append<MediaPickerPreValueMigrator>()
.Append<ContentPickerPreValueMigrator>()
.Append<NestedContentPreValueMigrator>()
.Append<DecimalPreValueMigrator>()
.Append<ListViewPreValueMigrator>()
.Append<ValueListPreValueMigrator>();
}
}
}
@@ -0,0 +1,27 @@
using System;
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class RenamingPreValueMigrator : DefaultPreValueMigrator
{
private readonly string[] _editors =
{
"Umbraco.NoEdit"
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
{
switch (editorAlias)
{
case "Umbraco.NoEdit":
return Constants.PropertyEditors.Aliases.Label;
default:
throw new Exception("panic");
}
}
}
}
@@ -0,0 +1,21 @@
using Newtonsoft.Json;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class RichTextPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.TinyMCEv3";
public override string GetNewAlias(string editorAlias)
=> Constants.PropertyEditors.Aliases.TinyMce;
protected override object GetPreValueValue(PreValueDto preValue)
{
if (preValue.Alias == "hideLabel")
return preValue.Value == "1";
return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
}
}
}
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class UmbracoSliderPreValueMigrator : PreValueMigratorBase
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.Slider";
public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
return new SliderConfiguration
{
EnableRange = GetBoolValue(preValues, "enableRange"),
InitialValue = GetDecimalValue(preValues, "initVal1"),
InitialValue2 = GetDecimalValue(preValues, "initVal2"),
MaximumValue = GetDecimalValue(preValues, "maxVal"),
MinimumValue = GetDecimalValue(preValues, "minVal"),
StepIncrements = GetDecimalValue(preValues, "step")
};
}
}
}
@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class ValueListPreValueMigrator : IPreValueMigrator
{
private readonly string[] _editors =
{
"Umbraco.RadioButtonList",
"Umbraco.DropDown",
"Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple",
"Umbraco.DropdownlistMultiplePublishKeys"
};
public bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public virtual string GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new ValueListConfiguration();
foreach (var preValue in preValues.Values)
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
return config;
}
}
}
@@ -1,39 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models;
using Umbraco.Core.Sync;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class DropDownPropertyEditorsMigration : MigrationBase
public class DropDownPropertyEditorsMigration : PropertyEditorsMigrationBase
{
private readonly CacheRefresherCollection _cacheRefreshers;
private readonly IServerMessenger _serverMessenger;
public DropDownPropertyEditorsMigration(IMigrationContext context, CacheRefresherCollection cacheRefreshers, IServerMessenger serverMessenger)
public DropDownPropertyEditorsMigration(IMigrationContext context)
: base(context)
{
_cacheRefreshers = cacheRefreshers;
_serverMessenger = serverMessenger;
}
// dummy editor for deserialization
private class ValueListConfigurationEditor : ConfigurationEditor<ValueListConfiguration>
{ }
public override void Migrate()
{
//need to convert the old drop down data types to use the new one
var dataTypes = Database.Fetch<DataTypeDto>(Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias.Contains(".DropDown")));
var refreshCache = Migrate(GetDataTypes(".DropDown", false));
// if some data types have been updated directly in the database (editing DataTypeDto and/or PropertyDataDto),
// bypassing the services, then we need to rebuild the cache entirely, including the umbracoContentNu table
if (refreshCache)
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
private bool Migrate(IEnumerable<DataTypeDto> dataTypes)
{
var refreshCache = false;
ConfigurationEditor configurationEditor = null;
foreach (var dataType in dataTypes)
{
@@ -42,14 +38,16 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
if (!dataType.Configuration.IsNullOrWhiteSpace())
{
// parse configuration, and update everything accordingly
if (configurationEditor == null)
configurationEditor = new ValueListConfigurationEditor();
try
{
config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase(dataType.Configuration);
config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration);
}
catch (Exception ex)
{
Logger.Error<DropDownPropertyEditorsMigration>(
ex, "Invalid drop down configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.",
dataType.Configuration);
// reset
@@ -65,7 +63,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.Where<PropertyTypeDto>(x => x.DataTypeId == dataType.NodeId));
// update dtos
var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config));
var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config, true));
// persist changes
foreach (var propertyDataDto in updatedDtos)
@@ -77,7 +75,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
config = new ValueListConfiguration();
}
var requiresCacheRebuild = false;
switch (dataType.EditorAlias)
{
case string ea when ea.InvariantEquals("Umbraco.DropDown"):
@@ -85,29 +82,25 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
break;
case string ea when ea.InvariantEquals("Umbraco.DropdownlistPublishingKeys"):
UpdateDataType(dataType, config, false);
requiresCacheRebuild = true;
break;
case string ea when ea.InvariantEquals("Umbraco.DropDownMultiple"):
UpdateDataType(dataType, config, true);
break;
case string ea when ea.InvariantEquals("Umbraco.DropdownlistMultiplePublishKeys"):
UpdateDataType(dataType, config, true);
requiresCacheRebuild = true;
break;
}
if (requiresCacheRebuild)
{
var dataTypeCacheRefresher = _cacheRefreshers[Guid.Parse("35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2")];
_serverMessenger.PerformRefreshAll(dataTypeCacheRefresher);
}
refreshCache = true;
}
return refreshCache;
}
private void UpdateDataType(DataTypeDto dataType, ValueListConfiguration config, bool isMultiple)
{
dataType.EditorAlias = Constants.PropertyEditors.Aliases.DropDownListFlexible;
dataType.DbType = ValueStorageType.Nvarchar.ToString();
dataType.EditorAlias = Constants.PropertyEditors.Aliases.DropDownListFlexible;
var flexConfig = new DropDownFlexibleConfiguration
{
@@ -118,68 +111,5 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Database.Update(dataType);
}
private bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
{
//Get the INT ids stored for this property/drop down
int[] ids = null;
if (!propData.VarcharValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.VarcharValue);
}
else if (!propData.TextValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.TextValue);
}
else if (propData.IntegerValue.HasValue)
{
ids = new[] { propData.IntegerValue.Value };
}
//if there are INT ids, convert them to values based on the configured pre-values
if (ids != null && ids.Length > 0)
{
//map the ids to values
var vals = new List<string>();
var canConvert = true;
foreach (var id in ids)
{
var val = config.Items.FirstOrDefault(x => x.Id == id);
if (val != null)
vals.Add(val.Value);
else
{
Logger.Warn<DropDownPropertyEditorsMigration>(
"Could not find associated data type configuration for stored Id {DataTypeId}", id);
canConvert = false;
}
}
if (canConvert)
{
propData.VarcharValue = string.Join(",", vals);
propData.TextValue = null;
propData.IntegerValue = null;
return true;
}
}
return false;
}
private int[] ConvertStringValues(string val)
{
var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var intVals = splitVals
.Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
.Where(x => x != int.MinValue)
.ToArray();
//only return if the number of values are the same (i.e. All INTs)
if (splitVals.Length == intVals.Length)
return intVals;
return null;
}
}
}
@@ -8,7 +8,8 @@
public override void Migrate()
{
Delete.Table("umbracoMigration").Do();
if (TableExists("umbracoMigration"))
Delete.Table("umbracoMigration").Do();
}
}
}
@@ -3,8 +3,7 @@
public class DropPreValueTable : MigrationBase
{
public DropPreValueTable(IMigrationContext context) : base(context)
{
}
{ }
public override void Migrate()
{
@@ -0,0 +1,21 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class FixLanguageIsoCodeLength : MigrationBase
{
public FixLanguageIsoCodeLength(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// there is some confusion here when upgrading from v7
// it should be 14 already but that's not always the case
Alter.Table("umbracoLanguage")
.AlterColumn("languageISOCode")
.AsString(14)
.Nullable()
.Do();
}
}
}
@@ -1,23 +0,0 @@
using System.Linq;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class FixLockTablePrimaryKey : MigrationBase
{
public FixLockTablePrimaryKey(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// at some point, the KeyValueService dropped the PK and failed to re-create it,
// so the PK is gone - make sure we have one, and create if needed
var constraints = SqlSyntax.GetConstraintsPerTable(Database);
var exists = constraints.Any(x => x.Item2 == "PK_umbracoLock");
if (!exists)
Create.PrimaryKey("PK_umbracoLock").OnTable(Constants.DatabaseSchema.Tables.Lock).Column("id").Do();
}
}
}
@@ -11,19 +11,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
AddColumn<RedirectUrlDto>("culture");
Delete.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl).Do();
Create.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl)
.OnColumn("urlHash")
.Ascending()
.OnColumn("contentKey")
.Ascending()
.OnColumn("culture")
.Ascending()
.OnColumn("createDateUtc")
.Ascending()
.WithOptions().Unique()
.Do();
}
}
}
@@ -11,17 +11,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
AddColumn<TagDto>("languageId");
Delete.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag).Do();
Create.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag)
.OnColumn("group")
.Ascending()
.OnColumn("tag")
.Ascending()
.OnColumn("languageId")
.Ascending()
.WithOptions().Unique()
.Do();
}
}
}
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public abstract class PropertyEditorsMigrationBase : MigrationBase
{
protected PropertyEditorsMigrationBase(IMigrationContext context)
: base(context)
{ }
internal List<DataTypeDto> GetDataTypes(string editorAlias, bool strict = true)
{
var sql = Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>();
sql = strict
? sql.Where<DataTypeDto>(x => x.EditorAlias == editorAlias)
: sql.Where<DataTypeDto>(x => x.EditorAlias.Contains(editorAlias));
return Database.Fetch<DataTypeDto>(sql);
}
protected int[] ConvertStringValues(string val)
{
var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var intVals = splitVals
.Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
.Where(x => x != int.MinValue)
.ToArray();
//only return if the number of values are the same (i.e. All INTs)
if (splitVals.Length == intVals.Length)
return intVals;
return null;
}
internal bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool isMultiple)
{
//Get the INT ids stored for this property/drop down
int[] ids = null;
if (!propData.VarcharValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.VarcharValue);
}
else if (!propData.TextValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.TextValue);
}
else if (propData.IntegerValue.HasValue)
{
ids = new[] { propData.IntegerValue.Value };
}
// if there are INT ids, convert them to values based on the configuration
if (ids == null || ids.Length <= 0) return false;
// map ids to values
var values = new List<string>();
var canConvert = true;
foreach (var id in ids)
{
var val = config.Items.FirstOrDefault(x => x.Id == id);
if (val != null)
{
values.Add(val.Value);
continue;
}
Logger.Warn(GetType(), "Could not find PropertyData {PropertyDataId} value '{PropertyValue}' in the datatype configuration: {Values}.",
propData.Id, id, string.Join(", ", config.Items.Select(x => x.Id + ":" + x.Value)));
canConvert = false;
}
if (!canConvert) return false;
propData.VarcharValue = isMultiple ? JsonConvert.SerializeObject(values) : values[0];
propData.TextValue = null;
propData.IntegerValue = null;
return true;
}
// dummy editor for deserialization
protected class ValueListConfigurationEditor : ConfigurationEditor<ValueListConfiguration>
{ }
}
}
@@ -1,183 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class RadioAndCheckboxAndDropdownPropertyEditorsMigration : MigrationBase
{
public RadioAndCheckboxAndDropdownPropertyEditorsMigration(IMigrationContext context)
: base(context)
{
}
public override void Migrate()
{
var refreshCache = false;
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.RadioButtonList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, true));
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.CheckBoxList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, false));
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.DropDownListFlexible, UpdateDropDownPropertyDataDto);
if (refreshCache)
{
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
private bool Migrate(string editorAlias, Func<PropertyDataDto, ValueListConfiguration, bool> updateRadioPropertyDataFunc)
{
var refreshCache = false;
var dataTypes = GetDataTypes(editorAlias);
foreach (var dataType in dataTypes)
{
ValueListConfiguration config;
if (dataType.Configuration.IsNullOrWhiteSpace())
continue;
// parse configuration, and update everything accordingly
try
{
config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase(
dataType.Configuration);
}
catch (Exception ex)
{
Logger.Error<DropDownPropertyEditorsMigration>(
ex,
"Invalid property editor configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
dataType.Configuration);
continue;
}
// get property data dtos
var propertyDataDtos = Database.Fetch<PropertyDataDto>(Sql()
.Select<PropertyDataDto>()
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyTypeDto, PropertyDataDto>((pt, pd) => pt.Id == pd.PropertyTypeId)
.InnerJoin<DataTypeDto>()
.On<DataTypeDto, PropertyTypeDto>((dt, pt) => dt.NodeId == pt.DataTypeId)
.Where<PropertyTypeDto>(x => x.DataTypeId == dataType.NodeId));
// update dtos
var updatedDtos = propertyDataDtos.Where(x => updateRadioPropertyDataFunc(x, config));
// persist changes
foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto);
UpdateDataType(dataType);
refreshCache = true;
}
return refreshCache;
}
private List<DataTypeDto> GetDataTypes(string editorAlias)
{
//need to convert the old drop down data types to use the new one
var dataTypes = Database.Fetch<DataTypeDto>(Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == editorAlias));
return dataTypes;
}
private void UpdateDataType(DataTypeDto dataType)
{
dataType.DbType = ValueStorageType.Nvarchar.ToString();
Database.Update(dataType);
}
private bool UpdateRadioOrCheckboxPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool singleValue)
{
//Get the INT ids stored for this property/drop down
int[] ids = null;
if (!propData.VarcharValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.VarcharValue);
}
else if (!propData.TextValue.IsNullOrWhiteSpace())
{
ids = ConvertStringValues(propData.TextValue);
}
else if (propData.IntegerValue.HasValue)
{
ids = new[] {propData.IntegerValue.Value};
}
//if there are INT ids, convert them to values based on the configuration
if (ids == null || ids.Length <= 0) return false;
//map the ids to values
var values = new List<string>();
var canConvert = true;
foreach (var id in ids)
{
var val = config.Items.FirstOrDefault(x => x.Id == id);
if (val != null)
values.Add(val.Value);
else
{
Logger.Warn<DropDownPropertyEditorsMigration>(
"Could not find associated data type configuration for stored Id {DataTypeId}", id);
canConvert = false;
}
}
if (!canConvert) return false;
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
propData.VarcharValue = singleValue ? values[0] : JsonConvert.SerializeObject(values);
propData.TextValue = null;
propData.IntegerValue = null;
return true;
}
private bool UpdateDropDownPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
{
//Get the INT ids stored for this property/drop down
var values = propData.VarcharValue.Split(new []{","}, StringSplitOptions.RemoveEmptyEntries);
//if there are INT ids, convert them to values based on the configuration
if (values == null || values.Length <= 0) return false;
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
propData.VarcharValue = JsonConvert.SerializeObject(values);
propData.TextValue = null;
propData.IntegerValue = null;
return true;
}
private int[] ConvertStringValues(string val)
{
var splitVals = val.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
var intVals = splitVals
.Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
.Where(x => x != int.MinValue)
.ToArray();
//only return if the number of values are the same (i.e. All INTs)
if (splitVals.Length == intVals.Length)
return intVals;
return null;
}
private class ValueListConfigurationEditor : ConfigurationEditor<ValueListConfiguration>
{
}
}
}
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class RadioAndCheckboxPropertyEditorsMigration : PropertyEditorsMigrationBase
{
public RadioAndCheckboxPropertyEditorsMigration(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
var refreshCache = false;
refreshCache |= Migrate(GetDataTypes(Constants.PropertyEditors.Aliases.RadioButtonList), false);
refreshCache |= Migrate(GetDataTypes(Constants.PropertyEditors.Aliases.CheckBoxList), true);
// if some data types have been updated directly in the database (editing DataTypeDto and/or PropertyDataDto),
// bypassing the services, then we need to rebuild the cache entirely, including the umbracoContentNu table
if (refreshCache)
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
private bool Migrate(IEnumerable<DataTypeDto> dataTypes, bool isMultiple)
{
var refreshCache = false;
ConfigurationEditor configurationEditor = null;
foreach (var dataType in dataTypes)
{
ValueListConfiguration config;
if (dataType.Configuration.IsNullOrWhiteSpace())
continue;
// parse configuration, and update everything accordingly
if (configurationEditor == null)
configurationEditor = new ValueListConfigurationEditor();
try
{
config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration);
}
catch (Exception ex)
{
Logger.Error<DropDownPropertyEditorsMigration>(
ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.",
dataType.Configuration);
continue;
}
// get property data dtos
var propertyDataDtos = Database.Fetch<PropertyDataDto>(Sql()
.Select<PropertyDataDto>()
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>().On<PropertyTypeDto, PropertyDataDto>((pt, pd) => pt.Id == pd.PropertyTypeId)
.InnerJoin<DataTypeDto>().On<DataTypeDto, PropertyTypeDto>((dt, pt) => dt.NodeId == pt.DataTypeId)
.Where<PropertyTypeDto>(x => x.DataTypeId == dataType.NodeId));
// update dtos
var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config, isMultiple));
// persist changes
foreach (var propertyDataDto in updatedDtos)
Database.Update(propertyDataDto);
UpdateDataType(dataType);
refreshCache = true;
}
return refreshCache;
}
private void UpdateDataType(DataTypeDto dataType)
{
dataType.DbType = ValueStorageType.Nvarchar.ToString();
Database.Update(dataType);
}
}
}
@@ -1,69 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class RefactorXmlColumns : MigrationBase
{
public RefactorXmlColumns(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
if (ColumnExists("cmsContentXml", "Rv") == false)
Alter.Table("cmsContentXml").AddColumn("Rv").AsInt64().NotNullable().WithDefaultValue(0).Do();
if (ColumnExists("cmsPreviewXml", "Rv") == false)
Alter.Table("cmsPreviewXml").AddColumn("Rv").AsInt64().NotNullable().WithDefaultValue(0).Do();
// remove the any PK_ and the FK_ to cmsContentVersion.VersionId
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
var dups = new List<string>();
foreach (var c in constraints.Where(x => x.Item1.InvariantEquals("cmsPreviewXml") && x.Item3.InvariantStartsWith("PK_")))
{
var keyName = c.Item3.ToLowerInvariant();
if (dups.Contains(keyName))
{
Logger.Warn<RefactorXmlColumns>("Duplicate constraint '{Constraint}'", c.Item3);
continue;
}
dups.Add(keyName);
Delete.PrimaryKey(c.Item3).FromTable(c.Item1).Do();
}
foreach (var c in constraints.Where(x => x.Item1.InvariantEquals("cmsPreviewXml") && x.Item3.InvariantStartsWith("FK_cmsPreviewXml_cmsContentVersion")))
{
Delete.ForeignKey().FromTable("cmsPreviewXml").ForeignColumn("VersionId")
.ToTable("cmsContentVersion").PrimaryColumn("VersionId")
.Do();
}
if (ColumnExists("cmsPreviewXml", "Timestamp"))
Delete.Column("Timestamp").FromTable("cmsPreviewXml").Do();
if (ColumnExists("cmsPreviewXml", "VersionId"))
{
RemoveDuplicates();
Delete.Column("VersionId").FromTable("cmsPreviewXml").Do();
}
// re-create the primary key
Create.PrimaryKey("PK_cmsPreviewXml")
.OnTable("cmsPreviewXml")
.Columns(new[] { "nodeId" })
.Do();
}
private void RemoveDuplicates()
{
const string sql = @"delete from cmsPreviewXml where versionId in (
select cmsPreviewXml.versionId from cmsPreviewXml
join cmsDocument on cmsPreviewXml.versionId=cmsDocument.versionId
where cmsDocument.newest <> 1)";
Context.Database.Execute(sql);
}
}
}
@@ -0,0 +1,46 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class RenameMediaVersionTable : MigrationBase
{
public RenameMediaVersionTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
Rename.Table("cmsMedia").To(Constants.DatabaseSchema.Tables.MediaVersion).Do();
// that is not supported on SqlCE
//Rename.Column("versionId").OnTable(Constants.DatabaseSchema.Tables.MediaVersion).To("id").Do();
AddColumn<MediaVersionDto>("id", out var sqls);
// SQLCE does not support UPDATE...FROM
var temp2 = Database.Fetch<dynamic>($@"SELECT v.versionId, v.id
FROM cmsContentVersion v
JOIN umbracoNode n on v.contentId=n.id
WHERE n.nodeObjectType='{Constants.ObjectTypes.Media}'");
foreach (var t in temp2)
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET id={t.id} WHERE versionId='{t.versionId}'").Do();
foreach (var sql in sqls)
Execute.Sql(sql).Do();
AddColumn<MediaVersionDto>("path", out sqls);
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET path=mediaPath").Do();
foreach (var sql in sqls)
Execute.Sql(sql).Do();
// we had to run sqls to get the NULL constraints, but we need to get rid of most
Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.MediaVersion).Do();
Delete.Column("mediaPath").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
Delete.Column("versionId").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
Delete.Column("nodeId").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
}
}
}
@@ -2,7 +2,9 @@
{
public class RenameUmbracoDomainsTable : MigrationBase
{
public RenameUmbracoDomainsTable(IMigrationContext context) : base(context) { }
public RenameUmbracoDomainsTable(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
@@ -11,20 +11,27 @@
var exists = Database.Fetch<int>("select id from umbracoUser where id=-1;").Count > 0;
if (exists) return;
Database.Execute("update umbracoUser set userLogin = userLogin + '__' where userId=0");
Database.Execute("update umbracoUser set userLogin = userLogin + '__' where id=0");
Database.Execute("set identity_insert umbracoUser on;");
Database.Execute(@"
insert into umbracoUser select -1,
userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2), userPassword, passwordConfig,
insert into umbracoUser (id,
userDisabled, userNoConsole, userName, userLogin, userPassword, passwordConfig,
userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,
lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
createDate, updateDate, avatar, tourData)
select
-1 id,
userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2) userLogin, userPassword, passwordConfig,
userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,
lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
createDate, updateDate, avatar
createDate, updateDate, avatar, tourData
from umbracoUser where id=0;");
Database.Execute("set identity_insert umbracoUser off;");
Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;");
Database.Execute("update umbracoNode set nodeUser=-1 where nodeUser=0;");
Database.Execute("update umbracoUserLogin set userId=-1 where userId=0;");
Database.Execute($"update {Constants.DatabaseSchema.Tables.ContentVersion} set userId=-1 where userId=0;");
Database.Execute("delete from umbracoUser where id=0;");
}
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Delete.Column("releaseDate").FromTable("umbracoDocument").Do();
Delete.Column("expireDate").FromTable("umbracoDocument").Do();
//add new table
Create.Table<ContentScheduleDto>().Do();
Create.Table<ContentScheduleDto>(true).Do();
//migrate the schedule
foreach(var s in schedules)
@@ -1,4 +1,5 @@
using Umbraco.Core.Persistence.Dtos;
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -14,13 +15,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
AlterColumn<TagDto>(Constants.DatabaseSchema.Tables.Tag, "group");
AlterColumn<TagDto>(Constants.DatabaseSchema.Tables.Tag, "tag");
//AddColumn<TagDto>(Constants.DatabaseSchema.Tables.Tag, "key");
// kill unused parentId column
Delete.ForeignKey("FK_cmsTags_cmsTags").OnTable(Constants.DatabaseSchema.Tables.Tag).Do();
Delete.Column("ParentId").FromTable(Constants.DatabaseSchema.Tables.Tag).Do();
}
}
// fixes TagsMigration that... originally failed to properly drop the ParentId column
}
@@ -2,6 +2,7 @@
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
@@ -1,6 +1,4 @@
using NPoco;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -15,24 +13,19 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
//first allow NULL-able
// first allow NULL-able
Alter.Table(ContentVersionCultureVariationDto.TableName).AlterColumn("availableUserId").AsInt32().Nullable().Do();
Alter.Table(ContentVersionDto.TableName).AlterColumn("userId").AsInt32().Nullable().Do();
Alter.Table(Constants.DatabaseSchema.Tables.Log).AlterColumn("userId").AsInt32().Nullable().Do();
Alter.Table(NodeDto.TableName).AlterColumn("nodeUser").AsInt32().Nullable().Do();
//then we can update any non existing users to NULL
// then we can update any non existing users to NULL
Execute.Sql($"UPDATE {ContentVersionCultureVariationDto.TableName} SET availableUserId = NULL WHERE availableUserId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {ContentVersionDto.TableName} SET userId = NULL WHERE userId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Log} SET userId = NULL WHERE userId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {NodeDto.TableName} SET nodeUser = NULL WHERE nodeUser NOT IN (SELECT id FROM {UserDto.TableName})").Do();
//now NULL-able with FKs
Alter.Table(ContentVersionCultureVariationDto.TableName).AlterColumn("availableUserId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
Alter.Table(ContentVersionDto.TableName).AlterColumn("userId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
Alter.Table(Constants.DatabaseSchema.Tables.Log).AlterColumn("userId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
Alter.Table(NodeDto.TableName).AlterColumn("nodeUser").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
// FKs will be created after migrations
}
}
}
@@ -18,9 +18,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
// delete *all* keys and indexes - because of FKs
Delete.KeysAndIndexes().Do();
MigratePropertyData();
MigrateContentAndPropertyTypes();
MigrateContent();
@@ -46,10 +43,6 @@ HAVING COUNT(v2.id) <> 1").Any())
Debugger.Break();
throw new Exception("Migration failed: missing or duplicate 'current' content versions.");
}
// re-create *all* keys and indexes
foreach (var x in DatabaseSchemaCreator.OrderedTables)
Create.KeysAndIndexes(x).Do();
}
private void MigratePropertyData()
@@ -220,8 +213,10 @@ WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE
Delete.Column("text").FromTable(PreTables.Document).Do();
Delete.Column("templateId").FromTable(PreTables.Document).Do();
Delete.Column("documentUser").FromTable(PreTables.Document).Do();
Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("updateDate").Do();
Delete.Column("updateDate").FromTable(PreTables.Document).Do();
Delete.Column("versionId").FromTable(PreTables.Document).Do();
Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("newest").Do();
Delete.Column("newest").FromTable(PreTables.Document).Do();
// add and populate edited column
@@ -320,7 +315,7 @@ WHERE v1.propertyTypeId=v2.propertyTypeId AND v1.languageId=v2.languageId AND v1
public const string Tag = "cmsTags";
public const string TagRelationship = "cmsTagRelationship";
// ReSharper restore UnusedMember.Local
}
}
@@ -1,16 +0,0 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}
@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -26,8 +26,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
var sqlPropertyData = Sql()
.Select<PropertyDataDto>(x => x.Id, x => x.TextValue)
.AndSelect<DataTypeDto>(x => x.EditorAlias)
.Select<PropertyDataDto>(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
@@ -63,7 +62,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
}
Database.Update(property, x => x.TextValue);
Database.Update(property);
}
Context.AddPostMigration<RebuildPublishedSnapshot>();
@@ -0,0 +1,17 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class FixContentNuCascade : MigrationBase
{
public FixContentNuCascade(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
Delete.KeysAndIndexes<ContentNuDto>().Do();
Create.KeysAndIndexes<ContentNuDto>().Do();
}
}
}
@@ -0,0 +1,36 @@
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class RenameUserLoginDtoDateIndex : MigrationBase
{
public RenameUserLoginDtoDateIndex(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// there has been some confusion with an index name, resulting in
// different names depending on which migration path was followed,
// and discrepancies between an upgraded or an installed database.
// better normalize
if (IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
return;
if (IndexExists("IX_userLoginDto_lastValidatedUtc"))
Delete
.Index("IX_userLoginDto_lastValidatedUtc")
.OnTable(UserLoginDto.TableName)
.Do();
Create
.Index("IX_umbracoUserLogin_lastValidatedUtc")
.OnTable(UserLoginDto.TableName)
.OnColumn("lastValidatedUtc")
.Ascending()
.WithOptions().NonClustered()
.Do();
}
}
}

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