Compare commits

..

287 Commits

Author SHA1 Message Date
swcs b686dc6362 disable "Add" button in Nested Content config when no available docTypes are left 2019-08-11 14:25:43 +02:00
swcs ab0c4d2700 add+delete anchors in Nested Content config should be <button/> elements 2019-08-11 14:19:09 +02:00
swcs 8b8a8c0ccb display docType alias in Nested Content property editor when necessary 2019-08-11 14:16:54 +02:00
Kenn Jacobsen 2f84e76952 Use mculture in content editor for multilingual content 2019-08-09 16:58:35 +02:00
Kenn Jacobsen 12a30d3ffd Always open the selected content template in infinite editing 2019-08-09 16:56:04 +02:00
Kenn Jacobsen 7e1f90fb3b Clear the content type "common" cache when deleting templates 2019-08-09 16:54:52 +02:00
Kenn Jacobsen feb5567621 Fix the disabled upload button in media picker (#6082) 2019-08-09 16:36:38 +02:00
Rachel Breeze ab3202b560 V8: Accessibility improvements for page name entry (#5760) 2019-08-09 16:25:51 +02:00
Kenn Jacobsen e10ce234db Fix "infinityMode" typo 2019-08-09 15:59:37 +02:00
Shannon 84554101f2 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-08-09 15:54:38 +10:00
Shannon 8a3b2e038c adds note 2019-08-09 15:54:21 +10:00
amitch17 296d7964ae Corrected comments to change usage examples
Corrected usage examples for entityResource.js

My first Umbraco commit! yay!
2019-08-08 18:55:38 +02:00
Steve Megson ed5effd190 Sorting of images in multiple media picker 2019-08-08 16:00:21 +02:00
Kenn Jacobsen 57e58c6cf7 Fix broken button to open content type from create dialog 2019-08-08 10:03:47 +02:00
leekelleher 34e45abcc7 Added constants for Property Editor Groups 2019-08-07 20:59:03 +02:00
Kenn Jacobsen b3497011e8 Make content types with description look ok in the create dialog (#5752) 2019-08-07 20:49:14 +02:00
Søren Gregersen a398881fa1 fix: spelling error in comment :)
infinie error(s) fixed
2019-08-07 20:38:37 +02:00
Sebastiaan Janssen 2cf3a7831c Merge pull request #5999 from kjac/v8-fix-allow-remove-user-start-nodes
V8: Allow removing user start nodes
2019-08-07 20:19:48 +02:00
Gopakumar R 0138091a6c Fix for issue #5816 (#5836) 2019-08-07 20:16:18 +02:00
Kenn Jacobsen 6c0fb2f849 Fix the create context menu overflows introduced with 405e9a79 (#5754) 2019-08-07 19:56:30 +02:00
Benjamin Carleski e495faf83c Fix FIPS compliance, add FIPS tests (#5978) 2019-08-07 19:31:08 +02:00
Sebastiaan Janssen 8721423f40 Merge pull request #6016 from umbraco/v8/fix/5906-support-stored-absolute-media-url
Fix exception when stored media url is already absolute
2019-07-29 14:30:03 +02:00
Rasmus John Pedersen 49b3351c72 Fix exception when stored media url is already absolute 2019-07-29 12:59:29 +02:00
Shannon Deminick faef449750 Merge pull request #6009 from bielu/v8/dev
V8: Value Set builder shouldn't stop indexing when one field is empty in …
2019-07-29 11:36:01 +10:00
arkadiuszbiel 4a24064783 Value Set builder shouldn't stop indexing when one field is empty in value sets 2019-07-27 20:41:15 +01:00
Kenn Jacobsen 0ab84fc443 Allow removing user start nodes 2019-07-25 10:28:16 +02:00
Bjarke Berg fca74ad8d7 Merge pull request #5862 from umbraco/v8/bugfix/5789-PublishedContentQuery-Search
Fixes #5789 - PublishedContentQuery Search always searches on culture
2019-07-24 14:16:32 +02:00
Shannon 7bc7dba86d fixes timing issue 2019-07-24 21:46:19 +10:00
Sebastiaan Janssen ca75a25802 Makes checks a little more robust 2019-07-24 11:33:12 +02:00
Shannon ece31733a9 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-07-24 19:25:48 +10:00
Shannon 28a8027179 removes reference to old packages.umbraco.org 2019-07-24 19:25:32 +10:00
Steve Megson a97604d6c4 Handle CSV values in TagsPropertyEditor 2019-07-24 11:14:00 +02:00
Bjarke Berg 308f929f7b Refactored tests to avoid duplicate code 2019-07-24 11:13:21 +02:00
Shannon c8d7df1515 Merge branch 'v8/bugfix/5789-PublishedContentQuery-Search' of https://github.com/umbraco/Umbraco-CMS into v8/bugfix/5789-PublishedContentQuery-Search 2019-07-24 18:46:48 +10:00
Shannon 2c795662d2 Adds tests for PublishedContentQuery search 2019-07-24 18:46:14 +10:00
Kenn Jacobsen 8a43e3a87e Make sure save options are up to date with the content state 2019-07-24 10:46:00 +02:00
Bjarke Berg 210e43fcb0 Fix for build 2019-07-24 09:53:51 +02:00
Shannon Deminick beb8c7ac7c Update src/Umbraco.Web/PublishedContentQuery.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-24 17:30:29 +10:00
Shannon Deminick 2f8979bbc3 Update src/Umbraco.Web/PublishedContentQuery.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-24 17:29:00 +10:00
Shannon a8ed7f2c17 adds new method 2019-07-23 22:11:02 +10:00
Frans de Jong 1c6bf55e5d GetCurrentLoginStatus()
In the summary of MembershipHelper.GetCurrentLoginStatus() it states that null will be returned when no member is logged in but that isn't the case (anymore?).
2019-07-23 13:02:11 +02:00
Bjarke Berg c246044ac7 Merge pull request #5972 from stevemegson/v8/temp-checkboxlist
Content migration - Include CheckBoxList in ValueListPreValueMigrator
2019-07-23 12:47:13 +02:00
Shannon 5126521d37 Fixes #5789 2019-07-23 19:09:15 +10:00
Shannon 27223738c6 Merge branch 'v8/8.1' into v8/dev
# Conflicts:
#	src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
2019-07-23 19:05:06 +10:00
Shannon 2faa4defd8 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
2019-07-23 19:03:14 +10:00
Warren Buckley bb8356d7db Merge pull request #5924 from umbraco/v/bugfix/5035-slot-swap2
Fixes race condition in PublishedSnapshotService and more...
2019-07-23 09:18:44 +01:00
Shannon Deminick 686f6752f3 Merge pull request #5951 from umbraco/v7/hotfix/5921-preview-failing
https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove…
2019-07-23 16:58:13 +10:00
Warren Buckley 66ff4d191a Merge pull request #5946 from umbraco/v8/bugfix/5886-fixes-Children
Fixes issue with Children(culture) method
2019-07-22 14:54:49 +01:00
Shannon 21218b0332 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
2019-07-22 13:59:14 +10:00
Shannon Deminick 23ccdeb2cf Merge pull request #5868 from umbraco/v7/hotfix/5835-AB#1693-add-null-checks-when-using-dataTypeId
Added null checks when *.dataTypeId is used
2019-07-22 13:44:05 +10:00
Shannon 6148ce4e52 oops no es6 support in 7.x 2019-07-22 13:41:26 +10:00
Shannon 06850ed25c Merge branch 'v7/7.15' into v7/hotfix/5835-AB#1693-add-null-checks-when-using-dataTypeId 2019-07-22 13:40:35 +10:00
Shannon 0320a56cb5 Fixes up dataTypeId var declarations 2019-07-22 13:27:51 +10:00
Steve Megson 968463912a Include CheckBoxList in ValueListPreValueMigrator 2019-07-21 14:47:37 +01:00
Warren Buckley b9e44f381b Merge pull request #5923 from umbraco/v8/hotfix/5902-migration-should-not-warn-about-build-in-renamed-data-types
V8: Migration should not warn about build in data types that is handled correct but renamed
2019-07-19 10:56:38 +01:00
Bjarke Berg cd27bb210f https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews 2019-07-19 11:25:33 +02:00
Bjarke Berg 67f680a675 Revert "https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews"
This reverts commit 47c3e3a7
2019-07-19 11:24:01 +02:00
Bjarke Berg 47c3e3a79f https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews 2019-07-19 11:20:31 +02:00
Shannon 02f49a0039 Cherry picks fix for 5894 and makes adjustments 2019-07-19 16:00:42 +10:00
Shannon Deminick 05c6b856f9 Merge pull request #5897 from kjac/v8-fix-media-type-add-property
V8: Fix YSOD when editing media types
2019-07-19 15:57:01 +10:00
Shannon b07df63422 Adds some better notes to the api docs 2019-07-19 15:49:39 +10:00
Shannon 487e45b45b updates note 2019-07-19 15:26:31 +10:00
Shannon 929c84822a Fixes the Children ext method and adds unit tests 2019-07-19 15:18:00 +10:00
Warren Buckley 993f11cd2c Merge pull request #5898 from umbraco/v8/hotfix/5846-AB#1695-Fix-for-migration-of-corrupt-data
V8: Give better exception if a json exception happens doing migration
2019-07-18 13:36:35 +01:00
Warren Buckley 6544b5c272 Update src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-18 13:03:14 +01:00
Shannon 817a458334 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Web.UI/packages.config
2019-07-18 16:22:38 +10:00
Shannon f3bfc1ffb2 Puts back UmbracoAntiForgeryAdditionalDataProvider for backwards compat reasons but it is not used 2019-07-18 16:18:11 +10:00
Shannon 3603090421 Fixes race condition in PublishedSnapshotService and more... 2019-07-17 22:51:14 +10:00
Shannon 6fe3089207 Merge branch 'v8/8.1' into v8/dev
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Mvc/HttpUmbracoFormRouteStringException.cs
#	src/Umbraco.Web/Mvc/ValidateUmbracoFormRouteStringAttribute.cs
2019-07-17 22:31:54 +10:00
Bjarke Berg 79159b684d https://github.com/umbraco/Umbraco-CMS/issues/5902
- Fixed issue with migration of Umbraco.Date if it was never saved in v7, the default format was added the time-part.
- Fixed issue with warnings of migrations of build in types, that was renamed between v7 and v8. These are handled correct.
- Added constants for some of the legacy property editor aliases.
2019-07-17 14:30:02 +02:00
Shannon 26d4d056be bumps version 2019-07-17 22:28:06 +10:00
Shannon 6ad28f1103 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Services/EntityService.cs
#	src/Umbraco.Core/Services/IEntityService.cs
#	src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs
#	src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
#	src/Umbraco.Web/Controllers/UmbLoginController.cs
#	src/Umbraco.Web/Controllers/UmbLoginStatusController.cs
#	src/Umbraco.Web/Controllers/UmbProfileController.cs
#	src/Umbraco.Web/Controllers/UmbRegisterController.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Mvc/HttpUmbracoFormRouteStringException.cs
#	src/Umbraco.Web/Mvc/ValidateUmbracoFormRouteStringAttribute.cs
#	src/Umbraco.Web/UmbracoHelper.cs
#	src/Umbraco.Web/WebBootManager.cs
2019-07-17 21:58:33 +10:00
Shannon 89cd655df2 Merge remote-tracking branch 'origin/v7/bugfix/build-without-vs2017' into v7/7.15 2019-07-17 21:48:21 +10:00
Shannon 14c4c4815d bumps version 2019-07-17 21:35:43 +10:00
Shannon bfb69a34ef re-adds back in the serialization overloads for the custom exception, re-adds detailed error messages, adds more documentation. Adds unit tests. 2019-07-17 21:15:18 +10:00
Shannon b675f6252c removes files (should have been part of cherry pick?), fixes logic 2019-07-16 23:07:31 +10:00
Shannon d52420183e Cherry picks ValidateUmbracoFormRouteStringAttribute implementation and fixes up some logic 2019-07-16 23:03:26 +10:00
Shannon 0cbe0b4796 Cherry picks ValidateUmbracoFormRouteStringAttribute implementation 2019-07-16 22:34:34 +10:00
Shannon Deminick 06b136fdf6 Merge pull request #5895 from ronaldbarendse/v8/feature/validate-umbracoformroutestring
Added attribute to validate Umbraco form route strings (ufprt)
2019-07-16 22:01:32 +10:00
Bjarke Berg c6246b5404 Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-07-16 13:46:07 +02:00
Bjarke Berg 3062f40ef5 Missing file in project file 2019-07-16 13:43:10 +02:00
Bjarke Berg dcd0d38419 Merge remote-tracking branch 'origin/v8/8.1' into v8/dev 2019-07-16 13:41:30 +02:00
Steve Megson 0feb053e51 Fixes #5852 - TablesForScheduledPublishing 2019-07-16 13:39:09 +02:00
Bjarke Berg c01a8f8f13 Merge pull request #5887 from stevemegson/temp-content-migration
PR fixes 7 -> 8 migration bugs for #5852 and #5864
2019-07-16 13:37:08 +02:00
Bjarke Berg 09c8ae4e7e Fixed null ref exception in related links migrations 2019-07-16 13:36:16 +02:00
Kenn Jacobsen da71a94c39 Use IsCollectionEmpty() as per review 2019-07-16 12:45:27 +02:00
Shannon Deminick f6413af3f4 Merge pull request #5885 from hifi-phil/v8/dev
Change PropertyType.Alias to virtual
2019-07-16 20:31:58 +10:00
skttl 2aaca865e7 changes innerjoin to left join, to allow folders in sql query 2019-07-16 07:26:26 +02:00
Shannon 77dda5a70f Fixes issue during upgrade where umbraco can't clear cdf log files 2019-07-15 14:34:32 +02:00
Bjarke Berg 440e649d6d Merge pull request #5861 from umbraco/v8/bugfix/cdf-upgrade-bug
Fixes issue during upgrade where umbraco can't clear cdf log files
2019-07-15 14:32:19 +02:00
Bjarke Berg f6a8d487cc AB#1695 - https://github.com/umbraco/Umbraco-CMS/issues/5846
Give better exception, if a json exception happens doing migration of grid properties in ConvertTinyMceAndGridMediaUrlsToLocalLink
2019-07-15 13:06:47 +02:00
Warren Buckley 47dcd37d1d Merge pull request #5784 from nathanwoulfe/5768-log-viewer-chart-naming
V8: Make log naming and colors consistent between Log Search and Log Overview
2019-07-15 11:47:20 +01:00
Kenn Jacobsen d60fc63e78 Fix YSOD when editing media types 2019-07-15 12:23:09 +02:00
Ronald Barendse b0c4042e87 Removed UmbracoAntiForgeryAdditionalDataProvider 2019-07-15 10:16:09 +02:00
Shannon da525513a3 Merge remote-tracking branch 'origin/v7/dev' into v8/dev
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/UmbracoHelper.cs
2019-07-15 16:18:04 +10:00
Shannon Deminick 2ac5e61e44 Merge pull request #5881 from bjarnef/dev-v7-link-picker-url-anchors
v7: Fix link picker url and anchors
2019-07-15 13:02:47 +10:00
Ronald Barendse 101a8b6c78 Added ValidateUmbracoFormRouteStringAttribute to public controllers 2019-07-14 23:18:21 +02:00
Ronald Barendse f7a10e3a15 Added attribute to validate Umbraco form route strings (ufprt) 2019-07-14 23:18:06 +02:00
Steve Megson 4e0dd728a8 Fixes #5864 - migrate prevalues for Umbraco.DropDown.Flexible 2019-07-14 16:48:33 +01:00
Steve Megson 320ccf8105 Fixes #5852 - TablesForScheduledPublishing 2019-07-14 16:46:01 +01:00
hifi-phil 62f924a757 Change PropertyType.Alias to virtual
When unit testing PropertyType.Alias needs to be virtual to make it mockable. The underlying code on the set triggers IOC logic and makes it hard to test anything that uses Property Types.
2019-07-14 09:45:12 +01:00
Bjarne Fyrstenborg c47a08b553 Add overload for NiceUrl 2019-07-13 16:40:01 +02:00
Bjarne Fyrstenborg de9241bcf5 Add UmbracoHelper overload methods to get url by guid 2019-07-13 14:50:25 +02:00
Bjarne Fyrstenborg 7c03fe3c1f Adjust parameter 2019-07-13 14:49:35 +02:00
Bjarne Fyrstenborg 82eb241119 Add overload method for Udi 2019-07-13 14:49:05 +02:00
Bjarne Fyrstenborg 1073e6257c Adjust comments 2019-07-13 14:48:35 +02:00
Nathan Woulfe bc3e4847fe Merge branch '5768-log-viewer-chart-naming' of https://github.com/nathanwoulfe/umbraco-cms into 5768-log-viewer-chart-naming 2019-07-13 13:50:21 +10:00
Nathan Woulfe 1a7251909c fix empty array - was checking index against empty array, so condition was never met 2019-07-13 13:45:13 +10:00
Warren Buckley 61a18297d9 Make v8/dev now 8.2.0 2019-07-12 13:03:20 +01:00
Warren Buckley bdd413f9ee Merge branch 'v8/dev' into 5768-log-viewer-chart-naming 2019-07-12 12:30:32 +01:00
Bjarke Berg fd8ca35e63 Merge pull request #5869 from umbraco/v8/bugfix/logviewer-error-count
V8: Fixes LogViewer Error Count search result click
2019-07-12 12:56:08 +02:00
Warren Buckley fdd9aee773 Fixes LogViewer Error Count search result clickthrough to include errors & fatal without exception as well 2019-07-12 11:07:15 +01:00
Bjarke Berg 59bf24c461 Added null checks when *.dataTypeId is used 2019-07-12 11:22:31 +02:00
Bjarke Berg 2748c3635d Merge pull request #5863 from umbraco/v7/bugfix/5822-entityservice-overloads
Fixes Change to Entity Service GetByKey isn't breaking in 7.15 #5822
2019-07-12 09:29:45 +02:00
Nathan Woulfe 3c2a92d3b6 map log values into logtypedata array - removes need to add these in the correct order. 2019-07-12 14:21:28 +10:00
Nathan Woulfe cf49e6160a critical => fatal 2019-07-12 14:20:28 +10:00
Shannon 2252db0d55 Fixes 5822 by reinstating optional method overloads of loadBaseType 2019-07-12 13:40:21 +10:00
Shannon ec93030e21 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-07-12 11:23:51 +10:00
Shannon 1d49c8626e Revert "V8: Don't show multiple open menus (take two) (#5609)"
This reverts commit 9ce996cbba.
2019-07-12 11:23:36 +10:00
Shannon 89bb94aa1a Fixes issue during upgrade where umbraco can't clear cdf log files 2019-07-12 10:57:26 +10:00
Warren Buckley 03a4b75176 Ran .\build SetUmbracoVersion 8.1.1 to bump version 2019-07-11 15:11:37 +01:00
Sebastiaan Janssen 943b54dcf7 Update 1_Bug.md 2019-07-11 11:55:01 +02:00
Warren Buckley 39bd18ec1a At some point we have upgraded Serilog.Filters.Expressions package & the signature/method name got changed to ByIncludingOnly() 2019-07-11 10:45:41 +01:00
Claus df896af476 adding build targets package. 2019-07-10 12:58:15 +02:00
Shannon e93ddff46b Merge branch 'nathanwoulfe-temp-5147-grid-reorder' into v8/dev 2019-07-09 11:01:11 +10:00
Nathan Woulfe 3144b51c91 fix behaviour on page load - don't add active class if sticky-bar is in viewport 2019-07-09 10:49:34 +10:00
Nathan Woulfe e92f68d040 improve variable naming 2019-07-09 10:46:29 +10:00
Nathan Woulfe 469054e9b3 No longer need scrollable-container attribute 2019-07-09 10:46:29 +10:00
Nathan Woulfe d17022d87d make it look pretty 2019-07-09 10:46:29 +10:00
Nathan Woulfe 6865629090 use position:sticky and IntersectionObserver instead of element cloning and position:fixed - much simpler. 2019-07-09 10:46:29 +10:00
Shannon a4749f201d Ensures luceneIndexer.WaitForIndexQueueOnShutdown is called even when not in MainDom 2019-07-08 23:03:20 +10:00
Shannon Deminick ad90264ef1 Merge pull request #5695 from linuselander/issue/5218
Enable removal of unpublished content from ExternalIndex
2019-07-08 19:34:25 +10:00
Shannon Deminick 9ba7e7742a Merge pull request #5801 from bielu/v8/dev
Remove last casting to LuceneIndex
2019-07-08 18:39:40 +10:00
arkadiuszbiel 6473f600c7 Remove last casting to LucenIndex 2019-07-08 08:48:49 +01:00
Claus 78735ff349 Merge pull request #5798 from kjac/v8-fix-save-member
V8: Can't save members without resetting their password
2019-07-08 09:29:37 +02:00
Claus 4b605b2580 Merge pull request #5799 from kjac/v7-fix-save-member
V7: Can't save members without resetting their password
2019-07-08 09:28:46 +02:00
Kenn Jacobsen 80d7f1b2c9 Make it possible to save a member without resetting the password 2019-07-07 11:36:26 +02:00
Kenn Jacobsen 1af43498d9 Make it possible to save a member without resetting the password 2019-07-07 11:16:02 +02:00
Nathan Woulfe 6329dfa629 Merge Andy's changes 2019-07-06 07:28:32 +10:00
Sebastiaan Janssen 5ada85df29 Provide the correct assembly redirects 2019-07-05 12:11:03 +02:00
Shannon 015ad64e30 Updates the exception thrown during upgrade to provide some meaningful feedback to the user. 2019-07-05 14:36:33 +10:00
Andy Butland 2cd0173534 Fixed incorrect label for "Fatal" errors on the log viewer pie chart.
Made the log viewer title variable so it either says "Log Overview For Today" or "Log Overview For Selected Time Period" (previously it said the former even if you'd adjusted the dates you were looking at.
Fixed up the selected date period display so the conjunction "to" is used between the dates when the selected time period is changed and querystring is updated.
Minor code tidy-up.
2019-07-04 14:35:06 +02:00
Bjarke Berg 6dbb988903 Refactor to limit to only v7.14.0 - V7.15.* 2019-07-04 11:44:05 +02:00
Bjarke Berg 926acb910e Forces the initial migration state of V7 sites that are allowed to be migrated into v7.14 state. 2019-07-04 11:44:05 +02:00
Nathan Woulfe a0bcfeddcc fix date range formatting on flatpickr - 'to' wasnt displayed after choosing a range 2019-07-04 11:48:02 +10:00
Nathan Woulfe c4b5483d8c make log naming and colors consistent between views 2019-07-04 11:19:10 +10:00
Sebastiaan Janssen 57e3187e3a For some reason this file was not part of the project any more :-( 2019-07-03 22:10:01 +02:00
Bjarke Berg 988d51c4c8 Merge pull request #5767 from umbraco/v8/bugfix/5671-fix-for-different-version-number-in-modelbuilder-models-in-live-mode
V8: Bugfix for Modelsbuilder models with different versions error
2019-07-03 13:43:00 +02:00
Bjarke Berg 4733256ca1 Merge pull request #5772 from umbraco/v8/bugfix/fix-n1-issue
Fixes N+1 Issues caused by the new bypass start nodes changes
2019-07-03 13:15:55 +02:00
Bjarke Berg 4133a1fe76 Refactored the ModelBindingExceptionFilter to also handle InvalidCastException, and also ensure the models are the same type.
Otherwise a infinite loop was introduced, when requesting a wrong model in the view.
Also refactored the why we do the retry from Html to Http headers
2019-07-03 13:14:35 +02:00
Shannon 37bf6fe938 Automatically refresh the page if we encounter a ModelBindingException 2019-07-03 19:15:54 +10:00
Shannon Deminick 31716e574c Update src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs
good catch!

Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-03 18:34:11 +10:00
Shannon 126c4cbd46 ensures media is rebuild and adds more notes 2019-07-03 18:25:19 +10:00
Shannon 7cc91f71c2 Fixes pure live mode when changing doc types 2019-07-03 18:11:00 +10:00
Shannon 7c52b9602c Reduce some allocations and in advertent SQL calls along with inadvertent enumeration of the entire cache, adds some notes 2019-07-03 17:43:30 +10:00
Bjarke Berg c5f1cc15fd Refactored dataTypeId when a guid into dataTypeKey 2019-07-03 08:33:30 +02:00
Shannon d089518681 Fixes SQL generation to populate the nodedto object of the datatypedto 2019-07-03 15:40:18 +10:00
Shannon cd6ef35bf9 comments out the fix during investigation - adds some notes 2019-07-03 15:17:51 +10:00
Shannon 47cdc79fcb Merge branch 'v8/dev' into v8/bugfix/5671-fix-for-different-version-number-in-modelbuilder-models-in-live-mode 2019-07-03 13:50:38 +10:00
Shannon f7382255c2 Fixes N+1 Issues caused by the new bypass start nodes changes 2019-07-03 13:16:40 +10:00
Shannon Deminick 2167eada0c Merge pull request #5764 from umbraco/v8/bugfix/fixes-for-bypass-securtiy-after-merge
V8: Bugfixes regarding the Bypass Security feature after merge from v7
2019-07-03 11:27:55 +10:00
Shannon df11935598 Revert and adjusts "Fixes issue when creating DateTypes of type Umbraco.MultiNodeTreePicker with type member, because -1 can't be casted to Udi" 2019-07-03 11:23:25 +10:00
Shannon d3b4b9fe64 fix merge 2019-07-03 11:10:34 +10:00
Shannon 33aff7ff61 Merge branch 'v8/dev' into v8/bugfix/fixes-for-bypass-securtiy-after-merge
# Conflicts:
#	src/Umbraco.Web/Editors/EntityController.cs
2019-07-03 11:04:34 +10:00
Sebastiaan Janssen 4d2c551b79 Merge branch 'v7/dev' into v8/dev 2019-07-02 22:01:34 +02:00
Sebastiaan Janssen 5b7ae7150f Fix weird merge 2019-07-02 21:55:54 +02:00
Sebastiaan Janssen 5bf29a907a Fixes #5206 2019-07-02 21:47:14 +02:00
Bjarke Berg 96d5bdd7b2 https://github.com/umbraco/Umbraco-CMS/issues/5671 - If modelsbuilder is in live mode, we need to clear cache for all document types when at least one is cleared. This is due to modelsbuilder updating all the models to different versions. 2019-07-02 15:26:54 +02:00
Bjarke Berg 7b4023fd5a Fixes issue when creating DateTypes of type Umbraco.MultiNodeTreePicker with type member, because -1 can't be casted to Udi 2019-07-02 13:17:47 +02:00
Bjarke Berg af72729905 Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-07-02 13:03:29 +02:00
Claus d5bc54cf6c refixing #4708 - old merge error. 2019-07-02 13:00:50 +02:00
Claus 5625102e2c making EditorValidatorOfT public instead of internal. 2019-07-02 12:42:18 +02:00
Bjarke Berg 66abd7b50c Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-07-02 11:31:14 +02:00
Bjarke Berg 2a9bcf0e98 Merge pull request #5763 from umbraco/v7/bugfix/fix-for-null-ref-exception-when-using-member-pickers
V7: Bugfix for Null ref-exception when using member pickers.
2019-07-02 11:20:53 +02:00
Bjarke Berg e6484687e5 Small fixes after v7 to v8 merge regarding the bypass security feature 2019-07-02 11:17:23 +02:00
Shannon 5da1e64bbc Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-07-02 19:15:20 +10:00
Shannon 7b0979f9fd Fixes install.ps1 and updates sln to remove old ps1 file 2019-07-02 19:15:04 +10:00
Dave Woestenborghs 1a437c1c6a #5750 - fix outside click directive so it doesn't close dialogues from create action 2019-07-02 11:11:03 +02:00
Bjarke Berg 3c0565e516 Bugfix: Null ref-exception when using member pickers. 2019-07-02 10:56:44 +02:00
Claus 178b1ccf40 Merge pull request #5743 from umbraco/v8/feature/sourcelink-update
V8: Adds in SourceLink Debugging Feature
2019-07-02 10:49:11 +02:00
Shannon Deminick c03cd81c23 Merge pull request #5748 from umbraco/v8/feature/mb-embed-prepare
Prepare MB future
2019-07-02 18:18:07 +10:00
Stephan 3d3647b476 Fix tests 2019-07-02 10:11:51 +02:00
Stephan a4cac670df Merge branch 'v8/dev' into v8/feature/mb-embed-prepare 2019-07-02 09:12:00 +02:00
Shannon c414dd06cc updates package lock 2019-07-02 15:38:17 +10:00
Shannon 4ed746e4ef Fixes tree refreshing when changing users, fixes memory/event leak 2019-07-02 13:37:40 +10:00
Shannon c270d8ecac Merge remote-tracking branch 'origin/v7/dev' into v8/dev
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Core/Constants-DataTypes.cs
#	src/Umbraco.Core/Models/DataTypeDefinition.cs
#	src/Umbraco.Core/Models/DataTypeExtensions.cs
#	src/Umbraco.Core/Models/IDataTypeDefinition.cs
#	src/Umbraco.Core/Models/UmbracoEntity.cs
#	src/Umbraco.Core/Models/UserExtensions.cs
#	src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs
#	src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
#	src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Core/Services/DateTypeServiceExtensions.cs
#	src/Umbraco.Core/Services/EntityService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/Services/IDataTypeService.cs
#	src/Umbraco.Core/Services/IEntityService.cs
#	src/Umbraco.Core/Services/IRelationService.cs
#	src/Umbraco.Core/Services/Implement/RelationService.cs
#	src/Umbraco.Tests/Models/UmbracoEntityTests.cs
#	src/Umbraco.Tests/Plugins/PluginManagerTests.cs
#	src/Umbraco.Tests/Services/EntityServiceTests.cs
#	src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/search.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contentpicker/contentpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
#	src/Umbraco.Web.UI/config/EmbeddedMedia.Release.config
#	src/Umbraco.Web.UI/config/EmbeddedMedia.config
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web.UI/web.Template.config
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
#	src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
#	src/Umbraco.Web/Mvc/RenderRouteHandler.cs
#	src/Umbraco.Web/PropertyEditors/ContentPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MediaPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiNodeTreePicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RichTextPreValueEditor.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs
#	src/Umbraco.Web/Trees/ContentTreeController.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
#	src/Umbraco.Web/Trees/MediaTreeController.cs
#	src/Umbraco.Web/Trees/TreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
#	src/Umbraco.Web/UmbracoHelper.cs
#	src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
#	src/Umbraco.Web/WebBootManager.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs
#	src/umbraco.cms/businesslogic/web/Access.cs
2019-07-02 12:24:05 +10:00
Shannon Deminick ade9bb7324 Merge pull request #5741 from umbraco/v8/merge/v715
Merging 7.15 - 8.1
2019-07-02 12:10:03 +10:00
Shannon 4134dd16df adds fixme note 2019-07-02 12:04:58 +10:00
Shannon f81588bb13 fixes search for content picker with ignore start nodes 2019-07-02 11:48:09 +10:00
Shannon 09793a1744 Fixes tests 2019-07-02 11:07:59 +10:00
Shannon ba7cd48b8f Merge remote-tracking branch 'origin/v8/dev' into v8/merge/v715
# Conflicts:
#	src/Umbraco.Core/Constants-DataTypes.cs
#	src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
2019-07-02 10:49:20 +10:00
Shannon 640d2cedb9 Gets the link and media pickers working in the grid in the rte with ignore start nodes 2019-07-01 21:48:45 +10:00
Shannon 0a6237af04 Gets the multi url picker working with ignore start nodes 2019-07-01 21:13:11 +10:00
Shannon 503183331f gets media picker with ignore start nodes working in rte 2019-07-01 20:59:41 +10:00
Warren Buckley 3effc66b2c Need to update NuSpec to ensure the PDB are getting coppied into the bin when Nuget pacakeg installed into a project 2019-07-01 11:53:22 +01:00
Warren Buckley b64f303537 Mark the release PDB as portable too - the Powershell build uses Release not Debug 2019-07-01 11:20:07 +01:00
Warren Buckley 760f6a1647 Umbraco.Web.UI revert change as no real CS code to F11 into this project 2019-07-01 10:54:29 +01:00
Warren Buckley 0b64e34f05 Add in SourceLink Nuget to Umbraco.ModelsBuilder csproj 2019-07-01 10:19:09 +01:00
Warren Buckley f01be09075 Update sourcelink & set from full to portable 2019-07-01 10:13:31 +01:00
Shannon 1c5ed58074 gets media picker working with ignore user start nodes 2019-07-01 18:54:39 +10:00
Shannon 42d86f147f gets content picker ignore start nodes working, fixes descriptions 2019-07-01 18:23:36 +10:00
Shannon fa4acb255b fixes missing 'var' 2019-07-01 17:09:11 +10:00
Shannon 1885767ef1 Internalizes the new Anchor logic and removes it from the IContentService interface into extensions. 2019-07-01 16:33:09 +10:00
Shannon 80e6880bb7 more manual merging - getting anchors back in tinymce 2019-07-01 16:22:54 +10:00
Adam Nelson fabacd1689 V8: Fixes case issue on metaData.hasChildren in mini list view as well as .toLowerCase() issue on undefined scope.entityTypeFilter.filter (#5744) 2019-07-01 07:48:57 +02:00
Warren Buckley 23a7654cea Merge branch 'v8/dev' into v8/feature/sourcelink-update 2019-06-28 12:37:20 +01:00
Sebastiaan Janssen b2d019bfe1 Merge pull request #5270 from umbraco/v8/bugfix/5268-audit-repository
Bugfix Audit service
2019-06-28 10:53:42 +02:00
Sebastiaan Janssen 9f817bf032 Merge pull request #5742 from umbraco/v8/fix/typeloader-static-fields
Typeloader change fields set by constructor to non static
2019-06-28 10:51:45 +02:00
Rasmus John Pedersen 01c89bd338 Make fields set by constructor non static 2019-06-28 10:11:20 +02:00
Kenn Jacobsen e5956e4955 V8: Don't cast IContent to Content in DocumentRepository (#4611) 2019-06-28 09:19:11 +02:00
Shannon 958c3b147b more manual merging 2019-06-28 15:42:23 +10:00
Shannon 4a33ca99ba More manual merging 2019-06-28 15:03:52 +10:00
Shannon 568835f7e2 manual merging/fixing, project builds now, but need to manually merge the remaining 2019-06-28 13:24:13 +10:00
Shannon 84aa861a5b Merge remote-tracking branch 'origin/v7/dev' into v8/dev - Iniital commit (broken)
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Core/Constants-DataTypes.cs
#	src/Umbraco.Core/Models/DataTypeDefinition.cs
#	src/Umbraco.Core/Models/DataTypeExtensions.cs
#	src/Umbraco.Core/Models/IDataTypeDefinition.cs
#	src/Umbraco.Core/Models/UmbracoEntity.cs
#	src/Umbraco.Core/Models/UserExtensions.cs
#	src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs
#	src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
#	src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Core/Services/EntityService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/Services/IDataTypeService.cs
#	src/Umbraco.Core/Services/IEntityService.cs
#	src/Umbraco.Core/Services/IRelationService.cs
#	src/Umbraco.Core/Services/Implement/RelationService.cs
#	src/Umbraco.Tests/Models/UmbracoEntityTests.cs
#	src/Umbraco.Tests/Plugins/PluginManagerTests.cs
#	src/Umbraco.Tests/Services/EntityServiceTests.cs
#	src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/search.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contentpicker/contentpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web.UI/web.Template.config
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
#	src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
#	src/Umbraco.Web/Mvc/RenderRouteHandler.cs
#	src/Umbraco.Web/PropertyEditors/ContentPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MediaPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiNodeTreePicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RichTextPreValueEditor.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs
#	src/Umbraco.Web/Trees/ContentTreeController.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
#	src/Umbraco.Web/Trees/MediaTreeController.cs
#	src/Umbraco.Web/Trees/TreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
#	src/Umbraco.Web/UmbracoHelper.cs
#	src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
#	src/Umbraco.Web/WebBootManager.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs
#	src/umbraco.cms/businesslogic/web/Access.cs
2019-06-28 13:03:36 +10:00
leekelleher ee2ebc7d14 ReadOnlyValueController - enabled filters
Previously the code checks if the `config` is an array,
but with how config options are set, this would typically
be an object (dictionary). So the previous code would
never allow a filter to be set.

Now the check is on the object property.
2019-06-27 22:43:14 +02:00
Kenn Jacobsen 9ce996cbba V8: Don't show multiple open menus (take two) (#5609) 2019-06-27 22:42:05 +02:00
leekelleher 580ba79619 Icon Constants consistency
Updated the `Constants.Icons` and replaced the hard-coded strings with
 the const references.
2019-06-27 22:35:29 +02:00
Lee Kelleher fbe184ef6e Prevent deletion of System DataTypes (#5623) 2019-06-27 22:33:19 +02:00
Kenn Jacobsen 2f7bf413ed V8: Make dialogs prompt to discard changes on outside click and ESC (#5740) 2019-06-27 22:27:42 +02:00
Andy Butland 390613c796 Fixed issue with node deletion not removing related records from the public access tables 2019-06-27 22:20:31 +02:00
BatJan b3e3475bf5 Make sure padding is not overwritten by other selectors 2019-06-27 22:19:27 +02:00
Bjarne Fyrstenborg 5333b23c23 v8: Add keyboard support to slider (#5651) 2019-06-27 22:17:31 +02:00
Patrick de Mooij 734086fcf5 temp-5612: Being able to add your own roles/startnodes etc 2019-06-27 22:05:50 +02:00
Morten Bock 12dff9bca3 Reduce size of LocalizedText output. Refactor localizationService to not expose internal dictionary. Refactor controllers to not access dictionary directly. 2019-06-27 21:59:33 +02:00
Kenn Jacobsen f370e738da V8: Use an overlay style dialog for deleting Nested Content ite… (#5357) 2019-06-27 21:34:19 +02:00
Marc Goodson a018ed9e52 V7: Less-Urgent-But-Still-Quite-Important - Add Giphy EmbeddedMedia support (#5736) 2019-06-27 14:27:33 +02:00
Marc Goodson 17f73b88dc Urgent: Add Giphy embed provider support (#5731) 2019-06-27 14:26:36 +02:00
Mike 405e9a79be V8: Make the content tree keyboard accessible (#5729) 2019-06-27 14:07:37 +02:00
Kenn Jacobsen 4d90322842 Fix broken on-outside-click 2019-06-27 13:58:43 +02:00
Kenn Jacobsen a8b5d69be0 Fix confirmation for permissions dialog 2019-06-27 13:56:50 +02:00
Kenn Jacobsen 5ebd90aba5 Make searched media pickable in linkpicker 2019-06-27 13:52:07 +02:00
Sebastiaan Janssen bec909c284 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-06-27 13:48:43 +02:00
Sebastiaan Janssen 46e0b08d65 Merge remote-tracking branch 'origin/v8/bugfix/fix-atroot' into v8/dev 2019-06-27 13:48:16 +02:00
Stephan 7a178be031 Fix getting content AtRoot 2019-06-27 13:29:35 +02:00
Kenn Jacobsen 9d14c9e0b7 Don't explicitly allow deleting the current editor's own content 2019-06-27 13:28:54 +02:00
Warren Buckley ef19633a90 Merge pull request #5134 from umbraco/v8/bugfix/image-cropper-converter
The ImageCropperPropertyValueEditor doesn't convert values in ConvertDbToString correctly
2019-06-27 12:20:43 +01:00
Sebastiaan Janssen 80ffd026f6 Reverts PR #5693 - we need to update the linkpicker search instead to return the correct results for us 2019-06-27 13:18:45 +02:00
Kenn Jacobsen cb7300688c Don't prompt for changes when cancelling empty properties 2019-06-27 12:53:58 +02:00
Kenn Jacobsen 040ebfe9dd Add auto-focus to the default action in overlay dialogs 2019-06-27 12:49:53 +02:00
Shannon fad33a97b2 don't throw JS exception when no MediaPath, instead warn. 2019-06-27 15:47:25 +10:00
Warren Buckley ac586c5207 Merge pull request #5715 from umbraco/v7/bugfix/AB-1085/antiforgery-per-form
Custom IAntiForgeryAdditionalDataProvider implementation
2019-06-26 09:23:32 +01:00
Bjarke Berg 8033931e31 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1085 - Fixed merge conflict 2019-06-26 09:58:01 +02:00
Bjarke Berg 8e29810598 Merge remote-tracking branch 'origin/v7/dev' into v7/bugfix/AB-1085/antiforgery-per-form 2019-06-26 09:52:44 +02:00
Shannon Deminick be96e2cf08 Merge pull request #5713 from umbraco/v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers
V7: Reintroduce the bypass security option in pickers
2019-06-26 17:02:17 +10:00
Shannon 534ee67ad2 Merge branch 'v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers' of https://github.com/umbraco/Umbraco-CMS into v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers 2019-06-26 16:49:00 +10:00
Shannon 571a3bc257 fixes test 2019-06-26 16:48:39 +10:00
Bjarke Berg e7a30d0a5d https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1085 - Fixes for gulp build 2019-06-26 07:39:34 +02:00
Shannon a55323176f Updates EntityController to support passing in the dataTypeId for the GetChildren methods and updates the mediapicker to pass along that data 2019-06-26 14:35:36 +10:00
Shannon 1b83e0a87d cleanup 2019-06-26 13:49:45 +10:00
Shannon ca15f340b0 Fixes a bunch of N+1, content/media trees should be much more snappy 2019-06-26 13:32:16 +10:00
Shannon 23b8e1cce8 Removes the remaining part of the EntityRepository that was loading in ALL properties for media which we don't want whatsoever which means some other code is cleaned up/removed 2019-06-26 13:31:04 +10:00
Shannon cf53ba363d Internalizes new methods classes + cleanup 2019-06-26 13:29:05 +10:00
Bjarke Berg 2f309a2fd6 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1085 - moved the code that adds the ufprt token to the context items, into the constructor of UmbracoForm. Because it needs to happen before the @Html.AntiForgeryToken() is called. The dispose method is too late. 2019-06-25 15:09:37 +02:00
Bjarke Berg 9f45d41a4a https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479
- Test fixes
2019-06-25 13:18:15 +02:00
Bjarke Berg 1994194656 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479
- Review fixes
2019-06-25 11:51:02 +02:00
Bjarke Berg 36559b8761 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Fix for NullReferenceException 2019-06-25 09:22:56 +02:00
Bjarke Berg 8fe7c5599a Merge remote-tracking branch 'origin/v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers' into v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers
# Conflicts:
#	src/Umbraco.Core/Services/ContentService.cs
2019-06-25 09:22:43 +02:00
Bjarke Berg 4dd325cec9 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Fix for NullReferenceException 2019-06-25 09:22:30 +02:00
Bjarke Berg d558646d75 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Fix for NullReferenceException 2019-06-25 09:21:51 +02:00
Bjarke Berg afac4bb918 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - missing entityResource injection 2019-06-25 09:18:30 +02:00
Bjarke Berg 0869bf27c7 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - clean up 2019-06-25 08:26:01 +02:00
Bjarke Berg 383a8617ce https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Fixed test 2019-06-25 08:19:50 +02:00
Bjarke Berg 3865f4fb50 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - bugfix - wrong constant used 2019-06-25 08:15:06 +02:00
Shannon 3e74bbfb45 Creates a custom IAntiForgeryAdditionalDataProvider that provides and validates custom token data in the request which allows having a custom AF token per form created with BeginUmbracoForm 2019-06-25 14:35:28 +10:00
Bjarke Berg 966b07ba1c https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Changed entity service to only return small model with media path. And updated media picker to use entity service when loading data. 2019-06-24 21:12:38 +02:00
Warren Buckley 60ed6f6b20 Remove snupkg aka newer Symbol nuget packages 2019-06-24 13:18:20 +01:00
Warren Buckley 903c163a57 Merge branch 'v8/bugfix/fix-js-tests-currentuser-auth' into v8/feature/sourcelink-update 2019-06-24 11:31:43 +01:00
Bjarke Berg d4311fe4ab https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Replaced client side method to get Auchors with a server side version, and eliminated the use of contentResource in linkPikers 2019-06-24 10:52:35 +02:00
Bjarke Berg eab597a2a8 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - fix for js linter 2019-06-24 08:58:25 +02:00
Warren Buckley 003ee1a991 Added in Microsoft.SourceLink.GitHub Nuget package 2019-06-23 19:57:43 +01:00
Warren Buckley 601d48277e Update NuSpecs with the XML MetaData for SourceLink 2019-06-23 19:53:57 +01:00
Sebastiaan Janssen 8d12170def Correct NuGet transform for the web.config file in the Views folder 2019-06-21 14:58:58 +02:00
Bjarke Berg d2655a9f2f Merge remote-tracking branch 'origin/v7/dev' into v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers 2019-06-21 13:59:11 +02:00
Bjarke Berg c4c2082fa9 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 - Only allow "ignoreUserStartNodes" for custom data types and not the default build in. 2019-06-21 13:57:17 +02:00
Sebastiaan Janssen 40d4a8fe6a Modelsbuilder is asking for too old a version of CodeAnalysis, Immutable and Metadata dependencies 2019-06-21 13:32:53 +02:00
Bjarke Berg 2898203cb9 https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1479 Bugfixes for the "Bypass security" feature + filter out possible sensitive data 2019-06-21 10:50:23 +02:00
Sebastiaan Janssen 5ebdfc7b1c Previously added a few too many binding redirects to the web.config 2019-06-21 10:22:16 +02:00
Bjarke Berg 31d7e58191 Merge remote-tracking branch 'origin/v7/dev' into v7/feature/AB-1479-Reintroduce-the-bypass-security-option-in-pickers 2019-06-21 10:20:51 +02:00
Sebastiaan Janssen ad4416f663 So apparently Microsoft.CodeAnalysis.CSharp version 1.3.2 contains the dll that has the version 1.3.1.. very confusing 2019-06-21 10:07:45 +02:00
Sebastiaan Janssen b55d2a8a41 Modelsbuilder is asking for too old a version of the CodeAnalysis dependency 2019-06-21 09:56:01 +02:00
Sebastiaan Janssen 17a4799b97 7.15 release needs a few more assembly redirects (#5698)
7.15 release needs a few more assembly redirects
2019-06-21 08:19:35 +02:00
Bjarke Berg 4df838c20c https://umbraco.visualstudio.com/D-Team%20Tracker/_workitems/edit/1358 - Changed the ignoreUserStartNodes in public endpoints to the data type id, and then look up the setting 2019-06-20 16:02:42 +02:00
Sebastiaan Janssen 4e44871671 The NuGet packages needs an extra DotNetCompilerPlatform transform to be sure it gets applied as it sometimes didn't
Added SignalR binding redirect for Umbraco Cloud
Added System.Web.Http.WebHost binding redirect for uCommerce
2019-06-20 15:57:31 +02:00
Linus Elander 7557c584d8 Adjusts conditions for which indexes should be affected when a node is unpublished 2019-06-19 21:41:47 +02:00
Bjarke Berg 1dd2c1cb91 Revert "Revert "U4 10147 - Bypass User Security option in pickers (#2441)""
This reverts commit 994c6eed
2019-06-19 14:30:44 +02:00
Stephan 6b23a8221d Bugfix Audit service 2019-04-15 16:34:01 +02:00
Shannon db867c66a3 The ImageCropperPropertyValueEditor doesn't convert values in ConvertDbToString correctly 2019-04-03 13:32:21 +11:00
371 changed files with 7348 additions and 5536 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
-->
+3 -2
View File
@@ -14,6 +14,7 @@
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
@@ -44,7 +45,7 @@
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</group>
</dependencies>
</metadata>
<files>
@@ -55,6 +56,6 @@
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\net472\Umbraco.Core.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib\net472\Umbraco.Core.pdb" />
</files>
</package>
+4 -6
View File
@@ -14,6 +14,7 @@
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
@@ -43,7 +44,7 @@
<dependency id="System.Threading.Tasks.Dataflow" version="[4.9.0,4.999999)" />
</group>
</dependencies>
</metadata>
<files>
@@ -51,17 +52,14 @@
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.dll" target="lib\net472\Umbraco.ModelsBuilder.dll" />
<!-- docs -->
<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" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.xml" target="lib\net472\Umbraco.ModelsBuilder.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\bin\Umbraco.ModelsBuilder.pdb" target="lib" />
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib\net472\Umbraco.Web.pdb" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib\net472\Umbraco.Examine.pdb" />
</files>
</package>
+2
View File
@@ -14,6 +14,7 @@
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
@@ -25,6 +26,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.1.0]" />
<dependency id="ImageProcessor.Web" version="[4.10.0.100,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.5.0.100,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
@@ -8,7 +8,7 @@
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="Umbraco.Web.PublishedContentModels" xdt:Transform="InsertIfMissing" />
@@ -18,13 +18,13 @@
<system.web>
<pages
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
<controls>
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
<add assembly="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
</controls>
</pages>
</system.web>
+21 -4
View File
@@ -18,9 +18,20 @@ if ($project) {
# Copy umbraco and umbraco_files from package to project folder
$umbracoFolder = Join-Path $projectPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoFolder
New-Item -ItemType Directory -Force -Path $umbracoFolder
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
Write-Host "copying files to $umbracoFolder ..."
# see https://support.microsoft.com/en-us/help/954404/return-codes-that-are-used-by-the-robocopy-utility-in-windows-server-2
robocopy $umbracoFolderSource $umbracoFolder /is /it /e
if (($lastexitcode -eq 1) -or ($lastexitcode -eq 3) -or ($lastexitcode -eq 5) -or ($lastexitcode -eq 7))
{
write-host "Copy succeeded!"
}
else
{
write-host "Copy failed with exit code:" $lastexitcode
}
$copyWebconfig = $true
$destinationWebConfig = Join-Path $projectPath "Web.config"
@@ -40,7 +51,11 @@ if ($project) {
}
}
}
Catch { }
Catch
{
Write-Host "An error occurred:"
Write-Host $_
}
}
if($copyWebconfig -eq $true)
@@ -74,7 +89,9 @@ if ($project) {
}
Catch
{
# Not a big problem if this fails, let it go
# Not a big problem if this fails, let it go
# Write-Host "An error occurred:"
# Write-Host $_
}
}
+10 -10
View File
@@ -15,7 +15,7 @@
[Parameter(Mandatory=$false)]
[Alias("doc")]
[switch] $docfx = $false,
# keep the build directories, don't clear them
[Parameter(Mandatory=$false)]
[Alias("c")]
@@ -392,13 +392,13 @@
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Core.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
@@ -429,37 +429,37 @@
Write-Host "Prepare Azure Gallery"
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
})
$ubuild.DefineMethod("PrepareCSharpDocs",
{
Write-Host "Prepare C# Documentation"
$src = "$($this.SolutionRoot)\src"
$tmp = $this.BuildTemp
$out = $this.BuildOutput
$DocFxJson = Join-Path -Path $src "\ApiDocs\docfx.json"
$DocFxSiteOutput = Join-Path -Path $tmp "\_site\*.*"
#restore nuget packages
$this.RestoreNuGet()
# run DocFx
$DocFx = $this.BuildEnv.DocFx
& $DocFx metadata $DocFxJson
& $DocFx build $DocFxJson
# zip it
& $this.BuildEnv.Zip a -tzip -r "$out\csharp-docs.zip" $DocFxSiteOutput
})
$ubuild.DefineMethod("PrepareAngularDocs",
{
Write-Host "Prepare Angular Documentation"
$src = "$($this.SolutionRoot)\src"
$out = $this.BuildOutput
$this.CompileBelle()
"Moving to Umbraco.Web.UI.Client folder"
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.1.0")]
[assembly: AssemblyInformationalVersion("8.1.0")]
[assembly: AssemblyFileVersion("8.2.0")]
[assembly: AssemblyInformationalVersion("8.2.0")]
+25 -22
View File
@@ -67,31 +67,34 @@ namespace Umbraco.Core
: new NamedSemaphoreReleaser(_semaphore2);
}
public Task<IDisposable> LockAsync()
{
var wait = _semaphore != null
? _semaphore.WaitAsync()
: _semaphore2.WaitOneAsync();
//NOTE: We don't use the "Async" part of this lock at all
//TODO: Remove this and rename this class something like SystemWideLock, then we can re-instate this logic if we ever need an Async lock again
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
//public Task<IDisposable> LockAsync()
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync()
// : _semaphore2.WaitOneAsync();
public Task<IDisposable> LockAsync(int millisecondsTimeout)
{
var wait = _semaphore != null
? _semaphore.WaitAsync(millisecondsTimeout)
: _semaphore2.WaitOneAsync(millisecondsTimeout);
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
//public Task<IDisposable> LockAsync(int millisecondsTimeout)
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync(millisecondsTimeout)
// : _semaphore2.WaitOneAsync(millisecondsTimeout);
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
public IDisposable Lock()
{
+2 -2
View File
@@ -42,8 +42,8 @@ namespace Umbraco.Core.Composing
private string _currentAssembliesHash;
private IEnumerable<Assembly> _assemblies;
private bool _reportedChange;
private static string _localTempPath;
private static string _fileBasePath;
private readonly string _localTempPath;
private string _fileBasePath;
/// <summary>
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
+350 -2
View File
@@ -1,27 +1,375 @@
namespace Umbraco.Core
using System;
namespace Umbraco.Core
{
public static partial class Constants
{
public static class DataTypes
{
public const int LabelString = -92;
//NOTE: unfortunately due to backwards compat we can't move/rename these, with the addition of the GUID
//constants, it would make more sense to have these suffixed with "ID" or in a Subclass called "INT", for
//now all we can do is make a subclass called Guids to put the GUID IDs.
public const int LabelString = System.DefaultLabelDataTypeId;
public const int LabelInt = -91;
public const int LabelBigint = -93;
public const int LabelDateTime = -94;
public const int LabelTime = -98;
public const int LabelDecimal = -99;
public const int Textarea = -89;
public const int Textbox = -88;
public const int RichtextEditor = -87;
public const int Boolean = -49;
public const int DateTime = -36;
public const int DropDownSingle = -39;
public const int DropDownMultiple = -42;
public const int Upload = -90;
public const int DefaultContentListView = -95;
public const int DefaultMediaListView = -96;
public const int DefaultMembersListView = -97;
public const int ImageCropper = 1043;
public const int Tags = 1041;
public static class ReservedPreValueKeys
{
public const string IgnoreUserStartNodes = "ignoreUserStartNodes";
}
/// <summary>
/// Defines the identifiers for Umbraco data types as constants for easy centralized access/management.
/// </summary>
public static class Guids
{
/// <summary>
/// Guid for Content Picker as string
/// </summary>
public const string ContentPicker = "FD1E0DA5-5606-4862-B679-5D0CF3A52A59";
/// <summary>
/// Guid for Content Picker
/// </summary>
public static readonly Guid ContentPickerGuid = new Guid(ContentPicker);
/// <summary>
/// Guid for Member Picker as string
/// </summary>
public const string MemberPicker = "1EA2E01F-EBD8-4CE1-8D71-6B1149E63548";
/// <summary>
/// Guid for Member Picker
/// </summary>
public static readonly Guid MemberPickerGuid = new Guid(MemberPicker);
/// <summary>
/// Guid for Media Picker as string
/// </summary>
public const string MediaPicker = "135D60E0-64D9-49ED-AB08-893C9BA44AE5";
/// <summary>
/// Guid for Media Picker
/// </summary>
public static readonly Guid MediaPickerGuid = new Guid(MediaPicker);
/// <summary>
/// Guid for Multiple Media Picker as string
/// </summary>
public const string MultipleMediaPicker = "9DBBCBBB-2327-434A-B355-AF1B84E5010A";
/// <summary>
/// Guid for Multiple Media Picker
/// </summary>
public static readonly Guid MultipleMediaPickerGuid = new Guid(MultipleMediaPicker);
/// <summary>
/// Guid for Related Links as string
/// </summary>
public const string RelatedLinks = "B4E3535A-1753-47E2-8568-602CF8CFEE6F";
/// <summary>
/// Guid for Related Links
/// </summary>
public static readonly Guid RelatedLinksGuid = new Guid(RelatedLinks);
/// <summary>
/// Guid for Member as string
/// </summary>
public const string Member = "d59be02f-1df9-4228-aa1e-01917d806cda";
/// <summary>
/// Guid for Member
/// </summary>
public static readonly Guid MemberGuid = new Guid(Member);
/// <summary>
/// Guid for Image Cropper as string
/// </summary>
public const string ImageCropper = "1df9f033-e6d4-451f-b8d2-e0cbc50a836f";
/// <summary>
/// Guid for Image Cropper
/// </summary>
public static readonly Guid ImageCropperGuid = new Guid(ImageCropper);
/// <summary>
/// Guid for Tags as string
/// </summary>
public const string Tags = "b6b73142-b9c1-4bf8-a16d-e1c23320b549";
/// <summary>
/// Guid for Tags
/// </summary>
public static readonly Guid TagsGuid = new Guid(Tags);
/// <summary>
/// Guid for List View - Content as string
/// </summary>
public const string ListViewContent = "C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4";
/// <summary>
/// Guid for List View - Content
/// </summary>
public static readonly Guid ListViewContentGuid = new Guid(ListViewContent);
/// <summary>
/// Guid for List View - Media as string
/// </summary>
public const string ListViewMedia = "3A0156C4-3B8C-4803-BDC1-6871FAA83FFF";
/// <summary>
/// Guid for List View - Media
/// </summary>
public static readonly Guid ListViewMediaGuid = new Guid(ListViewMedia);
/// <summary>
/// Guid for List View - Members as string
/// </summary>
public const string ListViewMembers = "AA2C52A0-CE87-4E65-A47C-7DF09358585D";
/// <summary>
/// Guid for List View - Members
/// </summary>
public static readonly Guid ListViewMembersGuid = new Guid(ListViewMembers);
/// <summary>
/// Guid for Date Picker with time as string
/// </summary>
public const string DatePickerWithTime = "e4d66c0f-b935-4200-81f0-025f7256b89a";
/// <summary>
/// Guid for Date Picker with time
/// </summary>
public static readonly Guid DatePickerWithTimeGuid = new Guid(DatePickerWithTime);
/// <summary>
/// Guid for Approved Color as string
/// </summary>
public const string ApprovedColor = "0225af17-b302-49cb-9176-b9f35cab9c17";
/// <summary>
/// Guid for Approved Color
/// </summary>
public static readonly Guid ApprovedColorGuid = new Guid(ApprovedColor);
/// <summary>
/// Guid for Dropdown multiple as string
/// </summary>
public const string DropdownMultiple = "f38f0ac7-1d27-439c-9f3f-089cd8825a53";
/// <summary>
/// Guid for Dropdown multiple
/// </summary>
public static readonly Guid DropdownMultipleGuid = new Guid(DropdownMultiple);
/// <summary>
/// Guid for Radiobox as string
/// </summary>
public const string Radiobox = "bb5f57c9-ce2b-4bb9-b697-4caca783a805";
/// <summary>
/// Guid for Radiobox
/// </summary>
public static readonly Guid RadioboxGuid = new Guid(Radiobox);
/// <summary>
/// Guid for Date Picker as string
/// </summary>
public const string DatePicker = "5046194e-4237-453c-a547-15db3a07c4e1";
/// <summary>
/// Guid for Date Picker
/// </summary>
public static readonly Guid DatePickerGuid = new Guid(DatePicker);
/// <summary>
/// Guid for Dropdown as string
/// </summary>
public const string Dropdown = "0b6a45e7-44ba-430d-9da5-4e46060b9e03";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid DropdownGuid = new Guid(Dropdown);
/// <summary>
/// Guid for Checkbox list as string
/// </summary>
public const string CheckboxList = "fbaf13a8-4036-41f2-93a3-974f678c312a";
/// <summary>
/// Guid for Checkbox list
/// </summary>
public static readonly Guid CheckboxListGuid = new Guid(CheckboxList);
/// <summary>
/// Guid for Checkbox as string
/// </summary>
public const string Checkbox = "92897bc6-a5f3-4ffe-ae27-f2e7e33dda49";
/// <summary>
/// Guid for Checkbox
/// </summary>
public static readonly Guid CheckboxGuid = new Guid(Checkbox);
/// <summary>
/// Guid for Numeric as string
/// </summary>
public const string Numeric = "2e6d3631-066e-44b8-aec4-96f09099b2b5";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid NumericGuid = new Guid(Numeric);
/// <summary>
/// Guid for Richtext editor as string
/// </summary>
public const string RichtextEditor = "ca90c950-0aff-4e72-b976-a30b1ac57dad";
/// <summary>
/// Guid for Richtext editor
/// </summary>
public static readonly Guid RichtextEditorGuid = new Guid(RichtextEditor);
/// <summary>
/// Guid for Textstring as string
/// </summary>
public const string Textstring = "0cc0eba1-9960-42c9-bf9b-60e150b429ae";
/// <summary>
/// Guid for Textstring
/// </summary>
public static readonly Guid TextstringGuid = new Guid(Textstring);
/// <summary>
/// Guid for Textarea as string
/// </summary>
public const string Textarea = "c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid TextareaGuid = new Guid(Textarea);
/// <summary>
/// Guid for Upload as string
/// </summary>
public const string Upload = "84c6b441-31df-4ffe-b67e-67d5bc3ae65a";
/// <summary>
/// Guid for Upload
/// </summary>
public static readonly Guid UploadGuid = new Guid(Upload);
/// <summary>
/// Guid for Label as string
/// </summary>
public const string LabelString = "f0bc4bfb-b499-40d6-ba86-058885a5178c";
/// <summary>
/// Guid for Label string
/// </summary>
public static readonly Guid LabelStringGuid = new Guid(LabelString);
/// <summary>
/// Guid for Label as int
/// </summary>
public const string LabelInt = "8e7f995c-bd81-4627-9932-c40e568ec788";
/// <summary>
/// Guid for Label int
/// </summary>
public static readonly Guid LabelIntGuid = new Guid(LabelInt);
/// <summary>
/// Guid for Label as big int
/// </summary>
public const string LabelBigInt = "930861bf-e262-4ead-a704-f99453565708";
/// <summary>
/// Guid for Label big int
/// </summary>
public static readonly Guid LabelBigIntGuid = new Guid(LabelBigInt);
/// <summary>
/// Guid for Label as date time
/// </summary>
public const string LabelDateTime = "0e9794eb-f9b5-4f20-a788-93acd233a7e4";
/// <summary>
/// Guid for Label date time
/// </summary>
public static readonly Guid LabelDateTimeGuid = new Guid(LabelDateTime);
/// <summary>
/// Guid for Label as time
/// </summary>
public const string LabelTime = "a97cec69-9b71-4c30-8b12-ec398860d7e8";
/// <summary>
/// Guid for Label time
/// </summary>
public static readonly Guid LabelTimeGuid = new Guid(LabelTime);
/// <summary>
/// Guid for Label as decimal
/// </summary>
public const string LabelDecimal = "8f1ef1e1-9de4-40d3-a072-6673f631ca64";
/// <summary>
/// Guid for Label decimal
/// </summary>
public static readonly Guid LabelDecimalGuid = new Guid(LabelDecimal);
}
}
}
}
+56 -6
View File
@@ -5,39 +5,89 @@
public static class Icons
{
/// <summary>
/// System contenttype icon
/// System default icon
/// </summary>
public const string ContentType = "icon-arrangement";
public const string DefaultIcon = Content;
/// <summary>
/// System datatype icon
/// System content icon
/// </summary>
public const string Content = "icon-document";
/// <summary>
/// System content type icon
/// </summary>
public const string ContentType = "icon-item-arrangement";
/// <summary>
/// System data type icon
/// </summary>
public const string DataType = "icon-autofill";
/// <summary>
/// System property editor icon
/// System list view icon
/// </summary>
public const string PropertyEditor = "icon-autofill";
public const string ListView = "icon-thumbnail-list";
/// <summary>
/// System macro icon
/// </summary>
public const string Macro = "icon-settings-alt";
/// <summary>
/// System media file icon
/// </summary>
public const string MediaFile = "icon-document";
/// <summary>
/// System media folder icon
/// </summary>
public const string MediaFolder = "icon-folder";
/// <summary>
/// System media image icon
/// </summary>
public const string MediaImage = "icon-picture";
/// <summary>
/// System media type icon
/// </summary>
public const string MediaType = "icon-thumbnails";
/// <summary>
/// System member icon
/// </summary>
public const string Member = "icon-user";
/// <summary>
/// System member icon
/// System member group icon
/// </summary>
public const string MemberGroup = "icon-users-alt";
/// <summary>
/// System member type icon
/// </summary>
public const string MemberType = "icon-users";
/// <summary>
/// System property editor icon
/// </summary>
public const string PropertyEditor = "icon-autofill";
/// <summary>
/// System member icon
/// </summary>
public const string Template = "icon-layout";
/// <summary>
/// System user icon
/// </summary>
public const string User = "icon-user";
/// <summary>
/// System user group icon
/// </summary>
public const string UserGroup = "icon-users";
}
}
}
@@ -14,6 +14,23 @@ namespace Umbraco.Core
/// </summary>
public const string InternalGenericPropertiesPrefix = "_umb_";
public static class Legacy
{
public static class Aliases
{
public const string Textbox = "Umbraco.Textbox";
public const string Date = "Umbraco.Date";
public const string ContentPicker2 = "Umbraco.ContentPicker2";
public const string MediaPicker2 = "Umbraco.MediaPicker2";
public const string MemberPicker2 = "Umbraco.MemberPicker2";
public const string MultiNodeTreePicker2 = "Umbraco.MultiNodeTreePicker2";
public const string TextboxMultiple = "Umbraco.TextboxMultiple";
public const string RelatedLinks2 = "Umbraco.RelatedLinks2";
public const string RelatedLinks = "Umbraco.RelatedLinks";
}
}
/// <summary>
/// Defines Umbraco built-in property editor aliases.
/// </summary>
@@ -186,6 +203,24 @@ namespace Umbraco.Core
/// <remarks>Must be a valid <see cref="ValueTypes"/> value.</remarks>
public const string DataValueType = "umbracoDataValueType";
}
/// <summary>
/// Defines Umbraco's built-in property editor groups.
/// </summary>
public static class Groups
{
public const string Common = "Common";
public const string Lists = "Lists";
public const string Media = "Media";
public const string People = "People";
public const string Pickers = "Pickers";
public const string RichContent = "Rich Content";
}
}
}
}
+2 -1
View File
@@ -10,6 +10,8 @@ namespace Umbraco.Core
///</summary>
public static class EnumerableExtensions
{
internal static bool IsCollectionEmpty<T>(this IReadOnlyCollection<T> list) => list == null || list.Count == 0;
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
{
var hs = new HashSet<T>();
@@ -112,7 +114,6 @@ namespace Umbraco.Core
}
}
/// <summary>
/// Returns true if all items in the other collection exist in this collection
/// </summary>
+6 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Web.Hosting;
@@ -113,7 +114,7 @@ namespace Umbraco.Core
lock (_locko)
{
_logger.Debug<MainDom>("Signaled {Signaled} ({SignalSource})", _signaled ? "(again)" : string.Empty, source);
_logger.Debug<MainDom>("Signaled ({Signaled}) ({SignalSource})", _signaled ? "again" : "first", source);
if (_signaled) return;
if (_isMainDom == false) return; // probably not needed
_signaled = true;
@@ -171,6 +172,7 @@ namespace Umbraco.Core
// if more than 1 instance reach that point, one will get the lock
// and the other one will timeout, which is accepted
//TODO: This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset?
_asyncLocker = _asyncLock.Lock(LockTimeoutMilliseconds);
_isMainDom = true;
@@ -181,6 +183,9 @@ namespace Umbraco.Core
// which is accepted
_signal.Reset();
//WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread
_signal.WaitOneAsync()
.ContinueWith(_ => OnSignal("signal"));
@@ -101,33 +101,33 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -1, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1", SortOrder = 0, UniqueId = new Guid("916724a5-173d-4619-b97e-b9de133dd6f5"), Text = "SYSTEM DATA: umbraco master root", NodeObjectType = Constants.ObjectTypes.SystemRoot, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -20, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-20", SortOrder = 0, UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.ContentRecycleBin, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -21, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-21", SortOrder = 0, UniqueId = new Guid("BF7C7CBC-952F-4518-97A2-69E9C7B33842"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.MediaRecycleBin, CreateDate = DateTime.Now });
InsertDataTypeNodeDto(Constants.DataTypes.LabelString, 35, "f0bc4bfb-b499-40d6-ba86-058885a5178c", "Label");
InsertDataTypeNodeDto(Constants.DataTypes.LabelInt, 36, "8e7f995c-bd81-4627-9932-c40e568ec788", "Label (integer)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelBigint, 36, "930861bf-e262-4ead-a704-f99453565708", "Label (bigint)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, "0e9794eb-f9b5-4f20-a788-93acd233a7e4", "Label (datetime)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, "a97cec69-9b71-4c30-8b12-ec398860d7e8", "Label (time)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, "8f1ef1e1-9de4-40d3-a072-6673f631ca64", "Label (decimal)");
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -90, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-90", SortOrder = 34, UniqueId = new Guid("84c6b441-31df-4ffe-b67e-67d5bc3ae65a"), Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -89, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-89", SortOrder = 33, UniqueId = new Guid("c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3"), Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -88, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-88", SortOrder = 32, UniqueId = new Guid("0cc0eba1-9960-42c9-bf9b-60e150b429ae"), Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -87, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-87", SortOrder = 4, UniqueId = new Guid("ca90c950-0aff-4e72-b976-a30b1ac57dad"), Text = "Richtext editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -51, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-51", SortOrder = 2, UniqueId = new Guid("2e6d3631-066e-44b8-aec4-96f09099b2b5"), Text = "Numeric", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -49, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-49", SortOrder = 2, UniqueId = new Guid("92897bc6-a5f3-4ffe-ae27-f2e7e33dda49"), Text = "True/false", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -43, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-43", SortOrder = 2, UniqueId = new Guid("fbaf13a8-4036-41f2-93a3-974f678c312a"), Text = "Checkbox list", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownSingle, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownSingle}", SortOrder = 2, UniqueId = new Guid("0b6a45e7-44ba-430d-9da5-4e46060b9e03"), Text = "Dropdown", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -41, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-41", SortOrder = 2, UniqueId = new Guid("5046194e-4237-453c-a547-15db3a07c4e1"), Text = "Date Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -40, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-40", SortOrder = 2, UniqueId = new Guid("bb5f57c9-ce2b-4bb9-b697-4caca783a805"), Text = "Radiobox", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownMultiple, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownMultiple}", SortOrder = 2, UniqueId = new Guid("f38f0ac7-1d27-439c-9f3f-089cd8825a53"), Text = "Dropdown multiple", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = new Guid("0225af17-b302-49cb-9176-b9f35cab9c17"), Text = "Approved Color", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -36, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-36", SortOrder = 2, UniqueId = new Guid("e4d66c0f-b935-4200-81f0-025f7256b89a"), Text = "Date Picker with time", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultContentListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultContentListView}", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMediaListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMediaListView}", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMembersListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMembersListView}", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
InsertDataTypeNodeDto(Constants.DataTypes.LabelString, 35, Constants.DataTypes.Guids.LabelString, "Label (string)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelInt, 36, Constants.DataTypes.Guids.LabelInt, "Label (integer)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelBigint, 36, Constants.DataTypes.Guids.LabelBigInt, "Label (bigint)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, Constants.DataTypes.Guids.LabelDateTime, "Label (datetime)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, Constants.DataTypes.Guids.LabelTime, "Label (time)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, Constants.DataTypes.Guids.LabelDecimal, "Label (decimal)");
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Upload, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Upload}", SortOrder = 34, UniqueId = Constants.DataTypes.Guids.UploadGuid, Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textarea, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textarea}", SortOrder = 33, UniqueId = Constants.DataTypes.Guids.TextareaGuid, Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textbox, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textbox}", SortOrder = 32, UniqueId = Constants.DataTypes.Guids.TextstringGuid, Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.RichtextEditor, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.RichtextEditor}", SortOrder = 4, UniqueId = Constants.DataTypes.Guids.RichtextEditorGuid, Text = "Richtext editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -51, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-51", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.NumericGuid, Text = "Numeric", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Boolean, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Boolean}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.CheckboxGuid, Text = "True/false", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -43, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-43", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.CheckboxListGuid, Text = "Checkbox list", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownSingle, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownSingle}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DropdownGuid, Text = "Dropdown", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -41, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-41", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DatePickerGuid, Text = "Date Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -40, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-40", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.RadioboxGuid, Text = "Radiobox", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownMultiple, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownMultiple}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DropdownMultipleGuid, Text = "Dropdown multiple", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ApprovedColorGuid, Text = "Approved Color", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DateTime, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DateTime}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DatePickerWithTimeGuid, Text = "Date Picker with time", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultContentListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultContentListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewContentGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMediaListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMediaListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewMediaGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMembersListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMembersListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewMembersGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Tags, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Tags}", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.ImageCropper, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.ImageCropper}", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = Constants.ObjectTypes.MemberType, CreateDate = DateTime.Now });
//New UDI pickers with newer Ids
@@ -155,10 +155,10 @@ namespace Umbraco.Core.Migrations.Install
private void CreateContentTypeData()
{
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "icon-folder", IsContainer = false, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "icon-picture", AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "icon-document", AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = "icon-user", Thumbnail = "icon-user", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = Constants.Icons.MediaFolder, Thumbnail = Constants.Icons.MediaFolder, IsContainer = false, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = Constants.Icons.MediaImage, Thumbnail = Constants.Icons.MediaImage, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = Constants.Icons.MediaFile, Thumbnail = Constants.Icons.MediaFile, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = Constants.Icons.Member, Thumbnail = Constants.Icons.Member, Variations = (byte) ContentVariation.Nothing });
}
private void CreateUserData()
@@ -210,19 +210,19 @@ namespace Umbraco.Core.Migrations.Install
private void CreatePropertyTypeData()
{
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = 1043, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = Constants.DataTypes.ImageCropper, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 10, UniqueId = 10.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = -90, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = Constants.DataTypes.Upload, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
//membership property types
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = -89, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = Constants.DataTypes.Textarea, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 30, UniqueId = 30.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsApproved, Name = Constants.Conventions.Member.IsApprovedLabel, SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 31, UniqueId = 31.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsLockedOut, Name = Constants.Conventions.Member.IsLockedOutLabel, SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 30, UniqueId = 30.ToGuid(), DataTypeId = Constants.DataTypes.Boolean, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsApproved, Name = Constants.Conventions.Member.IsApprovedLabel, SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 31, UniqueId = 31.ToGuid(), DataTypeId = Constants.DataTypes.Boolean, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsLockedOut, Name = Constants.Conventions.Member.IsLockedOutLabel, SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
@@ -266,30 +266,30 @@ namespace Umbraco.Core.Migrations.Install
const string layouts = "[" + cardLayout + "," + listLayout + "]";
// TODO: Check which of the DataTypeIds below doesn't exist in umbracoNode, which results in a foreign key constraint errors.
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -49, EditorAlias = Constants.PropertyEditors.Aliases.Boolean, DbType = "Integer" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Boolean, EditorAlias = Constants.PropertyEditors.Aliases.Boolean, DbType = "Integer" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -51, EditorAlias = Constants.PropertyEditors.Aliases.Integer, DbType = "Integer" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -87, EditorAlias = Constants.PropertyEditors.Aliases.TinyMce, DbType = "Ntext",
Configuration = "{\"value\":\",code,undo,redo,cut,copy,mcepasteword,stylepicker,bold,italic,bullist,numlist,outdent,indent,mcelink,unlink,mceinsertanchor,mceimage,umbracomacro,mceinserttable,umbracoembed,mcecharmap,|1|1,2,3,|0|500,400|1049,|true|\"}" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -88, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -89, EditorAlias = Constants.PropertyEditors.Aliases.TextArea, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -90, EditorAlias = Constants.PropertyEditors.Aliases.UploadField, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Textbox, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Textarea, EditorAlias = Constants.PropertyEditors.Aliases.TextArea, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Upload, EditorAlias = Constants.PropertyEditors.Aliases.UploadField, DbType = "Nvarchar" });
InsertDataTypeDto(Constants.DataTypes.LabelString, Constants.PropertyEditors.Aliases.Label, "Nvarchar", "{\"umbracoDataValueType\":\"STRING\"}");
InsertDataTypeDto(Constants.DataTypes.LabelInt, Constants.PropertyEditors.Aliases.Label, "Integer", "{\"umbracoDataValueType\":\"INT\"}");
InsertDataTypeDto(Constants.DataTypes.LabelBigint, Constants.PropertyEditors.Aliases.Label, "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\"}");
InsertDataTypeDto(Constants.DataTypes.LabelDateTime, Constants.PropertyEditors.Aliases.Label, "Date", "{\"umbracoDataValueType\":\"DATETIME\"}");
InsertDataTypeDto(Constants.DataTypes.LabelDecimal, Constants.PropertyEditors.Aliases.Label, "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}");
InsertDataTypeDto(Constants.DataTypes.LabelTime, Constants.PropertyEditors.Aliases.Label, "Date", "{\"umbracoDataValueType\":\"TIME\"}");
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -36, EditorAlias = Constants.PropertyEditors.Aliases.DateTime, DbType = "Date" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DateTime, EditorAlias = Constants.PropertyEditors.Aliases.DateTime, DbType = "Date" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -37, EditorAlias = Constants.PropertyEditors.Aliases.ColorPicker, DbType = "Nvarchar" });
InsertDataTypeDto(Constants.DataTypes.DropDownSingle, Constants.PropertyEditors.Aliases.DropDownListFlexible, "Nvarchar", "{\"multiple\":false}");
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -40, EditorAlias = Constants.PropertyEditors.Aliases.RadioButtonList, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -41, EditorAlias = "Umbraco.DateTime", DbType = "Date", Configuration = "{\"format\":\"YYYY-MM-DD\"}" });
InsertDataTypeDto(Constants.DataTypes.DropDownMultiple, Constants.PropertyEditors.Aliases.DropDownListFlexible, "Nvarchar", "{\"multiple\":true}");
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -43, EditorAlias = Constants.PropertyEditors.Aliases.CheckBoxList, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1041, EditorAlias = Constants.PropertyEditors.Aliases.Tags, DbType = "Ntext",
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Tags, EditorAlias = Constants.PropertyEditors.Aliases.Tags, DbType = "Ntext",
Configuration = "{\"group\":\"default\", \"storageType\":\"Json\"}"
});
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1043, EditorAlias = Constants.PropertyEditors.Aliases.ImageCropper, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.ImageCropper, EditorAlias = Constants.PropertyEditors.Aliases.ImageCropper, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultContentListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar",
Configuration = "{\"pageSize\":100, \"orderBy\":\"updateDate\", \"orderDirection\":\"desc\", \"layouts\":" + layouts + ", \"includeProperties\":[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]}" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultMediaListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar",
@@ -74,6 +74,11 @@ namespace Umbraco.Core.Migrations.Upgrade
throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}."
+ $" Please upgrade first to at least {minVersion}.");
// Force versions between 7.14.*-7.15.* into into 7.14 initial state. Because there is no db-changes,
// and we don't want users to workaround my putting in version 7.14.0 them self.
if (minVersion <= currentVersion && currentVersion < new SemVersion(7, 16))
return GetInitState(minVersion);
// initial state is eg "{init-7.14.0}"
return GetInitState(currentVersion);
}
@@ -19,8 +19,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var sqlDataTypes = Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.RelatedLinks"
|| x.EditorAlias == "Umbraco.RelatedLinks2");
.Where<DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks
|| x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2);
var dataTypes = Database.Fetch<DataTypeDto>(sqlDataTypes);
var dataTypeIds = dataTypes.Select(x => x.NodeId).ToList();
@@ -50,10 +50,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
// Create a Multi URL Picker datatype for the converted RelatedLinks data
foreach (var property in properties)
{
var value = property.Value.ToString();
var value = property.Value?.ToString();
if (string.IsNullOrWhiteSpace(value))
continue;
@@ -89,7 +89,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Name = relatedLink.Caption,
Target = relatedLink.NewWindow ? "_blank" : null,
Udi = udi,
// Should only have a URL if it's an external link otherwise it wil be a UDI
// Should only have a URL if it's an external link otherwise it wil be a UDI
Url = relatedLink.IsInternal == false ? relatedLink.Link : null
};
@@ -103,7 +103,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Database.Update(property);
}
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
@@ -18,6 +19,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
private static readonly ISet<string> LegacyAliases = new HashSet<string>()
{
Constants.PropertyEditors.Legacy.Aliases.Date,
Constants.PropertyEditors.Legacy.Aliases.Textbox,
Constants.PropertyEditors.Legacy.Aliases.ContentPicker2,
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Legacy.Aliases.MemberPicker2,
Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2,
Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple,
Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2,
};
public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger)
: base(context)
{
@@ -70,16 +83,23 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
if (newAlias == null)
{
_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);
if (!LegacyAliases.Contains(dataType.EditorAlias))
{
_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);
if (!LegacyAliases.Contains(newAlias))
{
_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
{
@@ -3,7 +3,7 @@
class ContentPickerPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.ContentPicker2";
=> editorAlias == Constants.PropertyEditors.Legacy.Aliases.ContentPicker2;
public override string GetNewAlias(string editorAlias)
=> null;
@@ -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 DropDownFlexiblePreValueMigrator : IPreValueMigrator
{
public bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.DropDown.Flexible";
public virtual string GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new DropDownFlexibleConfiguration();
foreach (var preValue in preValues.Values)
{
if (preValue.Alias == "multiple")
{
config.Multiple = (preValue.Value == "1");
}
else
{
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
}
}
return config;
}
}
}
@@ -6,15 +6,15 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
private readonly string[] _editors =
{
"Umbraco.MediaPicker2",
"Umbraco.MediaPicker"
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Aliases.MediaPicker
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
=> "Umbraco.MediaPicker";
=> Constants.PropertyEditors.Aliases.MediaPicker;
// you wish - but MediaPickerConfiguration lives in Umbraco.Web
/*
@@ -2,24 +2,25 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
public class PreValueMigratorComposer : ICoreComposer
[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
public class PreValueMigratorComposer : ICoreComposer
{
public void Compose(Composition composition)
{
public void Compose(Composition composition)
{
// do NOT add DefaultPreValueMigrator to this list!
// it will be automatically used if nothing matches
// 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>();
}
composition.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
.Append<RenamingPreValueMigrator>()
.Append<RichTextPreValueMigrator>()
.Append<UmbracoSliderPreValueMigrator>()
.Append<MediaPickerPreValueMigrator>()
.Append<ContentPickerPreValueMigrator>()
.Append<NestedContentPreValueMigrator>()
.Append<DecimalPreValueMigrator>()
.Append<ListViewPreValueMigrator>()
.Append<DropDownFlexiblePreValueMigrator>()
.Append<ValueListPreValueMigrator>();
}
}
}
@@ -9,6 +9,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
private readonly string[] _editors =
{
"Umbraco.RadioButtonList",
"Umbraco.CheckBoxList",
"Umbraco.DropDown",
"Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple",
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
var dataTypes = GetDataTypes("Umbraco.Date");
var dataTypes = GetDataTypes(Constants.PropertyEditors.Legacy.Aliases.Date);
foreach (var dataType in dataTypes)
{
@@ -25,6 +25,14 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
config = (DateTimeConfiguration) new CustomDateTimeConfigurationEditor().FromDatabase(
dataType.Configuration);
// If the Umbraco.Date type is the default from V7 and it has never been updated, then the
// configuration is empty, and the format stuff is handled by in JS by moment.js. - We can't do that
// after the migration, so we force the format to the default from V7.
if (string.IsNullOrEmpty(dataType.Configuration))
{
config.Format = "YYYY-MM-DD";
};
}
catch (Exception ex)
{
@@ -12,12 +12,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
RenameDataType(Constants.PropertyEditors.Aliases.ContentPicker + "2", Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MediaPicker + "2", Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MemberPicker + "2", Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MultiNodeTreePicker + "2", Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType("Umbraco.TextboxMultiple", Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType("Umbraco.Textbox", Constants.PropertyEditors.Aliases.TextBox, false);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.ContentPicker2, Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MediaPicker2, Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MemberPicker2, Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2, Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple, Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.Textbox, Constants.PropertyEditors.Aliases.TextBox, false);
}
private void RenameDataType(string fromAlias, string toAlias, bool checkCollision = true)
@@ -30,7 +30,20 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.Where<DataTypeDto>(x => x.EditorAlias == toAlias));
if (oldCount > 0)
throw new InvalidOperationException($"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used.");
{
// If we throw it means that the upgrade will exit and cannot continue.
// This will occur if a v7 site has the old "Obsolete" property editors that are already named with the `toAlias` name.
// TODO: We should have an additional upgrade step when going from 7 -> 8 like we did with 6 -> 7 that shows a compatibility report,
// this would include this check and then we can provide users with information on what they should do (i.e. before upgrading to v8 they will
// need to migrate these old obsolete editors to non-obsolete editors)
throw new InvalidOperationException(
$"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used." +
$"This is generally because when upgrading from a v7 to v8 site, the v7 site contains Data Types that reference old and already Obsolete " +
$"Property Editors. Before upgrading to v8, any Data Types using property editors that are named with the prefix '(Obsolete)' must be migrated " +
$"to the non-obsolete v7 property editors of the same type.");
}
}
Database.Execute(Sql()
@@ -14,11 +14,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
//Get anything currently scheduled
var scheduleSql = new Sql()
.Select("nodeId", "releaseDate", "expireDate")
var releaseSql = new Sql()
.Select("nodeId", "releaseDate")
.From("umbracoDocument")
.Where("releaseDate IS NOT NULL OR expireDate IS NOT NULL");
var schedules = Database.Dictionary<int, (DateTime? releaseDate, DateTime? expireDate)> (scheduleSql);
.Where("releaseDate IS NOT NULL");
var releases = Database.Dictionary<int, DateTime> (releaseSql);
var expireSql = new Sql()
.Select("nodeId", "expireDate")
.From("umbracoDocument")
.Where("expireDate IS NOT NULL");
var expires = Database.Dictionary<int, DateTime>(expireSql);
//drop old cols
Delete.Column("releaseDate").FromTable("umbracoDocument").Do();
@@ -27,20 +34,25 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Create.Table<ContentScheduleDto>(true).Do();
//migrate the schedule
foreach(var s in schedules)
foreach(var s in releases)
{
var date = s.Value.releaseDate;
var date = s.Value;
var action = ContentScheduleAction.Release.ToString();
if (!date.HasValue)
{
date = s.Value.expireDate;
action = ContentScheduleAction.Expire.ToString();
}
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { nodeId = s.Key, date = date.Value, action = action })
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Do();
}
foreach (var s in expires)
{
var date = s.Value;
var action = ContentScheduleAction.Expire.ToString();
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Do();
}
}
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -36,6 +37,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
var exceptions = new List<Exception>();
foreach (var property in properties)
{
var value = property.TextValue;
@@ -43,19 +45,34 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
{
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
try
{
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
}
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
catch (JsonException e)
{
exceptions.Add(new InvalidOperationException(
"Cannot deserialize the value as json. This can be because the property editor " +
"type is changed from another type into a grid. Old versions of the value in this " +
"property can have the structure from the old property editor type. This needs to be " +
"changed manually before updating the database.\n" +
$"Property info: Id = {property.Id}, LanguageId = {property.LanguageId}, VersionId = {property.VersionId}, Value = {property.Value}"
, e));
continue;
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
else
{
@@ -65,6 +82,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
Database.Update(property);
}
if (exceptions.Any())
{
throw new AggregateException("One or more errors related to unexpected data in grid values occurred.", exceptions);
}
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
@@ -35,5 +35,58 @@ namespace Umbraco.Core.Models
throw new InvalidCastException($"Cannot cast dataType configuration, of type {configuration.GetType().Name}, to {typeof(T).Name}.");
}
private static readonly ISet<Guid> IdsOfBuildInDataTypes = new HashSet<Guid>()
{
Constants.DataTypes.Guids.ContentPickerGuid,
Constants.DataTypes.Guids.MemberPickerGuid,
Constants.DataTypes.Guids.MediaPickerGuid,
Constants.DataTypes.Guids.MultipleMediaPickerGuid,
Constants.DataTypes.Guids.RelatedLinksGuid,
Constants.DataTypes.Guids.MemberGuid,
Constants.DataTypes.Guids.ImageCropperGuid,
Constants.DataTypes.Guids.TagsGuid,
Constants.DataTypes.Guids.ListViewContentGuid,
Constants.DataTypes.Guids.ListViewMediaGuid,
Constants.DataTypes.Guids.ListViewMembersGuid,
Constants.DataTypes.Guids.DatePickerWithTimeGuid,
Constants.DataTypes.Guids.ApprovedColorGuid,
Constants.DataTypes.Guids.DropdownMultipleGuid,
Constants.DataTypes.Guids.RadioboxGuid,
Constants.DataTypes.Guids.DatePickerGuid,
Constants.DataTypes.Guids.DropdownGuid,
Constants.DataTypes.Guids.CheckboxListGuid,
Constants.DataTypes.Guids.CheckboxGuid,
Constants.DataTypes.Guids.NumericGuid,
Constants.DataTypes.Guids.RichtextEditorGuid,
Constants.DataTypes.Guids.TextstringGuid,
Constants.DataTypes.Guids.TextareaGuid,
Constants.DataTypes.Guids.UploadGuid,
Constants.DataTypes.Guids.LabelStringGuid,
Constants.DataTypes.Guids.LabelDecimalGuid,
Constants.DataTypes.Guids.LabelDateTimeGuid,
Constants.DataTypes.Guids.LabelBigIntGuid,
Constants.DataTypes.Guids.LabelTimeGuid,
Constants.DataTypes.Guids.LabelDateTimeGuid,
};
/// <summary>
/// Returns true if this date type is build-in/default.
/// </summary>
/// <param name="dataType">The data type definition.</param>
/// <returns></returns>
internal static bool IsBuildInDataType(this IDataType dataType)
{
return IsBuildInDataType(dataType.Key);
}
/// <summary>
/// Returns true if this date type is build-in/default.
/// </summary>
internal static bool IsBuildInDataType(Guid key)
{
return IdsOfBuildInDataTypes.Contains(key);
}
}
}
+1 -31
View File
@@ -81,37 +81,7 @@ namespace Umbraco.Core.Models.Entities
_key = Guid.Empty;
_hasIdentity = false;
}
/// <summary>
/// Updates the entity when it is being saved for the first time.
/// </summary>
internal virtual void AddingEntity()
{
var now = DateTime.Now;
// set the create and update dates, if not already set
if (IsPropertyDirty("CreateDate") == false || _createDate == default)
CreateDate = now;
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default)
UpdateDate = now;
}
/// <summary>
/// Updates the entity when it is being saved.
/// </summary>
internal virtual void UpdatingEntity()
{
var now = DateTime.Now;
// just in case
if (_createDate == default)
CreateDate = now;
// set the update date if not already set
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default)
UpdateDate = now;
}
public virtual bool Equals(EntityBase other)
{
return other != null && (ReferenceEquals(this, other) || SameIdentityAs(other));
@@ -0,0 +1,46 @@
using System;
namespace Umbraco.Core.Models.Entities
{
internal static class EntityExtensions
{
/// <summary>
/// Updates the entity when it is being saved.
/// </summary>
internal static void UpdatingEntity(this IEntity entity)
{
var now = DateTime.Now;
// just in case
if (entity.CreateDate == default)
{
entity.CreateDate = now;
}
// set the update date if not already set
if (entity.UpdateDate == default || (entity is ICanBeDirty canBeDirty && canBeDirty.IsPropertyDirty("UpdateDate") == false))
{
entity.UpdateDate = now;
}
}
/// <summary>
/// Updates the entity when it is being saved for the first time.
/// </summary>
internal static void AddingEntity(this IEntity entity)
{
var now = DateTime.Now;
var canBeDirty = entity as ICanBeDirty;
// set the create and update dates, if not already set
if (entity.CreateDate == default || canBeDirty?.IsPropertyDirty("CreateDate") == false)
{
entity.CreateDate = now;
}
if (entity.UpdateDate == default || canBeDirty?.IsPropertyDirty("UpdateDate") == false)
{
entity.UpdateDate = now;
}
}
}
}
-13
View File
@@ -478,19 +478,6 @@ namespace Umbraco.Core.Models
set => SetPropertyValueAndDetectChanges(value, ref _providerUserKey, nameof(ProviderUserKey));
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
/// <remarks>Created date is set and a Unique key is assigned</remarks>
internal override void AddingEntity()
{
base.AddingEntity();
if (ProviderUserKey == null)
ProviderUserKey = Key;
}
/* Internal experiment - only used for mapping queries.
* Adding these to have first level properties instead of the Properties collection.
*/
+9 -1
View File
@@ -21,6 +21,7 @@ namespace Umbraco.Core.Models
private string _alias;
private string _description;
private int _dataTypeId;
private Guid _dataTypeKey;
private Lazy<int> _propertyGroupId;
private string _propertyEditorAlias;
private ValueStorageType _valueStorageType;
@@ -113,7 +114,7 @@ namespace Umbraco.Core.Models
/// Gets of sets the alias of the property type.
/// </summary>
[DataMember]
public string Alias
public virtual string Alias
{
get => _alias;
set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, nameof(Alias));
@@ -139,6 +140,13 @@ namespace Umbraco.Core.Models
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeId, nameof(DataTypeId));
}
[DataMember]
public Guid DataTypeKey
{
get => _dataTypeKey;
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeKey, nameof(DataTypeKey));
}
/// <summary>
/// Gets or sets the alias of the property editor for this property type.
/// </summary>
@@ -13,6 +13,10 @@
/// <summary>
/// Refreshes the factory.
/// </summary>
/// <remarks>
/// <para>This will typically re-compiled models/classes into a new DLL that are used to populate the cache.</para>
/// <para>This is called prior to refreshing the cache.</para>
/// </remarks>
void Refresh();
}
}
-13
View File
@@ -193,19 +193,6 @@ namespace Umbraco.Core.Models
return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool IsInBranchOfStartNode(this IUser user, IUmbracoEntity entity, IEntityService entityService, int recycleBinId, out bool hasPathAccess)
{
switch (recycleBinId)
{
case Constants.System.RecycleBinMedia:
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateMediaStartNodeIds(entityService), user.GetMediaStartNodePaths(entityService), out hasPathAccess);
case Constants.System.RecycleBinContent:
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateContentStartNodeIds(entityService), user.GetContentStartNodePaths(entityService), out hasPathAccess);
default:
throw new NotSupportedException("Path access is only determined on content or media");
}
}
/// <summary>
/// Determines whether this user has access to view sensitive data
/// </summary>
@@ -54,6 +54,7 @@ namespace Umbraco.Core.Persistence.Factories
propertyType.Alias = typeDto.Alias;
propertyType.DataTypeId = typeDto.DataTypeId;
propertyType.DataTypeKey = typeDto.DataTypeDto.NodeDto.UniqueId;
propertyType.Description = typeDto.Description;
propertyType.Id = typeDto.Id;
propertyType.Key = typeDto.UniqueId;
@@ -18,7 +18,8 @@ namespace Umbraco.Core.Persistence.Mappers
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Id), nameof(LogDto.NodeId));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.CreateDate), nameof(LogDto.Datestamp));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.UserId), nameof(LogDto.UserId));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.AuditType), nameof(LogDto.Header));
// we cannot map that one - because AuditType is an enum but Header is a string
//DefineMap<AuditItem, LogDto>(nameof(AuditItem.AuditType), nameof(LogDto.Header));
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Comment), nameof(LogDto.Comment));
}
}
@@ -85,6 +85,17 @@ namespace Umbraco.Core.Persistence.Querying
// I'm just unsure right now due to time constraints how to make it correct. It won't matter right now and has been working already with this bug but I've
// only just discovered what it is actually doing.
// TODO
// in most cases we want to convert the value to a plain object,
// but for in some rare cases, we may want to do it differently,
// for instance a Models.AuditType (an enum) may in some cases
// need to be converted to its string value.
// but - we cannot have specific code here, really - and how would
// we configure this? is it even possible?
/*
var toString = typeof(object).GetMethod("ToString");
var member = Expression.Call(m, toString);
*/
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
@@ -33,5 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
Direction orderDirection,
AuditType[] auditTypeFilter,
IQuery<IAuditItem> customFilter);
IEnumerable<IAuditItem> Get(AuditType type, IQuery<IAuditItem> query);
}
}
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <inheritdoc />
protected override void PersistNewItem(IAuditEntry entity)
{
((EntityBase) entity).AddingEntity();
entity.AddingEntity();
var dto = AuditEntryFactory.BuildDto(entity);
Database.Insert(dto);
@@ -74,6 +74,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return dtos.Select(x => new AuditItem(x.NodeId, Enum<AuditType>.Parse(x.Header), x.UserId ?? Constants.Security.UnknownUserId, x.EntityType, x.Comment, x.Parameters)).ToList();
}
public IEnumerable<IAuditItem> Get(AuditType type, IQuery<IAuditItem> query)
{
var sqlClause = GetBaseQuery(false)
.Where<LogDto>(x => x.Header == type.ToString());
var translator = new SqlTranslator<IAuditItem>(sqlClause, query);
var sql = translator.Translate();
var dtos = Database.Fetch<LogDto>(sql);
return dtos.Select(x => new AuditItem(x.NodeId, Enum<AuditType>.Parse(x.Header), x.UserId ?? Constants.Security.UnknownUserId, x.EntityType, x.Comment, x.Parameters)).ToList();
}
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
{
var sql = SqlContext.Sql();
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <inheritdoc />
protected override void PersistNewItem(IConsent entity)
{
((EntityBase) entity).AddingEntity();
entity.AddingEntity();
var dto = ConsentFactory.BuildDto(entity);
Database.Insert(dto);
@@ -80,7 +80,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <inheritdoc />
protected override void PersistUpdatedItem(IConsent entity)
{
((EntityBase) entity).UpdatingEntity();
entity.UpdatingEntity();
var dto = ConsentFactory.BuildDto(entity);
Database.Update(dto);
@@ -7,6 +7,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Scoping;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -188,10 +189,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var groupDtos = Database.Fetch<PropertyTypeGroupDto>(sql1);
var sql2 = Sql()
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto))
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto, r1 => r1.Select(x => x.NodeDto)))
.AndSelect<MemberPropertyTypeDto>()
.From<PropertyTypeDto>()
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((pt, dt) => pt.DataTypeId == dt.NodeId)
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
.InnerJoin<ContentTypeDto>().On<PropertyTypeDto, ContentTypeDto>((pt, ct) => pt.ContentTypeId == ct.NodeId)
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeDto, PropertyTypeGroupDto>((pt, ptg) => pt.PropertyTypeGroupId == ptg.Id)
.LeftJoin<MemberPropertyTypeDto>().On<PropertyTypeDto, MemberPropertyTypeDto>((pt, mpt) => pt.Id == mpt.PropertyTypeId)
@@ -290,6 +292,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
Description = dto.Description,
DataTypeId = dto.DataTypeId,
DataTypeKey = dto.DataTypeDto.NodeDto.UniqueId,
Id = dto.Id,
Key = dto.UniqueId,
Mandatory = dto.Mandatory,
@@ -5,6 +5,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -230,7 +231,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
throw ex;
}
((ContentType)entity).AddingEntity();
entity.AddingEntity();
PersistNewBaseContentType(entity);
PersistTemplates(entity, false);
@@ -270,7 +271,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
ValidateAlias(entity);
//Updates Modified date
((ContentType)entity).UpdatingEntity();
entity.UpdatingEntity();
//Look up parent to get and set the correct Path if ParentId has changed
if (entity.IsPropertyDirty("ParentId"))
@@ -1013,8 +1013,9 @@ AND umbracoNode.id <> @id",
if (propertyType.PropertyEditorAlias.IsNullOrWhiteSpace() == false)
{
var sql = Sql()
.SelectAll()
.Select<DataTypeDto>(dt => dt.Select(x => x.NodeDto))
.From<DataTypeDto>()
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
.Where("propertyEditorAlias = @propertyEditorAlias", new { propertyEditorAlias = propertyType.PropertyEditorAlias })
.OrderBy<DataTypeDto>(typeDto => typeDto.NodeId);
var datatype = Database.FirstOrDefault<DataTypeDto>(sql);
@@ -1022,6 +1023,7 @@ AND umbracoNode.id <> @id",
if (datatype != null)
{
propertyType.DataTypeId = datatype.NodeId;
propertyType.DataTypeKey = datatype.NodeDto.UniqueId;
}
else
{
@@ -9,6 +9,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -106,7 +107,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IDataType entity)
{
((DataType)entity).AddingEntity();
entity.AddingEntity();
//ensure a datatype has a unique name before creating it
entity.Name = EnsureUniqueNodeName(entity.Name);
@@ -174,7 +175,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
//Updates Modified date
((DataType)entity).UpdatingEntity();
entity.UpdatingEntity();
//Look up parent to get and set the correct Path if ParentId has changed
if (entity.IsPropertyDirty("ParentId"))
@@ -148,7 +148,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IDictionaryItem entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
foreach (var translation in entity.Translations)
translation.Value = translation.Value.ToValidXmlString();
@@ -6,6 +6,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
@@ -205,7 +206,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersionCultureVariation + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.AccessRule + " WHERE accessId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id OR loginNodeId = @id OR noAccessNodeId = @id)",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE loginNodeId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE noAccessNodeId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Node + " WHERE id = @id"
};
return list;
@@ -260,21 +264,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IContent entity)
{
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4234 - sort out IContent vs Content
// however, it's not just so we have access to AddingEntity
// there are tons of things at the end of the methods, that can only work with a true Content
// and basically, the repository requires a Content, not an IContent
var content = (Content)entity;
entity.AddingEntity();
content.AddingEntity();
var publishing = content.PublishedState == PublishedState.Publishing;
var publishing = entity.PublishedState == PublishedState.Publishing;
// ensure that the default template is assigned
if (entity.TemplateId.HasValue == false)
entity.TemplateId = entity.ContentType.DefaultTemplate?.Id;
// sanitize names
SanitizeNames(content, publishing);
SanitizeNames(entity, publishing);
// ensure that strings don't contain characters that are invalid in xml
// TODO: do we really want to keep doing this here?
@@ -324,11 +323,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
contentVersionDto.NodeId = nodeDto.NodeId;
contentVersionDto.Current = !publishing;
Database.Insert(contentVersionDto);
content.VersionId = contentVersionDto.Id;
entity.VersionId = contentVersionDto.Id;
// persist the document version dto
var documentVersionDto = dto.DocumentVersionDto;
documentVersionDto.Id = content.VersionId;
documentVersionDto.Id = entity.VersionId;
if (publishing)
documentVersionDto.Published = true;
Database.Insert(documentVersionDto);
@@ -336,62 +335,62 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// and again in case we're publishing immediately
if (publishing)
{
content.PublishedVersionId = content.VersionId;
entity.PublishedVersionId = entity.VersionId;
contentVersionDto.Id = 0;
contentVersionDto.Current = true;
contentVersionDto.Text = content.Name;
contentVersionDto.Text = entity.Name;
Database.Insert(contentVersionDto);
content.VersionId = contentVersionDto.Id;
entity.VersionId = contentVersionDto.Id;
documentVersionDto.Id = content.VersionId;
documentVersionDto.Id = entity.VersionId;
documentVersionDto.Published = false;
Database.Insert(documentVersionDto);
}
// persist the property data
var propertyDataDtos = PropertyFactory.BuildDtos(content.ContentType.Variations, content.VersionId, content.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out var editedCultures);
var propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, entity.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out var editedCultures);
foreach (var propertyDataDto in propertyDataDtos)
Database.Insert(propertyDataDto);
// if !publishing, we may have a new name != current publish name,
// also impacts 'edited'
if (!publishing && content.PublishName != content.Name)
if (!publishing && entity.PublishName != entity.Name)
edited = true;
// persist the document dto
// at that point, when publishing, the entity still has its old Published value
// so we need to explicitly update the dto to persist the correct value
if (content.PublishedState == PublishedState.Publishing)
if (entity.PublishedState == PublishedState.Publishing)
dto.Published = true;
dto.NodeId = nodeDto.NodeId;
content.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
entity.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
Database.Insert(dto);
//insert the schedule
PersistContentSchedule(content, false);
PersistContentSchedule(entity, false);
// persist the variations
if (content.ContentType.VariesByCulture())
if (entity.ContentType.VariesByCulture())
{
// bump dates to align cultures to version
if (publishing)
content.AdjustDates(contentVersionDto.VersionDate);
entity.AdjustDates(contentVersionDto.VersionDate);
// names also impact 'edited'
// ReSharper disable once UseDeconstruction
foreach (var cultureInfo in content.CultureInfos)
if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture))
foreach (var cultureInfo in entity.CultureInfos)
if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture))
(editedCultures ?? (editedCultures = new HashSet<string>(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture);
// insert content variations
Database.BulkInsertRecords(GetContentVariationDtos(content, publishing));
Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing));
// insert document variations
Database.BulkInsertRecords(GetDocumentVariationDtos(content, publishing, editedCultures));
Database.BulkInsertRecords(GetDocumentVariationDtos(entity, publishing, editedCultures));
}
// refresh content
content.SetCultureEdited(editedCultures);
entity.SetCultureEdited(editedCultures);
// trigger here, before we reset Published etc
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
@@ -399,23 +398,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// flip the entity's published property
// this also flips its published state
// note: what depends on variations (eg PublishNames) is managed directly by the content
if (content.PublishedState == PublishedState.Publishing)
if (entity.PublishedState == PublishedState.Publishing)
{
content.Published = true;
content.PublishTemplateId = content.TemplateId;
content.PublisherId = content.WriterId;
content.PublishName = content.Name;
content.PublishDate = content.UpdateDate;
entity.Published = true;
entity.PublishTemplateId = entity.TemplateId;
entity.PublisherId = entity.WriterId;
entity.PublishName = entity.Name;
entity.PublishDate = entity.UpdateDate;
SetEntityTags(entity, _tagRepository);
}
else if (content.PublishedState == PublishedState.Unpublishing)
else if (entity.PublishedState == PublishedState.Unpublishing)
{
content.Published = false;
content.PublishTemplateId = null;
content.PublisherId = null;
content.PublishName = null;
content.PublishDate = null;
entity.Published = false;
entity.PublishTemplateId = null;
entity.PublisherId = null;
entity.PublishName = null;
entity.PublishDate = null;
ClearEntityTags(entity, _tagRepository);
}
@@ -437,34 +436,33 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IContent entity)
{
// however, it's not just so we have access to AddingEntity
// there are tons of things at the end of the methods, that can only work with a true Content
// and basically, the repository requires a Content, not an IContent
var content = (Content)entity;
var entityBase = entity as EntityBase;
var isEntityDirty = entityBase != null && entityBase.IsDirty();
// check if we need to make any database changes at all
if ((content.PublishedState == PublishedState.Published || content.PublishedState == PublishedState.Unpublished)
&& !content.IsEntityDirty() && !content.IsAnyUserPropertyDirty())
if ((entity.PublishedState == PublishedState.Published || entity.PublishedState == PublishedState.Unpublished)
&& !isEntityDirty && !entity.IsAnyUserPropertyDirty())
return; // no change to save, do nothing, don't even update dates
// whatever we do, we must check that we are saving the current version
var version = Database.Fetch<ContentVersionDto>(SqlContext.Sql().Select<ContentVersionDto>().From<ContentVersionDto>().Where<ContentVersionDto>(x => x.Id == content.VersionId)).FirstOrDefault();
var version = Database.Fetch<ContentVersionDto>(SqlContext.Sql().Select<ContentVersionDto>().From<ContentVersionDto>().Where<ContentVersionDto>(x => x.Id == entity.VersionId)).FirstOrDefault();
if (version == null || !version.Current)
throw new InvalidOperationException("Cannot save a non-current version.");
// update
content.UpdatingEntity();
var publishing = content.PublishedState == PublishedState.Publishing;
entity.UpdatingEntity();
var publishing = entity.PublishedState == PublishedState.Publishing;
// check if we need to create a new version
if (publishing && content.PublishedVersionId > 0)
if (publishing && entity.PublishedVersionId > 0)
{
// published version is not published anymore
Database.Execute(Sql().Update<DocumentVersionDto>(u => u.Set(x => x.Published, false)).Where<DocumentVersionDto>(x => x.Id == content.PublishedVersionId));
Database.Execute(Sql().Update<DocumentVersionDto>(u => u.Set(x => x.Published, false)).Where<DocumentVersionDto>(x => x.Id == entity.PublishedVersionId));
}
// sanitize names
SanitizeNames(content, publishing);
SanitizeNames(entity, publishing);
// ensure that strings don't contain characters that are invalid in xml
// TODO: do we really want to keep doing this here?
@@ -504,13 +502,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// and, if publishing, insert new content & document version dtos
if (publishing)
{
content.PublishedVersionId = content.VersionId;
entity.PublishedVersionId = entity.VersionId;
contentVersionDto.Id = 0; // want a new id
contentVersionDto.Current = true; // current version
contentVersionDto.Text = content.Name;
contentVersionDto.Text = entity.Name;
Database.Insert(contentVersionDto);
content.VersionId = documentVersionDto.Id = contentVersionDto.Id; // get the new id
entity.VersionId = documentVersionDto.Id = contentVersionDto.Id; // get the new id
documentVersionDto.Published = false; // non-published version
Database.Insert(documentVersionDto);
@@ -518,31 +516,31 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// replace the property data (rather than updating)
// only need to delete for the version that existed, the new version (if any) has no property data yet
var versionToDelete = publishing ? content.PublishedVersionId : content.VersionId;
var versionToDelete = publishing ? entity.PublishedVersionId : entity.VersionId;
var deletePropertyDataSql = Sql().Delete<PropertyDataDto>().Where<PropertyDataDto>(x => x.VersionId == versionToDelete);
Database.Execute(deletePropertyDataSql);
// insert property data
var propertyDataDtos = PropertyFactory.BuildDtos(content.ContentType.Variations, content.VersionId, publishing ? content.PublishedVersionId : 0,
var propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, publishing ? entity.PublishedVersionId : 0,
entity.Properties, LanguageRepository, out var edited, out var editedCultures);
foreach (var propertyDataDto in propertyDataDtos)
Database.Insert(propertyDataDto);
// if !publishing, we may have a new name != current publish name,
// also impacts 'edited'
if (!publishing && content.PublishName != content.Name)
if (!publishing && entity.PublishName != entity.Name)
edited = true;
if (content.ContentType.VariesByCulture())
if (entity.ContentType.VariesByCulture())
{
// bump dates to align cultures to version
if (publishing)
content.AdjustDates(contentVersionDto.VersionDate);
entity.AdjustDates(contentVersionDto.VersionDate);
// names also impact 'edited'
// ReSharper disable once UseDeconstruction
foreach (var cultureInfo in content.CultureInfos)
if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture))
foreach (var cultureInfo in entity.CultureInfos)
if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture))
{
edited = true;
(editedCultures ?? (editedCultures = new HashSet<string>(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture);
@@ -560,7 +558,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
Database.Execute(deleteContentVariations);
// replace the document version variations (rather than updating)
var deleteDocumentVariations = Sql().Delete<DocumentCultureVariationDto>().Where<DocumentCultureVariationDto>(x => x.NodeId == content.Id);
var deleteDocumentVariations = Sql().Delete<DocumentCultureVariationDto>().Where<DocumentCultureVariationDto>(x => x.NodeId == entity.Id);
Database.Execute(deleteDocumentVariations);
// TODO: NPoco InsertBulk issue?
@@ -570,32 +568,32 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// (same in PersistNewItem above)
// insert content variations
Database.BulkInsertRecords(GetContentVariationDtos(content, publishing));
Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing));
// insert document variations
Database.BulkInsertRecords(GetDocumentVariationDtos(content, publishing, editedCultures));
Database.BulkInsertRecords(GetDocumentVariationDtos(entity, publishing, editedCultures));
}
// refresh content
content.SetCultureEdited(editedCultures);
entity.SetCultureEdited(editedCultures);
// update the document dto
// at that point, when un/publishing, the entity still has its old Published value
// so we need to explicitly update the dto to persist the correct value
if (content.PublishedState == PublishedState.Publishing)
if (entity.PublishedState == PublishedState.Publishing)
dto.Published = true;
else if (content.PublishedState == PublishedState.Unpublishing)
else if (entity.PublishedState == PublishedState.Unpublishing)
dto.Published = false;
content.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
entity.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
Database.Update(dto);
//update the schedule
if (content.IsPropertyDirty("ContentSchedule"))
PersistContentSchedule(content, true);
if (entity.IsPropertyDirty("ContentSchedule"))
PersistContentSchedule(entity, true);
// if entity is publishing, update tags, else leave tags there
// means that implicitly unpublished, or trashed, entities *still* have tags in db
if (content.PublishedState == PublishedState.Publishing)
if (entity.PublishedState == PublishedState.Publishing)
SetEntityTags(entity, _tagRepository);
// trigger here, before we reset Published etc
@@ -603,23 +601,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// flip the entity's published property
// this also flips its published state
if (content.PublishedState == PublishedState.Publishing)
if (entity.PublishedState == PublishedState.Publishing)
{
content.Published = true;
content.PublishTemplateId = content.TemplateId;
content.PublisherId = content.WriterId;
content.PublishName = content.Name;
content.PublishDate = content.UpdateDate;
entity.Published = true;
entity.PublishTemplateId = entity.TemplateId;
entity.PublisherId = entity.WriterId;
entity.PublishName = entity.Name;
entity.PublishDate = entity.UpdateDate;
SetEntityTags(entity, _tagRepository);
}
else if (content.PublishedState == PublishedState.Unpublishing)
else if (entity.PublishedState == PublishedState.Unpublishing)
{
content.Published = false;
content.PublishTemplateId = null;
content.PublisherId = null;
content.PublishName = null;
content.PublishDate = null;
entity.Published = false;
entity.PublishTemplateId = null;
entity.PublisherId = null;
entity.PublishName = null;
entity.PublishDate = null;
ClearEntityTags(entity, _tagRepository);
}
@@ -1335,7 +1333,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Utilities
private void SanitizeNames(Content content, bool publishing)
private void SanitizeNames(IContent content, bool publishing)
{
// a content item *must* have an invariant name, and invariant published name
// else we just cannot write the invariant rows (node, content version...) to the database
@@ -1400,7 +1398,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
x.NodeId != SqlTemplate.Arg<int>("id"))
.OrderBy<ContentVersionCultureVariationDto>(x => x.LanguageId));
private void EnsureVariantNamesAreUnique(Content content, bool publishing)
private void EnsureVariantNamesAreUnique(IContent content, bool publishing)
{
if (!EnsureUniqueNaming || !content.ContentType.VariesByCulture() || content.CultureInfos.Count == 0) return;
@@ -6,6 +6,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
@@ -101,7 +102,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (languageExists == 0) throw new NullReferenceException("No language exists with id " + entity.LanguageId.Value);
}
((UmbracoDomain)entity).AddingEntity();
entity.AddingEntity();
var factory = new DomainModelFactory();
var dto = factory.BuildDto(entity);
@@ -120,7 +121,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IDomain entity)
{
((UmbracoDomain)entity).UpdatingEntity();
entity.UpdatingEntity();
var exists = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoDomain WHERE domainName = @domainName AND umbracoDomain.id <> @id",
new { domainName = entity.DomainName, id = entity.Id });
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IIdentityUserLogin entity)
{
((EntityBase)entity).AddingEntity();
entity.AddingEntity();
var dto = ExternalLoginFactory.BuildDto(entity);
@@ -151,7 +151,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IIdentityUserLogin entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
var dto = ExternalLoginFactory.BuildDto(entity);
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (entity.IsoCode.IsNullOrWhiteSpace() || entity.CultureName.IsNullOrWhiteSpace())
throw new InvalidOperationException("Cannot save a language without an ISO code and a culture name.");
((EntityBase) entity).AddingEntity();
entity.AddingEntity();
// deal with entity becoming the new default entity
if (entity.IsDefault)
@@ -156,7 +156,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (entity.IsoCode.IsNullOrWhiteSpace() || entity.CultureName.IsNullOrWhiteSpace())
throw new InvalidOperationException("Cannot save a language without an ISO code and a culture name.");
((EntityBase) entity).UpdatingEntity();
entity.UpdatingEntity();
if (entity.IsDefault)
{
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMacro entity)
{
((EntityBase)entity).AddingEntity();
entity.AddingEntity();
var dto = MacroFactory.BuildDto(entity);
@@ -152,7 +152,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IMacro entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
;
var dto = MacroFactory.BuildDto(entity);
@@ -8,6 +8,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -217,7 +218,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMedia entity)
{
var media = (Models.Media) entity;
media.AddingEntity();
entity.AddingEntity();
// ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
@@ -5,6 +5,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
@@ -102,7 +103,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMediaType entity)
{
((MediaType)entity).AddingEntity();
entity.AddingEntity();
PersistNewBaseContentType(entity);
@@ -114,7 +115,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
ValidateAlias(entity);
//Updates Modified date
((MediaType)entity).UpdatingEntity();
entity.UpdatingEntity();
//Look up parent to get and set the correct Path if ParentId has changed
if (entity.IsPropertyDirty("ParentId"))
@@ -6,6 +6,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -91,8 +92,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMemberGroup entity)
{
//Save to db
entity.AddingEntity();
var group = (MemberGroup)entity;
group.AddingEntity();
var dto = MemberGroupFactory.BuildDto(group);
var o = Database.IsNew(dto) ? Convert.ToInt32(Database.Insert(dto)) : Database.Update(dto);
group.Id = dto.NodeId; //Set Id on entity to ensure an Id is set
@@ -6,6 +6,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -232,8 +233,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMember entity)
{
if (entity.ProviderUserKey == null)
{
entity.ProviderUserKey = entity.Key;
}
entity.AddingEntity();
var member = (Member) entity;
member.AddingEntity();
// ensure that strings don't contain characters that are invalid in xml
// TODO: do we really want to keep doing this here?
@@ -5,6 +5,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -131,12 +132,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
ValidateAlias(entity);
((MemberType)entity).AddingEntity();
entity.AddingEntity();
//set a default icon if one is not specified
if (entity.Icon.IsNullOrWhiteSpace())
{
entity.Icon = "icon-user";
entity.Icon = Constants.Icons.Member;
}
//By Convention we add 9 standard PropertyTypes to an Umbraco MemberType
@@ -165,7 +166,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
ValidateAlias(entity);
//Updates Modified date
((MemberType)entity).UpdatingEntity();
entity.UpdatingEntity();
//Look up parent to get and set the correct Path if ParentId has changed
if (entity.IsPropertyDirty("ParentId"))
@@ -224,6 +225,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
propertyType.DataTypeId = 0;
propertyType.DataTypeKey = default;
}
}
}
@@ -5,6 +5,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -134,7 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IRelation entity)
{
((EntityBase)entity).AddingEntity();
entity.AddingEntity();
var factory = new RelationFactory(entity.RelationType);
var dto = factory.BuildDto(entity);
@@ -147,7 +147,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IRelation entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
var factory = new RelationFactory(entity.RelationType);
var dto = factory.BuildDto(entity);
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IRelationType entity)
{
((EntityBase)entity).AddingEntity();
entity.AddingEntity();
var dto = RelationTypeFactory.BuildDto(entity);
@@ -145,7 +145,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IRelationType entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
var dto = RelationTypeFactory.BuildDto(entity);
Database.Update(dto);
@@ -5,6 +5,7 @@ using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
@@ -96,7 +97,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IServerRegistration entity)
{
((ServerRegistration)entity).AddingEntity();
entity.AddingEntity();
var dto = ServerRegistrationFactory.BuildDto(entity);
@@ -108,7 +109,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IServerRegistration entity)
{
((ServerRegistration)entity).UpdatingEntity();
entity.UpdatingEntity();
var dto = ServerRegistrationFactory.BuildDto(entity);
@@ -85,7 +85,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <inheritdoc />
protected override void PersistNewItem(ITag entity)
{
((EntityBase)entity).AddingEntity();
entity.AddingEntity();
var dto = TagFactory.BuildDto(entity);
var id = Convert.ToInt32(Database.Insert(dto));
@@ -97,7 +97,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <inheritdoc />
protected override void PersistUpdatedItem(ITag entity)
{
((EntityBase)entity).UpdatingEntity();
entity.UpdatingEntity();
var dto = TagFactory.BuildDto(entity);
Database.Update(dto);
@@ -290,7 +290,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IUserGroup entity)
{
((UserGroup) entity).AddingEntity();
entity.AddingEntity();
var userGroupDto = UserGroupFactory.BuildDto(entity);
@@ -304,7 +304,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistUpdatedItem(IUserGroup entity)
{
((UserGroup) entity).UpdatingEntity();
entity.UpdatingEntity();
var userGroupDto = UserGroupFactory.BuildDto(entity);
@@ -445,7 +445,7 @@ ORDER BY colName";
return;
}
((User) entity).AddingEntity();
entity.AddingEntity();
// ensure security stamp if missing
if (entity.SecurityStamp.IsNullOrWhiteSpace())
@@ -495,7 +495,7 @@ ORDER BY colName";
protected override void PersistUpdatedItem(IUser entity)
{
// updates Modified date
((User) entity).UpdatingEntity();
entity.UpdatingEntity();
// ensure security stamp if missing
if (entity.SecurityStamp.IsNullOrWhiteSpace())
@@ -30,7 +30,7 @@ namespace Umbraco.Core.PropertyEditors
// defaults
Type = type;
Icon = Constants.Icons.PropertyEditor;
Group = "common";
Group = Constants.PropertyEditors.Groups.Common;
// assign properties based on the attribute, if it is found
Attribute = GetType().GetCustomAttribute<DataEditorAttribute>(false);
@@ -121,7 +121,7 @@ namespace Umbraco.Core.PropertyEditors
/// Gets or sets an optional group.
/// </summary>
/// <remarks>The group can be used for example to group the editors by category.</remarks>
public string Group { get; set; } = "common";
public string Group { get; set; } = Constants.PropertyEditors.Groups.Common;
/// <summary>
/// Gets or sets a value indicating whether the value editor is deprecated.
@@ -0,0 +1,10 @@
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Marker interface for any editor configuration that supports Ignoring user start nodes
/// </summary>
internal interface IIgnoreUserStartNodesConfig
{
bool IgnoreUserStartNodes { get; set; }
}
}
@@ -5,7 +5,11 @@ namespace Umbraco.Core.PropertyEditors
/// <summary>
/// Represents a property editor for label properties.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.Label, "Label", "readonlyvalue", Icon = "icon-readonly")]
[DataEditor(
Constants.PropertyEditors.Aliases.Label,
"Label",
"readonlyvalue",
Icon = "icon-readonly")]
public class LabelPropertyEditor : DataEditor
{
/// <summary>
+14 -6
View File
@@ -103,18 +103,26 @@ namespace Umbraco.Core
/// Gets the children of the content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">The specific culture to get the url children for. If null is used the current culture is used (Default is null).</param>
/// <param name="culture">
/// The specific culture to get the url children for. Default is null which will use the current culture in <see cref="VariationContext"/>
/// </param>
/// <remarks>
/// <para>Gets children that are available for the specified culture.</para>
/// <para>Children are sorted by their sortOrder.</para>
/// <para>The '*' culture and supported and returns everything.</para>
/// <para>
/// For culture,
/// if null is used the current culture is used.
/// If an empty string is used only invariant children are returned.
/// If "*" is used all children are returned.
/// </para>
/// <para>
/// If a variant culture is specified or there is a current culture in the <see cref="VariationContext"/> then the Children returned
/// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture.
/// However, if an empty string is specified only invariant children are returned.
/// </para>
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
{
// invariant has invariant value (whatever the requested culture)
if (!content.ContentType.VariesByCulture() && culture != "*")
culture = "";
// handle context culture for variant
if (culture == null)
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
@@ -9,7 +9,14 @@ namespace Umbraco.Core
public static class PublishedModelFactoryExtensions
{
/// <summary>
/// Executes an action with a safe live factory/
/// Returns true if the current <see cref="IPublishedModelFactory"/> is an implementation of <see cref="ILivePublishedModelFactory"/>
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public static bool IsLiveFactory(this IPublishedModelFactory factory) => factory is ILivePublishedModelFactory;
/// <summary>
/// Executes an action with a safe live factory
/// </summary>
/// <remarks>
/// <para>If the factory is a live factory, ensures it is refreshed and locked while executing the action.</para>
@@ -20,6 +27,7 @@ namespace Umbraco.Core
{
lock (liveFactory.SyncRoot)
{
//Call refresh on the live factory to re-compile the models
liveFactory.Refresh();
action();
}
+3 -3
View File
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Runtime
// there should be none, really - this is here "just in case"
Compose(composition);
// acquire the main domain
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
AcquireMainDom(mainDom);
// determine our runtime level
@@ -218,13 +218,13 @@ namespace Umbraco.Core.Runtime
IOHelper.SetRootDirectory(path);
}
private void AcquireMainDom(MainDom mainDom)
private bool AcquireMainDom(MainDom mainDom)
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
mainDom.Acquire();
return mainDom.Acquire();
}
catch
{
+5
View File
@@ -97,6 +97,11 @@ namespace Umbraco.Core
/// <param name="request"></param>
internal void EnsureApplicationUrl(HttpRequestBase request = null)
{
//Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that
// it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part
// about this is that this is here specifically for the slot swap scenario https://issues.umbraco.org/issue/U4-10626
// see U4-10626 - in some cases we want to reset the application url
// (this is a simplified version of what was in 7.x)
// note: should this be optional? is it expensive?
@@ -6,9 +6,25 @@ namespace Umbraco.Core.Services.Changes
public enum ContentTypeChangeTypes : byte
{
None = 0,
Create = 1, // item type has been created, no impact
RefreshMain = 2, // changed, impacts content (adding property or composition does NOT)
RefreshOther = 4, // changed, other changes
Remove = 8 // item type has been removed
/// <summary>
/// Item type has been created, no impact
/// </summary>
Create = 1,
/// <summary>
/// Content type changes impact only the Content type being saved
/// </summary>
RefreshMain = 2,
/// <summary>
/// Content type changes impacts the content type being saved and others used that are composed of it
/// </summary>
RefreshOther = 4, // changed, other change
/// <summary>
/// Content type was removed
/// </summary>
Remove = 8
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -11,6 +12,42 @@ namespace Umbraco.Core.Services
/// </summary>
public static class ContentServiceExtensions
{
#region RTE Anchor values
private static readonly Regex AnchorRegex = new Regex("<a id=\"(.*?)\">", RegexOptions.Compiled);
internal static IEnumerable<string> GetAnchorValuesFromRTEs(this IContentService contentService, int id, string culture = "*")
{
var result = new List<string>();
var content = contentService.GetById(id);
foreach (var contentProperty in content.Properties)
{
if (contentProperty.PropertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.TinyMce))
{
var value = contentProperty.GetValue(culture)?.ToString();
if (!string.IsNullOrEmpty(value))
{
result.AddRange(contentService.GetAnchorValuesFromRTEContent(value));
}
}
}
return result;
}
internal static IEnumerable<string> GetAnchorValuesFromRTEContent(this IContentService contentService, string rteContent)
{
var result = new List<string>();
var matches = AnchorRegex.Matches(rteContent);
foreach (Match match in matches)
{
result.Add(match.Value.Split('\"')[1]);
}
return result;
}
#endregion
public static IEnumerable<IContent> GetByIds(this IContentService contentService, IEnumerable<Udi> ids)
{
var guids = new List<GuidUdi>();
@@ -0,0 +1,21 @@
using System;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Services
{
internal static class DateTypeServiceExtensions
{
public static bool IsDataTypeIgnoringUserStartNodes(this IDataTypeService dataTypeService, Guid key)
{
if (DataTypeExtensions.IsBuildInDataType(key)) return false; //built in ones can never be ignoring start nodes
var dataType = dataTypeService.GetDataType(key);
if (dataType != null && dataType.Configuration is IIgnoreUserStartNodesConfig ignoreStartNodesConfig)
return ignoreStartNodesConfig.IgnoreUserStartNodes;
return false;
}
}
}
@@ -526,5 +526,6 @@ namespace Umbraco.Core.Services
OperationResult Rollback(int id, int versionId, string culture = "*", int userId = Constants.Security.SuperUserId);
#endregion
}
}
@@ -4,6 +4,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Services
{
/// <summary>
/// Defines the DataType Service, which is an easy access to operations involving <see cref="IDataType"/>
/// </summary>
@@ -51,8 +51,8 @@ namespace Umbraco.Core.Services.Implement
using (var scope = ScopeProvider.CreateScope())
{
var result = sinceDate.HasValue == false
? _auditRepository.Get(Query<IAuditItem>().Where(x => x.UserId == userId && x.AuditType == type))
: _auditRepository.Get(Query<IAuditItem>().Where(x => x.UserId == userId && x.AuditType == type && x.CreateDate >= sinceDate.Value));
? _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.UserId == userId))
: _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.UserId == userId && x.CreateDate >= sinceDate.Value));
scope.Complete();
return result;
}
@@ -63,8 +63,8 @@ namespace Umbraco.Core.Services.Implement
using (var scope = ScopeProvider.CreateScope())
{
var result = sinceDate.HasValue == false
? _auditRepository.Get(Query<IAuditItem>().Where(x => x.AuditType == type))
: _auditRepository.Get(Query<IAuditItem>().Where(x => x.AuditType == type && x.CreateDate >= sinceDate.Value));
? _auditRepository.Get(type, Query<IAuditItem>())
: _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.CreateDate >= sinceDate.Value));
scope.Complete();
return result;
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
@@ -31,6 +32,7 @@ namespace Umbraco.Core.Services.Implement
private IQuery<IContent> _queryNotTrashed;
//TODO: The non-lazy object should be injected
private readonly Lazy<PropertyValidationService> _propertyValidationService = new Lazy<PropertyValidationService>(() => new PropertyValidationService());
#region Constructors
@@ -3024,5 +3026,8 @@ namespace Umbraco.Core.Services.Implement
}
#endregion
}
}
+11 -2
View File
@@ -13,7 +13,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
@@ -23,7 +23,7 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
@@ -55,6 +55,11 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Microsoft.SourceLink.GitHub">
<Version>1.0.0-beta2-19324-01</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Async">
<Version>1.3.0</Version>
</PackageReference>
@@ -236,7 +241,9 @@
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DefaultPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RenamingPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DropDownFlexiblePreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
<Compile Include="Models\Entities\EntityExtensions.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueDto.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\PropertyEditorsMigrationBase.cs" />
@@ -258,6 +265,7 @@
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
<Compile Include="Models\PublishedContent\IPublishedPropertyType.cs" />
<Compile Include="PropertyEditors\IIgnoreUserStartNodesConfig.cs" />
<Compile Include="PublishedContentExtensions.cs" />
<Compile Include="Models\PublishedContent\UrlMode.cs" />
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
@@ -267,6 +275,7 @@
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
<Compile Include="PublishedModelFactoryExtensions.cs" />
<Compile Include="Services\DateTypeServiceExtensions.cs" />
<Compile Include="Services\PropertyValidationService.cs" />
<Compile Include="Composing\TypeCollectionBuilderBase.cs" />
<Compile Include="TypeLoaderExtensions.cs" />
+2
View File
@@ -23,6 +23,8 @@ namespace Umbraco.Core
handle,
(state, timedOut) =>
{
//TODO: We aren't checking if this is timed out
tcs.SetResult(null);
// we take a lock here to make sure the outer method has completed setting the local variable callbackHandle.
+1 -1
View File
@@ -45,7 +45,7 @@ namespace Umbraco.Examine
continue;
case string strVal:
{
if (strVal.IsNullOrWhiteSpace()) return;
if (strVal.IsNullOrWhiteSpace()) continue;
var key = $"{keyVal.Key}{cultureSuffix}";
if (values.TryGetValue(key, out var v))
values[key] = new List<object>(v) { val }.ToArray();
+28 -1
View File
@@ -48,6 +48,31 @@ namespace Umbraco.Examine
}
}
/// <summary>
/// Returns all index fields that are culture specific (suffixed) or invariant
/// </summary>
/// <param name="index"></param>
/// <param name="culture"></param>
/// <returns></returns>
public static IEnumerable<string> GetCultureAndInvariantFields(this IUmbracoIndex index, string culture)
{
var allFields = index.GetFields();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var field in allFields)
{
var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
{
yield return field; //matches this culture field
}
else if (!match.Success)
{
yield return field; //matches no culture field (invariant)
}
}
}
internal static bool TryParseLuceneQuery(string query)
{
// TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
@@ -77,7 +102,7 @@ namespace Umbraco.Examine
/// <remarks>
/// This is not thread safe, use with care
/// </remarks>
internal static void UnlockLuceneIndexes(this IExamineManager examineManager, ILogger logger)
internal static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
{
foreach (var luceneIndexer in examineManager.Indexes.OfType<LuceneIndex>())
{
@@ -86,6 +111,8 @@ namespace Umbraco.Examine
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
luceneIndexer.WaitForIndexQueueOnShutdown = false;
if (disableExamineIndexing) continue; //exit if not enabled, we don't need to unlock them if we're not maindom
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
//the indexes are not operational unless MainDom is true
var dir = luceneIndexer.GetLuceneDirectory();
+7 -2
View File
@@ -13,7 +13,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
@@ -23,7 +23,7 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
@@ -49,6 +49,11 @@
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub">
<Version>1.0.0-beta2-19324-01</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="NPoco" Version="3.9.4" />
</ItemGroup>
@@ -0,0 +1,86 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http.Controllers;
using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Membership;
namespace Umbraco.ModelsBuilder.Api
{
//TODO: This needs to be changed:
// * Authentication cannot happen in a filter, only Authorization
// * The filter must be an AuthorizationFilter, not an ActionFilter
// * Authorization must be done using the Umbraco logic - it is very specific for claim checking for ASP.Net Identity
// * Theoretically this shouldn't be required whatsoever because when we authenticate a request that has Basic Auth (i.e. for
// VS to work, it will add the correct Claims to the Identity and it will automatically be authorized.
//
// we *do* have POC supporting ASP.NET identity, however they require some config on the server
// we'll keep using this quick-and-dirty method for the time being
public class ApiBasicAuthFilter : System.Web.Http.Filters.ActionFilterAttribute // use the http one, not mvc, with api controllers!
{
private static readonly char[] Separator = ":".ToCharArray();
private readonly string _section;
public ApiBasicAuthFilter(string section)
{
_section = section;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
try
{
var user = Authenticate(actionContext.Request);
if (user == null || !user.AllowedSections.Contains(_section))
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
//else
//{
// // note - would that be a proper way to pass data to the controller?
// // see http://stevescodingblog.co.uk/basic-authentication-with-asp-net-webapi/
// actionContext.ControllerContext.RouteData.Values["umbraco-user"] = user;
//}
base.OnActionExecuting(actionContext);
}
catch
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
}
private static IUser Authenticate(HttpRequestMessage request)
{
var ah = request.Headers.Authorization;
if (ah == null || ah.Scheme != "Basic")
return null;
var token = ah.Parameter;
var credentials = Encoding.ASCII
.GetString(Convert.FromBase64String(token))
.Split(Separator);
if (credentials.Length != 2)
return null;
var username = ApiClient.DecodeTokenElement(credentials[0]);
var password = ApiClient.DecodeTokenElement(credentials[1]);
var providerKey = UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider;
var provider = Membership.Providers[providerKey];
if (provider == null || !provider.ValidateUser(username, password))
return null;
var user = Current.Services.UserService.GetByUsername(username);
if (!user.IsApproved || user.IsLockedOut)
return null;
return user;
}
}
}
+159
View File
@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
namespace Umbraco.ModelsBuilder.Api
{
public class ApiClient
{
private readonly string _url;
private readonly string _user;
private readonly string _password;
private readonly JsonMediaTypeFormatter _formatter;
private readonly MediaTypeFormatter[] _formatters;
// fixme hardcoded?
// could be options - but we cannot "discover" them as the API client runs outside of the web app
// in addition, anything that references the controller forces API clients to reference Umbraco.Core
private const string ApiControllerUrl = "/Umbraco/BackOffice/ModelsBuilder/ModelsBuilderApi/";
public ApiClient(string url, string user, string password)
{
_url = url.TrimEnd('/');
_user = user;
_password = password;
_formatter = new JsonMediaTypeFormatter();
_formatters = new MediaTypeFormatter[] { _formatter };
}
private void SetBaseAddress(HttpClient client, string url)
{
try
{
client.BaseAddress = new Uri(url);
}
catch
{
throw new UriFormatException($"Invalid URI: the format of the URI \"{url}\" could not be determined.");
}
}
public void ValidateClientVersion()
{
// FIXME - add proxys support
var hch = new HttpClientHandler();
using (var client = new HttpClient(hch))
{
SetBaseAddress(client, _url);
Authorize(client);
var data = new ValidateClientVersionData
{
ClientVersion = ApiVersion.Current.Version,
MinServerVersionSupportingClient = ApiVersion.Current.MinServerVersionSupportingClient,
};
var result = client.PostAsync(_url + ApiControllerUrl + nameof(ModelsBuilderApiController.ValidateClientVersion),
data, _formatter).Result;
// this is not providing enough details in case of an error - do our own reporting
//result.EnsureSuccessStatusCode();
EnsureSuccess(result);
}
}
public IDictionary<string, string> GetModels(Dictionary<string, string> ourFiles, string modelsNamespace)
{
// FIXME - add proxys support
var hch = new HttpClientHandler();
//hch.Proxy = new WebProxy("path.to.proxy", 8888);
//hch.UseProxy = true;
using (var client = new HttpClient(hch))
{
SetBaseAddress(client, _url);
Authorize(client);
var data = new GetModelsData
{
Namespace = modelsNamespace,
ClientVersion = ApiVersion.Current.Version,
MinServerVersionSupportingClient = ApiVersion.Current.MinServerVersionSupportingClient,
Files = ourFiles
};
var result = client.PostAsync(_url + ApiControllerUrl + nameof(ModelsBuilderApiController.GetModels),
data, _formatter).Result;
// this is not providing enough details in case of an error - do our own reporting
//result.EnsureSuccessStatusCode();
EnsureSuccess(result);
var genFiles = result.Content.ReadAsAsync<IDictionary<string, string>>(_formatters).Result;
return genFiles;
}
}
private static void EnsureSuccess(HttpResponseMessage result)
{
if (result.IsSuccessStatusCode) return;
var text = result.Content.ReadAsStringAsync().Result;
throw new Exception($"Response status code does not indicate success ({result.StatusCode})\n{text}");
}
private void Authorize(HttpClient client)
{
AuthorizeBasic(client);
}
// fixme - for the time being, we don't cache the token and we auth on each API call
// not used at the moment
/*
private void AuthorizeIdentity(HttpClient client)
{
var formData = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("userName", _user),
new KeyValuePair<string, string>("password", _password),
});
var result = client.PostAsync(_url + UmbracoOAuthTokenUrl, formData).Result;
EnsureSuccess(result);
var token = result.Content.ReadAsAsync<TokenData>(_formatters).Result;
if (token.TokenType != "bearer")
throw new Exception($"Received invalid token type \"{token.TokenType}\", expected \"bearer\".");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
}
*/
private void AuthorizeBasic(HttpClient client)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.UTF8.GetBytes(EncodeTokenElement(_user) + ':' + EncodeTokenElement(_password))));
}
public static string EncodeTokenElement(string s)
{
return s.Replace("%", "%a").Replace(":", "%b");
}
public static string DecodeTokenElement(string s)
{
return s.Replace("%b", ":").Replace("%a", "%");
}
}
}
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Text;
using Umbraco.ModelsBuilder.Building;
using Umbraco.ModelsBuilder.Umbraco;
namespace Umbraco.ModelsBuilder.Api
{
internal static class ApiHelper
{
public static Dictionary<string, string> GetModels(UmbracoServices umbracoServices, string modelsNamespace, IDictionary<string, string> files)
{
var typeModels = umbracoServices.GetAllTypes();
var parseResult = new CodeParser().ParseWithReferencedAssemblies(files);
var builder = new TextBuilder(typeModels, parseResult, modelsNamespace);
var models = new Dictionary<string, string>();
foreach (var typeModel in builder.GetModelsToGenerate())
{
var sb = new StringBuilder();
builder.Generate(sb, typeModel);
models[typeModel.ClrName] = sb.ToString();
}
return models;
}
}
}
+61 -9
View File
@@ -1,6 +1,5 @@
using System;
using System.Reflection;
using Semver;
namespace Umbraco.ModelsBuilder.Api
{
@@ -9,28 +8,81 @@ namespace Umbraco.ModelsBuilder.Api
/// </summary>
public class ApiVersion
{
#region Configure
// indicate the minimum version of the client API that is supported by this server's API.
// eg our Version = 4.8 but we support connections from VSIX down to version 3.2
// => as a server, we accept connections from client down to version ...
private static readonly Version MinClientVersionSupportedByServerConst = new Version(3, 0, 0, 0);
// indicate the minimum version of the server that can support the client API
// eg our Version = 4.8 and we know we're compatible with website server down to version 3.2
// => as a client, we tell the server down to version ... that it should accept us
private static readonly Version MinServerVersionSupportingClientConst = new Version(3, 0, 0, 0);
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="ApiVersion"/> class.
/// </summary>
/// <param name="executingVersion">The currently executing version.</param>
/// <exception cref="ArgumentNullException"></exception>
internal ApiVersion(SemVersion executingVersion)
/// <param name="minClientVersionSupportedByServer">The min client version supported by the server.</param>
/// <param name="minServerVersionSupportingClient">An opt min server version supporting the client.</param>
internal ApiVersion(Version executingVersion, Version minClientVersionSupportedByServer, Version minServerVersionSupportingClient = null)
{
Version = executingVersion ?? throw new ArgumentNullException(nameof(executingVersion));
}
if (executingVersion == null) throw new ArgumentNullException(nameof(executingVersion));
if (minClientVersionSupportedByServer == null) throw new ArgumentNullException(nameof(minClientVersionSupportedByServer));
private static SemVersion CurrentAssemblyVersion
=> SemVersion.Parse(Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion);
Version = executingVersion;
MinClientVersionSupportedByServer = minClientVersionSupportedByServer;
MinServerVersionSupportingClient = minServerVersionSupportingClient;
}
/// <summary>
/// Gets the currently executing API version.
/// </summary>
public static ApiVersion Current { get; }
= new ApiVersion(CurrentAssemblyVersion);
= new ApiVersion(Assembly.GetExecutingAssembly().GetName().Version,
MinClientVersionSupportedByServerConst, MinServerVersionSupportingClientConst);
/// <summary>
/// Gets the executing version of the API.
/// </summary>
public SemVersion Version { get; }
public Version Version { get; }
/// <summary>
/// Gets the min client version supported by the server.
/// </summary>
public Version MinClientVersionSupportedByServer { get; }
/// <summary>
/// Gets the min server version supporting the client.
/// </summary>
public Version MinServerVersionSupportingClient { get; }
/// <summary>
/// Gets a value indicating whether the API server is compatible with a client.
/// </summary>
/// <param name="clientVersion">The client version.</param>
/// <param name="minServerVersionSupportingClient">An opt min server version supporting the client.</param>
/// <remarks>
/// <para>A client is compatible with a server if the client version is greater-or-equal _minClientVersionSupportedByServer
/// (ie client can be older than server, up to a point) AND the client version is lower-or-equal the server version
/// (ie client cannot be more recent than server) UNLESS the server .</para>
/// </remarks>
public bool IsCompatibleWith(Version clientVersion, Version minServerVersionSupportingClient = null)
{
// client cannot be older than server's min supported version
if (clientVersion < MinClientVersionSupportedByServer)
return false;
// if we know about this client (client is older than server), it is supported
if (clientVersion <= Version) // if we know about this client (client older than server)
return true;
// if we don't know about this client (client is newer than server),
// give server a chance to tell client it is, indeed, ok to support it
return minServerVersionSupportingClient != null && minServerVersionSupportingClient <= Version;
}
}
}
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.ModelsBuilder.Api
{
[DataContract]
public class GetModelsData : ValidateClientVersionData
{
[DataMember]
public string Namespace { get; set; }
[DataMember]
public IDictionary<string, string> Files { get; set; }
public override bool IsValid => base.IsValid && Files != null;
}
}
@@ -0,0 +1,85 @@
using System;
using System.Net;
using System.Net.Http;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.ModelsBuilder.Configuration;
using Umbraco.ModelsBuilder.Umbraco;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
namespace Umbraco.ModelsBuilder.Api
{
// read http://umbraco.com/follow-us/blog-archive/2014/1/17/heads-up,-breaking-change-coming-in-702-and-62.aspx
// read http://our.umbraco.org/forum/developers/api-questions/43025-Web-API-authentication
// UmbracoAuthorizedApiController :: /Umbraco/BackOffice/Zbu/ModelsBuilderApi/GetTypeModels
// UmbracoApiController :: /Umbraco/Zbu/ModelsBuilderApi/GetTypeModels ?? UNLESS marked with isbackoffice
//
// BEWARE! the controller url is hard-coded in ModelsBuilderApi and needs to be in sync!
[PluginController(ControllerArea)]
[IsBackOffice]
//[UmbracoApplicationAuthorize(Constants.Applications.Developer)] // see ApiBasicAuthFilter - that one would be for ASP.NET identity
public class ModelsBuilderApiController : UmbracoApiController // UmbracoAuthorizedApiController - for ASP.NET identity
{
public const string ControllerArea = "ModelsBuilder";
private readonly UmbracoServices _umbracoServices;
public ModelsBuilderApiController(UmbracoServices umbracoServices)
{
_umbracoServices = umbracoServices;
}
// invoked by the API
[System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers!
[ApiBasicAuthFilter("developer")] // have to use our own, non-cookie-based, auth
public HttpResponseMessage ValidateClientVersion(ValidateClientVersionData data)
{
if (!UmbracoConfig.For.ModelsBuilder().ApiServer)
return Request.CreateResponse(HttpStatusCode.Forbidden, "API server does not want to talk to you.");
if (!ModelState.IsValid || data == null || !data.IsValid)
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid data.");
var checkResult = CheckVersion(data.ClientVersion, data.MinServerVersionSupportingClient);
return (checkResult.Success
? Request.CreateResponse(HttpStatusCode.OK, "OK", Configuration.Formatters.JsonFormatter)
: checkResult.Result);
}
// invoked by the API
[System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers!
[ApiBasicAuthFilter("developer")] // have to use our own, non-cookie-based, auth
public HttpResponseMessage GetModels(GetModelsData data)
{
if (!UmbracoConfig.For.ModelsBuilder().ApiServer)
return Request.CreateResponse(HttpStatusCode.Forbidden, "API server does not want to talk to you.");
if (!ModelState.IsValid || data == null || !data.IsValid)
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid data.");
var checkResult = CheckVersion(data.ClientVersion, data.MinServerVersionSupportingClient);
if (!checkResult.Success)
return checkResult.Result;
var models = ApiHelper.GetModels(_umbracoServices, data.Namespace, data.Files);
return Request.CreateResponse(HttpStatusCode.OK, models, Configuration.Formatters.JsonFormatter);
}
private Attempt<HttpResponseMessage> CheckVersion(Version clientVersion, Version minServerVersionSupportingClient)
{
if (clientVersion == null)
return Attempt<HttpResponseMessage>.Fail(Request.CreateResponse(HttpStatusCode.Forbidden,
$"API version conflict: client version (<null>) is not compatible with server version({ApiVersion.Current.Version})."));
// minServerVersionSupportingClient can be null
var isOk = ApiVersion.Current.IsCompatibleWith(clientVersion, minServerVersionSupportingClient);
var response = isOk ? null : Request.CreateResponse(HttpStatusCode.Forbidden,
$"API version conflict: client version ({clientVersion}) is not compatible with server version({ApiVersion.Current.Version}).");
return Attempt<HttpResponseMessage>.If(isOk, response);
}
}
}
@@ -0,0 +1,17 @@
using System.Runtime.Serialization;
namespace Umbraco.ModelsBuilder.Api
{
[DataContract]
class TokenData
{
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "token_type")]
public string TokenType { get; set; }
[DataMember(Name = "expires_in")]
public int ExpiresIn { get; set; }
}
}
@@ -0,0 +1,57 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.ModelsBuilder.Api
{
[DataContract]
public class ValidateClientVersionData
{
// issues 32, 34... problems when serializing versions
//
// make sure System.Version objects are transfered as strings
// depending on the JSON serializer version, it looks like versions are causing issues
// see
// http://stackoverflow.com/questions/13170386/why-system-version-in-json-string-does-not-deserialize-correctly
//
// if the class is marked with [DataContract] then only properties marked with [DataMember]
// are serialized and the rest is ignored, see
// http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
[DataMember]
public string ClientVersionString
{
get { return VersionToString(ClientVersion); }
set { ClientVersion = ParseVersion(value, false, "client"); }
}
[DataMember]
public string MinServerVersionSupportingClientString
{
get { return VersionToString(MinServerVersionSupportingClient); }
set { MinServerVersionSupportingClient = ParseVersion(value, true, "minServer"); }
}
// not serialized
public Version ClientVersion { get; set; }
public Version MinServerVersionSupportingClient { get; set; }
private static string VersionToString(Version version)
{
return version?.ToString() ?? "0.0.0.0";
}
private static Version ParseVersion(string value, bool canBeNull, string name)
{
if (string.IsNullOrWhiteSpace(value) && canBeNull)
return null;
Version version;
if (Version.TryParse(value, out version))
return version;
throw new ArgumentException($"Failed to parse \"{value}\" as {name} version.");
}
public virtual bool IsValid => ClientVersion != null;
}
}
+120 -34
View File
@@ -5,7 +5,6 @@ using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.ModelsBuilder.Configuration;
@@ -26,8 +25,7 @@ namespace Umbraco.ModelsBuilder.Building
private readonly IList<TypeModel> _typeModels;
protected Dictionary<string, string> ModelsMap { get; } = new Dictionary<string, string>();
private static Config Config => Current.Configs.ModelsBuilder();
protected ParseResult ParseResult { get; }
// the list of assemblies that will be 'using' by default
protected readonly IList<string> TypesUsing = new List<string>
@@ -60,7 +58,7 @@ namespace Umbraco.ModelsBuilder.Building
/// <returns>The models to generate, ie those that are not ignored.</returns>
public IEnumerable<TypeModel> GetModelsToGenerate()
{
return _typeModels;
return _typeModels.Where(x => !x.IsContentIgnored);
}
/// <summary>
@@ -74,25 +72,27 @@ namespace Umbraco.ModelsBuilder.Building
/// and the result of code parsing.
/// </summary>
/// <param name="typeModels">The list of models to generate.</param>
protected Builder(IList<TypeModel> typeModels)
: this(typeModels, null)
{ }
/// <param name="parseResult">The result of code parsing.</param>
protected Builder(IList<TypeModel> typeModels, ParseResult parseResult)
{
_typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels));
ParseResult = parseResult ?? throw new ArgumentNullException(nameof(parseResult));
Prepare();
}
/// <summary>
/// Initializes a new instance of the <see cref="Builder"/> class with a list of models to generate,
/// the result of code parsing, and a models namespace.
/// </summary>
/// <param name="typeModels">The list of models to generate.</param>
/// <param name="parseResult">The result of code parsing.</param>
/// <param name="modelsNamespace">The models namespace.</param>
protected Builder(IList<TypeModel> typeModels, string modelsNamespace)
protected Builder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
: this(typeModels, parseResult)
{
_typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels));
// can be null or empty, we'll manage
ModelsNamespace = modelsNamespace;
// but we want it to prepare
Prepare();
}
// for unit tests only
@@ -108,9 +108,49 @@ namespace Umbraco.ModelsBuilder.Building
/// </remarks>
private void Prepare()
{
TypeModel.MapModelTypes(_typeModels, ModelsNamespace);
var pureLive = UmbracoConfig.For.ModelsBuilder().ModelsMode == ModelsMode.PureLive;
var pureLive = Config.ModelsMode == ModelsMode.PureLive;
// mark IsContentIgnored models that we discovered should be ignored
// then propagate / ignore children of ignored contents
// ignore content = don't generate a class for it, don't generate children
foreach (var typeModel in _typeModels.Where(x => ParseResult.IsIgnored(x.Alias)))
typeModel.IsContentIgnored = true;
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored && x.EnumerateBaseTypes().Any(xx => xx.IsContentIgnored)))
typeModel.IsContentIgnored = true;
// handle model renames
foreach (var typeModel in _typeModels.Where(x => ParseResult.IsContentRenamed(x.Alias)))
{
typeModel.ClrName = ParseResult.ContentClrName(typeModel.Alias);
typeModel.IsRenamed = true;
ModelsMap[typeModel.Alias] = typeModel.ClrName;
}
// handle implement
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasContentImplement(x.Alias)))
{
typeModel.HasImplement = true;
}
// mark OmitBase models that we discovered already have a base class
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasContentBase(ParseResult.ContentClrName(x.Alias) ?? x.ClrName)))
typeModel.HasBase = true;
foreach (var typeModel in _typeModels)
{
// mark IsRemoved properties that we discovered should be ignored
// ie is marked as ignored on type, or on any parent type
var tm = typeModel;
foreach (var property in typeModel.Properties
.Where(property => tm.EnumerateBaseTypes(true).Any(x => ParseResult.IsPropertyIgnored(ParseResult.ContentClrName(x.Alias) ?? x.ClrName, property.Alias))))
{
property.IsIgnored = true;
}
// handle property renames
foreach (var property in typeModel.Properties)
property.ClrName = ParseResult.PropertyClrName(ParseResult.ContentClrName(typeModel.Alias) ?? typeModel.ClrName, property.Alias) ?? property.ClrName;
}
// for the first two of these two tests,
// always throw, even in purelive: cannot happen unless ppl start fidling with attributes to rename
@@ -118,22 +158,22 @@ namespace Umbraco.ModelsBuilder.Building
// for the last one, don't throw in purelive, see comment
// ensure we have no duplicates type names
foreach (var xx in _typeModels.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
foreach (var xx in _typeModels.Where(x => !x.IsContentIgnored).GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
throw new InvalidOperationException($"Type name \"{xx.Key}\" is used"
+ $" for types with alias {string.Join(", ", xx.Select(x => x.ItemType + ":\"" + x.Alias + "\""))}. Names have to be unique."
+ " Consider using an attribute to assign different names to conflicting types.");
// ensure we have no duplicates property names
foreach (var typeModel in _typeModels)
foreach (var xx in typeModel.Properties.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored))
foreach (var xx in typeModel.Properties.Where(x => !x.IsIgnored).GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
throw new InvalidOperationException($"Property name \"{xx.Key}\" in type {typeModel.ItemType}:\"{typeModel.Alias}\""
+ $" is used for properties with alias {string.Join(", ", xx.Select(x => "\"" + x.Alias + "\""))}. Names have to be unique."
+ " Consider using an attribute to assign different names to conflicting properties.");
// ensure content & property type don't have identical name (csharp hates it)
foreach (var typeModel in _typeModels)
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored))
{
foreach (var xx in typeModel.Properties.Where(x => x.ClrName == typeModel.ClrName))
foreach (var xx in typeModel.Properties.Where(x => !x.IsIgnored && x.ClrName == typeModel.ClrName))
{
if (!pureLive)
throw new InvalidOperationException($"The model class for content type with alias \"{typeModel.Alias}\" is named \"{xx.ClrName}\"."
@@ -164,7 +204,7 @@ namespace Umbraco.ModelsBuilder.Building
// collect all the (non-removed) types implemented at parent level
// ie the parent content types and the mixins content types, recursively
var parentImplems = new List<TypeModel>();
if (typeModel.BaseType != null)
if (typeModel.BaseType != null && !typeModel.BaseType.IsContentIgnored)
TypeModel.CollectImplems(parentImplems, typeModel.BaseType);
// interfaces we must declare we implement (initially empty)
@@ -172,6 +212,7 @@ namespace Umbraco.ModelsBuilder.Building
// and except those that are already declared at the parent level
// in other words, DeclaringInterfaces is "local mixins"
var declaring = typeModel.MixinTypes
.Where(x => !x.IsContentIgnored)
.Except(parentImplems);
typeModel.DeclaringInterfaces.AddRange(declaring);
@@ -186,16 +227,43 @@ namespace Umbraco.ModelsBuilder.Building
typeModel.ImplementingInterfaces.AddRange(mixinImplems.Except(parentImplems));
}
// ensure elements don't inherit from non-elements
foreach (var typeModel in _typeModels.Where(x => x.IsElement))
// register using types
foreach (var usingNamespace in ParseResult.UsingNamespaces)
{
if (typeModel.BaseType != null && !typeModel.BaseType.IsElement)
throw new Exception($"Cannot generate model for type '{typeModel.Alias}' because it is an element type, but its parent type '{typeModel.BaseType.Alias}' is not.");
var errs = typeModel.MixinTypes.Where(x => !x.IsElement).ToList();
if (errs.Count > 0)
throw new Exception($"Cannot generate model for type '{typeModel.Alias}' because it is an element type, but it is composed of {string.Join(", ", errs.Select(x => "'" + x.Alias + "'"))} which {(errs.Count == 1 ? "is" : "are")} not.");
if (!TypesUsing.Contains(usingNamespace))
TypesUsing.Add(usingNamespace);
}
// discover static mixin methods
foreach (var typeModel in _typeModels)
typeModel.StaticMixinMethods.AddRange(ParseResult.StaticMixinMethods(typeModel.ClrName));
// handle ctor
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasCtor(x.ClrName)))
typeModel.HasCtor = true;
}
private SemanticModel _ambiguousSymbolsModel;
private int _ambiguousSymbolsPos;
// internal for tests
internal void PrepareAmbiguousSymbols()
{
var codeBuilder = new StringBuilder();
foreach (var t in TypesUsing)
codeBuilder.AppendFormat("using {0};\n", t);
codeBuilder.AppendFormat("namespace {0}\n{{ }}\n", GetModelsNamespace());
var compiler = new Compiler();
SyntaxTree[] trees;
var compilation = compiler.GetCompilation("MyCompilation", new Dictionary<string, string> { { "code", codeBuilder.ToString() } }, out trees);
var tree = trees[0];
_ambiguousSymbolsModel = compilation.GetSemanticModel(tree);
var namespaceSyntax = tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>().First();
//var namespaceSymbol = model.GetDeclaredSymbol(namespaceSyntax);
_ambiguousSymbolsPos = namespaceSyntax.OpenBraceToken.SpanStart;
}
// looking for a simple symbol eg 'Umbraco' or 'String'
@@ -205,10 +273,20 @@ namespace Umbraco.ModelsBuilder.Building
// - 1 symbol is found BUT not matching (implicitely ambiguous)
protected bool IsAmbiguousSymbol(string symbol, string match)
{
// cannot figure out is a symbol is ambiguous without Roslyn
// so... let's say everything is ambiguous - code won't be
// pretty but it'll work
return true;
if (_ambiguousSymbolsModel == null)
PrepareAmbiguousSymbols();
if (_ambiguousSymbolsModel == null)
throw new Exception("Could not prepare ambiguous symbols.");
var symbols = _ambiguousSymbolsModel.LookupNamespacesAndTypes(_ambiguousSymbolsPos, null, symbol);
if (symbols.Length > 1) return true;
if (symbols.Length == 0) return false; // what else?
// only 1 - ensure it matches
var found = symbols[0].ToDisplayString();
var pos = found.IndexOf('<'); // generic?
if (pos > 0) found = found.Substring(0, pos); // strip
return found != match; // and compare
}
internal string ModelsNamespaceForTests;
@@ -218,17 +296,25 @@ namespace Umbraco.ModelsBuilder.Building
if (ModelsNamespaceForTests != null)
return ModelsNamespaceForTests;
// code attribute overrides everything
if (ParseResult.HasModelsNamespace)
return ParseResult.ModelsNamespace;
// if builder was initialized with a namespace, use that one
if (!string.IsNullOrWhiteSpace(ModelsNamespace))
return ModelsNamespace;
// default
// fixme - should NOT reference config here, should make ModelsNamespace mandatory
return Config.ModelsNamespace;
return UmbracoConfig.For.ModelsBuilder().ModelsNamespace;
}
protected string GetModelsBaseClassName(TypeModel type)
{
// code attribute overrides everything
if (ParseResult.HasModelsBaseClassName)
return ParseResult.ModelsBaseClassName;
// default
return type.IsElement ? "PublishedElementModel" : "PublishedContentModel";
}
@@ -0,0 +1,113 @@
using System.CodeDom;
using System.Collections.Generic;
namespace Umbraco.ModelsBuilder.Building
{
// NOTE
// See nodes in Builder.cs class - that one does not work, is not complete,
// and was just some sort of experiment...
/// <summary>
/// Implements a builder that works by using CodeDom
/// </summary>
internal class CodeDomBuilder : Builder
{
/// <summary>
/// Initializes a new instance of the <see cref="CodeDomBuilder"/> class with a list of models to generate.
/// </summary>
/// <param name="typeModels">The list of models to generate.</param>
public CodeDomBuilder(IList<TypeModel> typeModels)
: base(typeModels, null)
{ }
/// <summary>
/// Outputs a generated model to a code namespace.
/// </summary>
/// <param name="ns">The code namespace.</param>
/// <param name="typeModel">The model to generate.</param>
public void Generate(CodeNamespace ns, TypeModel typeModel)
{
// what about USING?
// what about references?
if (typeModel.IsMixin)
{
var i = new CodeTypeDeclaration("I" + typeModel.ClrName)
{
IsInterface = true,
IsPartial = true,
Attributes = MemberAttributes.Public
};
i.BaseTypes.Add(typeModel.BaseType == null ? "IPublishedContent" : "I" + typeModel.BaseType.ClrName);
foreach (var mixinType in typeModel.DeclaringInterfaces)
i.BaseTypes.Add(mixinType.ClrName);
i.Comments.Add(new CodeCommentStatement($"Mixin content Type {typeModel.Id} with alias \"{typeModel.Alias}\""));
foreach (var propertyModel in typeModel.Properties)
{
var p = new CodeMemberProperty
{
Name = propertyModel.ClrName,
Type = new CodeTypeReference(propertyModel.ModelClrType),
Attributes = MemberAttributes.Public,
HasGet = true,
HasSet = false
};
i.Members.Add(p);
}
}
var c = new CodeTypeDeclaration(typeModel.ClrName)
{
IsClass = true,
IsPartial = true,
Attributes = MemberAttributes.Public
};
c.BaseTypes.Add(typeModel.BaseType == null ? "PublishedContentModel" : typeModel.BaseType.ClrName);
// if it's a missing it implements its own interface
if (typeModel.IsMixin)
c.BaseTypes.Add("I" + typeModel.ClrName);
// write the mixins, if any, as interfaces
// only if not a mixin because otherwise the interface already has them
if (typeModel.IsMixin == false)
foreach (var mixinType in typeModel.DeclaringInterfaces)
c.BaseTypes.Add("I" + mixinType.ClrName);
foreach (var mixin in typeModel.MixinTypes)
c.BaseTypes.Add("I" + mixin.ClrName);
c.Comments.Add(new CodeCommentStatement($"Content Type {typeModel.Id} with alias \"{typeModel.Alias}\""));
foreach (var propertyModel in typeModel.Properties)
{
var p = new CodeMemberProperty
{
Name = propertyModel.ClrName,
Type = new CodeTypeReference(propertyModel.ModelClrType),
Attributes = MemberAttributes.Public,
HasGet = true,
HasSet = false
};
p.GetStatements.Add(new CodeMethodReturnStatement( // return
new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeThisReferenceExpression(), // this
"Value", // .Value
new[] // <T>
{
new CodeTypeReference(propertyModel.ModelClrType)
}),
new CodeExpression[] // ("alias")
{
new CodePrimitiveExpression(propertyModel.Alias)
})));
c.Members.Add(p);
}
}
}
}
@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.ModelsBuilder.Building
{
/// <summary>
/// Implements code parsing.
/// </summary>
/// <remarks>Parses user's code and look for generator's instructions.</remarks>
internal class CodeParser
{
/// <summary>
/// Parses a set of file.
/// </summary>
/// <param name="files">A set of (filename,content) representing content to parse.</param>
/// <returns>The result of the code parsing.</returns>
/// <remarks>The set of files is a dictionary of name, content.</remarks>
public ParseResult Parse(IDictionary<string, string> files)
{
return Parse(files, Enumerable.Empty<PortableExecutableReference>());
}
/// <summary>
/// Parses a set of file.
/// </summary>
/// <param name="files">A set of (filename,content) representing content to parse.</param>
/// <param name="references">Assemblies to reference in compilations.</param>
/// <returns>The result of the code parsing.</returns>
/// <remarks>The set of files is a dictionary of name, content.</remarks>
public ParseResult Parse(IDictionary<string, string> files, IEnumerable<PortableExecutableReference> references)
{
SyntaxTree[] trees;
var compiler = new Compiler { References = references };
var compilation = compiler.GetCompilation("Umbraco.ModelsBuilder.Generated", files, out trees);
var disco = new ParseResult();
foreach (var tree in trees)
Parse(disco, compilation, tree);
return disco;
}
public ParseResult ParseWithReferencedAssemblies(IDictionary<string, string> files)
{
return Parse(files, ReferencedAssemblies.References);
}
private static void Parse(ParseResult disco, CSharpCompilation compilation, SyntaxTree tree)
{
var model = compilation.GetSemanticModel(tree);
//we quite probably have errors but that is normal
//var diags = model.GetDiagnostics();
var classDecls = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var classSymbol in classDecls.Select(x => model.GetDeclaredSymbol(x)))
{
ParseClassSymbols(disco, classSymbol);
var baseClassSymbol = classSymbol.BaseType;
if (baseClassSymbol != null)
//disco.SetContentBaseClass(SymbolDisplay.ToDisplayString(classSymbol), SymbolDisplay.ToDisplayString(baseClassSymbol));
disco.SetContentBaseClass(classSymbol.Name, baseClassSymbol.Name);
var interfaceSymbols = classSymbol.Interfaces;
disco.SetContentInterfaces(classSymbol.Name, //SymbolDisplay.ToDisplayString(classSymbol),
interfaceSymbols.Select(x => x.Name)); //SymbolDisplay.ToDisplayString(x)));
var hasCtor = classSymbol.Constructors
.Any(x =>
{
if (x.IsStatic) return false;
if (x.Parameters.Length != 1) return false;
var type1 = x.Parameters[0].Type;
var type2 = typeof (IPublishedContent);
return type1.ToDisplayString() == type2.FullName;
});
if (hasCtor)
disco.SetHasCtor(classSymbol.Name);
foreach (var propertySymbol in classSymbol.GetMembers().Where(x => x is IPropertySymbol))
ParsePropertySymbols(disco, classSymbol, propertySymbol);
foreach (var staticMethodSymbol in classSymbol.GetMembers().Where(x => x is IMethodSymbol))
ParseMethodSymbol(disco, classSymbol, staticMethodSymbol);
}
var interfaceDecls = tree.GetRoot().DescendantNodes().OfType<InterfaceDeclarationSyntax>();
foreach (var interfaceSymbol in interfaceDecls.Select(x => model.GetDeclaredSymbol(x)))
{
ParseClassSymbols(disco, interfaceSymbol);
var interfaceSymbols = interfaceSymbol.Interfaces;
disco.SetContentInterfaces(interfaceSymbol.Name, //SymbolDisplay.ToDisplayString(interfaceSymbol),
interfaceSymbols.Select(x => x.Name)); // SymbolDisplay.ToDisplayString(x)));
}
ParseAssemblySymbols(disco, compilation.Assembly);
}
private static void ParseClassSymbols(ParseResult disco, ISymbol symbol)
{
foreach (var attrData in symbol.GetAttributes())
{
var attrClassSymbol = attrData.AttributeClass;
// handle errors
if (attrClassSymbol is IErrorTypeSymbol) continue;
if (attrData.AttributeConstructor == null) continue;
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
switch (attrClassName)
{
case "Umbraco.ModelsBuilder.IgnorePropertyTypeAttribute":
var propertyAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
disco.SetIgnoredProperty(symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/, propertyAliasToIgnore);
break;
case "Umbraco.ModelsBuilder.RenamePropertyTypeAttribute":
var propertyAliasToRename = (string)attrData.ConstructorArguments[0].Value;
var propertyRenamed = (string)attrData.ConstructorArguments[1].Value;
disco.SetRenamedProperty(symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/, propertyAliasToRename, propertyRenamed);
break;
// that one causes all sorts of issues with references to Umbraco.Core in Roslyn
//case "Umbraco.Core.Models.PublishedContent.PublishedContentModelAttribute":
// var contentAliasToRename = (string)attrData.ConstructorArguments[0].Value;
// disco.SetRenamedContent(contentAliasToRename, symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/);
// break;
case "Umbraco.ModelsBuilder.ImplementContentTypeAttribute":
var contentAliasToRename = (string)attrData.ConstructorArguments[0].Value;
disco.SetRenamedContent(contentAliasToRename, symbol.Name, true /*SymbolDisplay.ToDisplayString(symbol)*/);
break;
}
}
}
private static void ParsePropertySymbols(ParseResult disco, ISymbol classSymbol, ISymbol symbol)
{
foreach (var attrData in symbol.GetAttributes())
{
var attrClassSymbol = attrData.AttributeClass;
// handle errors
if (attrClassSymbol is IErrorTypeSymbol) continue;
if (attrData.AttributeConstructor == null) continue;
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
// ReSharper disable once SwitchStatementMissingSomeCases
switch (attrClassName)
{
case "Umbraco.ModelsBuilder.ImplementPropertyTypeAttribute":
var propertyAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
disco.SetIgnoredProperty(classSymbol.Name /*SymbolDisplay.ToDisplayString(classSymbol)*/, propertyAliasToIgnore);
break;
}
}
}
private static void ParseAssemblySymbols(ParseResult disco, ISymbol symbol)
{
foreach (var attrData in symbol.GetAttributes())
{
var attrClassSymbol = attrData.AttributeClass;
// handle errors
if (attrClassSymbol is IErrorTypeSymbol) continue;
if (attrData.AttributeConstructor == null) continue;
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
switch (attrClassName)
{
case "Umbraco.ModelsBuilder.IgnoreContentTypeAttribute":
var contentAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
// see notes in IgnoreContentTypeAttribute
//var ignoreContent = (bool)attrData.ConstructorArguments[1].Value;
//var ignoreMixin = (bool)attrData.ConstructorArguments[1].Value;
//var ignoreMixinProperties = (bool)attrData.ConstructorArguments[1].Value;
disco.SetIgnoredContent(contentAliasToIgnore /*, ignoreContent, ignoreMixin, ignoreMixinProperties*/);
break;
case "Umbraco.ModelsBuilder.RenameContentTypeAttribute":
var contentAliasToRename = (string) attrData.ConstructorArguments[0].Value;
var contentRenamed = (string)attrData.ConstructorArguments[1].Value;
disco.SetRenamedContent(contentAliasToRename, contentRenamed, false);
break;
case "Umbraco.ModelsBuilder.ModelsBaseClassAttribute":
var modelsBaseClass = (INamedTypeSymbol) attrData.ConstructorArguments[0].Value;
if (modelsBaseClass is IErrorTypeSymbol)
throw new Exception($"Invalid base class type \"{modelsBaseClass.Name}\".");
disco.SetModelsBaseClassName(SymbolDisplay.ToDisplayString(modelsBaseClass));
break;
case "Umbraco.ModelsBuilder.ModelsNamespaceAttribute":
var modelsNamespace= (string) attrData.ConstructorArguments[0].Value;
disco.SetModelsNamespace(modelsNamespace);
break;
case "Umbraco.ModelsBuilder.ModelsUsingAttribute":
var usingNamespace = (string)attrData.ConstructorArguments[0].Value;
disco.SetUsingNamespace(usingNamespace);
break;
}
}
}
private static void ParseMethodSymbol(ParseResult disco, ISymbol classSymbol, ISymbol symbol)
{
var methodSymbol = symbol as IMethodSymbol;
if (methodSymbol == null
|| !methodSymbol.IsStatic
|| methodSymbol.IsGenericMethod
|| methodSymbol.ReturnsVoid
|| methodSymbol.IsExtensionMethod
|| methodSymbol.Parameters.Length != 1)
return;
var returnType = methodSymbol.ReturnType;
var paramSymbol = methodSymbol.Parameters[0];
var paramType = paramSymbol.Type;
// cannot do this because maybe the param type is ISomething and we don't have
// that type yet - will be generated - so cannot put any condition on it really
//const string iPublishedContent = "Umbraco.Core.Models.IPublishedContent";
//var implements = paramType.AllInterfaces.Any(x => x.ToDisplayString() == iPublishedContent);
//if (!implements)
// return;
disco.SetStaticMixinMethod(classSymbol.Name, methodSymbol.Name, returnType.Name, paramType.Name);
}
}
}
@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Umbraco.Core.Configuration;
using Umbraco.ModelsBuilder.Configuration;
namespace Umbraco.ModelsBuilder.Building
{
// main Roslyn compiler
internal class Compiler
{
private readonly LanguageVersion _languageVersion;
public Compiler()
: this(UmbracoConfig.For.ModelsBuilder().LanguageVersion)
{ }
public Compiler(LanguageVersion languageVersion)
{
_languageVersion = languageVersion;
References = ReferencedAssemblies.References;
Debug = HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled;
}
// gets or sets the references
public IEnumerable<PortableExecutableReference> References { get; set; }
public bool Debug { get; set; }
// gets a compilation
public CSharpCompilation GetCompilation(string assemblyName, IDictionary<string, string> files)
{
SyntaxTree[] trees;
return GetCompilation(assemblyName, files, out trees);
}
// gets a compilation
// used by CodeParser to get a "compilation" of the existing files
public CSharpCompilation GetCompilation(string assemblyName, IDictionary<string, string> files, out SyntaxTree[] trees)
{
var options = new CSharpParseOptions(_languageVersion);
trees = files.Select(x =>
{
var text = x.Value;
var tree = CSharpSyntaxTree.ParseText(text, /*options:*/ options);
var diagnostic = tree.GetDiagnostics().FirstOrDefault(y => y.Severity == DiagnosticSeverity.Error);
if (diagnostic != null)
ThrowExceptionFromDiagnostic(x.Key, x.Value, diagnostic);
return tree;
}).ToArray();
var refs = References;
var compilationOptions = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default,
optimizationLevel: Debug ? OptimizationLevel.Debug : OptimizationLevel.Release
);
var compilation = CSharpCompilation.Create(
assemblyName,
/*syntaxTrees:*/ trees,
/*references:*/ refs,
compilationOptions);
return compilation;
}
// compile files into a Dll
// used by ModelsBuilderBackOfficeController in [Live]Dll mode, to compile the models to disk
public void Compile(string assemblyName, IDictionary<string, string> files, string binPath)
{
var assemblyPath = Path.Combine(binPath, assemblyName + ".dll");
using (var stream = new FileStream(assemblyPath, FileMode.Create))
{
Compile(assemblyName, files, stream);
}
// this is how we'd create the pdb:
/*
var pdbPath = Path.Combine(binPath, assemblyName + ".pdb");
// create the compilation
var compilation = GetCompilation(assemblyName, files);
// check diagnostics for errors (not warnings)
foreach (var diag in compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))
ThrowExceptionFromDiagnostic(files, diag);
// emit
var result = compilation.Emit(assemblyPath, pdbPath);
if (result.Success) return;
// deal with errors
var diagnostic = result.Diagnostics.First(x => x.Severity == DiagnosticSeverity.Error);
ThrowExceptionFromDiagnostic(files, diagnostic);
*/
}
// compile files into an assembly
public Assembly Compile(string assemblyName, IDictionary<string, string> files)
{
using (var stream = new MemoryStream())
{
Compile(assemblyName, files, stream);
return Assembly.Load(stream.GetBuffer());
}
}
// compile one file into an assembly
public Assembly Compile(string assemblyName, string path, string code)
{
using (var stream = new MemoryStream())
{
Compile(assemblyName, new Dictionary<string, string> { { path, code } }, stream);
return Assembly.Load(stream.GetBuffer());
}
}
// compiles files into a stream
public void Compile(string assemblyName, IDictionary<string, string> files, Stream stream)
{
// create the compilation
var compilation = GetCompilation(assemblyName, files);
// check diagnostics for errors (not warnings)
foreach (var diag in compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))
ThrowExceptionFromDiagnostic(files, diag);
// emit
var result = compilation.Emit(stream);
if (result.Success) return;
// deal with errors
var diagnostic = result.Diagnostics.First(x => x.Severity == DiagnosticSeverity.Error);
ThrowExceptionFromDiagnostic(files, diagnostic);
}
// compiles one file into a stream
public void Compile(string assemblyName, string path, string code, Stream stream)
{
Compile(assemblyName, new Dictionary<string, string> { { path, code } }, stream);
}
private static void ThrowExceptionFromDiagnostic(IDictionary<string, string> files, Diagnostic diagnostic)
{
var message = diagnostic.GetMessage();
if (diagnostic.Location == Location.None)
throw new CompilerException(message);
var position = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1;
var path = diagnostic.Location.SourceTree.FilePath;
var code = files.ContainsKey(path) ? files[path] : string.Empty;
throw new CompilerException(message, path, code, position);
}
private static void ThrowExceptionFromDiagnostic(string path, string code, Diagnostic diagnostic)
{
var message = diagnostic.GetMessage();
if (diagnostic.Location == Location.None)
throw new CompilerException(message);
var position = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1;
throw new CompilerException(message, path, code, position);
}
}
}
@@ -0,0 +1,25 @@
using System;
namespace Umbraco.ModelsBuilder.Building
{
public class CompilerException : Exception
{
public CompilerException(string message)
: base(message)
{ }
public CompilerException(string message, string path, string sourceCode, int line)
: base(message)
{
Path = path;
SourceCode = sourceCode;
Line = line;
}
public string Path { get; } = string.Empty;
public string SourceCode { get; } = string.Empty;
public int Line { get; } = -1;
}
}
@@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.ModelsBuilder.Building
{
/// <summary>
/// Contains the result of a code parsing.
/// </summary>
internal class ParseResult
{
// "alias" is the umbraco alias
// content "name" is the complete name eg Foo.Bar.Name
// property "name" is just the local name
// see notes in IgnoreContentTypeAttribute
private readonly HashSet<string> _ignoredContent
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
//private readonly HashSet<string> _ignoredMixin
// = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
//private readonly HashSet<string> _ignoredMixinProperties
// = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, string> _renamedContent
= new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
private readonly HashSet<string> _withImplementContent
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, HashSet<string>> _ignoredProperty
= new Dictionary<string, HashSet<string>>();
private readonly Dictionary<string, Dictionary<string, string>> _renamedProperty
= new Dictionary<string, Dictionary<string, string>>();
private readonly Dictionary<string, string> _contentBase
= new Dictionary<string, string>();
private readonly Dictionary<string, string[]> _contentInterfaces
= new Dictionary<string, string[]>();
private readonly List<string> _usingNamespaces
= new List<string>();
private readonly Dictionary<string, List<StaticMixinMethodInfo>> _staticMixins
= new Dictionary<string, List<StaticMixinMethodInfo>>();
private readonly HashSet<string> _withCtor
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
public static readonly ParseResult Empty = new ParseResult();
private class StaticMixinMethodInfo
{
public StaticMixinMethodInfo(string contentName, string methodName, string returnType, string paramType)
{
ContentName = contentName;
MethodName = methodName;
//ReturnType = returnType;
//ParamType = paramType;
}
// short name eg Type1
public string ContentName { get; private set; }
// short name eg GetProp1
public string MethodName { get; private set; }
// those types cannot be FQ because when parsing, some of them
// might not exist since we're generating them... and so prob.
// that info is worthless - not using it anyway at the moment...
//public string ReturnType { get; private set; }
//public string ParamType { get; private set; }
}
#region Declare
// content with that alias should not be generated
// alias can end with a * (wildcard)
public void SetIgnoredContent(string contentAlias /*, bool ignoreContent, bool ignoreMixin, bool ignoreMixinProperties*/)
{
//if (ignoreContent)
_ignoredContent.Add(contentAlias);
//if (ignoreMixin)
// _ignoredMixin.Add(contentAlias);
//if (ignoreMixinProperties)
// _ignoredMixinProperties.Add(contentAlias);
}
// content with that alias should be generated with a different name
public void SetRenamedContent(string contentAlias, string contentName, bool withImplement)
{
_renamedContent[contentAlias] = contentName;
if (withImplement)
_withImplementContent.Add(contentAlias);
}
// property with that alias should not be generated
// applies to content name and any content that implements it
// here, contentName may be an interface
// alias can end with a * (wildcard)
public void SetIgnoredProperty(string contentName, string propertyAlias)
{
HashSet<string> ignores;
if (!_ignoredProperty.TryGetValue(contentName, out ignores))
ignores = _ignoredProperty[contentName] = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
ignores.Add(propertyAlias);
}
// property with that alias should be generated with a different name
// applies to content name and any content that implements it
// here, contentName may be an interface
public void SetRenamedProperty(string contentName, string propertyAlias, string propertyName)
{
Dictionary<string, string> renames;
if (!_renamedProperty.TryGetValue(contentName, out renames))
renames = _renamedProperty[contentName] = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
renames[propertyAlias] = propertyName;
}
// content with that name has a base class so no need to generate one
public void SetContentBaseClass(string contentName, string baseName)
{
if (baseName.ToLowerInvariant() != "object")
_contentBase[contentName] = baseName;
}
// content with that name implements the interfaces
public void SetContentInterfaces(string contentName, IEnumerable<string> interfaceNames)
{
_contentInterfaces[contentName] = interfaceNames.ToArray();
}
public void SetModelsBaseClassName(string modelsBaseClassName)
{
ModelsBaseClassName = modelsBaseClassName;
}
public void SetModelsNamespace(string modelsNamespace)
{
ModelsNamespace = modelsNamespace;
}
public void SetUsingNamespace(string usingNamespace)
{
_usingNamespaces.Add(usingNamespace);
}
public void SetStaticMixinMethod(string contentName, string methodName, string returnType, string paramType)
{
if (!_staticMixins.ContainsKey(contentName))
_staticMixins[contentName] = new List<StaticMixinMethodInfo>();
_staticMixins[contentName].Add(new StaticMixinMethodInfo(contentName, methodName, returnType, paramType));
}
public void SetHasCtor(string contentName)
{
_withCtor.Add(contentName);
}
#endregion
#region Query
public bool IsIgnored(string contentAlias)
{
return IsContentOrMixinIgnored(contentAlias, _ignoredContent);
}
//public bool IsMixinIgnored(string contentAlias)
//{
// return IsContentOrMixinIgnored(contentAlias, _ignoredMixin);
//}
//public bool IsMixinPropertiesIgnored(string contentAlias)
//{
// return IsContentOrMixinIgnored(contentAlias, _ignoredMixinProperties);
//}
private static bool IsContentOrMixinIgnored(string contentAlias, HashSet<string> ignored)
{
if (ignored.Contains(contentAlias)) return true;
return ignored
.Where(x => x.EndsWith("*"))
.Select(x => x.Substring(0, x.Length - 1))
.Any(x => contentAlias.StartsWith(x, StringComparison.InvariantCultureIgnoreCase));
}
public bool HasContentBase(string contentName)
{
return _contentBase.ContainsKey(contentName);
}
public bool IsContentRenamed(string contentAlias)
{
return _renamedContent.ContainsKey(contentAlias);
}
public bool HasContentImplement(string contentAlias)
{
return _withImplementContent.Contains(contentAlias);
}
public string ContentClrName(string contentAlias)
{
string name;
return (_renamedContent.TryGetValue(contentAlias, out name)) ? name : null;
}
public bool IsPropertyIgnored(string contentName, string propertyAlias)
{
HashSet<string> ignores;
if (_ignoredProperty.TryGetValue(contentName, out ignores))
{
if (ignores.Contains(propertyAlias)) return true;
if (ignores
.Where(x => x.EndsWith("*"))
.Select(x => x.Substring(0, x.Length - 1))
.Any(x => propertyAlias.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
return true;
}
string baseName;
if (_contentBase.TryGetValue(contentName, out baseName)
&& IsPropertyIgnored(baseName, propertyAlias)) return true;
string[] interfaceNames;
if (_contentInterfaces.TryGetValue(contentName, out interfaceNames)
&& interfaceNames.Any(interfaceName => IsPropertyIgnored(interfaceName, propertyAlias))) return true;
return false;
}
public string PropertyClrName(string contentName, string propertyAlias)
{
Dictionary<string, string> renames;
string name;
if (_renamedProperty.TryGetValue(contentName, out renames)
&& renames.TryGetValue(propertyAlias, out name)) return name;
string baseName;
if (_contentBase.TryGetValue(contentName, out baseName)
&& null != (name = PropertyClrName(baseName, propertyAlias))) return name;
string[] interfaceNames;
if (_contentInterfaces.TryGetValue(contentName, out interfaceNames)
&& null != (name = interfaceNames
.Select(interfaceName => PropertyClrName(interfaceName, propertyAlias))
.FirstOrDefault(x => x != null))) return name;
return null;
}
public bool HasModelsBaseClassName
{
get { return !string.IsNullOrWhiteSpace(ModelsBaseClassName); }
}
public string ModelsBaseClassName { get; private set; }
public bool HasModelsNamespace
{
get { return !string.IsNullOrWhiteSpace(ModelsNamespace); }
}
public string ModelsNamespace { get; private set; }
public IEnumerable<string> UsingNamespaces
{
get { return _usingNamespaces; }
}
public IEnumerable<string> StaticMixinMethods(string contentName)
{
return _staticMixins.ContainsKey(contentName)
? _staticMixins[contentName].Select(x => x.MethodName)
: Enumerable.Empty<string>() ;
}
public bool HasCtor(string contentName)
{
return _withCtor.Contains(contentName);
}
#endregion
}
}
@@ -41,6 +41,11 @@ namespace Umbraco.ModelsBuilder.Building
/// </summary>
public string ClrTypeName;
/// <summary>
/// Gets a value indicating whether this property should be excluded from generation.
/// </summary>
public bool IsIgnored;
/// <summary>
/// Gets the generation errors for the property.
/// </summary>
@@ -3,9 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.ModelsBuilder.Api;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.ModelsBuilder.Configuration;
namespace Umbraco.ModelsBuilder.Building
@@ -20,8 +19,9 @@ namespace Umbraco.ModelsBuilder.Building
/// and the result of code parsing.
/// </summary>
/// <param name="typeModels">The list of models to generate.</param>
public TextBuilder(IList<TypeModel> typeModels)
: base(typeModels)
/// <param name="parseResult">The result of code parsing.</param>
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult)
: base(typeModels, parseResult)
{ }
/// <summary>
@@ -29,22 +29,21 @@ namespace Umbraco.ModelsBuilder.Building
/// the result of code parsing, and a models namespace.
/// </summary>
/// <param name="typeModels">The list of models to generate.</param>
/// <param name="parseResult">The result of code parsing.</param>
/// <param name="modelsNamespace">The models namespace.</param>
public TextBuilder(IList<TypeModel> typeModels, string modelsNamespace)
: base(typeModels, modelsNamespace)
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
: base(typeModels, parseResult, modelsNamespace)
{ }
// internal for unit tests only
internal TextBuilder()
{ }
private static Config Config => Current.Configs.ModelsBuilder();
/// <summary>
/// Outputs a generated model to a string builder.
/// </summary>
/// <param name="sb">The string builder.</param>
/// <param name="typeModel">The model to generate.</param>
/// Outputs a generated model to a string builder.
/// </summary>
/// <param name="sb">The string builder.</param>
/// <param name="typeModel">The model to generate.</param>
public void Generate(StringBuilder sb, TypeModel typeModel)
{
WriteHeader(sb);
@@ -98,20 +97,6 @@ namespace Umbraco.ModelsBuilder.Building
TextHeaderWriter.WriteHeader(sb);
}
// writes an attribute that identifies code generated by a tool
// (helps reduce warnings, tools such as FxCop use it)
// see https://github.com/zpqrtbnk/Zbu.ModelsBuilder/issues/107
// see https://docs.microsoft.com/en-us/dotnet/api/system.codedom.compiler.generatedcodeattribute
// see https://blogs.msdn.microsoft.com/codeanalysis/2007/04/27/correct-usage-of-the-compilergeneratedattribute-and-the-generatedcodeattribute/
//
// note that the blog post above clearly states that "Nor should it be applied at the type level if the type being generated is a partial class."
// and since our models are partial classes, we have to apply the attribute against the individual members, not the class itself.
//
private static void WriteGeneratedCodeAttribute(StringBuilder sb, string tabs)
{
sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder\", \"{1}\")]\n", tabs, ApiVersion.Current.Version);
}
private void WriteContentType(StringBuilder sb, TypeModel type)
{
string sep;
@@ -119,11 +104,11 @@ namespace Umbraco.ModelsBuilder.Building
if (type.IsMixin)
{
// write the interface declaration
sb.AppendFormat("\t// Mixin Content Type with alias \"{0}\"\n", type.Alias);
sb.AppendFormat("\t// Mixin content Type {0} with alias \"{1}\"\n", type.Id, type.Alias);
if (!string.IsNullOrWhiteSpace(type.Name))
sb.AppendFormat("\t/// <summary>{0}</summary>\n", XmlCommentString(type.Name));
sb.AppendFormat("\tpublic partial interface I{0}", type.ClrName);
var implements = type.BaseType == null
var implements = type.BaseType == null || type.BaseType.IsContentIgnored
? (type.HasBase ? null : (type.IsElement ? "PublishedElement" : "PublishedContent"))
: type.BaseType.ClrName;
if (implements != null)
@@ -141,7 +126,7 @@ namespace Umbraco.ModelsBuilder.Building
// write the properties - only the local (non-ignored) ones, we're an interface
var more = false;
foreach (var prop in type.Properties.OrderBy(x => x.ClrName))
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
{
if (more) sb.Append("\n");
more = true;
@@ -152,6 +137,8 @@ namespace Umbraco.ModelsBuilder.Building
}
// write the class declaration
if (type.IsRenamed)
sb.AppendFormat("\t// Content Type {0} with alias \"{1}\"\n", type.Id, type.Alias);
if (!string.IsNullOrWhiteSpace(type.Name))
sb.AppendFormat("\t/// <summary>{0}</summary>\n", XmlCommentString(type.Name));
// cannot do it now. see note in ImplementContentTypeAttribute
@@ -161,7 +148,7 @@ namespace Umbraco.ModelsBuilder.Building
sb.AppendFormat("\tpublic partial class {0}", type.ClrName);
var inherits = type.HasBase
? null // has its own base already
: (type.BaseType == null
: (type.BaseType == null || type.BaseType.IsContentIgnored
? GetModelsBaseClassName(type)
: type.BaseType.ClrName);
if (inherits != null)
@@ -191,25 +178,22 @@ namespace Umbraco.ModelsBuilder.Building
// as 'new' since parent has its own - or maybe not - disable warning
sb.Append("\t\t// helpers\n");
sb.Append("#pragma warning disable 0109 // new is redundant\n");
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.AppendFormat("\t\tpublic new const string ModelTypeAlias = \"{0}\";\n",
type.Alias);
var itemType = type.IsElement ? TypeModel.ItemTypes.Content : type.ItemType; // fixme
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.AppendFormat("\t\tpublic new const PublishedItemType ModelItemType = PublishedItemType.{0};\n",
itemType);
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.Append("\t\tpublic new static PublishedContentType GetModelContentType()\n");
sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias);\n");
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.AppendFormat("\t\tpublic static PublishedPropertyType GetModelPropertyType<TValue>(Expression<Func<{0}, TValue>> selector)\n",
type.ClrName);
sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector);\n");
sb.Append("#pragma warning restore 0109\n\n");
// write the ctor
sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n",
type.ClrName, type.IsElement ? "Element" : "Content");
if (!type.HasCtor)
sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n",
type.ClrName, type.IsElement ? "Element" : "Content");
// write the properties
sb.Append("\t\t// properties\n");
@@ -221,10 +205,10 @@ namespace Umbraco.ModelsBuilder.Building
private void WriteContentTypeProperties(StringBuilder sb, TypeModel type)
{
var staticMixinGetters = true;
var staticMixinGetters = UmbracoConfig.For.ModelsBuilder().StaticMixinGetters;
// write the properties
foreach (var prop in type.Properties.OrderBy(x => x.ClrName))
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
WriteProperty(sb, type, prop, staticMixinGetters && type.IsMixin ? type.ClrName : null);
// no need to write the parent properties since we inherit from the parent
@@ -233,7 +217,7 @@ namespace Umbraco.ModelsBuilder.Building
// write the mixins properties
foreach (var mixinType in type.ImplementingInterfaces.OrderBy(x => x.ClrName))
foreach (var prop in mixinType.Properties.OrderBy(x => x.ClrName))
foreach (var prop in mixinType.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
if (staticMixinGetters)
WriteMixinProperty(sb, prop, mixinType.ClrName);
else
@@ -258,7 +242,6 @@ namespace Umbraco.ModelsBuilder.Building
sb.Append("\t\t///</summary>\n");
}
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias);
sb.Append("\t\tpublic ");
@@ -273,7 +256,7 @@ namespace Umbraco.ModelsBuilder.Building
private static string MixinStaticGetterName(string clrName)
{
return string.Format("Get{0}", clrName);
return string.Format(UmbracoConfig.For.ModelsBuilder().StaticMixinGetterPattern, clrName);
}
private void WriteProperty(StringBuilder sb, TypeModel type, PropertyModel property, string mixinClrName = null)
@@ -317,7 +300,6 @@ namespace Umbraco.ModelsBuilder.Building
sb.Append("\t\t///</summary>\n");
}
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias);
if (mixinStatic)
@@ -361,7 +343,6 @@ namespace Umbraco.ModelsBuilder.Building
if (!string.IsNullOrWhiteSpace(property.Name))
sb.AppendFormat("\t\t/// <summary>Static getter for {0}</summary>\n", XmlCommentString(property.Name));
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.Append("\t\tpublic static ");
WriteClrType(sb, property.ClrTypeName);
sb.AppendFormat(" {0}(I{1} that) => that.Value",
@@ -416,7 +397,6 @@ namespace Umbraco.ModelsBuilder.Building
if (!string.IsNullOrWhiteSpace(property.Name))
sb.AppendFormat("\t\t/// <summary>{0}</summary>\n", XmlCommentString(property.Name));
WriteGeneratedCodeAttribute(sb, "\t\t");
sb.Append("\t\t");
WriteClrType(sb, property.ClrTypeName);
sb.AppendFormat(" {0} {{ get; }}\n",
@@ -481,7 +461,7 @@ namespace Umbraco.ModelsBuilder.Building
s = Regex.Replace(s, @"\{(.*)\}\[\*\]", m => ModelsMap[m.Groups[1].Value + "[]"]);
// takes care eg of "System.Int32" vs. "int"
if (TypesMap.TryGetValue(s, out string typeName))
if (TypesMap.TryGetValue(s.ToLowerInvariant(), out string typeName))
{
sb.Append(typeName);
return;
@@ -501,11 +481,6 @@ namespace Umbraco.ModelsBuilder.Building
typeName = typeName.Substring(p + 1);
typeUsing = x;
}
else if (x == ModelsNamespace) // that one is used by default
{
typeName = typeName.Substring(p + 1);
typeUsing = ModelsNamespace;
}
}
// nested types *after* using
@@ -556,24 +531,24 @@ namespace Umbraco.ModelsBuilder.Building
return s.Replace('<', '{').Replace('>', '}').Replace('\r', ' ').Replace('\n', ' ');
}
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>
{
{ "System.Int16", "short" },
{ "System.Int32", "int" },
{ "System.Int64", "long" },
{ "System.String", "string" },
{ "System.Object", "object" },
{ "System.Boolean", "bool" },
{ "System.Void", "void" },
{ "System.Char", "char" },
{ "System.Byte", "byte" },
{ "System.UInt16", "ushort" },
{ "System.UInt32", "uint" },
{ "System.UInt64", "ulong" },
{ "System.SByte", "sbyte" },
{ "System.Single", "float" },
{ "System.Double", "double" },
{ "System.Decimal", "decimal" }
{ "system.int16", "short" },
{ "system.int32", "int" },
{ "system.int64", "long" },
{ "system.string", "string" },
{ "system.object", "object" },
{ "system.boolean", "bool" },
{ "system.void", "void" },
{ "system.char", "char" },
{ "system.byte", "byte" },
{ "system.uint16", "ushort" },
{ "system.uint32", "uint" },
{ "system.uint64", "ulong" },
{ "system.sbyte", "sbyte" },
{ "system.single", "float" },
{ "system.double", "double" },
{ "system.decimal", "decimal" }
};
}
}

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