Compare commits

..

249 Commits

Author SHA1 Message Date
Steve Megson 88349c6b66 Sorting of images in multiple media picker
(cherry picked from commit ed5effd190)
2019-08-08 16:02:35 +02:00
Sebastiaan Janssen 046ed8ec85 Bump version to 8.1.2 2019-08-08 12:23:57 +02:00
Steve Megson aabe6defb2 Fixes #5864 - migrate prevalues for Umbraco.DropDown.Flexible
(cherry picked from commit 4e0dd728a8)
2019-08-08 10:56:02 +02:00
Bjarke Berg 3245c82ea6 Missing file in project file
(cherry picked from commit 3062f40ef5)
2019-08-08 10:45:34 +02:00
Kenn Jacobsen beacc5bba8 Fix broken button to open content type from create dialog
(cherry picked from commit 57e58c6cf7)
2019-08-08 10:05:33 +02:00
leekelleher 7ffe0398f9 DocType Editor sorting - vertical direction
In the DocType Editor, when sorting the groups and properties,
the draggable direction is freeform (horizontal, vertical or even
diagonal).

We can restrict the direction, by setting the `axis` property in
the sort options.
2019-08-07 20:55:35 +02:00
Kenn Jacobsen ce5b3531e0 Make content types with description look ok in the create dialog (#5752)
(cherry picked from commit b3497011e8)
2019-08-07 20:50:08 +02:00
Sebastiaan Janssen a9a5d00916 Merge pull request #5999 from kjac/v8-fix-allow-remove-user-start-nodes
V8: Allow removing user start nodes
(cherry picked from commit 2cf3a7831c)
2019-08-07 20:25:44 +02:00
Gopakumar R 62a71f8052 Fix for issue #5816 (#5836)
(cherry picked from commit 0138091a6c)
2019-08-07 20:16:50 +02:00
Kenn Jacobsen 36eccb472c Fix the create context menu overflows introduced with 405e9a79 (#5754)
(cherry picked from commit 6c0fb2f849)
2019-08-07 19:58:13 +02:00
Benjamin Carleski 289d50d170 Fix FIPS compliance, add FIPS tests (#5978)
(cherry picked from commit e495faf83c)
2019-08-07 19:34:13 +02:00
Linus Elander 0517f29134 Adjusts conditions for which indexes should be affected when a node is unpublished
(cherry picked from commit 7557c584d8)
2019-08-07 16:38:13 +02:00
Shannon 467cf8d762 Adds comments/notes 2019-08-07 15:40:27 +10:00
Bjarke Berg 2cdb6d86ad Merge pull request #6019 from umbraco/v8/bugfix/pending-changes-issue
v8 Changing a property type from invariant to variant and back again causes issues with reporting that a document is edited or not
2019-08-06 09:09:12 +02:00
Bjarke Berg d474f60465 Merge pull request #5992 from umbraco/v8/bugfix/5554-unpublish-state
V8/bugfix/5554 unpublish state
2019-08-05 11:54:49 +02:00
Bjarke Berg caf4d1fe34 Merge pull request #6038 from umbraco/v8/bugfix/examine-startup
Fixes how examine starts up to make it easier for custom index developers
2019-08-05 10:39:29 +02:00
Bjarke Berg e4f346620e Added runtime level to ExamineFinalComposer 2019-08-05 10:38:35 +02:00
Shannon be4536cf16 Refactors ugly statics and nested classes 2019-08-05 17:14:29 +10:00
Shannon 89429bd65a fixes ctor 2019-08-05 16:28:23 +10:00
Shannon 6d3faf91d8 fixes spacing with ext login providers 2019-08-05 13:50:50 +10:00
Shannon 345e6091d2 fixes null check, was on the wrong element 2019-08-02 13:01:02 +10:00
Shannon 86a97c30d1 fixes up LuceneIndexDiagnostics 2019-08-02 12:40:45 +10:00
Shannon 14915e9da7 oops 2019-08-02 01:16:37 +10:00
Shannon 366058581a Adds LuceneIndexDiagnostics to make it easier for devs and custom indexes 2019-08-02 01:15:08 +10:00
Shannon 9f6a7dec2e Fixes how examine starts up to make it easier for custom index developers 2019-08-02 00:28:48 +10:00
Shannon be30bb0ad0 adds test 2019-08-01 21:41:43 +10:00
Shannon 600a29514f more asserts 2019-08-01 21:27:31 +10:00
Shannon 9efec9244b removes commented out code 2019-08-01 19:09:19 +10:00
Shannon ded1a22e45 fixes validation check 2019-08-01 19:01:41 +10:00
Shannon 2e83ac9282 Cleans up some tests 2019-08-01 18:54:19 +10:00
Shannon 9538981730 Adds more assertions and tests and validates variations 2019-08-01 18:49:05 +10:00
Shannon 791222c3ce Merge remote-tracking branch 'origin/v8/8.1' into v8/bugfix/5554-unpublish-state 2019-08-01 16:11:16 +10:00
Shannon 1095815878 removes notes 2019-08-01 16:09:52 +10:00
Shannon a8bdab8f5c Merge remote-tracking branch 'origin/v8/8.1' into v8/bugfix/pending-changes-issue 2019-08-01 15:56:24 +10:00
Shannon ff952a6df1 Passes test! Now to add more tests/assertions and then the logic to renormalize based on name changes. 2019-08-01 15:54:44 +10:00
Shannon 87e7cec02e WIP - commiting what i have. Solved part of the problem but there are others. 2019-07-31 18:30:34 +10:00
Shannon 5c8cd60275 Writes up a test to show the issue with edited culture flags, this shows that the current fix works but there's still an issue 2019-07-31 00:13:40 +10:00
Bjarke Berg e2483dc874 Merge pull request #6020 from umbraco/v8/bugfix/panic-exception
Adds PanicException with details instead of throwing "panic" strings
2019-07-30 15:22:05 +02:00
Shannon 6482d849e3 Moves test to different fixture 2019-07-30 22:59:33 +10:00
Shannon 34f137c8cf Merge branch 'v8/bugfix/panic-exception' into v8/bugfix/5554-unpublish-state 2019-07-30 22:50:06 +10:00
Shannon 16d8f8846e Adds PanicException with details instead of throwing "panic" strings 2019-07-30 22:40:15 +10:00
Shannon 108416638c removes commented out code 2019-07-30 22:28:06 +10:00
Shannon 20d28ea215 removes commented out code 2019-07-30 22:20:28 +10:00
Shannon 27bc309c55 Removes unused code 2019-07-30 22:20:28 +10:00
Shannon b5b4ee79b4 Adds notes, fixes logic with a double save 2019-07-30 22:20:28 +10:00
Shannon 45227357fd adds notes on why this is failing 2019-07-30 22:20:28 +10:00
Shannon a2ba0f6a4c more tests - failing that need fixing 2019-07-30 22:20:27 +10:00
Shannon 415916c527 Fixes an issue with the content service + test 2019-07-30 22:20:27 +10:00
Shannon 40a55cb9df Fixes issue/tests 2019-07-30 22:20:27 +10:00
Shannon 5a9ca8d09f wip added more tests and notes 2019-07-30 22:20:27 +10:00
Shannon 1bfcc9053e Fixes issues: we never properly used SuccessUnpublishMandatoryCulture, fixed issue of unpublishing last culture with a new status 2019-07-30 22:20:27 +10:00
Shannon 3930ae244c Created unit test to show the problem. 2019-07-30 22:20:27 +10:00
Shannon 365ad2981d Fixing issue when changing a property type from invariant to variant and back again and the document always reporting pending changes. 2019-07-30 19:02:03 +10:00
Rasmus John Pedersen ca56655d07 Fix exception when stored media url is already absolute
(cherry picked from commit 49b3351c72)
2019-07-29 14:31:04 +02:00
Shannon 4612c03657 Fixes #5789 - PublishedContentQuery Search always searches on culture 2019-07-29 15:43:03 +10:00
Shannon 41093e5b8b Value Set builder shouldn't stop indexing when one field is empty in value sets 2019-07-29 15:38:08 +10:00
Shannon efd6bd82bd Revert "V8: Don't show multiple open menus (take two) (#5609)"
This reverts commit 9ce996cbba.

(cherry picked from commit 1d49c8626e)
2019-07-24 12:02:41 +02:00
Sebastiaan Janssen 17527c99eb Makes checks a little more robust
(cherry picked from commit ca75a25802)
2019-07-24 11:37:29 +02:00
Steve Megson 361557dc39 Handle CSV values in TagsPropertyEditor
(cherry picked from commit a97604d6c4)
2019-07-24 11:37:17 +02:00
Kenn Jacobsen 342b2087e9 Make sure save options are up to date with the content state
(cherry picked from commit 8a43e3a87e)
2019-07-24 10:59:01 +02:00
Steve Megson dc371c1979 Include CheckBoxList in ValueListPreValueMigrator 2019-07-23 12:48:48 +02: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
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 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
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
Steve Megson 0feb053e51 Fixes #5852 - TablesForScheduledPublishing 2019-07-16 13:39:09 +02:00
Bjarke Berg 09c8ae4e7e Fixed null ref exception in related links migrations 2019-07-16 13:36:16 +02: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 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
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
Shannon 2252db0d55 Fixes 5822 by reinstating optional method overloads of loadBaseType 2019-07-12 13:40:21 +10:00
Claus df896af476 adding build targets package. 2019-07-10 12:58:15 +02: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
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
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
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
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
348 changed files with 8526 additions and 4076 deletions
+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.1.2")]
[assembly: AssemblyInformationalVersion("8.1.2")]
+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()
{
+49 -18
View File
@@ -12,31 +12,62 @@
/// or MS.DI, PerDependency in Autofac.</remarks>
Transient,
// TODO: We need to fix this up, currently LightInject is the only one that behaves differently from all other containers.
// ... the simple fix would be to map this to PerScopeLifetime in LI but need to wait on a response here https://github.com/seesharper/LightInject/issues/494#issuecomment-518942625
//
// we use it for controllers, httpContextBase and other request scoped objects: MembershpHelper, TagQuery, UmbracoTreeSearcher and ISearchableTree
// - so that they are automatically disposed at the end of the scope (ie request)
// - not sure they should not be simply 'scoped'?
/// <summary>
/// One unique instance per request.
/// </summary>
// TODO: review lifetimes for LightInject vs other containers
// currently, corresponds to 'Request' in LightInject which is 'Transient + disposed by Scope'
// but NOT (in LightInject) a per-web-request lifetime, more a TransientScoped
//
// we use it for controllers, httpContextBase and umbracoContext
// - so that they are automatically disposed at the end of the scope (ie request)
// - not sure they should not be simply 'scoped'?
//
// Castle has an extra PerWebRequest something, and others use scope
// what about Request before first request ie during application startup?
// see http://blog.ploeh.dk/2009/11/17/UsingCastleWindsor'sPerWebRequestlifestylewithASP.NETMVConIIS7/
// Castle ends up requiring a special scope manager too
// see https://groups.google.com/forum/#!topic/castle-project-users/1E2W9LVIYR4
//
// but maybe also - why are we requiring scoped services at startup?
/// <remarks>
/// <para>
/// Any instance created with this lifetime will be disposed at the end of a request.
/// </para>
/// Corresponds to
/// <para>
/// PerRequestLifeTime in LightInject - means transient but disposed at the end of the current web request.
/// see: https://github.com/seesharper/LightInject/issues/494#issuecomment-518493262
/// </para>
/// <para>
/// Scoped in MS.DI - means one per web request.
/// see https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2#service-lifetimes</para>
/// <para>
/// InstancePerRequest in Autofac - means one per web request.
/// see https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-request
/// But "Behind the scenes, though, its still just instance per matching lifetime scope."
/// </para>
/// <para>
/// LifestylePerWebRequest in Castle Windsor - means one per web request.
/// see https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-part-7-lifestyles.md#the-perwebrequest-lifestyle
/// </para>
/// </remarks>
Request,
/// <summary>
/// One unique instance per container scope.
/// One unique instance per scope.
/// </summary>
/// <remarks>Corresponds to Scope in LightInject, Scoped in MS.DI
/// or Castle Windsor, PerLifetimeScope in Autofac.</remarks>
/// <remarks>
/// <para>
/// Any instance created with this lifetime will be disposed at the end of the current scope.
/// </para>
/// Corresponds to
/// <para>PerScopeLifetime in LightInject (when in a request, means one per web request)</para>
/// <para>
/// Scoped in MS.DI (when in a request, means one per web request)
/// see https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2#service-lifetimes</para>
/// <para>
/// InstancePerLifetimeScope in Autofac (when in a request, means one per web request)
/// see https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-lifetime-scope
/// Also note that Autofac's InstancePerRequest is the same as this, see https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-request
/// it says "Behind the scenes, though, its still just instance per matching lifetime scope."
/// </para>
/// <para>
/// LifestyleScoped in Castle Windsor
/// </para>
/// </remarks>
Scope,
/// <summary>
+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>
+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>
@@ -0,0 +1,28 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Exceptions
{
/// <summary>
/// Internal exception that in theory should never ben thrown, it is only thrown in circumstances that should never happen
/// </summary>
[Serializable]
internal class PanicException : Exception
{
public PanicException()
{
}
public PanicException(string message) : base(message)
{
}
public PanicException(string message, Exception innerException) : base(message, innerException)
{
}
protected PanicException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
+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"));
+3 -2
View File
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Exceptions;
namespace Umbraco.Core.Mapping
{
@@ -259,7 +260,7 @@ namespace Umbraco.Core.Mapping
if (typeof(TTarget).IsArray)
{
var elementType = typeof(TTarget).GetElementType();
if (elementType == null) throw new Exception("panic");
if (elementType == null) throw new PanicException("elementType == null which should never occur");
var targetArray = Array.CreateInstance(elementType, targetList.Count);
targetList.CopyTo(targetArray, 0);
target = targetArray;
@@ -382,7 +383,7 @@ namespace Umbraco.Core.Mapping
{
if (type.IsArray) return type.GetElementType();
if (type.IsGenericType) return type.GenericTypeArguments[0];
throw new Exception("panic");
throw new PanicException($"Could not get enumerable or array type from {type}");
}
/// <summary>
@@ -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>();
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using Umbraco.Core.Exceptions;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
@@ -20,7 +21,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
case "Umbraco.NoEdit":
return Constants.PropertyEditors.Aliases.Label;
default:
throw new Exception("panic");
throw new PanicException($"The alias {editorAlias} is not supported");
}
}
}
@@ -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>();
}
@@ -222,7 +222,13 @@ namespace Umbraco.Core.Models
return true;
}
public static void UnpublishCulture(this IContent content, string culture = "*")
/// <summary>
/// Returns false if the culture is already unpublished
/// </summary>
/// <param name="content"></param>
/// <param name="culture"></param>
/// <returns></returns>
public static bool UnpublishCulture(this IContent content, string culture = "*")
{
culture = culture.NullOrWhiteSpaceAsNull();
@@ -230,16 +236,31 @@ namespace Umbraco.Core.Models
if (!content.ContentType.SupportsPropertyVariation(culture, "*", true))
throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\".");
if (culture == "*") // all cultures
var keepProcessing = true;
if (culture == "*")
{
// all cultures
content.ClearPublishInfos();
else // one single culture
content.ClearPublishInfo(culture);
}
else
{
// one single culture
keepProcessing = content.ClearPublishInfo(culture);
}
// property.PublishValues only publishes what is valid, variation-wise
foreach (var property in content.Properties)
property.UnpublishValues(culture);
if (keepProcessing)
{
// property.PublishValues only publishes what is valid, variation-wise
foreach (var property in content.Properties)
property.UnpublishValues(culture);
content.PublishedState = PublishedState.Publishing;
content.PublishedState = PublishedState.Publishing;
}
return keepProcessing;
}
public static void ClearPublishInfos(this IContent content)
@@ -247,15 +268,24 @@ namespace Umbraco.Core.Models
content.PublishCultureInfos = null;
}
public static void ClearPublishInfo(this IContent content, string culture)
/// <summary>
/// Returns false if the culture is already unpublished
/// </summary>
/// <param name="content"></param>
/// <param name="culture"></param>
/// <returns></returns>
public static bool ClearPublishInfo(this IContent content, string culture)
{
if (culture.IsNullOrWhiteSpace())
throw new ArgumentNullOrEmptyException(nameof(culture));
content.PublishCultureInfos.Remove(culture);
// set the culture to be dirty - it's been modified
content.TouchCulture(culture);
var removed = content.PublishCultureInfos.Remove(culture);
if (removed)
{
// set the culture to be dirty - it's been modified
content.TouchCulture(culture);
}
return removed;
}
/// <summary>
@@ -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;
}
}
}
}
+1 -1
View File
@@ -101,7 +101,7 @@ namespace Umbraco.Core.Models
PropertyGroupCollection PropertyGroups { get; set; }
/// <summary>
/// Gets all local property types belonging to a group, across all local property groups.
/// Gets all local property types all local property groups or ungrouped.
/// </summary>
IEnumerable<PropertyType> PropertyTypes { get; }
-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.
*/
+8
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;
@@ -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();
}
}
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Models.PublishedContent
return type;
var def = type.GetGenericTypeDefinition();
if (def == null)
throw new InvalidOperationException("panic");
throw new PanicException($"The type {type} has not generic type definition");
var args = type.GetGenericArguments().Select(x => Map(x, modelTypes, true)).ToArray();
return def.MakeGenericType(args);
@@ -114,7 +114,7 @@ namespace Umbraco.Core.Models.PublishedContent
return type.FullName;
var def = type.GetGenericTypeDefinition();
if (def == null)
throw new InvalidOperationException("panic");
throw new PanicException($"The type {type} has not generic type definition");
var args = type.GetGenericArguments().Select(x => MapToName(x, map, true)).ToArray();
var defFullName = def.FullName.Substring(0, def.FullName.IndexOf('`'));
-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>
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Persistence.Factories
public static IEnumerable<Property> BuildEntities(PropertyType[] propertyTypes, IReadOnlyCollection<PropertyDataDto> dtos, int publishedVersionId, ILanguageRepository languageRepository)
{
var properties = new List<Property>();
var xdtos = dtos.GroupBy(x => x.PropertyTypeId).ToDictionary(x => x.Key, x => (IEnumerable<PropertyDataDto>) x);
var xdtos = dtos.GroupBy(x => x.PropertyTypeId).ToDictionary(x => x.Key, x => (IEnumerable<PropertyDataDto>)x);
foreach (var propertyType in propertyTypes)
{
@@ -104,10 +104,14 @@ namespace Umbraco.Core.Persistence.Factories
/// <param name="properties">The properties to map</param>
/// <param name="languageRepository"></param>
/// <param name="edited">out parameter indicating that one or more properties have been edited</param>
/// <param name="editedCultures">out parameter containing a collection of edited cultures when the contentVariation varies by culture</param>
/// <param name="editedCultures">
/// Out parameter containing a collection of edited cultures when the contentVariation varies by culture.
/// The value of this will be used to populate the edited cultures in the umbracoDocumentCultureVariation table.
/// </param>
/// <returns></returns>
public static IEnumerable<PropertyDataDto> BuildDtos(ContentVariation contentVariation, int currentVersionId, int publishedVersionId, IEnumerable<Property> properties,
ILanguageRepository languageRepository, out bool edited, out HashSet<string> editedCultures)
ILanguageRepository languageRepository, out bool edited,
out HashSet<string> editedCultures)
{
var propertyDataDtos = new List<PropertyDataDto>();
edited = false;
@@ -130,6 +134,9 @@ namespace Umbraco.Core.Persistence.Factories
// publishing = deal with edit and published values
foreach (var propertyValue in property.Values)
{
var isInvariantValue = propertyValue.Culture == null;
var isCultureValue = propertyValue.Culture != null && propertyValue.Segment == null;
// deal with published value
if (propertyValue.PublishedValue != null && publishedVersionId > 0)
propertyDataDtos.Add(BuildDto(publishedVersionId, property, languageRepository.GetIdByIsoCode(propertyValue.Culture), propertyValue.Segment, propertyValue.PublishedValue));
@@ -138,26 +145,36 @@ namespace Umbraco.Core.Persistence.Factories
if (propertyValue.EditedValue != null)
propertyDataDtos.Add(BuildDto(currentVersionId, property, languageRepository.GetIdByIsoCode(propertyValue.Culture), propertyValue.Segment, propertyValue.EditedValue));
// property.Values will contain ALL of it's values, both variant and invariant which will be populated if the
// administrator has previously changed the property type to be variant vs invariant.
// We need to check for this scenario here because otherwise the editedCultures and edited flags
// will end up incorrectly set in the umbracoDocumentCultureVariation table so here we need to
// only process edited cultures based on the current value type and how the property varies.
// The above logic will still persist the currently saved property value for each culture in case the admin
// decides to swap the property's variance again, in which case the edited flag will be recalculated.
if (property.PropertyType.VariesByCulture() && isInvariantValue || !property.PropertyType.VariesByCulture() && isCultureValue)
continue;
// use explicit equals here, else object comparison fails at comparing eg strings
var sameValues = propertyValue.PublishedValue == null ? propertyValue.EditedValue == null : propertyValue.PublishedValue.Equals(propertyValue.EditedValue);
edited |= !sameValues;
if (entityVariesByCulture // cultures can be edited, ie CultureNeutral is supported
&& propertyValue.Culture != null && propertyValue.Segment == null // and value is CultureNeutral
&& !sameValues) // and edited and published are different
if (entityVariesByCulture && !sameValues)
{
editedCultures.Add(propertyValue.Culture); // report culture as edited
}
if (isCultureValue)
{
editedCultures.Add(propertyValue.Culture); // report culture as edited
}
else if (isInvariantValue)
{
// flag culture as edited if it contains an edited invariant property
if (defaultCulture == null)
defaultCulture = languageRepository.GetDefaultIsoCode();
// flag culture as edited if it contains an edited invariant property
if (propertyValue.Culture == null //invariant property
&& !sameValues // and edited and published are different
&& entityVariesByCulture) //only when the entity is variant
{
if (defaultCulture == null)
defaultCulture = languageRepository.GetDefaultIsoCode();
editedCultures.Add(defaultCulture);
editedCultures.Add(defaultCulture);
}
}
}
}
@@ -167,7 +184,7 @@ namespace Umbraco.Core.Persistence.Factories
{
// not publishing = only deal with edit values
if (propertyValue.EditedValue != null)
propertyDataDtos.Add(BuildDto(currentVersionId, property, languageRepository.GetIdByIsoCode(propertyValue.Culture), propertyValue.Segment, propertyValue.EditedValue));
propertyDataDtos.Add(BuildDto(currentVersionId, property, languageRepository.GetIdByIsoCode(propertyValue.Culture), propertyValue.Segment, propertyValue.EditedValue));
}
edited = true;
}
@@ -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);
@@ -512,31 +512,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
foreach (var a in allPropertyDataDtos)
a.PropertyTypeDto = indexedPropertyTypeDtos[a.PropertyTypeId];
// prefetch configuration for tag properties
var tagEditors = new Dictionary<string, TagConfiguration>();
foreach (var propertyTypeDto in indexedPropertyTypeDtos.Values)
{
var editorAlias = propertyTypeDto.DataTypeDto.EditorAlias;
var editorAttribute = PropertyEditors[editorAlias].GetTagAttribute();
if (editorAttribute == null) continue;
var tagConfigurationSource = propertyTypeDto.DataTypeDto.Configuration;
var tagConfiguration = string.IsNullOrWhiteSpace(tagConfigurationSource)
? new TagConfiguration()
: JsonConvert.DeserializeObject<TagConfiguration>(tagConfigurationSource);
if (tagConfiguration.Delimiter == default) tagConfiguration.Delimiter = editorAttribute.Delimiter;
tagEditors[editorAlias] = tagConfiguration;
}
// now we have
// - the definitions
// - all property data dtos
// - tag editors
// - tag editors (Actually ... no we don't since i removed that code, but we don't need them anyways it seems)
// and we need to build the proper property collections
return GetPropertyCollections(temps, allPropertyDataDtos, tagEditors);
return GetPropertyCollections(temps, allPropertyDataDtos);
}
private IDictionary<int, PropertyCollection> GetPropertyCollections<T>(List<TempContent<T>> temps, IEnumerable<PropertyDataDto> allPropertyDataDtos, Dictionary<string, TagConfiguration> tagConfigurations)
private IDictionary<int, PropertyCollection> GetPropertyCollections<T>(List<TempContent<T>> temps, IEnumerable<PropertyDataDto> allPropertyDataDtos)
where T : class, IContentBase
{
var result = new Dictionary<int, PropertyCollection>();
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Exceptions;
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
{
@@ -89,7 +91,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
contentType = ContentTypeFactory.BuildContentTypeEntity(contentTypeDto);
else if (contentTypeDto.NodeDto.NodeObjectType == Constants.ObjectTypes.MemberType)
contentType = ContentTypeFactory.BuildMemberTypeEntity(contentTypeDto);
else throw new Exception("panic");
else throw new PanicException($"The node object type {contentTypeDto.NodeDto.NodeObjectType} is not supported");
contentTypes.Add(contentType.Id, contentType);
// map allowed content types
@@ -188,10 +190,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 +293,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,
@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
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.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -17,8 +19,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class ContentTypeRepository : ContentTypeRepositoryBase<IContentType>, IContentTypeRepository
{
public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository)
: base(scopeAccessor, cache, logger, commonRepository, languageRepository)
{ }
protected override bool SupportsPublishing => ContentType.SupportsPublishingConst;
@@ -55,7 +57,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
if (ids.Any()) throw new PanicException("There can be no ids specified");
return CommonRepository.GetAllTypes().OfType<IContentType>();
}
@@ -230,7 +232,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
throw ex;
}
((ContentType)entity).AddingEntity();
entity.AddingEntity();
PersistNewBaseContentType(entity);
PersistTemplates(entity, false);
@@ -270,7 +272,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"))
@@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Core.Persistence.Repositories.Implement
{
@@ -26,14 +27,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
internal abstract class ContentTypeRepositoryBase<TEntity> : NPocoRepositoryBase<int, TEntity>, IReadRepository<Guid, TEntity>
where TEntity : class, IContentTypeComposition
{
protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository)
: base(scopeAccessor, cache, logger)
{
CommonRepository = commonRepository;
LanguageRepository = languageRepository;
}
protected IContentTypeCommonRepository CommonRepository { get; }
protected ILanguageRepository LanguageRepository { get; }
protected abstract bool SupportsPublishing { get; }
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity moving, EntityContainer container)
@@ -98,6 +100,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected void PersistNewBaseContentType(IContentTypeComposition entity)
{
ValidateVariations(entity);
var dto = ContentTypeFactory.BuildContentTypeDto(entity);
//Cannot add a duplicate content type
@@ -163,11 +167,11 @@ AND umbracoNode.nodeObjectType = @objectType",
foreach (var allowedContentType in entity.AllowedContentTypes)
{
Database.Insert(new ContentTypeAllowedContentTypeDto
{
Id = entity.Id,
AllowedId = allowedContentType.Id.Value,
SortOrder = allowedContentType.SortOrder
});
{
Id = entity.Id,
AllowedId = allowedContentType.Id.Value,
SortOrder = allowedContentType.SortOrder
});
}
@@ -214,6 +218,8 @@ AND umbracoNode.nodeObjectType = @objectType",
protected void PersistUpdatedBaseContentType(IContentTypeComposition entity)
{
ValidateVariations(entity);
var dto = ContentTypeFactory.BuildContentTypeDto(entity);
// ensure the alias is not used already
@@ -370,7 +376,7 @@ AND umbracoNode.id <> @id",
foreach (var propertyGroup in entity.PropertyGroups)
{
// insert or update group
var groupDto = PropertyGroupFactory.BuildGroupDto(propertyGroup,entity.Id);
var groupDto = PropertyGroupFactory.BuildGroupDto(propertyGroup, entity.Id);
var groupId = propertyGroup.HasIdentity
? Database.Update(groupDto)
: Convert.ToInt32(Database.Insert(groupDto));
@@ -388,7 +394,7 @@ AND umbracoNode.id <> @id",
//check if the content type variation has been changed
var contentTypeVariationDirty = entity.IsPropertyDirty("Variations");
var oldContentTypeVariation = (ContentVariation) dtoPk.Variations;
var oldContentTypeVariation = (ContentVariation)dtoPk.Variations;
var newContentTypeVariation = entity.Variations;
var contentTypeVariationChanging = contentTypeVariationDirty && oldContentTypeVariation != newContentTypeVariation;
if (contentTypeVariationChanging)
@@ -449,7 +455,7 @@ AND umbracoNode.id <> @id",
// via composition, with their original variations (ie not filtered by this
// content type variations - we need this true value to make decisions.
foreach (var propertyType in ((ContentTypeCompositionBase) entity).RawComposedPropertyTypes)
foreach (var propertyType in ((ContentTypeCompositionBase)entity).RawComposedPropertyTypes)
{
if (propertyType.VariesBySegment() || newContentTypeVariation.VariesBySegment())
throw new NotSupportedException(); // TODO: support this
@@ -518,6 +524,25 @@ AND umbracoNode.id <> @id",
CommonRepository.ClearCache(); // always
}
/// <summary>
/// Ensures that no property types are flagged for a variance that is not supported by the content type itself
/// </summary>
/// <param name="entity"></param>
private void ValidateVariations(IContentTypeComposition entity)
{
//if the entity does not vary at all, then the property cannot have a variance value greater than it
if (entity.Variations == ContentVariation.Nothing)
{
foreach (var prop in entity.PropertyTypes)
{
if (prop.IsPropertyDirty(nameof(prop.Variations)) && prop.Variations > entity.Variations)
throw new InvalidOperationException($"The property {prop.Alias} cannot have variations of {prop.Variations} with the content type variations of {entity.Variations}");
}
}
}
private IEnumerable<IContentTypeComposition> GetImpactedContentTypes(IContentTypeComposition contentType, IEnumerable<IContentTypeComposition> all)
{
var impact = new List<IContentTypeComposition>();
@@ -525,12 +550,12 @@ AND umbracoNode.id <> @id",
var tree = new Dictionary<int, List<IContentTypeComposition>>();
foreach (var x in all)
foreach (var y in x.ContentTypeComposition)
{
if (!tree.TryGetValue(y.Id, out var list))
list = tree[y.Id] = new List<IContentTypeComposition>();
list.Add(x);
}
foreach (var y in x.ContentTypeComposition)
{
if (!tree.TryGetValue(y.Id, out var list))
list = tree[y.Id] = new List<IContentTypeComposition>();
list.Add(x);
}
var nset = new List<IContentTypeComposition>();
do
@@ -572,7 +597,7 @@ AND umbracoNode.id <> @id",
// new property type, ignore
if (!oldVariations.TryGetValue(propertyType.Id, out var oldVariationB))
continue;
var oldVariation = (ContentVariation) oldVariationB; // NPoco cannot fetch directly
var oldVariation = (ContentVariation)oldVariationB; // NPoco cannot fetch directly
// only those property types that *actually* changed
var newVariation = propertyType.Variations;
@@ -636,7 +661,7 @@ AND umbracoNode.id <> @id",
var impactedL = impacted.Select(x => x.Id).ToList();
//Group by the "To" variation so we can bulk update in the correct batches
foreach(var grouping in propertyTypeChanges.GroupBy(x => x.Value.ToVariation))
foreach (var grouping in propertyTypeChanges.GroupBy(x => x.Value.ToVariation))
{
var propertyTypeIds = grouping.Select(x => x.Key).ToList();
var toVariation = grouping.Key;
@@ -646,10 +671,12 @@ AND umbracoNode.id <> @id",
case ContentVariation.Culture:
CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL);
CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL);
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
break;
case ContentVariation.Nothing:
CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL);
CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL);
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
break;
case ContentVariation.CultureAndSegment:
case ContentVariation.Segment:
@@ -963,6 +990,205 @@ AND umbracoNode.id <> @id",
Database.Execute(sqlDelete);
}
}
/// <summary>
/// Re-normalizes the edited value in the umbracoDocumentCultureVariation and umbracoDocument table when variations are changed
/// </summary>
/// <param name="propertyTypeIds"></param>
/// <param name="contentTypeIds"></param>
/// <remarks>
/// If this is not done, then in some cases the "edited" value for a particular culture for a document will remain true when it should be false
/// if the property was changed to invariant. In order to do this we need to recalculate this value based on the values stored for each
/// property, culture and current/published version.
/// </remarks>
private void RenormalizeDocumentEditedFlags(IReadOnlyCollection<int> propertyTypeIds, IReadOnlyCollection<int> contentTypeIds = null)
{
var defaultLang = LanguageRepository.GetDefaultId();
//This will build up a query to get the property values of both the current and the published version so that we can check
//based on the current variance of each item to see if it's 'edited' value should be true/false.
var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0);
if (whereInArgsCount > 2000)
throw new NotSupportedException("Too many property/content types.");
var propertySql = Sql()
.Select<PropertyDataDto>()
.AndSelect<ContentVersionDto>(x => x.NodeId, x => x.Current)
.AndSelect<DocumentVersionDto>(x => x.Published)
.AndSelect<PropertyTypeDto>(x => x.Variations)
.From<PropertyDataDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, PropertyDataDto>((left, right) => left.Id == right.VersionId)
.InnerJoin<PropertyTypeDto>().On<PropertyTypeDto, PropertyDataDto>((left, right) => left.Id == right.PropertyTypeId);
if (contentTypeIds != null)
{
propertySql.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>((c, cversion) => c.NodeId == cversion.NodeId);
}
propertySql.LeftJoin<DocumentVersionDto>().On<DocumentVersionDto, ContentVersionDto>((docversion, cversion) => cversion.Id == docversion.Id)
.Where<DocumentVersionDto, ContentVersionDto>((docversion, cversion) => cversion.Current || docversion.Published)
.WhereIn<PropertyDataDto>(x => x.PropertyTypeId, propertyTypeIds);
if (contentTypeIds != null)
{
propertySql.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIds);
}
propertySql
.OrderBy<ContentVersionDto>(x => x.NodeId)
.OrderBy<PropertyDataDto>(x => x.PropertyTypeId, x => x.LanguageId, x => x.VersionId);
//keep track of this node/lang to mark or unmark a culture as edited
var editedLanguageVersions = new Dictionary<(int nodeId, int? langId), bool>();
//keep track of which node to mark or unmark as edited
var editedDocument = new Dictionary<int, bool>();
var nodeId = -1;
var propertyTypeId = -1;
PropertyValueVersionDto pubRow = null;
//This is a reader (Query), we are not fetching this all into memory so we cannot make any changes during this iteration, we are just collecting data.
//Published data will always come before Current data based on the version id sort.
//There will only be one published row (max) and one current row per property.
foreach (var row in Database.Query<PropertyValueVersionDto>(propertySql))
{
//make sure to reset on each node/property change
if (nodeId != row.NodeId || propertyTypeId != row.PropertyTypeId)
{
nodeId = row.NodeId;
propertyTypeId = row.PropertyTypeId;
pubRow = null;
}
if (row.Published)
pubRow = row;
if (row.Current)
{
var propVariations = (ContentVariation)row.Variations;
//if this prop doesn't vary but the row has a lang assigned or vice versa, flag this as not edited
if (!propVariations.VariesByCulture() && row.LanguageId.HasValue
|| propVariations.VariesByCulture() && !row.LanguageId.HasValue)
{
//Flag this as not edited for this node/lang if the key doesn't exist
if (!editedLanguageVersions.TryGetValue((row.NodeId, row.LanguageId), out _))
editedLanguageVersions.Add((row.NodeId, row.LanguageId), false);
//mark as false if the item doesn't exist, else coerce to true
editedDocument[row.NodeId] = editedDocument.TryGetValue(row.NodeId, out var edited) ? (edited |= false) : false;
}
else if (pubRow == null)
{
//this would mean that that this property is 'edited' since there is no published version
editedLanguageVersions[(row.NodeId, row.LanguageId)] = true;
editedDocument[row.NodeId] = true;
}
//compare the property values, if they differ from versions then flag the current version as edited
else if (IsPropertyValueChanged(pubRow, row))
{
//Here we would check if the property is invariant, in which case the edited language should be indicated by the default lang
editedLanguageVersions[(row.NodeId, !propVariations.VariesByCulture() ? defaultLang : row.LanguageId)] = true;
editedDocument[row.NodeId] = true;
}
//reset
pubRow = null;
}
}
//lookup all matching rows in umbracoDocumentCultureVariation
var docCultureVariationsToUpdate = editedLanguageVersions.InGroupsOf(2000)
.SelectMany(_ => Database.Fetch<DocumentCultureVariationDto>(
Sql().Select<DocumentCultureVariationDto>().From<DocumentCultureVariationDto>()
.WhereIn<DocumentCultureVariationDto>(x => x.LanguageId, editedLanguageVersions.Keys.Select(x => x.langId).ToList())
.WhereIn<DocumentCultureVariationDto>(x => x.NodeId, editedLanguageVersions.Keys.Select(x => x.nodeId))))
//convert to dictionary with the same key type
.ToDictionary(x => (x.NodeId, (int?)x.LanguageId), x => x);
var toUpdate = new List<DocumentCultureVariationDto>();
foreach (var ev in editedLanguageVersions)
{
if (docCultureVariationsToUpdate.TryGetValue(ev.Key, out var docVariations))
{
//check if it needs updating
if (docVariations.Edited != ev.Value)
{
docVariations.Edited = ev.Value;
toUpdate.Add(docVariations);
}
}
else if (ev.Key.langId.HasValue)
{
//This should never happen! If a property culture is flagged as edited then the culture must exist at the document level
throw new PanicException($"The existing DocumentCultureVariationDto was not found for node {ev.Key.nodeId} and language {ev.Key.langId}");
}
}
//Now bulk update the table DocumentCultureVariationDto, once for edited = true, another for edited = false
foreach (var editValue in toUpdate.GroupBy(x => x.Edited))
{
Database.Execute(Sql().Update<DocumentCultureVariationDto>(u => u.Set(x => x.Edited, editValue.Key))
.WhereIn<DocumentCultureVariationDto>(x => x.Id, editValue.Select(x => x.Id)));
}
//Now bulk update the umbracoDocument table
foreach (var editValue in editedDocument.GroupBy(x => x.Value))
{
Database.Execute(Sql().Update<DocumentDto>(u => u.Set(x => x.Edited, editValue.Key))
.WhereIn<DocumentDto>(x => x.NodeId, editValue.Select(x => x.Key)));
}
}
private static bool IsPropertyValueChanged(PropertyValueVersionDto pubRow, PropertyValueVersionDto row)
{
return !pubRow.TextValue.IsNullOrWhiteSpace() && pubRow.TextValue != row.TextValue
|| !pubRow.VarcharValue.IsNullOrWhiteSpace() && pubRow.VarcharValue != row.VarcharValue
|| pubRow.DateValue.HasValue && pubRow.DateValue != row.DateValue
|| pubRow.DecimalValue.HasValue && pubRow.DecimalValue != row.DecimalValue
|| pubRow.IntValue.HasValue && pubRow.IntValue != row.IntValue;
}
private class NameCompareDto
{
public int NodeId { get; set; }
public int CurrentVersion { get; set; }
public int LanguageId { get; set; }
public string CurrentName { get; set; }
public string PublishedName { get; set; }
public int? PublishedVersion { get; set; }
public int Id { get; set; } // the Id of the DocumentCultureVariationDto
public bool Edited { get; set; }
}
private class PropertyValueVersionDto
{
public int VersionId { get; set; }
public int PropertyTypeId { get; set; }
public int? LanguageId { get; set; }
public string Segment { get; set; }
public int? IntValue { get; set; }
private decimal? _decimalValue;
[Column("decimalValue")]
public decimal? DecimalValue
{
get => _decimalValue;
set => _decimalValue = value?.Normalize();
}
public DateTime? DateValue { get; set; }
public string VarcharValue { get; set; }
public string TextValue { get; set; }
public int NodeId { get; set; }
public bool Current { get; set; }
public bool Published { get; set; }
public byte Variations { get; set; }
}
private void DeletePropertyType(int contentTypeId, int propertyTypeId)
@@ -1013,8 +1239,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 +1249,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, 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,45 +502,45 @@ 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);
Database.Insert(documentVersionDto);
}
// 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, 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);
}
@@ -1299,25 +1297,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
};
}
private IEnumerable<DocumentCultureVariationDto> GetDocumentVariationDtos(IContent content, bool publishing, HashSet<string> editedCultures)
private IEnumerable<DocumentCultureVariationDto> GetDocumentVariationDtos(IContent content, HashSet<string> editedCultures)
{
var allCultures = content.AvailableCultures.Union(content.PublishedCultures); // union = distinct
foreach (var culture in allCultures)
yield return new DocumentCultureVariationDto
{
var dto = new DocumentCultureVariationDto
{
NodeId = content.Id,
LanguageId = LanguageRepository.GetIdByIsoCode(culture) ?? throw new InvalidOperationException("Not a valid culture."),
Culture = culture,
Name = content.GetCultureName(culture) ?? content.GetPublishName(culture),
// note: can't use IsCultureEdited at that point - hasn't been updated yet - see PersistUpdatedItem
Available = content.IsCultureAvailable(culture),
Published = content.IsCulturePublished(culture),
// note: can't use IsCultureEdited at that point - hasn't been updated yet - see PersistUpdatedItem
Edited = content.IsCultureAvailable(culture) &&
(!content.IsCulturePublished(culture) || (editedCultures != null && editedCultures.Contains(culture)))
};
yield return dto;
}
}
private class ContentVariation
@@ -1335,7 +1336,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 +1401,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);
@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
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.Querying;
using Umbraco.Core.Scoping;
@@ -16,8 +18,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class MediaTypeRepository : ContentTypeRepositoryBase<IMediaType>, IMediaTypeRepository
{
public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository)
: base(scopeAccessor, cache, logger, commonRepository, languageRepository)
{ }
protected override bool SupportsPublishing => MediaType.SupportsPublishingConst;
@@ -49,7 +51,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
if (ids.Any()) throw new PanicException("There can be no ids specified");
return CommonRepository.GetAllTypes().OfType<IMediaType>();
}
@@ -102,7 +104,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMediaType entity)
{
((MediaType)entity).AddingEntity();
entity.AddingEntity();
PersistNewBaseContentType(entity);
@@ -114,7 +116,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?
@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using NPoco;
using Umbraco.Core.Cache;
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;
@@ -17,8 +19,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class MemberTypeRepository : ContentTypeRepositoryBase<IMemberType>, IMemberTypeRepository
{
public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository)
: base(scopeAccessor, cache, logger, commonRepository)
public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository)
: base(scopeAccessor, cache, logger, commonRepository, languageRepository)
{ }
protected override bool SupportsPublishing => MemberType.SupportsPublishingConst;
@@ -56,7 +58,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
// the cache policy will always want everything
// even GetMany(ids) gets everything and filters afterwards
if (ids.Any()) throw new Exception("panic");
if (ids.Any()) throw new PanicException("There can be no ids specified");
return CommonRepository.GetAllTypes().OfType<IMemberType>();
}
@@ -131,12 +133,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 +167,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 +226,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())
@@ -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; }
}
}
@@ -55,6 +55,7 @@ namespace Umbraco.Core.PropertyEditors
/// <summary>
/// Gets the type of the dynamic configuration provider.
/// </summary>
//TODO: This is not used and should be implemented in a nicer way, see https://github.com/umbraco/Umbraco-CMS/issues/6017#issuecomment-516253562
public Type TagsConfigurationProviderType { get; }
}
}
+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
@@ -884,6 +886,8 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
var allLangs = _languageRepository.GetMany().ToList();
var saveEventArgs = new ContentSavingEventArgs(content, evtMsgs);
if (raiseEvents && scope.Events.DispatchCancelable(Saving, this, saveEventArgs, nameof(Saving)))
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
@@ -892,13 +896,13 @@ namespace Umbraco.Core.Services.Implement
// if culture is '*', then publish them all (including variants)
//this will create the correct culture impact even if culture is * or null
var impact = CultureImpact.Create(culture, _languageRepository.IsDefault(culture), content);
var impact = CultureImpact.Create(culture, IsDefaultCulture(allLangs, culture), content);
// publish the culture(s)
// we don't care about the response here, this response will be rechecked below but we need to set the culture info values now.
content.PublishCulture(impact);
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, userId, raiseEvents);
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, allLangs, userId, raiseEvents);
scope.Complete();
return result;
}
@@ -919,6 +923,8 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
var allLangs = _languageRepository.GetMany().ToList();
var evtMsgs = EventMessagesFactory.Get();
var saveEventArgs = new ContentSavingEventArgs(content, evtMsgs);
if (raiseEvents && scope.Events.DispatchCancelable(Saving, this, saveEventArgs, nameof(Saving)))
@@ -926,25 +932,23 @@ namespace Umbraco.Core.Services.Implement
var varies = content.ContentType.VariesByCulture();
if (cultures.Length == 0)
if (cultures.Length == 0 && !varies)
{
//no cultures specified and doesn't vary, so publish it, else nothing to publish
return !varies
? SaveAndPublish(content, userId: userId, raiseEvents: raiseEvents)
: new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content);
return SaveAndPublish(content, userId: userId, raiseEvents: raiseEvents);
}
if (cultures.Any(x => x == null || x == "*"))
throw new InvalidOperationException("Only valid cultures are allowed to be used in this method, wildcards or nulls are not allowed");
var impacts = cultures.Select(x => CultureImpact.Explicit(x, _languageRepository.IsDefault(x)));
var impacts = cultures.Select(x => CultureImpact.Explicit(x, IsDefaultCulture(allLangs, x)));
// publish the culture(s)
// we don't care about the response here, this response will be rechecked below but we need to set the culture info values now.
foreach (var impact in impacts)
content.PublishCulture(impact);
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, userId, raiseEvents);
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, allLangs, userId, raiseEvents);
scope.Complete();
return result;
}
@@ -984,6 +988,8 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
var allLangs = _languageRepository.GetMany().ToList();
var saveEventArgs = new ContentSavingEventArgs(content, evtMsgs);
if (scope.Events.DispatchCancelable(Saving, this, saveEventArgs, nameof(Saving)))
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
@@ -991,26 +997,39 @@ namespace Umbraco.Core.Services.Implement
// all cultures = unpublish whole
if (culture == "*" || (!content.ContentType.VariesByCulture() && culture == null))
{
// It's important to understand that when the document varies by culture but the "*" is used,
// we are just unpublishing the whole document but leaving all of the culture's as-is. This is expected
// because we don't want to actually unpublish every culture and then the document, we just want everything
// to be non-routable so that when it's re-published all variants were as they were.
content.PublishedState = PublishedState.Unpublishing;
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, allLangs, userId);
scope.Complete();
return result;
}
else
{
// If the culture we want to unpublish was already unpublished, nothing to do.
// To check for that we need to lookup the persisted content item
var persisted = content.HasIdentity ? GetById(content.Id) : null;
// Unpublish the culture, this will change the document state to Publishing! ... which is expected because this will
// essentially be re-publishing the document with the requested culture removed.
// The call to CommitDocumentChangesInternal will perform all the checks like if this is a mandatory culture or the last culture being unpublished
// and will then unpublish the document accordingly.
// If the result of this is false it means there was no culture to unpublish (i.e. it was already unpublished or it did not exist)
var removed = content.UnpublishCulture(culture);
if (persisted != null && !persisted.IsCulturePublished(culture))
//save and publish any changes
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, allLangs, userId);
scope.Complete();
// In one case the result will be PublishStatusType.FailedPublishNothingToPublish which means that no cultures
// were specified to be published which will be the case when removed is false. In that case
// we want to swap the result type to PublishResultType.SuccessUnpublishAlready (that was the expectation before).
if (result.Result == PublishResultType.FailedPublishNothingToPublish && !removed)
return new PublishResult(PublishResultType.SuccessUnpublishAlready, evtMsgs, content);
// unpublish the culture
content.UnpublishCulture(culture);
return result;
}
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, userId);
scope.Complete();
return result;
}
}
/// <summary>
@@ -1045,15 +1064,35 @@ namespace Umbraco.Core.Services.Implement
if (raiseEvents && scope.Events.DispatchCancelable(Saving, this, saveEventArgs, nameof(Saving)))
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, userId, raiseEvents);
var allLangs = _languageRepository.GetMany().ToList();
var result = CommitDocumentChangesInternal(scope, content, saveEventArgs, allLangs, userId, raiseEvents);
scope.Complete();
return result;
}
}
/// <summary>
/// Handles a lot of business logic cases for how the document should be persisted
/// </summary>
/// <param name="scope"></param>
/// <param name="content"></param>
/// <param name="saveEventArgs"></param>
/// <param name="userId"></param>
/// <param name="raiseEvents"></param>
/// <param name="branchOne"></param>
/// <param name="branchRoot"></param>
/// <returns></returns>
/// <remarks>
/// <para>
/// Business logic cases such: as unpublishing a mandatory culture, or unpublishing the last culture, checking for pending scheduled publishing, etc... is dealt with in this method.
/// There is quite a lot of cases to take into account along with logic that needs to deal with scheduled saving/publishing, branch saving/publishing, etc...
/// </para>
/// </remarks>
private PublishResult CommitDocumentChangesInternal(IScope scope, IContent content,
ContentSavingEventArgs saveEventArgs,
int userId = Constants.Security.SuperUserId, bool raiseEvents = true, bool branchOne = false, bool branchRoot = false)
ContentSavingEventArgs saveEventArgs, IReadOnlyCollection<ILanguage> allLangs,
int userId = Constants.Security.SuperUserId,
bool raiseEvents = true, bool branchOne = false, bool branchRoot = false)
{
if (scope == null) throw new ArgumentNullException(nameof(scope));
if (content == null) throw new ArgumentNullException(nameof(content));
@@ -1068,8 +1107,8 @@ namespace Umbraco.Core.Services.Implement
if (content.PublishedState != PublishedState.Publishing && content.PublishedState != PublishedState.Unpublishing)
content.PublishedState = PublishedState.Publishing;
// state here is either Publishing or Unpublishing
// (even though, Publishing to unpublish a culture may end up unpublishing everything)
// State here is either Publishing or Unpublishing
// Publishing to unpublish a culture may end up unpublishing everything so these flags can be flipped later
var publishing = content.PublishedState == PublishedState.Publishing;
var unpublishing = content.PublishedState == PublishedState.Unpublishing;
@@ -1086,6 +1125,18 @@ namespace Umbraco.Core.Services.Implement
var changeType = isNew ? TreeChangeTypes.RefreshNode : TreeChangeTypes.RefreshBranch;
var previouslyPublished = content.HasIdentity && content.Published;
//inline method to persist the document with the documentRepository since this logic could be called a couple times below
void SaveDocument(IContent c)
{
// save, always
if (c.HasIdentity == false)
c.CreatorId = userId;
c.WriterId = userId;
// saving does NOT change the published version, unless PublishedState is Publishing or Unpublishing
_documentRepository.Save(c);
}
if (publishing)
{
//determine cultures publishing/unpublishing which will be based on previous calls to content.PublishCulture and ClearPublishInfo
@@ -1095,11 +1146,25 @@ namespace Umbraco.Core.Services.Implement
: null;
// ensure that the document can be published, and publish handling events, business rules, etc
publishResult = StrategyCanPublish(scope, content, /*checkPath:*/ (!branchOne || branchRoot), culturesPublishing, culturesUnpublishing, evtMsgs, saveEventArgs);
publishResult = StrategyCanPublish(scope, content, /*checkPath:*/ (!branchOne || branchRoot), culturesPublishing, culturesUnpublishing, evtMsgs, saveEventArgs, allLangs);
if (publishResult.Success)
{
// note: StrategyPublish flips the PublishedState to Publishing!
publishResult = StrategyPublish(content, culturesPublishing, culturesUnpublishing, evtMsgs);
//check if a culture has been unpublished and if there are no cultures left, and then unpublish document as a whole
if (publishResult.Result == PublishResultType.SuccessUnpublishCulture && content.PublishCultureInfos.Count == 0)
{
// This is a special case! We are unpublishing the last culture and to persist that we need to re-publish without any cultures
// so the state needs to remain Publishing to do that. However, we then also need to unpublish the document and to do that
// the state needs to be Unpublishing and it cannot be both. This state is used within the documentRepository to know how to
// persist certain things. So before proceeding below, we need to save the Publishing state to publish no cultures, then we can
// mark the document for Unpublishing.
SaveDocument(content);
//set the flag to unpublish and continue
unpublishing = content.Published; // if not published yet, nothing to do
}
}
else
{
@@ -1160,13 +1225,8 @@ namespace Umbraco.Core.Services.Implement
}
}
// save, always
if (content.HasIdentity == false)
content.CreatorId = userId;
content.WriterId = userId;
// saving does NOT change the published version, unless PublishedState is Publishing or Unpublishing
_documentRepository.Save(content);
//Persist the document
SaveDocument(content);
// raise the Saved event, always
if (raiseEvents)
@@ -1184,17 +1244,34 @@ namespace Umbraco.Core.Services.Implement
if (culturesUnpublishing != null)
{
//If we are here, it means we tried unpublishing a culture but it was mandatory so now everything is unpublished
var langs = string.Join(", ", _languageRepository.GetMany()
// This will mean that that we unpublished a mandatory culture or we unpublished the last culture.
var langs = string.Join(", ", allLangs
.Where(x => culturesUnpublishing.InvariantContains(x.IsoCode))
.Select(x => x.CultureName));
Audit(AuditType.UnpublishVariant, userId, content.Id, $"Unpublished languages: {langs}", langs);
//log that the whole content item has been unpublished due to mandatory culture unpublished
Audit(AuditType.Unpublish, userId, content.Id, "Unpublished (mandatory language unpublished)");
}
else
Audit(AuditType.Unpublish, userId, content.Id);
if (publishResult == null)
throw new PanicException("publishResult == null - should not happen");
switch(publishResult.Result)
{
case PublishResultType.FailedPublishMandatoryCultureMissing:
//occurs when a mandatory culture was unpublished (which means we tried publishing the document without a mandatory culture)
//log that the whole content item has been unpublished due to mandatory culture unpublished
Audit(AuditType.Unpublish, userId, content.Id, "Unpublished (mandatory language unpublished)");
return new PublishResult(PublishResultType.SuccessUnpublishMandatoryCulture, evtMsgs, content);
case PublishResultType.SuccessUnpublishCulture:
//occurs when the last culture is unpublished
Audit(AuditType.Unpublish, userId, content.Id, "Unpublished (last language unpublished)");
return new PublishResult(PublishResultType.SuccessUnpublishLastCulture, evtMsgs, content);
}
}
Audit(AuditType.Unpublish, userId, content.Id);
return new PublishResult(PublishResultType.SuccessUnpublish, evtMsgs, content);
}
@@ -1234,7 +1311,7 @@ namespace Umbraco.Core.Services.Implement
case PublishResultType.SuccessPublishCulture:
if (culturesPublishing != null)
{
var langs = string.Join(", ", _languageRepository.GetMany()
var langs = string.Join(", ", allLangs
.Where(x => culturesPublishing.InvariantContains(x.IsoCode))
.Select(x => x.CultureName));
Audit(AuditType.PublishVariant, userId, content.Id, $"Published languages: {langs}", langs);
@@ -1243,7 +1320,7 @@ namespace Umbraco.Core.Services.Implement
case PublishResultType.SuccessUnpublishCulture:
if (culturesUnpublishing != null)
{
var langs = string.Join(", ", _languageRepository.GetMany()
var langs = string.Join(", ", allLangs
.Where(x => culturesUnpublishing.InvariantContains(x.IsoCode))
.Select(x => x.CultureName));
Audit(AuditType.UnpublishVariant, userId, content.Id, $"Unpublished languages: {langs}", langs);
@@ -1257,14 +1334,14 @@ namespace Umbraco.Core.Services.Implement
// should not happen
if (branchOne && !branchRoot)
throw new Exception("panic");
throw new PanicException("branchOne && !branchRoot - should not happen");
//if publishing didn't happen or if it has failed, we still need to log which cultures were saved
if (!branchOne && (publishResult == null || !publishResult.Success))
{
if (culturesChanging != null)
{
var langs = string.Join(", ", _languageRepository.GetMany()
var langs = string.Join(", ", allLangs
.Where(x => culturesChanging.InvariantContains(x.IsoCode))
.Select(x => x.CultureName));
Audit(AuditType.SaveVariant, userId, content.Id, $"Saved languages: {langs}", langs);
@@ -1295,6 +1372,8 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
var allLangs = _languageRepository.GetMany().ToList();
foreach (var d in _documentRepository.GetContentForRelease(date))
{
PublishResult result;
@@ -1323,7 +1402,7 @@ namespace Umbraco.Core.Services.Implement
//publish the culture values and validate the property values, if validation fails, log the invalid properties so the develeper has an idea of what has failed
Property[] invalidProperties = null;
var impact = CultureImpact.Explicit(culture, _languageRepository.IsDefault(culture));
var impact = CultureImpact.Explicit(culture, IsDefaultCulture(allLangs, culture));
var tryPublish = d.PublishCulture(impact) && _propertyValidationService.Value.IsPropertyDataValid(d, out invalidProperties, impact);
if (invalidProperties != null && invalidProperties.Length > 0)
Logger.Warn<ContentService>("Scheduled publishing will fail for document {DocumentId} and culture {Culture} because of invalid properties {InvalidProperties}",
@@ -1338,7 +1417,7 @@ namespace Umbraco.Core.Services.Implement
else if (!publishing)
result = new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, d);
else
result = CommitDocumentChangesInternal(scope, d, saveEventArgs, d.WriterId);
result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs, d.WriterId);
if (result.Success == false)
@@ -1388,7 +1467,7 @@ namespace Umbraco.Core.Services.Implement
d.UnpublishCulture(c);
}
result = CommitDocumentChangesInternal(scope, d, saveEventArgs, d.WriterId);
result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs, d.WriterId);
if (result.Success == false)
Logger.Error<ContentService>(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result);
yield return result;
@@ -1414,7 +1493,7 @@ namespace Umbraco.Core.Services.Implement
}
// utility 'PublishCultures' func used by SaveAndPublishBranch
private bool SaveAndPublishBranch_PublishCultures(IContent content, HashSet<string> culturesToPublish)
private bool SaveAndPublishBranch_PublishCultures(IContent content, HashSet<string> culturesToPublish, IReadOnlyCollection<ILanguage> allLangs)
{
//TODO: This does not support being able to return invalid property details to bubble up to the UI
@@ -1424,7 +1503,7 @@ namespace Umbraco.Core.Services.Implement
{
return culturesToPublish.All(culture =>
{
var impact = CultureImpact.Create(culture, _languageRepository.IsDefault(culture), content);
var impact = CultureImpact.Create(culture, IsDefaultCulture(allLangs, culture), content);
return content.PublishCulture(impact) && _propertyValidationService.Value.IsPropertyDataValid(content, out _, impact);
});
}
@@ -1533,7 +1612,7 @@ namespace Umbraco.Core.Services.Implement
internal IEnumerable<PublishResult> SaveAndPublishBranch(IContent document, bool force,
Func<IContent, HashSet<string>> shouldPublish,
Func<IContent, HashSet<string>, bool> publishCultures,
Func<IContent, HashSet<string>, IReadOnlyCollection<ILanguage>, bool> publishCultures,
int userId = Constants.Security.SuperUserId)
{
if (shouldPublish == null) throw new ArgumentNullException(nameof(shouldPublish));
@@ -1547,6 +1626,8 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
var allLangs = _languageRepository.GetMany().ToList();
if (!document.HasIdentity)
throw new InvalidOperationException("Cannot not branch-publish a new document.");
@@ -1555,7 +1636,7 @@ namespace Umbraco.Core.Services.Implement
throw new InvalidOperationException("Cannot mix PublishCulture and SaveAndPublishBranch.");
// deal with the branch root - if it fails, abort
var result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, evtMsgs, userId);
var result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, evtMsgs, userId, allLangs);
if (result != null)
{
results.Add(result);
@@ -1586,7 +1667,7 @@ namespace Umbraco.Core.Services.Implement
}
// no need to check path here, parent has to be published here
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, evtMsgs, userId);
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, evtMsgs, userId, allLangs);
if (result != null)
{
results.Add(result);
@@ -1618,10 +1699,10 @@ namespace Umbraco.Core.Services.Implement
// publishValues: a function publishing values (using the appropriate PublishCulture calls)
private PublishResult SaveAndPublishBranchItem(IScope scope, IContent document,
Func<IContent, HashSet<string>> shouldPublish,
Func<IContent, HashSet<string>, bool> publishCultures,
Func<IContent, HashSet<string>, IReadOnlyCollection<ILanguage>, bool> publishCultures,
bool isRoot,
ICollection<IContent> publishedDocuments,
EventMessages evtMsgs, int userId)
EventMessages evtMsgs, int userId, IReadOnlyCollection<ILanguage> allLangs)
{
var culturesToPublish = shouldPublish(document);
if (culturesToPublish == null) // null = do not include
@@ -1634,13 +1715,13 @@ namespace Umbraco.Core.Services.Implement
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, document);
// publish & check if values are valid
if (!publishCultures(document, culturesToPublish))
if (!publishCultures(document, culturesToPublish, allLangs))
{
//TODO: Based on this callback behavior there is no way to know which properties may have been invalid if this failed, see other results of FailedPublishContentInvalid
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, document);
}
var result = CommitDocumentChangesInternal(scope, document, saveEventArgs, userId, branchOne: true, branchRoot: isRoot);
var result = CommitDocumentChangesInternal(scope, document, saveEventArgs, allLangs, userId, branchOne: true, branchRoot: isRoot);
if (result.Success)
publishedDocuments.Add(document);
return result;
@@ -2341,6 +2422,9 @@ namespace Umbraco.Core.Services.Implement
_auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.Document), message, parameters));
}
private bool IsDefaultCulture(IReadOnlyCollection<ILanguage> langs, string culture) => langs.Any(x => x.IsDefault && x.IsoCode.InvariantEquals(culture));
private bool IsMandatoryCulture(IReadOnlyCollection<ILanguage> langs, string culture) => langs.Any(x => x.IsMandatory && x.IsoCode.InvariantEquals(culture));
#endregion
#region Event Handlers
@@ -2495,7 +2579,9 @@ namespace Umbraco.Core.Services.Implement
/// <param name="culturesPublishing"></param>
/// <param name="savingEventArgs"></param>
/// <returns></returns>
private PublishResult StrategyCanPublish(IScope scope, IContent content, bool checkPath, IReadOnlyList<string> culturesPublishing, IReadOnlyCollection<string> culturesUnpublishing, EventMessages evtMsgs, ContentSavingEventArgs savingEventArgs)
private PublishResult StrategyCanPublish(IScope scope, IContent content, bool checkPath, IReadOnlyList<string> culturesPublishing,
IReadOnlyCollection<string> culturesUnpublishing, EventMessages evtMsgs, ContentSavingEventArgs savingEventArgs,
IReadOnlyCollection<ILanguage> allLangs)
{
// raise Publishing event
if (scope.Events.DispatchCancelable(Publishing, this, savingEventArgs.ToContentPublishingEventArgs()))
@@ -2508,7 +2594,7 @@ namespace Umbraco.Core.Services.Implement
var impactsToPublish = culturesPublishing == null
? new[] {CultureImpact.Invariant} //if it's null it's invariant
: culturesPublishing.Select(x => CultureImpact.Explicit(x, _languageRepository.IsDefault(x))).ToArray();
: culturesPublishing.Select(x => CultureImpact.Explicit(x, allLangs.Any(lang => lang.IsoCode.InvariantEquals(x) && lang.IsMandatory))).ToArray();
// publish the culture(s)
if (!impactsToPublish.All(content.PublishCulture))
@@ -2529,11 +2615,17 @@ namespace Umbraco.Core.Services.Implement
if (culturesPublishing == null)
throw new InvalidOperationException("Internal error, variesByCulture but culturesPublishing is null.");
if (content.Published && culturesPublishing.Count == 0 && culturesUnpublishing.Count == 0) // no published cultures = cannot be published
if (content.Published && culturesPublishing.Count == 0 && culturesUnpublishing.Count == 0)
{
// no published cultures = cannot be published
// This will occur if for example, a culture that is already unpublished is sent to be unpublished again, or vice versa, in that case
// there will be nothing to publish/unpublish.
return new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content);
}
// missing mandatory culture = cannot be published
var mandatoryCultures = _languageRepository.GetMany().Where(x => x.IsMandatory).Select(x => x.IsoCode);
var mandatoryCultures = allLangs.Where(x => x.IsMandatory).Select(x => x.IsoCode);
var mandatoryMissing = mandatoryCultures.Any(x => !content.PublishedCultures.Contains(x, StringComparer.OrdinalIgnoreCase));
if (mandatoryMissing)
return new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, evtMsgs, content);
@@ -2674,6 +2766,7 @@ namespace Umbraco.Core.Services.Implement
{
var attempt = new PublishResult(PublishResultType.SuccessUnpublish, evtMsgs, content);
//TODO: What is this check?? we just created this attempt and of course it is Success?!
if (attempt.Success == false)
return attempt;
@@ -3024,5 +3117,8 @@ namespace Umbraco.Core.Services.Implement
}
#endregion
}
}
@@ -49,6 +49,11 @@
/// </summary>
SuccessUnpublishMandatoryCulture = 6,
/// <summary>
/// The specified document culture was unpublished, and was the last published culture in the document, therefore the document itself was unpublished.
/// </summary>
SuccessUnpublishLastCulture = 8,
#endregion
#region Success - Mixed
@@ -113,9 +118,9 @@
FailedPublishContentInvalid = FailedPublish | 8,
/// <summary>
/// The document could not be published because it has no publishing flags or values.
/// The document could not be published because it has no publishing flags or values or if its a variant document, no cultures were specified to be published.
/// </summary>
FailedPublishNothingToPublish = FailedPublish | 9, // TODO: in ContentService.StrategyCanPublish - weird
FailedPublishNothingToPublish = FailedPublish | 9,
/// <summary>
/// The document could not be published because some mandatory cultures are missing.
+12 -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>
@@ -199,6 +204,7 @@
<Compile Include="CompositionExtensions_Essentials.cs" />
<Compile Include="CompositionExtensions_FileSystems.cs" />
<Compile Include="CompositionExtensions_Uniques.cs" />
<Compile Include="Exceptions\PanicException.cs" />
<Compile Include="FactoryExtensions.cs" />
<Compile Include="Composing\RegisterFactory.cs" />
<Compile Include="Composing\Current.cs" />
@@ -236,7 +242,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 +266,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 +276,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();
@@ -54,7 +54,7 @@ namespace Umbraco.Examine
{"updateDate", new object[] {c.UpdateDate}}, //Always add invariant updateDate
{"nodeName", (PublishedValuesOnly //Always add invariant nodeName
? c.PublishName?.Yield()
: c?.Name.Yield()) ?? Enumerable.Empty<string>()},
: c.Name?.Yield()) ?? Enumerable.Empty<string>()},
{"urlName", urlValue?.Yield() ?? Enumerable.Empty<string>()}, //Always add invariant urlName
{"path", c.Path?.Yield() ?? Enumerable.Empty<string>()},
{"nodeType", c.ContentType.Id.ToString().Yield() ?? Enumerable.Empty<string>()},
+50
View File
@@ -28,6 +28,31 @@ namespace Umbraco.Examine
/// </remarks>
internal static readonly Regex CultureIsoCodeFieldNameMatchExpression = new Regex("^([_\\w]+)_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
private static volatile bool _isUnlocked = false;
private static readonly object IsUnlockedLocker = new object();
/// <summary>
/// Unlocks all Lucene based indexes registered with the <see cref="IExamineManager"/>
/// </summary>
/// <remarks>
/// Indexing rebuilding can occur on a normal boot if the indexes are empty or on a cold boot by the database server messenger. Before
/// either of these happens, we need to configure the indexes.
/// </remarks>
internal static void EnsureUnlocked(this IExamineManager examineManager, IMainDom mainDom, ILogger logger)
{
if (!mainDom.IsMainDom) return;
if (_isUnlocked) return;
lock (IsUnlockedLocker)
{
//double check
if (_isUnlocked) return;
_isUnlocked = true;
examineManager.UnlockLuceneIndexes(logger);
}
}
//TODO: We need a public method here to just match a field name against CultureIsoCodeFieldNameMatchExpression
/// <summary>
@@ -48,6 +73,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
+2 -1
View File
@@ -5,7 +5,8 @@ using System.Threading.Tasks;
using Examine;
namespace Umbraco.Examine
{
{
/// <summary>
/// Utility to rebuild all indexes ensuring minimal data queries
/// </summary>
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using Examine.LuceneEngine.Providers;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Lucene.Net.Store;
using Umbraco.Core.IO;
using System.Linq;
namespace Umbraco.Examine
{
public class LuceneIndexDiagnostics : IIndexDiagnostics
{
public LuceneIndexDiagnostics(LuceneIndex index, ILogger logger)
{
Index = index;
Logger = logger;
}
public LuceneIndex Index { get; }
public ILogger Logger { get; }
public int DocumentCount
{
get
{
try
{
return Index.GetIndexDocumentCount();
}
catch (AlreadyClosedException)
{
Logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexDocumentCount, the writer is already closed");
return 0;
}
}
}
public int FieldCount
{
get
{
try
{
return Index.GetIndexFieldCount();
}
catch (AlreadyClosedException)
{
Logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexFieldCount, the writer is already closed");
return 0;
}
}
}
public Attempt<string> IsHealthy()
{
var isHealthy = Index.IsHealthy(out var indexError);
return isHealthy ? Attempt<string>.Succeed() : Attempt.Fail(indexError.Message);
}
public virtual IReadOnlyDictionary<string, object> Metadata
{
get
{
var luceneDir = Index.GetLuceneDirectory();
var d = new Dictionary<string, object>
{
[nameof(UmbracoExamineIndex.CommitCount)] = Index.CommitCount,
[nameof(UmbracoExamineIndex.DefaultAnalyzer)] = Index.DefaultAnalyzer.GetType().Name,
["LuceneDirectory"] = luceneDir.GetType().Name
};
if (luceneDir is FSDirectory fsDir)
{
d[nameof(UmbracoExamineIndex.LuceneIndexFolder)] = fsDir.Directory.ToString().ToLowerInvariant().TrimStart(IOHelper.MapPath(SystemDirectories.Root).ToLowerInvariant()).Replace("\\", "/").EnsureStartsWith('/');
}
return d;
}
}
}
}
+8 -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>
@@ -67,6 +72,7 @@
<Compile Include="IPublishedContentValueSetBuilder.cs" />
<Compile Include="IUmbracoIndex.cs" />
<Compile Include="IValueSetBuilder.cs" />
<Compile Include="LuceneIndexDiagnostics.cs" />
<Compile Include="MediaIndexPopulator.cs" />
<Compile Include="MediaValueSetBuilder.cs" />
<Compile Include="MemberIndexPopulator.cs" />
@@ -7,73 +7,24 @@ using Umbraco.Core.Logging;
namespace Umbraco.Examine
{
public class UmbracoExamineIndexDiagnostics : IIndexDiagnostics
public class UmbracoExamineIndexDiagnostics : LuceneIndexDiagnostics
{
private readonly UmbracoExamineIndex _index;
private readonly ILogger _logger;
public UmbracoExamineIndexDiagnostics(UmbracoExamineIndex index, ILogger logger)
: base(index, logger)
{
_index = index;
_logger = logger;
}
public int DocumentCount
public override IReadOnlyDictionary<string, object> Metadata
{
get
{
try
{
return _index.GetIndexDocumentCount();
}
catch (AlreadyClosedException)
{
_logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexDocumentCount, the writer is already closed");
return 0;
}
}
}
var d = base.Metadata.ToDictionary(x => x.Key, x => x.Value);
public int FieldCount
{
get
{
try
{
return _index.GetIndexFieldCount();
}
catch (AlreadyClosedException)
{
_logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexFieldCount, the writer is already closed");
return 0;
}
}
}
public Attempt<string> IsHealthy()
{
var isHealthy = _index.IsHealthy(out var indexError);
return isHealthy ? Attempt<string>.Succeed() : Attempt.Fail(indexError.Message);
}
public virtual IReadOnlyDictionary<string, object> Metadata
{
get
{
var d = new Dictionary<string, object>
{
[nameof(UmbracoExamineIndex.CommitCount)] = _index.CommitCount,
[nameof(UmbracoExamineIndex.DefaultAnalyzer)] = _index.DefaultAnalyzer.GetType().Name,
["LuceneDirectory"] = _index.GetLuceneDirectory().GetType().Name,
[nameof(UmbracoExamineIndex.EnableDefaultEventHandler)] = _index.EnableDefaultEventHandler,
[nameof(UmbracoExamineIndex.LuceneIndexFolder)] =
_index.LuceneIndexFolder == null
? string.Empty
: _index.LuceneIndexFolder.ToString().ToLowerInvariant().TrimStart(IOHelper.MapPath(SystemDirectories.Root).ToLowerInvariant()).Replace("\\", "/").EnsureStartsWith('/'),
[nameof(UmbracoExamineIndex.PublishedValuesOnly)] = _index.PublishedValuesOnly,
//There's too much info here
//[nameof(UmbracoExamineIndexer.FieldDefinitionCollection)] = _index.FieldDefinitionCollection,
};
d[nameof(UmbracoExamineIndex.EnableDefaultEventHandler)] = _index.EnableDefaultEventHandler;
d[nameof(UmbracoExamineIndex.PublishedValuesOnly)] = _index.PublishedValuesOnly;
if (_index.ValueSetValidator is ValueSetValidator vsv)
{
@@ -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;
}
}

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