Compare commits

...
Author SHA1 Message Date
Warren Buckley fb71988a2c Merge pull request #7627 from umbraco/v8/bugfix/AB4828-resetpassword-mail
AB4828 - Reset Password Email

(cherry picked from commit f00680bfe6)
2020-02-12 11:54:05 +00:00
Warren Buckley d38a2be2bb Bump version to 8.4.2 2020-02-12 08:55:47 +00:00
ClausandWarren Buckley a65c1f55ca Merge pull request #7315 from umbraco/v8/bug/3935-useractions-xsrf-validation
Adding extra validation for anti forgery tokens

(cherry picked from commit b613f8b56d)
2020-02-11 15:34:07 +00:00
Claus 838b26cedb bump version to 8.4.1 2020-01-07 13:04:52 +01:00
ClausandGitHub 53286c66a0 Merge pull request #7418 from umbraco/v8/bugfix/7404-deadlock
Fixes #7404 - Deadlock issue
2020-01-07 12:44:38 +01:00
Shannon 94d05b1768 Fixes #7404 - Deadlock issue 2020-01-06 21:14:46 +11:00
Kenn JacobsenandNiels Lyngsø 12376fb6be Make Nested Content actually save the item content again (#7301) 2019-12-10 09:44:05 +01:00
mikkelhmandBjarke Berg 7c5a2dd6f1 Close unclosed key element in italian language file 2019-12-05 08:35:49 +01:00
abiandShannon d162b17931 MediaIndexPopulator should use IUmbracoContentIndex instead of UmbracoContentIndex 2019-12-04 10:57:36 +11:00
Bjarke Berg 76742f0554 Merge remote-tracking branch 'origin/v8/8.4' into v8/8.4 2019-12-03 19:32:24 +01:00
Bjarke Berg 12a831d178 Removed RC version 2019-12-03 19:31:02 +01:00
Warren BuckleyandGitHub 36c8285daf Merge pull request #7267 from umbraco/v8/bugfix/7247-fixing-auto-resize-to-show-docType-alias
adding timeout for Chrome to render before making the correction
2019-12-03 13:43:51 +00:00
Claus b17326c9c0 Marking default json ctor for serialization. 2019-12-03 14:28:53 +01:00
Warren BuckleyandGitHub dc4b9a3c4d Merge pull request #7265 from umbraco/v8/bugfix/7258-hideLabel-for-Grid-RTE-PreValue-for-8.4
7258 hide label for grid rte pre value for 8.4
2019-12-03 13:21:08 +00:00
Niels Lyngsø 2d0a8d52d9 adding timeout for Chrome to render before making the correction 2019-12-03 12:06:31 +01:00
Warren BuckleyandGitHub 153eb219f9 Merge pull request #7266 from umbraco/v8/bugfix/7236-Property-Action-Toggle-position-corrected-for-non-horizontal-form-for-8.4
7236 property action toggle position corrected for non horizontal form for 8.4
2019-12-03 10:01:03 +00:00
Niels Lyngsø fa783e4861 corrected position of Property-Action toggle for non horizontal form 2019-12-03 09:51:41 +01:00
Niels Lyngsø de712cd89d Adds HideLabel for Rich Text Editor prevalue property 2019-12-03 09:47:27 +01:00
Niels Lyngsø 5616dcb807 moved hideLabel to control-header 2019-12-03 09:46:40 +01:00
Shannon 2ec5a8101a fixes binary breaking change introduced 2019-12-02 17:15:47 +11:00
Bjarke Berg 0680f104b5 Added "rc" to AssemblyInformationalVersion 2019-11-26 12:39:12 +01:00
Shannon DeminickandGitHub 0eea70b50b Merge pull request #7222 from umbraco/v8/bugfix/5551-refactorying-of-property-actions-api
Refactorying of PropertyActions
2019-11-26 12:22:06 +11:00
Shannon ba625e6181 fix up minor inconsistency 2019-11-26 12:20:49 +11:00
Niels Lyngsø ea8f1c3ae3 make umbProperty optional, since its not present in DocumentTypeEditor 2019-11-25 15:47:45 +01:00
Niels Lyngsø b4ae7ebe2c refactored how communication is done between propertyEditorController and umbPropertyDirective 2019-11-25 15:38:11 +01:00
Niels Lyngsø b0b67ca957 removed PropertyEditorService as its not needed anymore 2019-11-25 15:36:56 +01:00
Niels Lyngsø 503fd1887e Change NestedContent property editor controller into a component 2019-11-25 13:16:04 +01:00
Warren BuckleyandGitHub f9d59f9270 Merge pull request #7211 from umbraco/v8/bugfix/3909-Rename-reference-to-info
Rename reference to info
2019-11-25 10:46:01 +01:00
Niels Lyngsø b9104dfaf8 moved info properties to the into tab. 2019-11-22 14:53:15 +01:00
Warren BuckleyandGitHub ab9478ff6d Merge pull request #7207 from umbraco/v8/bugfix/7181-Check-if-template-tree-exists-for-8.4
check if template tree exists, to avoid error if its not present.
2019-11-22 10:32:48 +01:00
Niels Lyngsø e83589a024 rename reference tab to info tab 2019-11-22 09:59:11 +01:00
Niels Lyngsø 3402f36de3 check if template tree exists, to avoid error if its not present. 2019-11-22 09:02:28 +01:00
Warren BuckleyandGitHub 096bcf8a11 Merge pull request #7203 from umbraco/v8/bugfix/AB3875-untouchability-fix-8.4-cherry
Bugfix - AB3875 untouchability checker: do not check style for document fragments
2019-11-21 15:28:47 +01:00
Warren Buckley f209905d2a Update src/Umbraco.Web.UI.Client/src/common/services/tabbable.service.js
(cherry picked from commit 7798937ea7)
2019-11-21 14:30:44 +01:00
Niels LyngsøandWarren Buckley 213fa0e71e return true, cause DocumentFragment is never displayed.
(cherry picked from commit ec9c99554a)
2019-11-21 14:30:36 +01:00
Niels LyngsøandWarren Buckley 7ccfe809ae Do not check style of DocumentFragment.
(cherry picked from commit 3b7d5995e4)
2019-11-21 14:30:24 +01:00
Bjarke Berg c0dc545c27 Fix for csproj 2019-11-14 13:54:04 +01:00
Bjarke Berg 7c72fb57f2 Merge remote-tracking branch 'origin/v8/8.3' into v8/dev
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
#	src/Umbraco.Web/Cache/LanguageCacheRefresher.cs
2019-11-14 13:40:32 +01:00
Bjarke Berg ba73ad5792 Merge remote-tracking branch 'skttl/grid-editor-name-templates' into v8/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js
#	src/Umbraco.Web.UI/config/grid.editors.config.js
2019-11-14 13:08:05 +01:00
Shannon DeminickandGitHub 075937de59 Merge pull request #7145 from umbraco/v8/feature/0000-Remove-non-production-mode-from-gulp
remove isProd from Gulp script
2019-11-14 13:14:02 +11:00
Shannon 7cbb2840a4 Merge branch 'Jeavon-v8/feature/search-media-files' into v8/dev 2019-11-14 12:40:53 +11:00
Jeavon 88f6ddeae4 Code tweaks from PR review - also led to adding logging for Deserialization issues and therefore needing to mock the logger for the tests 2019-11-13 12:07:11 +00:00
Niels Lyngsø e2adb4964c remove isProd from Gulp script 2019-11-13 09:36:40 +01:00
Shannon DeminickandGitHub 89e9b14f88 Merge pull request #7131 from umbraco/v8/hotfix/7125-update-dependencies-to-same-as-nuspec
V8: Update the projects to use the same dependencies as required by our nuspec
2019-11-13 09:21:53 +11:00
Jeavon 10622cc430 Switched to using a dummy Uri so that runtimeState isn't needed as per review 2019-11-12 10:26:25 +00:00
Jeavon b30f7b6a48 Merge branch 'v8/dev' into v8/feature/search-media-files 2019-11-12 10:12:03 +00:00
Bjarke Berg 7eef6b4037 https://github.com/umbraco/Umbraco-CMS/issues/7125 - Updates the projects to use the same versions as required by our nuspec 2019-11-12 08:50:31 +01:00
Jan SkovgaardandSebastiaan Janssen a2551521e4 Settings dashboard: Add translations (#6880) 2019-11-11 20:48:52 +01:00
Niels LyngsøandGitHub 5528c721c7 Merge pull request #6811 from umbraco/v8/feature/0000-DataType-DeleteWarning-with-links-to-references
Adding reference links to DataType delete dialog
2019-11-08 09:36:11 +01:00
Niels Lyngsø 73f7e85f41 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/0000-DataType-DeleteWarning-with-links-to-references
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html
2019-11-08 09:28:52 +01:00
Richard Thompsonandemma burstow 0d2c2846d4 Corrected the model variable name
The model variable name is registerModel rather than profileModel.
2019-11-07 15:21:11 +00:00
andyneilandemma burstow 41915080b2 Fix incorrect data types for default member properties. (#7086)
Issue https://github.com/umbraco/Umbraco-CMS/issues/7051
2019-11-07 15:01:22 +00:00
Poornima Nayarandemma burstow 52dcdb396f Accessibility Improvement - Open Template in info content app changed from anchor tag to button 2019-11-07 14:34:46 +00:00
Poornima Nayarandemma burstow 603f720636 Changed the styling of Resend Invitation button and fixed the margin 2019-11-07 14:17:08 +00:00
Paul Sealandemma burstow 466610bd32 - added delete title to trash icons in the grid 2019-11-07 14:05:23 +00:00
John Sheardandemma burstow d747312eb7 encode name of folder rename 2019-11-07 13:06:50 +00:00
Jeffrey SchoemakerandSebastiaan Janssen 55b76ecc4e Add some help if you're on the wrong repo (#7082) 2019-11-07 12:46:48 +01:00
Bill Bixbyandemma burstow 6307a0173b Edit text file to remove reference to App_Data\NuGetBackup folder 2019-11-07 11:24:31 +00:00
Sebastiaan JanssenandGitHub 60e4727e51 Update CONTRIBUTING.md 2019-11-07 12:05:16 +01:00
Jeffrey Schoemakerandemma burstow 2bbe2c01de Added to switch to the correct repository
I always forget this.... And it's nowhere in the documentation
2019-11-07 10:48:00 +00:00
KBandemma burstow d41e5bb27f Update JQuery CDN In partial snippets, to use newer version without vulnerability 2019-11-05 18:16:47 +00:00
Kenn Jacobsenandemma burstow 759e3ddf5e Make sure we can't rollback trashed items serverside 2019-11-05 18:15:14 +00:00
Kenn Jacobsenandemma burstow a78aab628f Don't show rollback for deleted content 2019-11-05 18:15:14 +00:00
Søren Kottal 1c70d04ce2 Moves editor name part out of template. Adds null checking in templates 2019-11-05 15:33:29 +01:00
Jan SkovgaardandSebastiaan Janssen 68de8a1fa6 Video dashboard (Settings & Members): Add translations (#6881) 2019-11-05 12:20:00 +01:00
Jan SkovgaardandSebastiaan Janssen c8ec7ce8ba Profiling dashboard: Add translations (#6879) 2019-11-05 12:10:41 +01:00
Matt BrailsfordandSebastiaan Janssen 0b16c48fc3 Split PagedResult into a typed and non-typed version (Fixes #46… (#6871) 2019-11-05 11:59:04 +01:00
Kevin JumpandSebastiaan Janssen 3211054063 look for the system.web section under the root configuration node
use Element to get the root system.web. DescendantsAndSelf can return multiple
2019-11-05 11:52:48 +01:00
Jan SkovgaardandSebastiaan Janssen 8dd92bc720 NuCache dashboard: Add translation keys (#6867) 2019-11-05 11:46:55 +01:00
Jan SkovgaardandSebastiaan Janssen fd649ea0e2 Languages: Add missing "none" translation (#6865) 2019-11-05 10:27:27 +01:00
Jan SkovgaardandSebastiaan Janssen 1759813795 Examine management dashboard: Add missing translations (#6866) 2019-11-05 10:20:11 +01:00
Bjarke Berg 88e57277fa Bump version to 8.4.0 2019-11-04 12:58:08 +01:00
Sebastiaan JanssenandGitHub 4e908e9dd1 Update 1_Bug.md 2019-11-01 15:23:53 +01:00
MikeandSebastiaan Janssen 88af496f29 Accessibilty improvement to media picker (#6805) 2019-11-01 10:17:28 +01:00
Marc GoodsonandSebastiaan Janssen a873c9188f Allow querystring parameters to set IsElementType checkbox on create document type route (#6779)
* Allow query string parameters sent to create document type route 'set' the default checkboxes for either Is an element type or Allow varying by culture

* allow isElement and AllowVaryByCulture to be set in infinite editor

not sure where this is used, but in theory this might be useful to be wired up too?

* Release the camels!

update the model properties to follow camelcase, ignoring the existing notemplate that doesn't!!
2019-10-31 16:20:02 +01:00
Poornima NayarandSebastiaan Janssen b2e5d64d6e Better exception handling for templates when they exceed 255 ch… (#6649) 2019-10-31 15:54:14 +01:00
Poornima NayarandSebastiaan Janssen 5db47ad546 Buttons on the healthcheck dashboard made more consistent (#6667) 2019-10-31 15:35:56 +01:00
Rachel BreezeandSebastiaan Janssen ce0833719b Fix for #6315 where the loading banner continues to display if there is no current editor state 2019-10-31 15:15:37 +01:00
Bjarke Berg 5c82968829 Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-10-31 12:32:12 +01:00
Warren BuckleyandGitHub ecc9e2665c Merge pull request #6823 from umbraco/v8/feature/6816-property-actions
PropertyActions + Copy all entries for Nested Content
2019-10-31 11:22:47 +00:00
Warren BuckleyandGitHub 2842c65ee6 Merge pull request #6948 from umbraco/v8/feature/0000-DataType-DeleteWarning-styling
Styling for the DataType Delete Dialog
2019-10-31 11:21:47 +00:00
Niels Lyngsø 9e4b9e6431 changed span to div 2019-10-31 11:53:30 +01:00
Bjarke Berg 851a4e0d56 Fix Umbraco.Web.UI.csproj after auto merge 2019-10-31 11:49:43 +01:00
Bjarke Berg ad6343719b Merge branch 'v8/8.2' into v8/dev
# Conflicts:
#	src/SolutionInfo.cs
2019-10-31 11:48:53 +01:00
Niels LyngsøandGitHub 5ccb10d092 Fix for Umb Request Helper unit test. (#7008)
Fix for Umb Request Helper unit test.
2019-10-31 11:11:18 +01:00
Niels Lyngsø 6c21279216 require because we need underscore to be available... 2019-10-31 11:03:19 +01:00
ClausandGitHub 77077c8000 Merge pull request #6954 from kjac/v8/fix/grid-rte-reorder
V8: Fix broken grid when reordering grid rows that contain RTE's
2019-10-31 09:33:58 +01:00
Shannon DeminickandGitHub 1dc3a023c4 Merge pull request #6824 from bielu/v8/feature/InterfaceForContentPopulators
Create Interface for Member and Content Index to use in Populators
2019-10-31 14:16:41 +11:00
BatJanandemma burstow bf62bfa17f Remove unused dashboards 2019-10-30 19:18:17 +00:00
BatJanandemma burstow e60abea32c Remove outdated media dashboards 2019-10-30 19:16:28 +00:00
Søren Kottalandemma burstow cd4002b165 open templates from umb-grid-selector in infinite editor 2019-10-30 15:32:06 +00:00
Søren Kottalandemma burstow eb81aae3e9 remove text saying open button on content picker is in preview 2019-10-30 15:16:10 +00:00
Søren Kottalandemma burstow 23c0c502d3 css changes to make the previewer nav look like the top nav in v8 (#6875) 2019-10-30 15:06:50 +00:00
Matt Brailsfordandemma burstow eebc06c1a3 Sets the appState current node when executing a menu action (#6874) 2019-10-30 14:53:24 +00:00
Kevin Jumpandemma burstow e113b56ce1 log warning if siteUri is null, (#6868) 2019-10-30 14:36:15 +00:00
Niels Lyngsø 946fb38924 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions
# Conflicts:
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
2019-10-30 13:24:30 +01:00
Niels Lyngsø bef9696628 Show error before submitting the form, so editors know in advance that they have reached the limit. 2019-10-30 12:08:17 +01:00
Kenn JacobsenandSebastiaan Janssen ff36cf11d1 Allow file upload and image cropper properties to be optional 2019-10-30 11:24:13 +01:00
Rachel Breezeandemma burstow 1bac8141f5 V8: Accessibility Changes For umbEditorHeader Directive (#6315)
* Umb editor control contains a11y support for the media section

* Started work to align to the settings section

* A11Y Amends for umbraco header directive specifically to support document type

* Fixed error when creating a new user

* This change makes sure that if a relationship type is edited, followed by a create, the title of the page is reset, a seperate PR will address the a11y requirements for this controller

* Umbraco Header directive now uses "create" rather than create item

* Made the ediorFor property more generic

* Made the ediorFor property more generic
Umbraco Header directive now uses "create" rather than create item

* Edit and create template now aligns to the more a11y header directive

* Added support for a11y name and title on settings->scripts

* Added support for a11y name and title on settings->stylesheets

* Added support for a11y name and title on settings->partial views

* Added support for a11y name and title on settings->partial view macros

* Added support for a11y name and title when editing members

* Added support for a11y name and title when editing member groups

* Updated to ignore package-lock

* Added support for a11y name and title when editing media types

* Added the ability to prevent the title being set via the umbeditorheader directive, currently for use when the content editor is editing media via a content page

* No longer sets the page title by default

* No longer sets the page title by default

* Added support for a11y name and title when editing members

* Added support for a11y name and title when editing dictionary items

* Removed bug where by screen reader was reading "blank" when the name-locked value was set to true or there was no message/ name to display

* Fixing redering issues following refactor

* Don't ignore package-lock.json

* Merged languages

* Fix up merge errors
2019-10-30 10:14:47 +00:00
Niels Lyngsø c86b63f7fd Changed validation for NestedContent, allow for pasting many items, but do not allow to save them. 2019-10-30 10:49:34 +01:00
Niels Lyngsø 0e308e1ad0 fixing umb-mediapicker-upload template to work with new CSS for umb-control-group 2019-10-30 08:58:47 +01:00
Sebastiaan Janssen 06e2146b54 Merge branch 'v8/dev' into pr/6823
# Conflicts:
#	src/Umbraco.Web.UI.Client/gulp/tasks/watchTask.js
#	src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
2019-10-30 07:28:00 +01:00
Jan SkovgaardandSebastiaan Janssen e90670425e Grid layout config: Replace the old checkbox with the umb-checbox directive (#6859) 2019-10-29 22:48:49 +01:00
Jan SkovgaardandSebastiaan Janssen c7af35937c Log viewer: Filter toggle (#6863) 2019-10-29 22:44:22 +01:00
Jan SkovgaardandSebastiaan Janssen c563d617fb Log viewer: Localize texts and titles (#6861) 2019-10-29 22:11:08 +01:00
Anders BjernerandSebastiaan Janssen 82d6b14eaa Improved the editor service documentation a bit 2019-10-29 22:03:03 +01:00
Jan SkovgaardandSebastiaan Janssen 6beb507033 Confirm uninstall package: Change old checkbox to use umb-checkbox (#6858) 2019-10-29 21:55:29 +01:00
Sebastiaan JanssenandGitHub 3abe4f6a52 Removed the extra padding on the left on the overlay header (#6848) 2019-10-29 21:53:19 +01:00
SANDIP PALITandSebastiaan Janssen 5f83f199cb Fixed Grammatical errors (#6857) 2019-10-29 21:52:45 +01:00
Kenn Jacobsen 891b3419ee Fix broken RTEs when reordering grid rows 2019-10-29 21:48:39 +01:00
Kenn JacobsenandSebastiaan Janssen 150cd07ccf V8: Even out the padding in dialog footers (#6800) 2019-10-29 21:43:18 +01:00
JeavonandSebastiaan Janssen 4be1c3b4c4 Add UmbracoVirtualNodeByUdiRouteHandler (#6796)
* Add UmbracoVirtualNodeByUdiRouteHandler

* Parameter must be a GuidUdi
2019-10-29 21:38:29 +01:00
Steve MegsonandSebastiaan Janssen 8463f1db08 Cache lookup of macro by alias 2019-10-29 21:34:25 +01:00
Steve MegsonandSebastiaan Janssen 0554b47864 Rollback dropdown - convert version dates to local 2019-10-29 21:31:33 +01:00
Poornima NayarandSebastiaan Janssen 6c13e4a762 Create package form missing "Include all child nodes" label by… (#6766) 2019-10-29 21:30:09 +01:00
Poornima NayarandSebastiaan Janssen 227a0ec0d8 Changed button style to danger, change confirm dialog button to danger syle and removed duplicate button-style attribute on the enable button 2019-10-29 21:28:37 +01:00
Poornima NayarandSebastiaan Janssen 1371120e7c Content Blueprint save button style change 2019-10-29 21:27:36 +01:00
nfJakobsenandSebastiaan Janssen 63060a88c6 added apostrophe so Installer becomes Installér 2019-10-29 21:07:09 +01:00
Poornima NayarandSebastiaan Janssen 86ce1d9311 Notifications span full width on user group save or delete 2019-10-29 21:05:52 +01:00
Poornima NayarandSebastiaan Janssen 46ce5f7ca9 Change the style of the confirm button on delete media (#6725) 2019-10-29 21:00:28 +01:00
Poornima NayarandSebastiaan Janssen 978ab88b75 Change the confirm button style on delete dictionary item 2019-10-29 20:58:01 +01:00
Poornima NayarandSebastiaan Janssen a1a709342d Changes to delete saved searches overlay 2019-10-29 20:57:00 +01:00
Poornima NayarandSebastiaan Janssen f0ea76a3ce Move all inline styles in the logviewer search screen to a stylesheet 2019-10-29 20:55:59 +01:00
Bjarne FyrstenborgandSebastiaan Janssen 1de9ec3259 Use umb-checkbox in doctype collection (#6719) 2019-10-29 20:53:03 +01:00
Harry GordonandSebastiaan Janssen 0e91bb647d Asset service load now throws for unknown assets. Additionally, now allows optional default asset type to handle unknown assets. 2019-10-29 20:43:50 +01:00
kfcandSebastiaan Janssen 92c17a853f Removed *.security.js from karma.conf.js 2019-10-29 20:36:03 +01:00
Andy ButlandandSebastiaan Janssen 66b709653a Added custom FormatValidator for the MultipleTextStringPropertyEditor to validate each text string individually against the configured regular expression. 2019-10-29 20:22:08 +01:00
Poornima NayarandSebastiaan Janssen c314ab1e0b Clean up of the published cache status dashboard (#6666) 2019-10-29 19:57:26 +01:00
Poornima NayarandSebastiaan Janssen 40358ff6fb Tweak the examine management dashboard (#6665) 2019-10-29 19:51:39 +01:00
Poornima NayarandSebastiaan Janssen 6a90a8755b Update the create dialog on Relation to use umb-radiobutton 2019-10-29 19:46:21 +01:00
Sebastiaan JanssenandGitHub 0d7caa0f80 Clean up of change password section in member details (#6643)
* Clean up of change password section in member details

* Added missing attributes to umb-checkbox

* More tweaks based on comments

* Removed href from the button
2019-10-29 19:42:13 +01:00
Ronald BarendseandSebastiaan Janssen 7f0a077f58 Add SecurityCodeScan static code analyzer (#6636)
* Added SecurityCodeScan to all projects

* Enable analysing of content items
2019-10-29 19:37:15 +01:00
Steve MegsonandSebastiaan Janssen 3a111eceb3 Set focus to RTE when clicking property label (#6609) 2019-10-29 19:15:22 +01:00
Steve MegsonandSebastiaan Janssen 990d14e791 Set focus to Umb-Tags when clicking property label (#6608) 2019-10-29 19:12:06 +01:00
Carole Rennie LoganandSebastiaan Janssen 99272a48f3 Copy to clipboard in query builder (#6584) 2019-10-29 19:07:40 +01:00
Bjarne FyrstenborgandSebastiaan Janssen f018b32f99 Use umb-checkbox in template section (#6531) 2019-10-29 18:25:08 +01:00
Anders BjernerandSebastiaan Janssen bfdbc4cb8b Introduced confirm and confirmDelete functions in the Angular overlay service (#6526) 2019-10-29 18:18:43 +01:00
Niels Lyngsø 4cf42bbb68 Added specific styling to the DataType Delete dialog for better looks and overview 2019-10-29 17:38:02 +01:00
Niels Lyngsø 5641a6cd35 correcting minor typo in gulp watch script 2019-10-29 17:19:15 +01:00
Sebastiaan Janssen 77fd959166 Fix bad merge 2019-10-29 16:31:31 +01:00
Jeavon 76bbf01cbe Changed field to a List as suggested in review 2019-10-29 15:25:10 +00:00
Niels Lyngsø 3d542acc42 Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered 2019-10-29 15:24:23 +01:00
Niels Lyngsø 0c29d57ef9 ensured that all entry aliases meets the allowed aliases + refactored the test method 2019-10-29 14:54:31 +01:00
Jeavon 04004876b1 Merge branch 'v8/dev' into v8/feature/search-media-files 2019-10-29 12:13:09 +00:00
Niels Lyngsø 338c4b7bcf Set notification to error + removed console.logs 2019-10-29 12:50:47 +01:00
3a8123f00c Update src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js
Removed comment

Co-Authored-By: Warren Buckley <warren@umbraco.com>
2019-10-29 11:26:35 +01:00
Niels Lyngsø 312a069531 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/less/main.less
2019-10-29 11:08:06 +01:00
Warren BuckleyandGitHub bd4e66e0c6 Merge pull request #6664 from umbraco/v8/bug/6663-lang-variant-deletion
Language variant deletion
2019-10-29 09:43:29 +00:00
Warren Buckley 38b96beb0d Merge branch 'v8/dev' into v8/bug/6663-lang-variant-deletion
# Conflicts:
#	src/Umbraco.Web/Cache/LanguageCacheRefresher.cs
2019-10-29 09:16:52 +00:00
Niels Lyngsø 1f954fb9be sligthly less bottom border on contextmenu. 2019-10-29 09:55:59 +01:00
Tom PipeandSebastiaan Janssen 1614dc6e34 V8: Health check http header case sensitivity (#6753) 2019-10-28 18:04:20 +01:00
Niels Lyngsø 11560aa138 sligthly darker line in the bottom to enhance the depth 2019-10-28 17:21:58 +01:00
Niels Lyngsø 1c5d8efe77 corrected variable name for property-action 2019-10-28 17:18:08 +01:00
Niels Lyngsø ed909e9f93 updated look + ability to disable a property-action 2019-10-28 15:55:02 +01:00
Niels Lyngsø 5dd7eda2ab Revert change. 2019-10-28 10:25:51 +01:00
Niels Lyngsø 0868b2e1b6 Revert "Everything was squished but now it is not."
This reverts commit 29de4fd63f.
2019-10-28 10:19:40 +01:00
Niels Lyngsø c6ed307e62 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions
# Conflicts:
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
2019-10-28 10:00:05 +01:00
Matthew-Wiseandemma burstow 4153cfe78f WIP/Issue - Improving accessibility of the three dot tree options button (#6561)
* Improves accessability of the three dot tree options button

* Updated list view headers styling to have the link/hand cursor visible only if the header is sortable (and hence clicking has an effect)

* Allows members to be ordered by additional system fields (#6575)

* Fix ContentType.Alias matching in PublishedContentExtensions an… (#6577)

* Fixes an error in #6538 by moving the colon character to the sr-only span

* V8: Move misplaced colon in language selector (#6692)

* V8: It should be possible to disallow all types at content root (#6580)

* Pick macro parameters in an infinite editor like content type properties (#6586)

* Reload node children after publishing with descendants

* Correct URL decoding of macro partial view names (#6592)

* Fix semantics for list views (#6595)

* fixes test

* fixing tests

* Improved menu context
2019-10-27 14:07:06 +00:00
Poornima Nayar 43692c81e4 Removed href from the button 2019-10-27 10:06:06 +00:00
Poornima Nayar 68687080ab More tweaks based on comments 2019-10-27 09:48:24 +00:00
Niels Lyngsø 0a91e384ae further fixes merge conflict with #6699 2019-10-25 16:03:43 +02:00
Anders BjernerandSebastiaan Janssen a4b4014d6c Improved a few Danish translations for the Users section 2019-10-25 15:55:20 +02:00
Kenn JacobsenandSebastiaan Janssen 2a016a9ad0 Do not allow copying items in the recycle bin 2019-10-25 15:53:29 +02:00
Kenn JacobsenandSebastiaan Janssen c66676517f Apply trashed state to deleted content items with list view enabled 2019-10-25 15:52:11 +02:00
Kenn JacobsenandSebastiaan Janssen 9b00bb824c Make the listview delete dialog warn about irreversible deletions 2019-10-25 15:50:52 +02:00
Kenn JacobsenandSebastiaan Janssen 0f6e8dc9ff Fix the styling for the publish/unpublish dialogs in listviews (#6854) 2019-10-25 15:47:05 +02:00
Kenn JacobsenandSebastiaan Janssen c4acf124b9 Automatically select all languages when selecting a mandatory language in the listview unpublish dialog 2019-10-25 15:44:52 +02:00
Niels Lyngsø f4a06a628d Updated to match result from recent PR #6699 2019-10-25 15:30:39 +02:00
Niels Lyngsø 9fc52103c4 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/less/main.less
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
2019-10-25 15:24:01 +02:00
Bjarke Bergandemma burstow 9d91402aca V8: Follow guidelines from .editorconfig (#6849)
* Removed unused variable

* Align usage of C# type keywords vs Universal type names. Now we use C# keywords all over.
2019-10-25 14:16:50 +01:00
Poornima Nayar fdbef5b87d Added missing attributes to umb-checkbox 2019-10-25 14:09:29 +01:00
Jan SkovgaardandElitsa Marinovska ee17cb1463 Refactor labels to actually reference the proper input fields (#6838) 2019-10-25 14:53:02 +02:00
Niels Lyngsø d7ded94f98 Mobile layout for control.header + use after element for bottom border on umb-control-group, so we can use margin to space above, to allow for margin collapse for margin-bottom on controls and control-description. 2019-10-25 13:51:15 +02:00
elitsa 77f04a2efe Merge branch 'v8/dev' into Clean-up-members-reset-password 2019-10-25 13:30:57 +02:00
Poornima Nayar 4f4588561e Removed the extra padding on the left on the overlay header 2019-10-25 12:08:12 +01:00
Søren KottalandElitsa Marinovska 56f33e1006 Adds nametemplates for grid editors (#6634)
* Adds nametemplates for grid editors
2019-10-25 12:35:15 +02:00
elitsa f20394556c Removed trailing newlines 2019-10-25 11:58:04 +02:00
Niels Lyngsø 548bb48f38 PropertyActions first version 2019-10-25 11:50:52 +02:00
Søren KottalandElitsa Marinovska 131273bb5c V8 style preview badge (#6585)
* V8 style preview badge

* updates the preview badges in other places

* Removes umbraco logo

* changes the "click to end" icon

* Set flex-shrink to 0 on the badge end element

* adds width:1em to the svg
2019-10-25 11:37:58 +02:00
elitsa c03a2c6ed4 Merge remote-tracking branch 'origin/v8/dev' into grid-editor-name-templates 2019-10-25 11:30:18 +02:00
Niels Lyngsø 957520aca0 fix watch task for LESS 2019-10-25 10:29:57 +02:00
Shannon DeminickandGitHub 5121df5b2e Merge pull request #6764 from Adolfi/v8/dev-umbracoapicontroller-testable
UmbracoApiController Testable
2019-10-25 10:01:16 +11:00
Kenn JacobsenandSebastiaan Janssen 8b18233d4e Don't YSOD when publishing if a property editor has been removed 2019-10-24 22:21:19 +02:00
BatJanandSebastiaan Janssen 20f886aaec Extend the umb-radio button directive to handle localizations 2019-10-24 22:19:09 +02:00
Jan SkovgaardandSebastiaan Janssen 2b22350d56 Media picker: Fix semantics, missing dictionary items and hide… (#6707) 2019-10-24 22:12:54 +02:00
Kenn JacobsenandSebastiaan Janssen 759bba93b8 Limit the number of tabbable elements in tree nodes (#6834) 2019-10-24 22:00:11 +02:00
Kenn JacobsenandSebastiaan Janssen 9310638a7f Set focus on the name field when editing, also for existing items (#6833) 2019-10-24 21:58:35 +02:00
Kenn JacobsenandSebastiaan Janssen ce6a217577 Performance boost for Nested Content: Don't load all content types all the time. 2019-10-24 21:56:47 +02:00
Kenn JacobsenandSebastiaan Janssen d3344e2cd4 V8: Make "add property" shortcut work with multiple groups (#6821) 2019-10-24 21:54:34 +02:00
Kenn JacobsenandSebastiaan Janssen 551a54a9d6 V8: Make it possible to open tabs with the keyboard (#6778) 2019-10-24 21:43:26 +02:00
Kenn JacobsenandSebastiaan Janssen 0a5594f56a Remove "double tabbing" for datatype picker 2019-10-24 21:41:58 +02:00
Kenn JacobsenandSebastiaan Janssen 057839a402 Do not allow deleting inherited content type groups 2019-10-24 21:40:15 +02:00
Kenn JacobsenandSebastiaan Janssen 58275366f2 Submit the datetime picker on enter (when entering time) 2019-10-24 21:39:01 +02:00
BatJanandSebastiaan Janssen 5c52d6b219 Replace old checkbox markup with umb-checkbox 2019-10-24 21:32:19 +02:00
BatJanandSebastiaan Janssen 68425fa46e Fix text alignment 2019-10-24 21:31:06 +02:00
Kenn JacobsenandSebastiaan Janssen bfe359bd1e Remove duplicate language labels in publish with descendants dialog 2019-10-24 21:29:50 +02:00
Kenn JacobsenandSebastiaan Janssen 62ff2c4d35 Harmonize content save/publish dialogs with mandatory languages 2019-10-24 21:27:32 +02:00
Kenn JacobsenandSebastiaan Janssen 01b9a09c09 V8: Make Nested Content resilient to missing property editors (#6768) 2019-10-24 21:25:15 +02:00
Kenn JacobsenandSebastiaan Janssen 847e82868a Make sure lazy loaded properties do not break the taborder when creating content types 2019-10-24 21:10:59 +02:00
Kenn JacobsenandSebastiaan Janssen c6ab73b806 Style the umb-overlay header and footer like the rest of the overlays 2019-10-24 21:09:51 +02:00
Kenn JacobsenandSebastiaan Janssen b46d6718c4 Use the member type icon in the members section 2019-10-24 21:05:13 +02:00
Kenn JacobsenandSebastiaan Janssen df8347d5f4 V8: General UX overhaul of the media picker in the RTE (#6722) 2019-10-24 21:01:01 +02:00
Kenn JacobsenandSebastiaan Janssen b1037786ca V8: Use member type icon in member pickers (#6696) 2019-10-24 20:46:01 +02:00
Kenn JacobsenandSebastiaan Janssen 6a8d3141c9 V8: Fix sorting of the immediate children of editor start nodes (#6686) 2019-10-24 20:43:54 +02:00
Kenn JacobsenandSebastiaan Janssen d312dc5f92 Show the "remove" action for assigned user groups when editing users 2019-10-24 17:25:01 +02:00
Kenn JacobsenandSebastiaan Janssen 0c1b56e671 Fix section and user assignment to groups 2019-10-24 17:24:09 +02:00
Kenn JacobsenandSebastiaan Janssen b0d7bdaa77 V8: Filter out invalid selections in the MNTP "Allowed items" picker (#6641) 2019-10-24 17:21:38 +02:00
Sebastiaan JanssenandGitHub f2dfdd6086 Merge pull request #6780 from kjac/v8/fix/sections-tray-keyboard-navigation
V8: Fix keyboard through the sections tray on small screens
2019-10-24 17:10:54 +02:00
Kenn JacobsenandSebastiaan Janssen b6a1a4ebb1 Ensure that the active state is clearly visible for property "edit" and "delete" icons 2019-10-24 17:09:30 +02:00
Kenn JacobsenandSebastiaan Janssen 04b736870c Style and translate the composition removal confirmation dialog (#6769) 2019-10-24 17:06:41 +02:00
Mario LopezandSebastiaan Janssen 4bc4b6946e #5294 Full path for DocType on Nested Content configuration (#5430) 2019-10-24 16:49:04 +02:00
Niels Lyngsø 2b4c35bcd8 Better label for copying all entries of nested content 2019-10-24 13:30:56 +02:00
Niels Lyngsø 1f0c1602f7 fix console log 2019-10-24 11:50:43 +02:00
arkadiuszbiel ffaf12c548 Create Interface for Member and Content Index to use in Populators 2019-10-24 09:55:41 +01:00
Niels Lyngsø d68cb1f802 Copy all entries feature for nested content 2019-10-24 10:02:33 +02:00
Shannon DeminickandGitHub dc54924b52 Merge pull request #6730 from lars-erik/pr/fix-our-tests
Pr/fix our tests
2019-10-24 13:45:41 +11:00
Callum WhyteandSebastiaan Janssen 6301371e59 Updating references to our.umbraco.org 2019-10-23 18:07:53 +02:00
Kenn JacobsenandSebastiaan Janssen 0a6e9df7f4 Dim down the alias of locked/inherited properties 2019-10-23 17:49:49 +02:00
Poornima NayarandSebastiaan Janssen 59b9d3d473 style delete package overlay 2019-10-23 17:46:44 +02:00
Kenn JacobsenandSebastiaan Janssen d8f6556f3c Fix RTE fullscreen mode 2019-10-23 17:43:31 +02:00
Dave WoestenborghsandSebastiaan Janssen e13bf327af 6671 - make the macro tree reload after a new macro partial view is created 2019-10-23 17:35:25 +02:00
Dave WoestenborghsandSebastiaan Janssen 88f153e7a3 V8 - Make it possible to set content app badge through content… (#6706) 2019-10-23 17:31:18 +02:00
Jan SkovgaardandSebastiaan Janssen 2b4e86b62f Add "umb-auto-focus" on media and link pickers (#6704) 2019-10-23 17:23:33 +02:00
emma burstowandSebastiaan Janssen 3871f408de Update CONTRIBUTING.md
I know it's cheesy to update a .md for hacktoberfest but I have been dying to put some things in here and to switch some things around. Perhaps you'll disagree on the 'easiest way to build the source code' but I wanted to invert the two because I find clicking lots easier.
2019-10-23 17:21:10 +02:00
Ronald BarendseandSebastiaan Janssen d0303f74fd Allow hash type on GenerateHash and remove obsoleted ToMd5 and ToSHA1 methods (#6679) 2019-10-23 17:19:49 +02:00
Kenn JacobsenandSebastiaan Janssen e3bc30c4ca Add validation to user groups when creating new users 2019-10-23 17:15:38 +02:00
Sebastiaan JanssenandGitHub 72dc1c29b1 Merge pull request #6699 from emmaburstow/temp-padding-for-content-boxes
V8: Padding for umb-control-group so that it's not as squished
2019-10-23 17:03:19 +02:00
Niels Lyngsø 1056493626 ClipboardService support for copying an array/list of nodes/data 2019-10-23 16:40:59 +02:00
Niels Lyngsø e2417da2f0 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions 2019-10-23 16:00:25 +02:00
Niels LyngsøandSebastiaan Janssen 6dbbe1bdd6 correct mistake in WatchTask of our Gulp Script 2019-10-23 15:52:48 +02:00
Nathan WoulfeandSebastiaan Janssen a41b018f98 V8: Use infinite editor for list view settings (5021) (#6028) 2019-10-23 15:49:36 +02:00
Niels Lyngsø a42fc8fc8e work on copyArray feature for clipboardService 2019-10-23 15:23:23 +02:00
Nathan WoulfeandSebastiaan Janssen debf65a92f V8: Add option for medium-sized infinite editor (#6808) 2019-10-23 15:10:25 +02:00
Niels Lyngsø c6e78d8c9b Merge remote-tracking branch 'origin/v8/dev' into v8/feature/6816-property-actions 2019-10-23 14:28:22 +02:00
Niels Lyngsø 88a34f5bcd current state, not complete. 2019-10-23 14:28:06 +02:00
Niels Lyngsø 6cf697acb2 Added property actions button 2019-10-23 11:48:13 +02:00
Marc StöckerandSebastiaan Janssen f019473b0a Keep wording consistent
Keep it similar to "addGridLayout" or "addRowConfiguration" and also in line with "areAdded".
2019-10-23 11:31:44 +02:00
Bjarke BergandGitHub 35fff2af87 Merge pull request #6810 from umbraco/v8/bugfix/6763-rte-images-in-grid
fixes images not showing up when rendering rte from the grid.
2019-10-23 10:50:42 +02:00
Niels LyngsøandSebastiaan Janssen cc3ef9de0c Upgrade Gulp to v4 (#6809) 2019-10-23 10:31:07 +02:00
Dennis Adolfi faeb3e052a * Removed unnessasary test. 2019-10-23 07:30:16 +02:00
Dennis Adolfi ff05293452 * Updated obsolete description on UmbracoApiController.
* Added back the old construcor in UmbracoApiControllerBase and added a obsolete attribute.
2019-10-23 07:29:23 +02:00
Bjarke Berg 01ddc97e25 Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-10-22 16:39:36 +02:00
Bjarke Berg 733defd463 Revert "Downgraded cherry picked test to work on 8.2.1"
This was only a fix for 8.2.1. The correct code was in dev branch before
This reverts commit a4c4a978
2019-10-22 16:39:14 +02:00
elitsa 09128db858 Merge branch 'v8/dev' into grid-editor-name-templates 2019-10-22 16:25:25 +02:00
Bjarke Berg 050fc1576b Merge branch 'v8/8.2' into v8/dev
# Conflicts:
#	src/SolutionInfo.cs
2019-10-22 16:23:13 +02:00
Niels Lyngsø 6776d6cde6 hide dialog if opening reference in this tab/window. 2019-10-22 15:35:50 +02:00
Niels Lyngsø 89e6cc3611 do close dialog, even thought people might open in a tab. 2019-10-22 15:26:59 +02:00
Niels Lyngsø 67db3778f3 links to edit references 2019-10-22 15:24:36 +02:00
Niels Lyngsø 0f07ecba54 umb-confirm ability to set wether the confirm button is disabled via confirmDisabled 2019-10-22 15:23:46 +02:00
Niels Lyngsø 98df5eae67 never underline icons in table 2019-10-22 15:22:52 +02:00
Niels Lyngsø 0ee9c2d327 ability to disable confirm button in umb-confirm 2019-10-22 15:22:34 +02:00
Søren KottalandElitsa Marinovska 89fc8133d2 Enables list view column templates
* add template property
* Apply template to column value
* Removed trailing newline
2019-10-22 14:38:00 +02:00
Claus 680fdb3ad1 fixes images not showing up when rendering rte from the grid. 2019-10-22 14:33:31 +02:00
ClausandGitHub 3573df3531 Merge pull request #6751 from Jeavon/v8/bugfix/null-user-rte-editor
Add additional null conditionals to the FromEditor method of RichTextPropertyValueEditor
2019-10-22 14:19:21 +02:00
Poornima NayarandElitsa Marinovska d2cde44b1f Changed "Chage password" button style in Users section to be action style 2019-10-22 12:37:40 +02:00
Lars-Erik Aabech d9c1853543 Totally helpful exception message for test classes that can't be resolved 2019-10-21 23:07:36 +02:00
Lars-Erik Aabech 7bd8dee6a2 Changed TestOptionAttributeBase type resolving to use Assemby instead of String 2019-10-21 23:01:23 +02:00
Rasmus John PedersenandSebastiaan Janssen 1362a953f2 Fix wrong assembly name for UmbracoModule 2019-10-21 16:50:39 +02:00
Jeavon a854dcb737 Add additional null checks on GridPropertyEditor in case it's executed in the front end context without CurrentUser 2019-10-21 10:10:08 +01:00
Bjarke BergandGitHub ed6fee4fa4 Merge pull request #6625 from umbraco/v8/feature/AB2913-DataTypeTracking
Data type usage reporting and deletion warning
2019-10-21 10:10:37 +02:00
Bjarke Berg c072015288 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/AB2913-DataTypeTracking
# Conflicts:
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
2019-10-21 09:40:21 +02:00
Bjarke Berg ba215f8700 fix name to follow the class name 2019-10-21 09:34:35 +02:00
Niels Lyngsø c89ea71adf removed comment 2019-10-21 08:51:08 +02:00
Niels Lyngsø f2381daa24 no need for this comment anymore 2019-10-21 08:49:50 +02:00
Bjarke BergandGitHub 9ffb3bed57 Merge pull request #6688 from umbraco/v8/bugfix/AB3172-long-running-ops
Long running operations causes SQL timeout
2019-10-21 07:56:53 +02:00
Shannon DeminickandGitHub 16abdcac46 Merge pull request #6208 from PerplexDaniel/6174-saving-content-type-segment-variation
Support for Segments in ContentTypeRepositoryBase
2019-10-21 16:54:56 +11:00
Bjarke Berg debe4b381c Fixed tests 2019-10-21 07:26:39 +02:00
Bjarke Berg 538a8cf41b Change to case when, just to support if someone change values to something invalid directly in the database, and fixed tes 2019-10-21 07:23:11 +02:00
Shannon DeminickandGitHub d2c43d6f13 Merge pull request #6789 from umbraco/v8/bugfix/6754-StatusCode-Skip-CustomErrors
fixes #6754 - skip custom errors when using StatusCodeFilterAttribute.
2019-10-21 16:17:27 +11:00
Kenn Jacobsen e8d159db46 Remove unused event argument 2019-10-20 11:16:14 +02:00
Kenn Jacobsen 5c670b620c Allow tabbing through the section tray and adjust styles accordingly 2019-10-20 11:08:29 +02:00
Dennis Adolfi 8d70d53ed6 * Added test for mocking UmbracoApiController dependencies with injected UmbracoMapper
* Added test for mocking UmbracoApiController dependencies with ServiceLocator resolved UmbracoMapper for backward compability.
2019-10-18 14:27:55 +02:00
Dennis Adolfi c131759688 * Removed service locator resolvning UmbracoMapper (Current.Mapper) in the UmbracoApiControllerBase constructor.
* Added Obsolete marker to old UmbracoApiController constructor injecting Current.Mapper for backward compability, use new full construcor injection instead.
2019-10-18 14:18:19 +02:00
Dave WoestenborghsandSebastiaan Janssen 3260fec444 V8 - umb-box-header shows values for non-localized and localized title and description (#6689)
* Fix displaying of title and description and also the localized values for title-key and description-key on the umb-box-header directive

* Handle invalide localization keys by setting a fall back value
2019-10-18 13:39:26 +02:00
Poornima NayarandSebastiaan Janssen b199a54038 Clean up of the compositions dialog (#6716) 2019-10-18 13:36:16 +02:00
Kenn JacobsenandSebastiaan Janssen 9af135e7e7 Make the color class prefix configurable for the umb-color-swatches directive 2019-10-18 13:20:03 +02:00
Kenn JacobsenandSebastiaan Janssen d49ad81448 V8: Handle save keyboard shortcut from within the RTE (#6756) 2019-10-18 13:17:16 +02:00
ClausandGitHub 1d39a25240 Merge pull request #6734 from umbraco/v8/bugfix/6698-nucache-panic
Fixes nucache #6698
2019-10-18 10:36:19 +02:00
Claus b87a952c6a fixes #6754 - skip custom errors when using StatusCodeFilterAttribute. 2019-10-18 09:39:36 +02:00
Jeavon 7af15b3a28 Add additional null conditionals as this method is sometimes called for front end rendering where this is no current user (DTGE) 2019-10-17 17:26:32 +01:00
Jan SkovgaardandSebastiaan Janssen 20fd5acae6 v8: Extend the umb-checkbox component to handle localization (#5635) 2019-10-17 17:32:19 +02:00
Tom PipeandSebastiaan Janssen 4c86756640 Fix for #3510 - health check for http headers was case sensitive, but HTTP spec states http headers are case insensitive 2019-10-17 17:02:01 +02:00
Matthew-WiseandSebastiaan Janssen 04a201f5f0 install ngAria (#6628) 2019-10-17 16:41:25 +02:00
Rasmus KongshøjandSebastiaan Janssen 2aede644f4 Only show time in datepicker if format is HH/HH:mm/HH:mm:ss (#6525) 2019-10-17 16:27:34 +02:00
nfJakobsenandSebastiaan Janssen 6b4f7f9ec8 Added apostrophe to Filtrer... in danish 2019-10-17 14:15:22 +02:00
nfJakobsenandSebastiaan Janssen fef6730c1f Fixed title to proper danish 2019-10-17 14:14:22 +02:00
nfJakobsenandSebastiaan Janssen 0355f7111e Documenttypes correctly spelled in danish is one word. 2019-10-17 14:13:34 +02:00
James GeorgeandSebastiaan Janssen a3779b5be9 [Docs]: minor tweak (#6743) 2019-10-17 13:06:21 +02:00
Shannon 4a7c73993b formatting 2019-10-17 21:05:27 +11:00
Shannon DeminickandGitHub 406ac131a2 Merge pull request #6570 from ronaldbarendse/v8/bugfix/umbracomapper
Fixed adding/updating UmbracoMapper constructors
2019-10-17 21:04:42 +11:00
Shannon b95404f585 Adds simpler test to validate RefreshNode 2019-10-17 18:51:15 +11:00
Bjarke Berg 9d7aacbfc0 Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/AB3172-long-running-ops 2019-10-17 09:44:51 +02:00
Shannon c91680e4c7 removes test code 2019-10-17 18:43:54 +11:00
Shannon ea642b3c51 removes TODO 2019-10-17 18:43:09 +11:00
Shannon 439bacff07 Fixes issue - when calling Set, we were not setting all node graph elements. 2019-10-17 18:41:05 +11:00
Bjarke BergandGitHub 13488be0a3 Merge pull request #6685 from umbraco/v8/bugfix/AB3057-change-lang-culture
Ability to change the culture of an existing language
2019-10-17 08:51:27 +02:00
Shannon f384b31e98 Gets a test to confirm the issue, now to fix 2019-10-17 15:47:15 +11:00
Steve MegsonandSebastiaan Janssen 1d0def72f3 Handle duplicate keys in DataTypeMigration (#6651) 2019-10-16 17:51:06 +02:00
VolkenandSebastiaan Janssen fe5996aaf7 Update ModelStateExtensions.cs
Line 76
There is a duplicated word "errors" change this line 
/// Returns a list of cultures that have property validation errors errors
To
/// Returns a list of cultures that have property validation errors
Or if i missunderstood what you mean change with that for a better understanding.
/// Returns a list of cultures that have property validation errors "errors"
2019-10-16 17:35:42 +02:00
KewbishandSebastiaan Janssen 86c6b3d7f8 Grammar changes
There were a few grammatical mistakes and one spelling error in
the various .md files, so I fixed them :)
Signed-off-by: Kewbish <kewbish@gmail.com>
2019-10-16 17:32:51 +02:00
KrnlsoftandSebastiaan Janssen 9c7d3d8c2a Missing Italian translations
Added missing Italian translations
Removed TODO
2019-10-16 16:46:53 +02:00
Paul SealandSebastiaan Janssen 77f2b28aed - set the border for the today class on the date picker (#6619)
* - set the border for the today class on the date picker

* - added the actual styling for the today border
2019-10-16 16:18:06 +02:00
Kenn JacobsenandSebastiaan Janssen 008505354b V8: Do not warn about unpublishing multiple languages for invar… (#6613) 2019-10-16 16:15:29 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 0b395482f1 Use umb-radiobutton in public access overlay (#6612) 2019-10-16 16:00:59 +02:00
Kenn JacobsenandSebastiaan Janssen 6c6b23c465 V8: Add irreversible warning when deleting items from the recycle bin (#6600) 2019-10-16 15:28:03 +02:00
Kenn JacobsenandSebastiaan Janssen 82b8302f25 Turn the "empty recycle bin" warning into an actual warning 2019-10-16 15:26:31 +02:00
Jan SkovgaardandSebastiaan Janssen 8e73198979 Hide icons and use buttons instead of empty anchors in Examine… (#6596) 2019-10-16 12:09:19 +02:00
Shannon 5ca32ba1e9 starts writing tests 2019-10-16 17:29:45 +11:00
Shannon 4e51a2d184 Fixes tests - Nucache tests were not disposing the snapshot service so was binding to all events!! renames the test snapshot service to avoid confusion 2019-10-16 15:49:19 +11:00
Shannon 6d38f946a4 ensures nucache table isn't rebuilt when adding a new lang 2019-10-16 15:00:13 +11:00
Shannon 9be7f536d3 Merge branch 'v8/dev' into v8/bugfix/AB3057-change-lang-culture 2019-10-16 14:49:46 +11:00
Shannon 0c5b832627 fixing tests 2019-10-16 14:21:03 +11:00
Shannon c832e2a3f5 Merge branch 'v8/dev' into v8/bugfix/AB3057-change-lang-culture 2019-10-16 12:39:17 +11:00
Shannon 72cae37a28 fixes test 2019-10-16 12:38:42 +11:00
Shannon 64279c1b6d Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/AB3057-change-lang-culture 2019-10-16 12:29:22 +11:00
Lars-Erik Aabech c56f6c161e Don't throw when type not found by TestOptionAttribute 2019-10-15 23:57:54 +02:00
Lars-Erik Aabech 1b8f9e91df TestOptionAttibute seam to discover testassemblies 2019-10-15 23:29:13 +02:00
Jan SkovgaardandSebastiaan Janssen 9c601ab631 Fix semantics for list views (#6595) 2019-10-15 18:42:52 +02:00
Steve MegsonandSebastiaan Janssen b8425fa662 Correct URL decoding of macro partial view names (#6592) 2019-10-15 18:30:12 +02:00
Kenn JacobsenandSebastiaan Janssen 8fa3ebdd04 Reload node children after publishing with descendants 2019-10-15 18:19:03 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 426aa981f8 Pick macro parameters in an infinite editor like content type properties (#6586) 2019-10-15 18:13:18 +02:00
Kenn JacobsenandSebastiaan Janssen 8a85c3cbf9 V8: It should be possible to disallow all types at content root (#6580) 2019-10-15 17:57:06 +02:00
Kenn JacobsenandSebastiaan Janssen 178185e411 V8: Move misplaced colon in language selector (#6692) 2019-10-15 15:11:42 +02:00
Sebastiaan Janssen 4e345a8f79 Fixes an error in #6538 by moving the colon character to the sr-only span 2019-10-15 15:04:51 +02:00
rbottemaandSebastiaan Janssen c8c5dfe594 Fix ContentType.Alias matching in PublishedContentExtensions an… (#6577) 2019-10-15 13:25:50 +02:00
Andy ButlandandSebastiaan Janssen 28ec4da0fa Allows members to be ordered by additional system fields (#6575) 2019-10-15 13:18:45 +02:00
Andy ButlandandSebastiaan Janssen 14d0bd056c Updated list view headers styling to have the link/hand cursor visible only if the header is sortable (and hence clicking has an effect) 2019-10-15 13:14:00 +02:00
Emma Burstow 29de4fd63f Everything was squished but now it is not. 2019-10-15 11:50:26 +01:00
Daniël Knippers 4495a4ab5a Updated various test cases to include the Segment flag.
The original test method has been changed to a method with parameters for the
ContentVariation "from" and "to" options and [TestCase] attributes are applied
to run the different combinations.
2019-10-15 11:50:16 +02:00
Daniël Knippers c8a8d2e235 Moved property type variation "auto correction" into separate method and perform before validation. 2019-10-15 11:25:47 +02:00
Daniël Knippers 2b14408693 Revert "Moved property type variation auto correct."
This reverts commit 3858bd40ad.
2019-10-15 11:17:03 +02:00
Daniël Knippers 4a42b2fb43 Merge branch 'v8/dev' into 6174-saving-content-type-segment-variation 2019-10-15 11:07:22 +02:00
Shannon 37024664f5 streamlines exception types 2019-10-15 11:15:17 +11:00
Shannon dcc46fa32d no generic exception 2019-10-15 11:14:28 +11:00
Kenn JacobsenandSebastiaan Janssen 81d70cb5a8 V8: Help users create their first content type on blank installs (#6573) 2019-10-14 18:05:18 +02:00
Kenn JacobsenandSebastiaan Janssen f1e6da9d38 Remove "Generic Properties" group from default member type 2019-10-14 18:00:08 +02:00
Kenn JacobsenandSebastiaan Janssen cfa1f2bcfb Don't allow deleting property groups with locked properties (#6567) 2019-10-14 17:57:11 +02:00
Rachel BreezeandSebastiaan Janssen c9ea3656bd Added a test for if an empty titlePrefix is passed into the $changeTitle call 2019-10-14 17:45:38 +02:00
Kenn JacobsenandSebastiaan Janssen dce4f49a3b V8: Enable editing the search results directly from Examine Management (#6560) 2019-10-14 17:41:32 +02:00
Kenn JacobsenandSebastiaan Janssen 529d0fd0aa Reload the media tree when folder contents changes 2019-10-14 17:26:36 +02:00
Florian BeijersandSebastiaan Janssen e8f84e5974 Labeled controls in Belle (#6555) 2019-10-14 17:25:16 +02:00
Nathan WoulfeandSebastiaan Janssen cbcef8ba6c allow node preview content to wrap 2019-10-14 17:14:57 +02:00
Nathan WoulfeandSebastiaan Janssen 35c8c40340 push overlay-right when opening help drawer 2019-10-14 17:13:26 +02:00
Nathan WoulfeandSebastiaan Janssen 8d3b74fbec use regex for finding img where src is a blob 2019-10-14 17:11:28 +02:00
Bjarne FyrstenborgandSebastiaan Janssen d7b25fc4dc Replace checkbox with umb-checkbox in listview publish and unpu… (#6544) 2019-10-14 17:06:36 +02:00
Sebastiaan JanssenandGitHub 7d5d424045 Fix ContentService.DeleteVersions (#6543)
Fix ContentService.DeleteVersions
2019-10-14 16:46:47 +02:00
Sebastiaan JanssenandGitHub fcb142fb04 Replace checkbox with umb-checkbox for relate to original (#6542)
* Replace relate to original checkbox with umb-checkbox

* Remove unused localization of search text
2019-10-14 16:02:51 +02:00
Bjarne FyrstenborgandSebastiaan Janssen a439606a05 Adjust layout in profiler dashboard (#6539) 2019-10-14 16:01:00 +02:00
Jan SkovgaardandSebastiaan Janssen fc91ab034e Refactor language picker to improve accessibility (#6538) 2019-10-14 16:00:02 +02:00
Søren KottalandSebastiaan Janssen 8f300761ef Makes it possible to change the icon for list view content apps 2019-10-14 15:57:17 +02:00
Rasmus John PedersenandSebastiaan Janssen b8e5146baa Add publish and unpublish date to info app 2019-10-14 15:38:26 +02:00
Shannon DeminickandSebastiaan Janssen 63ae00b0f3 Fixes Search an element from its GUID with the backoffice #6185 (#6530) 2019-10-14 15:07:44 +02:00
Shannon d0435f6625 Moves read/write locking and isolation level to the responsibility of the sql provider based on the db type 2019-10-15 00:04:41 +11:00
Jan SkovgaardandSebastiaan Janssen fa7a46389c Split events.directive into separate event directives (#6533) 2019-10-14 15:03:46 +02:00
Kenn JacobsenandSebastiaan Janssen 81c7503c54 Make upload and image cropper mandatory validation work clientside 2019-10-14 14:46:05 +02:00
Kenn JacobsenandSebastiaan Janssen f6d00a177e V8: Support allowed types for MNTP member picker (#6524) 2019-10-14 14:34:33 +02:00
Kenn JacobsenandSebastiaan Janssen 0d3e330b12 Support allowed types for MNTP media picker 2019-10-14 14:24:11 +02:00
pirvandrandSebastiaan Janssen 174a1d731d # fix issue 6467: removed all the MacroContainer related files… (#6518) 2019-10-14 14:03:51 +02:00
Lee KelleherandSebastiaan Janssen 16dc634cf9 Boolean editors - adds ID attribute to umbToggle (#6512) 2019-10-14 13:56:21 +02:00
Sebastiaan JanssenandGitHub e0481ac4de add aria markup to umb-toggle so it behaves like the checkbox it is (#6506) 2019-10-14 13:49:42 +02:00
Ronald BarendseandSebastiaan Janssen 0dea83543e Removed Microsoft.Net.Compilers dependency (#6501) 2019-10-14 13:39:53 +02:00
Shannon 00b5f59bce simplifies lang refresher a bit 2019-10-14 22:09:47 +11:00
Shannon 9008641965 ensures the domain cache is totally refreshed when changing langs 2019-10-14 22:02:42 +11:00
Shannon ae0ad2b897 Updates UI to allow updating a culture for a language and warn the user if they are changing it, updates the controller to be able to udpate a culture on a lang 2019-10-14 19:04:51 +11:00
Shannon DeminickandGitHub 1a593a8ef4 Merge pull request #6582 from bielu/feature/split_indexcreator_and_config
V8: Split IndexCreator and Index config methods
2019-10-14 15:55:11 +11:00
Shannon DeminickandGitHub e59abe852a Merge pull request #6656 from hkooikerspeak/v8/bugfix/6655-contentindexpopulator-not-getting-publishedquery
Fix ContetIndexPopulator publishedQuery
2019-10-14 15:51:51 +11:00
Shannon 348afd3d0a updates logic for cache refreshers for languages to deal with updating nucache and examine 2019-10-14 15:21:00 +11:00
elitsa 913db21350 Added missing ; 2019-10-11 15:41:16 +02:00
elitsa 175253a1a6 Clear Cache and remove mculture from the url if the last non-default language is deleted 2019-10-11 15:40:55 +02:00
elitsa 016bed03ae Deleting a language will set the selectedLanguage to the default language and update the mculture attribute in the url. 2019-10-11 15:38:26 +02:00
Bjarke Berg 261dc2af98 AB2913 - Added unit tests for the umbCmsJoinArray filter, and a small change when using null for separator 2019-10-11 13:32:23 +02:00
Harmen Kooiker 79e6c106d3 Fix ContetIndexPopulator publishedQuery 2019-10-11 09:38:43 +02:00
arkadiuszbiel a7412dfe79 Correct name in DI 2019-10-10 18:37:30 +02:00
arkadiuszbiel 511751d147 refactor based on shannon comments 2019-10-10 15:50:00 +02:00
Poornima Nayar 3158b8b644 Clean up of change password section in member details 2019-10-10 12:26:09 +01:00
Shannon 2675516b96 Adds logic to ensure you can't change to a culture that is already assigned + test 2019-10-10 20:45:16 +11:00
ClausandGitHub ec6b38175c Merge pull request #6458 from umbraco/fix/6377-disable-deleting-sensitive-data-user-group
Disallow deleting "Sensitive data" user group
2019-10-10 10:59:37 +02:00
Shannon b400a72e77 Changes filter name 2019-10-10 17:56:53 +11:00
Søren Kottal 702aa41ff2 Adds nametemplates for grid editors 2019-10-09 22:19:28 +02:00
Jeavon 0c957c2fd9 Also replace underscores 2019-10-09 16:46:57 +01:00
Jeavon 82af5f26e5 Added a fix to handle hyphens in file names 2019-10-09 16:16:19 +01:00
Niels Lyngsø c091d21034 align icons if the are in a umb-table 2019-10-09 16:53:30 +02:00
Niels Lyngsø 188cc2a9fd listing out properties with exclamation mark icon in front of each 2019-10-09 16:43:52 +02:00
Niels Lyngsø 5035438a28 simplified wording by removing "based on it" 2019-10-09 16:33:18 +02:00
Niels Lyngsø e7faa14956 changed wording 2019-10-09 16:31:04 +02:00
Niels Lyngsø e7363adc2d highlight properties begin deleted + corrected array 2019-10-09 16:29:29 +02:00
Niels Lyngsø f658c15a06 rename relations to references, to avoid misunderstanding. 2019-10-09 16:22:58 +02:00
Niels Lyngsø 042971103f rename to Reference 2019-10-09 16:01:54 +02:00
Niels Lyngsø dda99272aa Delete dialog for datatype that has relations 2019-10-09 16:01:01 +02:00
Niels Lyngsø 18e8caeb7e adding new localizations 2019-10-09 16:00:34 +02:00
Niels Lyngsø 2d693ddd35 ups, misspelling of localization key 2019-10-09 13:05:47 +02:00
Niels Lyngsø 7024bc495b set template to cache output since its not going to update unless you reloaded the view. 2019-10-09 13:03:57 +02:00
Niels Lyngsø fd7b85f447 added no overflow for properties 2019-10-09 12:54:00 +02:00
Niels Lyngsø dd29fe5745 added used by properties 2019-10-09 11:37:45 +02:00
Paul SealandSebastiaan Janssen 6f5665f6a5 - updated this in 3 more places 2019-10-09 10:41:48 +02:00
Paul SealandSebastiaan Janssen 4e6bbcf6c2 - updated usage of EmptyRecycleBin to pass in the user id as instructed in warning messages 2019-10-09 10:41:48 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 0567ed9a34 Fix incorrect path in member group mapping 2019-10-09 10:15:45 +02:00
Shannon 4c344fcb9e fixes build 2019-10-09 16:07:43 +11:00
Shannon cf9add767a Fixes navigating to other items via url 2019-10-09 15:55:09 +11:00
Shannon 4c131d14fc ensure the data type refs are only loaded when the tab is activated 2019-10-09 15:31:13 +11:00
Shannon ac300179e6 Adds new endpoint to DataTypeController to return the correct data and wires that up to angular 2019-10-09 15:19:03 +11:00
Shannon DeminickandGitHub 484d08b72a Merge pull request #6610 from bjarnef/dev-v8-grid-pe-null-check
Check if value is null or whitespace before reading grid configuration
2019-10-09 03:10:59 +04:00
Bjarne Fyrstenborg 646bfb02f2 Check if value is null or whitespace before reading grid configuration 2019-10-08 18:55:44 +02:00
Niels Lyngsø 0e34c5e3c2 Merge remote-tracking branch 'origin/v8/feature/AB2918-update-datatype-edit-view' into v8/feature/AB2913-DataTypeTracking 2019-10-08 15:45:44 +02:00
Niels Lyngsø a178a4d77b removing console.logs 2019-10-08 15:45:25 +02:00
Niels Lyngsø ab6f4af439 dont know why this was removed, brain fart... 2019-10-08 15:45:14 +02:00
Niels Lyngsø b53eae0510 Merge remote-tracking branch 'origin/v8/feature/AB2918-update-datatype-edit-view' into v8/feature/AB2913-DataTypeTracking 2019-10-08 15:12:13 +02:00
Niels Lyngsø 982a7c6b51 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/AB2913-DataTypeTracking 2019-10-08 15:11:51 +02:00
Niels Lyngsø 5deaf996e0 auto width for actions 2019-10-08 14:48:42 +02:00
Niels Lyngsø dfc642e787 seperate row for icons 2019-10-08 14:32:41 +02:00
Niels Lyngsø eff284cb04 corrected open links 2019-10-08 14:20:42 +02:00
Niels Lyngsø 69fb12a270 changed wording 2019-10-08 14:20:30 +02:00
Shannon bcc76b2072 Implements DataTypeService.FindUsages 2019-10-08 23:09:45 +11:00
Niels Lyngsø 3da64651b0 changed to headlines to h5 2019-10-08 14:02:30 +02:00
Niels Lyngsø 097ef82d41 corrected working 2019-10-08 14:02:18 +02:00
Niels Lyngsø 8e17245dc0 changed look and translation keys 2019-10-08 13:58:34 +02:00
Niels Lyngsø dbee0da6a5 tabName translation 2019-10-08 13:14:25 +02:00
Niels Lyngsø 79d20bfddb whitespace 2019-10-08 13:10:45 +02:00
Niels Lyngsø 3365d6fc88 correctied area key for translation 2019-10-08 13:10:17 +02:00
Niels Lyngsø 65c4989575 added more translations 2019-10-08 13:05:48 +02:00
Niels Lyngsø cca66be3d2 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/AB2918-update-datatype-edit-view 2019-10-08 12:03:07 +02:00
Bjarke Berg e7196d5edf Merge branch 'v8/8.2' into v8/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
2019-10-08 11:56:43 +02:00
Niels Lyngsø 3ff2996cb9 added a view for datatype relations 2019-10-08 10:41:41 +02:00
Niels Lyngsø ab1f9f3acb added fake test for this prototype 2019-10-08 10:41:16 +02:00
Søren KottalandSebastiaan Janssen 0e4727f5df Adds missing danish language keys, and changes a few others 2019-10-06 12:58:22 +02:00
arkadiuszbiel 1ca35b2fbb Obsolete instead of remove functions 2019-10-05 14:36:47 +02:00
Jeavon 61465ed997 Add null check to umbracoFilePath and used Yield extension method 2019-10-04 18:30:35 +01:00
Jeavon 7130c99810 Rename new field and ensure Id is also searchable 2019-10-04 17:44:26 +01:00
arkadiuszbiel c0fa66799f Split config and index creator to allow to override only config not whole index creator 2019-10-04 16:41:29 +02:00
Daniël Knippers 4a3b3c4151 Property type correction test 2019-10-04 14:29:01 +02:00
Daniël Knippers 3858bd40ad Moved property type variation auto correct. 2019-10-04 14:29:01 +02:00
Daniël Knippers 2e79a515c9 Updated tests 2019-10-04 14:29:01 +02:00
Jeavon 68866e9faf Adding a constant for the new field name 2019-10-04 11:17:36 +01:00
Jeavon 72147ab8f2 Fixing Examine unit tests 2019-10-04 10:34:10 +01:00
Daniël Knippers c7d00b2c00 Corrected ValidateVariations method
Triggered by a failing unit test that was updated for segments
2019-10-04 08:53:41 +02:00
Jeavon e4df2f4205 Add ability for editors to search for media items by file name as well as node name. 2019-10-03 17:46:18 +01:00
Daniël Knippers 8892afe219 Merge branch 'upstream-v8-dev' into 6174-saving-content-type-segment-variation 2019-10-03 16:49:01 +02:00
Daniël Knippers d76ff8b999 Updated a couple unit tests for segments 2019-10-03 16:40:44 +02:00
Ronald Barendse 65b49f1a29 Fixed adding/updating UmbracoMapper constructors 2019-10-03 15:06:16 +02:00
Daniël Knippers fc717d1e37 Code comments 2019-10-03 14:01:00 +02:00
Rachel BreezeandSebastiaan Janssen 09df60455c Added missing syntax to controller 2019-10-03 01:16:52 +02:00
Shannon b4c6930c11 Merge branch 'v8/8.2' into v8/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
2019-10-02 10:47:09 +02:00
Niels Lyngsø 69d97bc984 first step for changing the datatype edit view 2019-10-02 10:28:26 +02:00
Rasmus John PedersenandSebastiaan Janssen f65140854d Too much scope 2019-10-02 08:48:37 +02:00
Steve Megson dbce1147a8 Fix ContentService.DeleteVersions 2019-10-01 22:31:42 +01:00
Bjarne Fyrstenborg 76c1d10701 Remove unused localization of search text 2019-10-01 22:53:26 +02:00
Bjarne Fyrstenborg e0cc87f9a2 Replace relate to original checkbox with umb-checkbox 2019-10-01 22:52:26 +02:00
Rasmus KongshøjandSebastiaan Janssen 7e0abeb6e5 Added missing class 2019-10-01 20:25:26 +02:00
Rasmus John PedersenandSebastiaan Janssen 41126c2c73 Allow editing name and saving on on list views 2019-10-01 20:09:21 +02:00
Anders BjernerandSebastiaan Janssen 9378316ed3 Marking the umb-overlay directive as deprecated 2019-10-01 19:52:19 +02:00
jmayntzhusenandSebastiaan Janssen 85cc7d82d0 Update styles of API docs to match new identity (#6517) 2019-10-01 19:49:40 +02:00
Dennis AaenandSebastiaan Janssen a025871b8c Added new translation for issue #6484 (#6515) 2019-10-01 19:42:17 +02:00
ShannonandSebastiaan Janssen 62ee1899ad Fixes Return 503 status code when in upgrade mode #6334 2019-10-01 18:26:36 +02:00
Kenn JacobsenandSebastiaan Janssen 29383f37e7 V8: Lazy load thumbnails in the media grid (#6510) 2019-10-01 18:21:46 +02:00
Florian Beijers 5b2d2d22c4 add aria markup to umb-toggle so it behaves like the checkbox it is 2019-10-01 17:13:50 +02:00
Carole Rennie LoganandSebastiaan Janssen 77dc014b58 More inclusive language 2019-10-01 12:08:56 +02:00
Shannon 3a1078824d Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-10-01 12:02:29 +02:00
Shannon 3422f1c3cf Merge branch 'PerplexDaniel-6179+6180-read-write-segmented-property-values' into v8/dev 2019-10-01 12:01:57 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 038e650e0f Adjust log viewer search layout (#6491) 2019-10-01 09:57:08 +02:00
Shannon d97101a14b Updates tests to rename assertion method parameters including code comments 2019-10-01 09:37:43 +02:00
Anders BjernerandSebastiaan Janssen 279efb0e85 Added missing translations for Danish 2019-09-30 23:34:44 +02:00
Anders BjernerandSebastiaan Janssen 968acb183f Added punctuation (#6489) 2019-09-30 23:32:56 +02:00
Bjarne FyrstenborgandSebastiaan Janssen bd13619b18 Use umb-checkbox for loglevel selection 2019-09-30 23:30:19 +02:00
Anders BjernerandSebastiaan Janssen e9cecd0526 More punctuation for the Danish descriptions 2019-09-30 23:21:20 +02:00
Anders BjernerandSebastiaan Janssen 1079bfce1b Proper punctuation for the Danish translation 2019-09-30 23:04:14 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 5b8da1ce19 Add umb-checkbox for publish unpublished content items with no… (#6485) 2019-09-30 22:39:37 +02:00
Dave WoestenborghsandSebastiaan Janssen 5f6ab6c146 V8/fix section selection (#6481) 2019-09-30 22:38:09 +02:00
Dave WoestenborghsandSebastiaan Janssen aab35ae3ba V8/fix user group selection (#6480) 2019-09-30 22:36:51 +02:00
Anders BjernerandSebastiaan Janssen 48f04f302f Sorter -> Sortér 2019-09-30 22:30:29 +02:00
Kenn JacobsenandSebastiaan Janssen 9527059abf Make sure search doesn't close when clicking "Clear" (#5797) 2019-09-30 19:24:00 +02:00
Kenn JacobsenandSebastiaan Janssen e286e60a3b Use umb-checkbox in the delete doctype confirm (#4982) 2019-09-30 19:22:36 +02:00
Kenn JacobsenandSebastiaan Janssen 47f27e8eec Remove "RenderModel" from various comments throughout the code (#4814) 2019-09-30 19:14:26 +02:00
Søren GregersenandSebastiaan Janssen 3fd412e962 fix: Missing "=" in Flickr markup
Seems to have been missing in quite a lot of versions :)
2019-09-30 19:13:12 +02:00
Dirk SeefeldandSebastiaan Janssen 9e1809eeec Idseefeld umbraco config lang de (#5776) 2019-09-30 19:07:37 +02:00
Kenn JacobsenandSebastiaan Janssen 985df6e32b V8: Show the breadcrumb when creating new content (#6128) 2019-09-30 18:51:05 +02:00
Sebastiaan JanssenandGitHub f1b724bdc4 5867 enables tabbing to field-lock-toggler, and adds tab-focus styling (#5876) 2019-09-30 18:36:37 +02:00
Sebastiaan Janssen 765d1576e0 Hide the icon from screen readers 2019-09-30 18:35:35 +02:00
Sebastiaan Janssen 6d57fcca8c Merge branch 'v8/dev' into pr/5876 2019-09-30 18:34:24 +02:00
Kenn JacobsenandSebastiaan Janssen 53a129ab22 V8: Support multiple URL aliases in umbracoUrlAlias (#5875) 2019-09-30 18:32:24 +02:00
Kenn JacobsenandSebastiaan Janssen 37dd442682 V8: Fix alignment between dashboard headers and root nodes (#5787) 2019-09-30 18:30:18 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 48fbd4aec2 Update noUiSlider to latest patch version 2019-09-30 18:29:30 +02:00
Kenn JacobsenandSebastiaan Janssen 1101391659 Remove the GUID input hover title (#4829) 2019-09-30 18:21:50 +02:00
Sebastiaan Janssen 45249be8b2 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/ObjectExtensions.cs
2019-09-30 18:13:06 +02:00
Benjamin HowarthandSebastiaan Janssen 79bf9b753c #2996 resubmitting ContentExtensions and ObjectExtensions fixes (#6473) 2019-09-30 17:54:28 +02:00
mh@ecreo.dkandSebastiaan Janssen b4f2b023de adds missing language key 2019-09-30 16:41:05 +02:00
Shannon af8c3459e3 Moves Assert4A/B methods to methods and renames some parameters ... need to figure out what the rest mean 2019-09-30 15:59:45 +02:00
Shannon f992da41f7 Merge branch '6179+6180-read-write-segmented-property-values' of https://github.com/PerplexDaniel/Umbraco-CMS into PerplexDaniel-6179+6180-read-write-segmented-property-values 2019-09-30 15:04:06 +02:00
Warren BuckleyandGitHub 1f37974f15 Merge pull request #6462 from umbraco/v8/bugfix/2997-get-by-key-cache-refresher
Fixes #2997 - ContentService returns outdated result
2019-09-30 12:33:51 +01:00
Jan SkovgaardandSebastiaan Janssen f3086cf22e Fix minor issues in umb-app-header (#6457) 2019-09-30 10:55:41 +02:00
Bjarne FyrstenborgandSebastiaan Janssen a83b72ed47 v8: Add umb file icon component (#6293) 2019-09-29 17:51:17 +02:00
Bjarne FyrstenborgandSebastiaan Janssen ca824b01d6 v8: Add confirm overlay when deleting user account (#5487) 2019-09-29 17:02:12 +02:00
Steve MegsonandSebastiaan Janssen 88c6bb9c21 V8: Redirect tracking on move (#6344) 2019-09-29 16:49:04 +02:00
Kenn JacobsenandSebastiaan Janssen ca8d5b948c Don't YSOD when editing doctype from content that hasn't been saved yet 2019-09-29 16:07:29 +02:00
Andy ButlandandSebastiaan Janssen 1acb6f5215 Re-ordered and updatesd language delete clauses in language repository to ensure any tags for the language are deleted before the language itself is deleted 2019-09-29 16:04:54 +02:00
Jan SkovgaardandSebastiaan Janssen 2cd92e7394 Use aria attributes in dialog markup (#6402) 2019-09-29 15:54:04 +02:00
Andy ButlandandSebastiaan Janssen cb5b9ed7e4 Hide settings and delete option when re-ordering doc type properties 2019-09-29 15:40:14 +02:00
Andy ButlandandSebastiaan Janssen d984014258 Fixes #6400: Content Templates don't set name correctly when cr… (#6404) 2019-09-29 15:37:09 +02:00
BatJanandSebastiaan Janssen e1d28608cf Ensure notifications are announced by screen readers and tweak semanics and a litle styling too 2019-09-29 15:24:32 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 795b64dadd v8: Change button style for "create package" and "show more" (in the log viewer) (#6428) 2019-09-29 15:16:50 +02:00
Bjarne FyrstenborgandSebastiaan Janssen fa0bdd5aaf v8: Fix media picker svg preview (#6418) 2019-09-29 14:28:00 +02:00
Bjarne FyrstenborgandSebastiaan Janssen e20437d8db v8: Change confirm delete button style (#6429) 2019-09-29 13:49:17 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 9ec1c05304 v8: Use umb-radiobutton component in relation types (#6454) 2019-09-29 13:48:00 +02:00
Sebastiaan Janssen b87fc4a779 Fix #6461 - declares missing variable 2019-09-29 13:35:40 +02:00
Søren KottalandSebastiaan Janssen 5b79d780f7 enables infinite editing for partial views 2019-09-29 13:34:24 +02:00
Søren KottalandSebastiaan Janssen 7ad97de848 enables infinite editing for members 2019-09-29 13:21:33 +02:00
Bjarne FyrstenborgandSebastiaan Janssen ea0dc9d68f v8: Package repo categories selection updates (#6459) 2019-09-29 11:49:28 +02:00
GunnarandSebastiaan Janssen 8a06f2f062 fixed xml comment for GridConfigurationEditor 2019-09-29 11:42:55 +02:00
Sebastiaan Janssen 7de7e59f55 Something went wrong with the title update
Instead of $rootScope, which is not injected, we need to use scope
The title prefix didn't include the original title
2019-09-28 11:29:04 +02:00
Shannon 35a7283952 Fixes #2997 - ContentService returns outdated result 2019-09-27 10:59:29 +02:00
Shannon 99d2bef704 Merge branch 'v8/8.2' into v8/dev 2019-09-27 10:58:45 +02:00
Sebastiaan JanssenandRasmus John Pedersen 52c4a57247 In addition to #6236 - now this now longer keeps appending the content name on each change of the language dropdown 2019-09-26 19:04:09 +02:00
Rasmus John Pedersen ae6004166f Disallow deleting "Sensitive data" user group 2019-09-26 18:40:45 +02:00
Jan SkovgaardandSebastiaan Janssen d67a89114c Health Check - Text alternatives for icons missing (In Groups) (#6453) 2019-09-26 18:38:38 +02:00
Rasmus John PedersenandSebastiaan Janssen 6beb84442c Disable rename alias of system user groups 2019-09-26 18:34:48 +02:00
BatJanandSebastiaan Janssen 885f0f0cae Lower the z-index so it does not clash with the publishing menu 2019-09-26 16:47:16 +02:00
Martin JensenandSebastiaan Janssen 99dcbd3272 Removing unnecessary delete confirmation (#6448) 2019-09-26 16:27:24 +02:00
9c366fe42b Provide text alternatives for non-visual context
Co-authored-by: webdokkeren <thormadsenholm@gmail.com>
2019-09-26 16:11:03 +02:00
Andrei Ilie PîrvanandSebastiaan Janssen b188bfa059 fix issue #6248 2019-09-26 15:34:51 +02:00
Bjarke Berg 6a7b9fa6f7 Merge branch 'v8/8.2' into v8/dev 2019-09-26 15:30:51 +02:00
Sebastiaan Janssen 5831cd9159 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Serialization/JsonNetSerializer.cs
#	src/Umbraco.Web/Editors/BackOfficeController.cs
2019-09-26 13:45:50 +02:00
Benjamin HowarthandSebastiaan Janssen 16837d018a #2996 changed formatting to none for both data transfer & persistence 2019-09-26 13:33:41 +02:00
Benjamin HowarthandSebastiaan Janssen d3c4aace16 #2996 added GlobalSettings.DebugMode switch for JSON formatting indentation. 2019-09-26 13:33:41 +02:00
Bjarke Berg 4904060d7f Merge remote-tracking branch 'origin/v8/8.2' into v8/dev 2019-09-26 13:04:54 +02:00
Bjarke Berg 6c1df64eee Merge branch 'v8/8.2' into v8/dev 2019-09-26 11:47:38 +02:00
Sebastiaan Janssen 8ec73b1810 Merge branch 'v8/8.2' into v8/dev 2019-09-26 11:31:30 +02:00
Nathan WoulfeandSebastiaan Janssen 713cf2312f adding visibility:hidden to the un-hovered list fixes the problem. have also tidied up the css a bit to remove duplicate class references 2019-09-26 11:28:23 +02:00
Tobias KlikaandSebastiaan Janssen c652e47c3e overlay "target"-positioning updates correctly on content changes and container resize 2019-09-26 11:26:29 +02:00
Bjarke Berg 1a9ed95235 Bumb version to 8.3 2019-09-26 10:05:41 +02:00
Daniël Knippers 8e5b37cbc8 Merge branch 'upstream-v8-dev' into 6179+6180-read-write-segmented-property-values 2019-09-20 09:05:57 +02:00
Daniël Knippers aa4677e1dd Added and updated unit tests for the ValidateVariation method 2019-09-19 14:52:05 +02:00
Daniël Knippers 82c3af51fe Fixes writing / reading segment data combined with segment null 2019-08-27 15:43:07 +02:00
Daniël Knippers 4b4f571d14 Support for Segments in ContentTypeRepositoryBase 2019-08-27 15:07:41 +02:00
skttl 5d5bd54aee 5867 enables tabbing to field-lock-toggler, and adds tab-focus styling 2019-07-12 21:07:55 +02:00
510 changed files with 17784 additions and 12114 deletions
+5 -3
View File
@@ -1,4 +1,4 @@
# Umbraco Cms Build
# Umbraco CMS Build
## Are you sure?
@@ -39,6 +39,8 @@ To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the
build/build.ps1
If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (dev-v8) the file will appear and you can build it.
You might run into [Powershell quirks](#powershell-quirks).
### Build Infrastructure
@@ -66,7 +68,7 @@ The Visual Studio object is `null` when Visual Studio has not been detected (eg
* `Path`: Visual Studio installation path (eg some place under `Program Files`)
* `Major`: Visual Studio major version (eg `15` for VS 2017)
* `Minor`: Visual Studio minor version
* `MsBUild`: the absolute path to the MsBuild executable
* `MsBuild`: the absolute path to the MsBuild executable
#### GetUmbracoVersion
@@ -209,4 +211,4 @@ The best solution is to unblock the Zip file before un-zipping: right-click the
### Git Quirks
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
+1 -1
View File
@@ -29,4 +29,4 @@ Don't rest on your laurels and never accept the status quo. Contribute and give
## Friendly
Dont judge upon mistakes made but rather upon the speed and quality with which mistakes are corrected. Friendly posts and contributions generate smiles and builds long lasting relationships.
Dont judge upon mistakes made but rather upon the speed and quality with which mistakes are corrected. Friendly posts and contributions generate smiles and build long lasting relationships.
+39 -30
View File
@@ -2,15 +2,15 @@
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
The following is a set of guidelines for contributing to Umbraco CMS.
The following is a set of guidelines, for contributing to Umbraco CMS.
These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
Remember, we're a friendly bunch and are happy with whatever contribution you might provide. Below are guidelines for success that we've gathered over the years. If you choose to ignore them then we still love you 💖.
**Code of conduct**
This project and everyone participating in it is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
This project and everyone participating in it, is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
**Table of contents**
@@ -38,11 +38,11 @@ This document gives you a quick overview on how to get started.
### Guidelines for contributions we welcome
Not all changes are wanted, so on occassion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
Not all changes are wanted, so on occasion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes.
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes, so we can ensure that you don't put all your hard work into something we would not be able to merge.
Remember, if an issue is in the `Up for grabs` list or you've asked for some feedback before you sent us a PR, your PR will not be closed as unwanted.
Remember, it is always worth working on an issue from the `Up for grabs` list or even asking for some feedback before you send us a PR. This way, your PR will not be closed as unwanted.
### What can I start with?
@@ -59,37 +59,38 @@ Great question! The short version goes like this:
* **Clone** - when GitHub has created your fork, you can clone it in your favorite Git tool
![Clone the fork](img/clonefork.png)
* **Switch to the correct branch** - switch to the v8-dev branch
* **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](BUILD.md)
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
* **Commit** - done? Yay! 🎉 **Important:** create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`. When you have a branch, commit your changes. Don't commit to `v8/dev`, create a new branch first.
* **Push** - great, now you can push the changes up to your fork on GitHub
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here] (https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
![Create a pull request](img/createpullrequest.png)
### Pull requests
The most successful pull requests usually look a like this:
* Fill in the required template
* Fill in the required template, linking your pull request to an issue on the [issue tracker,](https://github.com/umbraco/Umbraco-CMS/issues) if applicable.
* Include screenshots and animated GIFs in your pull request whenever possible.
* Unit tests, while optional are awesome, thank you!
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
* Unit tests, while optional, are awesome. Thank you!
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated.
Again, these are guidelines, not strict requirements.
Again, these are guidelines, not strict requirements. However, the more information that you give to us, the more we have to work with when considering your contributions. Good documentation of a pull request can really speed up the time it takes to review and merge your work!
## Reviews
You've sent us your first contribution, congratulations! Now what?
You've sent us your first contribution - congratulations! Now what?
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request you to make some additional changes.
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request that you make some additional changes.
We have [a process in place which you can read all about](REVIEW_PROCESS.md). The very abbreviated version is:
- Your PR will get a reply within 48 hours
- An in-depth reply will be added within at most 2 weeks
- The PR will be either merged or rejected within at most 4 weeks
- Sometimes it is difficult to meet these timelines and we'll talk to you
- Sometimes it is difficult to meet these timelines and we'll talk to you if this is the case.
### Styleguides
@@ -99,21 +100,21 @@ That said, the Umbraco development team likes to follow the hints that ReSharper
### The PR team
The pull request team consists of a member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members
The pull request team consists of one member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members who have comitted to volunteering their free time:
- [Anders Bjerner](https://github.com/abjerner)
- [Dave Woestenborghs](https://github.com/dawoe)
- [Emma Burstow](https://github.com/emmaburstow)
- [Poornima Nayar](https://github.com/poornimanayar)
These wonderful volunteers will provide you with a first reply to your PR, review and test out your changes and might ask more questions. After that they'll let Umbraco HQ know if everything seems okay.
These wonderful people aim to provide you with a first reply to your PR, review and test out your changes and on occasions, they might ask more questions. If they are happy with your work, they'll let Umbraco HQ know by approving the PR. Hq will have final sign-off and will check the work again before it is merged.
### Questions?
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
You can get in touch with [the PR team](#the-pr-team) in multiple ways; we love open conversations and we are a friendly bunch. No question you have is stupid. Any question you have usually helps out multiple people with the same question. Ask away:
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward.
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum. The team monitors that one closely, so one of us will be on hand and ready to point you in the right direction.
## Working with the code
@@ -125,19 +126,19 @@ In order to build the Umbraco source code locally, first make sure you have the
* Node v10+
* npm v6.4.1+
The easiest way to get started is to run `build.ps1` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
The easiest way to get started is to open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
Alternatively, you can run `build.ps1` from the Powershell command line, which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
![Gulp build in Visual Studio](img/gulpbuild.png)
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser, follow the directions there to get a working Umbraco install up and running.
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser. Follow the directions there to get a working Umbraco install up and running.
### Working with the source code
Some parts of our source code are over 10 years old now. And when we say "old", we mean "mature" of course!
There's two big areas that you should know about:
There are two big areas that you should know about:
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
You may need to run the following commands to set up gulp properly:
@@ -146,30 +147,34 @@ There's two big areas that you should know about:
npm install
npm run build
```
The caching for the back office has been described as 'aggressive' so we often find it's best when making back office changes to disable caching in the browser to help you to see the changes you're making.
2. "The rest" is a C# based codebase, which is mostly ASP.NET MVC based. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
To find the general areas for something you're looking to fix or improve, have a look at the following two parts of the API documentation.
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
* [The C# application](https://our.umbraco.com/apidocs/csharp/)
### Which branch should I target for my contributions?
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. Whatever the default is, that's where we'd like you to target your contributions.
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. If you are working on v8, this is the branch you should be targetting. For v7 contributions, please target 'v7/dev'.
Please note: we are no longer accepting features for v7 but will continue to merge bug fixes as and when they arise.
![Which branch should I target?](img/defaultbranch.png)
### Making changes after the PR was opened
### Making changes after the PR is open
If you make the corrections we ask for in the same branch and push them to your fork again, the pull request automatically updates with the additional commit(s) so we can review it again. If all is well, we'll merge the code and your commits are forever part of Umbraco!
### Keeping your Umbraco fork in sync with the main repository
We recommend you sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
We recommend you to sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
Also, if you've submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
Also, if you have submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
To sync your fork with this original one, you'll have to add the upstream url, you only have to do this once:
To sync your fork with this original one, you'll have to add the upstream url. You only have to do this once:
```
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
@@ -185,3 +190,7 @@ git rebase upstream/v8/dev
In this command we're syncing with the `v8/dev` branch, but you can of course choose another one if needed.
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
### And finally
We welcome all kinds of contributions to this repository. If you don't feel you'd like to make code changes here, you can visit our [documentation repository](https://github.com/umbraco/UmbracoDocs) and use your experience to contribute to making the docs we have, even better. We also encourage community members to feel free to comment on others' pull requests and issues - the expertise we have is not limited to the PR team and HQ. So, if you see something on the issue tracker or pull requests you feel you can add to, please don't be shy.
+2 -2
View File
@@ -13,7 +13,7 @@ Were usually able to handle small PRs pretty quickly. A community volunteer w
Umbraco HQ will regularly mark newly created issues on the issue tracker with the `Up for grabs` tag. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. We encourage anyone to pick them up and help out.
If you do start working on something, make sure leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
If you do start working on something, make sure to leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
## Large PRs
New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGets packages.config, NPMs packages.json, etc.).
@@ -30,6 +30,6 @@ It is highly recommended that you speak to the HQ before making large, complex c
### Pull request or package?
If it doesnt fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and to fix bugs.
If it doesnt fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and fix bugs.
Eventually, a package could "graduate" to be included in the CMS.
+5 -5
View File
@@ -7,15 +7,15 @@ A brief description of the issue goes here.
<!--
If you haven't yet done so, please read the "contributing guidelines"
thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
Please fill out the rest of the details in the issue template below.
The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
-->
## Umbraco version
I am seeing this issue on Umbraco version: <!-- please note the version here -->
Reproduction
+3 -3
View File
@@ -1,4 +1,4 @@
# [Umbraco CMS](https://umbraco.com) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md) [![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=v8/dev)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) [![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)
# [Umbraco CMS](https://umbraco.com) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md) [![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=v8/dev)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) [![Twitter](https://img.shields.io/twitter/follow/umbraco.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=umbraco)
Umbraco is the friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 500,000 websites worldwide. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
@@ -21,7 +21,7 @@ Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet, with full support for all your custom .NET code and integrations. You're up and running in less than a minute, and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14-day trial, no credit card needed.
If you want to DIY, you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
If you want to DIY, then you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
## Documentation
@@ -29,7 +29,7 @@ The documentation for Umbraco CMS can be found [on Our Umbraco](https://our.umbr
## Join the Umbraco community
Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
Our friendly community is available 24/7 at the community hub, we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
Besides "Our", we all support each other also via Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco)
-1
View File
@@ -30,7 +30,6 @@
<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)" />
<dependency id="Microsoft.Net.Compilers" version="[2.10.0,2.999999)" />
</group>
+3 -8
View File
@@ -11,21 +11,16 @@ Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
Don't forget to build!
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
We've overwritten all the files in the Umbraco folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
We've done our best to transform your configuration files but in case something is not quite right: we recommmend you look in source control for the previous version so you can find the original files before they were transformed.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
http://our.umbraco.com/contribute/releases
https://our.umbraco.com/contribute/releases
- Umbraco
+2 -2
View File
@@ -53,7 +53,7 @@
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</httpModules>
<httpHandlers xdt:Transform="InsertIfMissing" />
@@ -76,7 +76,7 @@
<!-- Note, we're removing the one that starts with a space here, don't correct it -->
<!-- This to fix a quirk we for a lot of releases where we added it with the space by default -->
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</modules>
<staticContent xdt:Transform="InsertIfMissing" />
+205 -63
View File
@@ -1,65 +1,11 @@
body {
color: rgba(0,0,0,.8);
}
.navbar-inverse {
background: #a3db78;
}
.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text {
color: rgba(0,0,0,.8);
}
.navbar-inverse {
border-color: transparent;
}
.sidetoc {
background-color: #f5fbf1;
}
body .toc {
background-color: #f5fbf1;
}
.sidefilter {
background-color: #daf0c9;
}
.subnav {
background-color: #f5fbf1;
}
.navbar-inverse .navbar-nav>.active>a {
color: rgba(0,0,0,.8);
background-color: #daf0c9;
}
.navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover {
color: rgba(0,0,0,.8);
background-color: #daf0c9;
}
.btn-primary {
color: rgba(0,0,0,.8);
background-color: #fff;
border-color: rgba(0,0,0,.8);
}
.btn-primary:hover {
background-color: #daf0c9;
color: rgba(0,0,0,.8);
border-color: rgba(0,0,0,.8);
}
.toc .nav > li > a {
color: rgba(0,0,0,.8);
}
button, a {
color: #f36f21;
}
button:hover,
button:focus,
a:hover,
a:focus {
color: #143653;
text-decoration: none;
color: #34393e;
font-family: 'Roboto', sans-serif;
line-height: 1.5;
font-size: 16px;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
word-wrap: break-word
}
.navbar-header .navbar-brand {
@@ -68,6 +14,202 @@ a:focus {
width:50px;
}
.toc .nav > li.active > a {
color: #f36f21;
#_content>a {
margin-top: 5px;
}
/* HEADINGS */
h1 {
font-weight: 600;
font-size: 32px;
}
h2 {
font-weight: 600;
font-size: 24px;
line-height: 1.8;
}
h3 {
font-weight: 600;
font-size: 20px;
line-height: 1.8;
}
h5 {
font-size: 14px;
padding: 10px 0px;
}
article h1,
article h2,
article h3,
article h4 {
margin-top: 35px;
margin-bottom: 15px;
}
article h4 {
padding-bottom: 8px;
border-bottom: 2px solid #ddd;
}
/* NAVBAR */
.navbar-brand>img {
color: #fff;
}
.navbar {
border: none;
/* Both navbars use box-shadow */
-webkit-box-shadow: 0px 1px 3px 0px rgba(100, 100, 100, 0.5);
-moz-box-shadow: 0px 1px 3px 0px rgba(100, 100, 100, 0.5);
box-shadow: 0px 1px 3px 0px rgba(100, 100, 100, 0.5);
}
.subnav {
border-top: 1px solid #ddd;
background-color: #fff;
}
.navbar-inverse {
background-color: #303ea1;
z-index: 100;
}
.navbar-inverse .navbar-nav>li>a,
.navbar-inverse .navbar-text {
color: #fff;
background-color: #303ea1;
border-bottom: 3px solid transparent;
padding-bottom: 12px;
}
.navbar-inverse .navbar-nav>li>a:focus,
.navbar-inverse .navbar-nav>li>a:hover {
color: #fff;
background-color: #303ea1;
border-bottom: 3px solid white;
}
.navbar-inverse .navbar-nav>.active>a,
.navbar-inverse .navbar-nav>.active>a:focus,
.navbar-inverse .navbar-nav>.active>a:hover {
color: #fff;
background-color: #303ea1;
border-bottom: 3px solid white;
}
.navbar-form .form-control {
border: none;
border-radius: 20px;
}
/* SIDEBAR */
.toc .level1>li {
font-weight: 400;
}
.toc .nav>li>a {
color: #34393e;
}
.sidefilter {
background-color: #fff;
border-left: none;
border-right: none;
}
.sidefilter {
background-color: #fff;
border-left: none;
border-right: none;
}
.toc-filter {
padding: 10px;
margin: 0;
}
.toc-filter>input {
border: 2px solid #ddd;
border-radius: 20px;
}
.toc-filter>.filter-icon {
display: none;
}
.sidetoc>.toc {
background-color: #fff;
overflow-x: hidden;
}
.sidetoc {
background-color: #fff;
border: none;
}
/* ALERTS */
.alert {
padding: 0px 0px 5px 0px;
color: inherit;
background-color: inherit;
border: none;
box-shadow: 0px 2px 2px 0px rgba(100, 100, 100, 0.4);
}
.alert>p {
margin-bottom: 0;
padding: 5px 10px;
}
.alert>ul {
margin-bottom: 0;
padding: 5px 40px;
}
.alert>h5 {
padding: 10px 15px;
margin-top: 0;
text-transform: uppercase;
font-weight: bold;
border-radius: 4px 4px 0 0;
}
.alert-info>h5 {
color: #1976d2;
border-bottom: 4px solid #1976d2;
background-color: #e3f2fd;
}
.alert-warning>h5 {
color: #f57f17;
border-bottom: 4px solid #f57f17;
background-color: #fff3e0;
}
.alert-danger>h5 {
color: #d32f2f;
border-bottom: 4px solid #d32f2f;
background-color: #ffebee;
}
/* CODE HIGHLIGHT */
pre {
padding: 9.5px;
margin: 0 0 10px;
font-size: 13px;
word-break: break-all;
word-wrap: break-word;
background-color: #fffaef;
border-radius: 4px;
box-shadow: 0px 1px 4px 1px rgba(100, 100, 100, 0.4);
}
.sideaffix {
overflow: visible;
}
+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.3.0")]
[assembly: AssemblyInformationalVersion("8.3.0")]
[assembly: AssemblyFileVersion("8.4.2")]
[assembly: AssemblyInformationalVersion("8.4.2")]
+1
View File
@@ -11,5 +11,6 @@
public const string TemplateFrontEndCacheKey = "template";
public const string MacroContentCacheKey = "macroContent_"; // used in MacroRenderers
public const string MacroFromAliasCacheKey = "macroFromAlias_";
}
}
@@ -6,6 +6,7 @@ namespace Umbraco.Core.Configuration.Grid
public interface IGridEditorConfig
{
string Name { get; }
string NameTemplate { get; }
string Alias { get; }
string View { get; }
string Render { get; }
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class ContentElement : UmbracoConfigurationElement, IContentSection
{
private const string DefaultPreviewBadge = @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>";
private const string DefaultPreviewBadge = @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
[ConfigurationProperty("imaging")]
internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
+12 -6
View File
@@ -221,7 +221,8 @@ namespace Umbraco.Core
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
Name = FailedPasswordAttemptsLabel,
DataTypeId = Constants.DataTypes.LabelInt
}
},
{
@@ -242,35 +243,40 @@ namespace Umbraco.Core
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
Name = LastLockoutDateLabel,
DataTypeId = Constants.DataTypes.LabelDateTime
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
Name = LastLoginDateLabel,
DataTypeId = Constants.DataTypes.LabelDateTime
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
Name = LastPasswordChangeDateLabel,
DataTypeId = Constants.DataTypes.LabelDateTime
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
Name = PasswordAnswerLabel,
DataTypeId = Constants.DataTypes.LabelString
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
Name = PasswordQuestionLabel,
DataTypeId = Constants.DataTypes.LabelString
}
}
};
@@ -85,12 +85,7 @@ namespace Umbraco.Core
/// ListView.
/// </summary>
public const string ListView = "Umbraco.ListView";
/// <summary>
/// Macro Container.
/// </summary>
public const string MacroContainer = "Umbraco.MacroContainer";
/// <summary>
/// Media Picker.
/// </summary>
+33 -26
View File
@@ -150,39 +150,46 @@ namespace Umbraco.Core
culture = culture.NullOrWhiteSpaceAsNull();
segment = segment.NullOrWhiteSpaceAsNull();
bool Validate(bool variesBy, string value)
{
if (variesBy)
{
// varies by
// in exact mode, the value cannot be null (but it can be a wildcard)
// in !wildcards mode, the value cannot be a wildcard (but it can be null)
if ((exact && value == null) || (!wildcards && value == "*"))
return false;
}
else
{
// does not vary by value
// the value cannot have a value
// unless wildcards and it's "*"
if (value != null && (!wildcards || value != "*"))
return false;
}
return true;
}
if (!Validate(variation.VariesByCulture(), culture))
// if wildcards are disabled, do not allow "*"
if (!wildcards && (culture == "*" || segment == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Culture value \"{culture ?? "<null>"}\" is invalid.");
throw new NotSupportedException($"Variation wildcards are not supported.");
return false;
}
if (!Validate(variation.VariesBySegment(), segment))
if (variation.VariesByCulture())
{
// varies by culture
// in exact mode, the culture cannot be null
if (exact && culture == null)
{
if (throwIfInvalid)
throw new NotSupportedException($"Culture may not be null because culture variation is enabled.");
return false;
}
}
else
{
// does not vary by culture
// the culture cannot have a value
// unless wildcards and it's "*"
if (culture != null && !(wildcards && culture == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Culture \"{culture}\" is invalid because culture variation is disabled.");
return false;
}
}
// if it does not vary by segment
// the segment cannot have a value
// segment may always be null, even when the ContentVariation.Segment flag is set for this variation,
// therefore the exact parameter is not used in segment validation.
if (!variation.VariesBySegment() && segment != null && !(wildcards && segment == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Segment value \"{segment ?? "<null>"}\" is invalid.");
throw new NotSupportedException($"Segment \"{segment}\" is invalid because segment variation is disabled.");
return false;
}
+2 -2
View File
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Web.Hosting;
using Umbraco.Core.Logging;
@@ -65,7 +65,7 @@ namespace Umbraco.Core
// a new process for the same application path
var appPath = HostingEnvironment.ApplicationPhysicalPath;
var hash = (appId + ":::" + appPath).ToSHA1();
var hash = (appId + ":::" + appPath).GenerateHash<SHA1>();
var lockName = "UMBRACO-" + hash + "-MAINDOM-LCK";
_asyncLock = new AsyncLock(lockName);
+11 -7
View File
@@ -343,16 +343,20 @@ namespace Umbraco.Core.Mapping
if (ctor == null) return null;
if (_ctors.ContainsKey(sourceType))
_ctors.AddOrUpdate(sourceType, sourceCtor, (k, v) =>
{
// Add missing constructors
foreach (var c in sourceCtor)
{
if (!_ctors[sourceType].TryGetValue(c.Key, out _))
_ctors[sourceType].Add(c.Key, c.Value);
}
}
else
_ctors[sourceType] = sourceCtor;
if (!v.ContainsKey(c.Key))
{
v.Add(c.Key, c.Value);
}
}
return v;
});
return ctor;
}
@@ -227,8 +227,8 @@ namespace Umbraco.Core.Migrations.Install
_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 });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
}
@@ -74,9 +74,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.NodeId == group.Key)).First();
// check for duplicate aliases
var aliases = group.Select(x => x.Alias).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
if (aliases.Distinct().Count() != aliases.Length)
throw new InvalidOperationException($"Cannot migrate prevalues for datatype id={dataType.NodeId}, editor={dataType.EditorAlias}: duplicate alias.");
// handle null/empty aliases
int index = 0;
var dictionary = group.ToDictionary(x => string.IsNullOrWhiteSpace(x.Alias) ? index++.ToString() : x.Alias);
// migrate the preValues to configuration
var migrator = _preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator();
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, group.ToDictionary(x => x.Alias, x => x));
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, dictionary);
var json = JsonConvert.SerializeObject(config);
// validate - and kill the migration if it fails
@@ -24,8 +24,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
}
// assuming we don't want to fall back to array
if (aliases.Length != preValuesA.Count || aliases.Any(string.IsNullOrWhiteSpace))
throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataTypeId} preValues: duplicate or null/empty alias.");
if (aliases.Any(string.IsNullOrWhiteSpace))
throw new InvalidOperationException($"Cannot migrate prevalues for datatype id={dataTypeId}, editor={editorAlias}: null/empty alias.");
// dictionary-base prevalues
return GetPreValues(preValuesA).ToDictionary(x => x.Alias, GetPreValueValue);
@@ -67,6 +67,12 @@ namespace Umbraco.Core.Models.ContentEditing
/// </remarks>
[DataMember(Name = "active")]
public bool Active { get; set; }
/// <summary>
/// Gets or sets the content app badge.
/// </summary>
[DataMember(Name = "badge")]
public ContentAppBadge Badge { get; set; }
}
}
@@ -0,0 +1,39 @@
namespace Umbraco.Core.Models.ContentEditing
{
using System.Runtime.Serialization;
using Umbraco.Core.Events;
/// <summary>
/// Represents a content app badge
/// </summary>
[DataContract(Name = "badge", Namespace = "")]
public class ContentAppBadge
{
/// <summary>
/// Initializes a new instance of the <see cref="ContentAppBadge"/> class.
/// </summary>
public ContentAppBadge()
{
this.Type = ContentAppBadgeType.Default;
}
/// <summary>
/// Gets or sets the number displayed in the badge
/// </summary>
[DataMember(Name = "count")]
public int Count { get; set; }
/// <summary>
/// Gets or sets the type of badge to display
/// </summary>
/// <remarks>
/// <para>This controls the background color of the badge.</para>
/// <para>Warning will display a dark yellow badge</para>
/// <para>Alert will display a red badge</para>
/// <para>Default will display a turquoise badge</para>
/// </remarks>
[DataMember(Name = "type")]
public ContentAppBadgeType Type { get; set; }
}
}
@@ -0,0 +1,24 @@
namespace Umbraco.Core.Models.ContentEditing
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
/// <summary>
/// Represent the content app badge types
/// </summary>
[DataContract(Name = "contentAppBadgeType")]
[JsonConverter(typeof(StringEnumConverter))]
public enum ContentAppBadgeType
{
[EnumMember(Value = "default")]
Default = 0,
[EnumMember(Value = "warning")]
Warning = 1,
[EnumMember(Value = "alert")]
Alert = 2
}
}
@@ -0,0 +1,7 @@
namespace Umbraco.Core.Models.Entities
{
public interface IMemberEntitySlim : IContentEntitySlim
{
}
}
@@ -0,0 +1,13 @@
namespace Umbraco.Core.Models.Entities
{
public class MemberEntitySlim : EntitySlim, IMemberEntitySlim
{
public string ContentTypeAlias { get; set; }
/// <inheritdoc />
public string ContentTypeIcon { get; set; }
/// <inheritdoc />
public string ContentTypeThumbnail { get; set; }
}
}
+1 -5
View File
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models
@@ -9,7 +8,7 @@ namespace Umbraco.Core.Models
/// </summary>
/// <typeparam name="T"></typeparam>
[DataContract(Name = "pagedCollection", Namespace = "")]
public class PagedResult<T>
public abstract class PagedResult
{
public PagedResult(long totalItems, long pageNumber, long pageSize)
{
@@ -39,9 +38,6 @@ namespace Umbraco.Core.Models
[DataMember(Name = "totalItems")]
public long TotalItems { get; private set; }
[DataMember(Name = "items")]
public IEnumerable<T> Items { get; set; }
/// <summary>
/// Calculates the skip size based on the paged parameters specified
/// </summary>
+20
View File
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a paged result for a model collection
/// </summary>
/// <typeparam name="T"></typeparam>
[DataContract(Name = "pagedCollection", Namespace = "")]
public class PagedResult<T> : PagedResult
{
public PagedResult(long totalItems, long pageNumber, long pageSize)
: base(totalItems, pageNumber, pageSize)
{ }
[DataMember(Name = "items")]
public IEnumerable<T> Items { get; set; }
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Models
if (user.Avatar.IsNullOrWhiteSpace())
{
var gravatarHash = user.Email.ToMd5();
var gravatarHash = user.Email.GenerateHash<MD5>();
var gravatarUrl = "https://www.gravatar.com/avatar/" + gravatarHash + "?d=404";
//try Gravatar
+3 -3
View File
@@ -542,7 +542,7 @@ namespace Umbraco.Core
{
return "\"{0}\"".InvariantFormat(obj);
}
if (obj is int || obj is Int16 || obj is Int64 || obj is float || obj is double || obj is bool || obj is int? || obj is Int16? || obj is Int64? || obj is float? || obj is double? || obj is bool?)
if (obj is int || obj is short || obj is long || obj is float || obj is double || obj is bool || obj is int? || obj is float? || obj is double? || obj is bool?)
{
return "{0}".InvariantFormat(obj);
}
@@ -723,7 +723,7 @@ namespace Umbraco.Core
{
return typeConverter;
}
var converter = TypeDescriptor.GetConverter(target);
if (converter.CanConvertFrom(source))
{
@@ -788,6 +788,6 @@ namespace Umbraco.Core
return BoolConvertCache[type] = false;
}
}
}
+30 -30
View File
@@ -470,7 +470,7 @@ namespace Umbraco.Core.Persistence
break;
case SqlDbType.SmallInt:
dataType = typeof(Int16);
dataType = typeof(short);
dataTypeName = "smallint";
break;
@@ -688,34 +688,34 @@ namespace Umbraco.Core.Persistence
DataColumnCollection columns = _schemaTable.Columns;
columns.Add(SchemaTableColumn.ColumnName, typeof(System.String));
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32));
columns.Add(SchemaTableColumn.ColumnSize, typeof(System.Int32));
columns.Add(SchemaTableColumn.NumericPrecision, typeof(System.Int16));
columns.Add(SchemaTableColumn.NumericScale, typeof(System.Int16));
columns.Add(SchemaTableColumn.IsUnique, typeof(System.Boolean));
columns.Add(SchemaTableColumn.IsKey, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(System.String));
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String));
columns.Add(SchemaTableColumn.BaseColumnName, typeof(System.String));
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(System.String));
columns.Add(SchemaTableColumn.BaseTableName, typeof(System.String));
columns.Add(SchemaTableColumn.DataType, typeof(System.Type));
columns.Add(SchemaTableColumn.AllowDBNull, typeof(System.Boolean));
columns.Add(SchemaTableColumn.ProviderType, typeof(System.Int32));
columns.Add(SchemaTableColumn.IsAliased, typeof(System.Boolean));
columns.Add(SchemaTableColumn.IsExpression, typeof(System.Boolean));
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean));
columns.Add(SchemaTableColumn.IsLong, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean));
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type));
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(System.String));
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(System.String));
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(System.String));
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(System.String));
columns.Add(SchemaTableColumn.ColumnName, typeof(string));
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
columns.Add(SchemaTableColumn.NumericScale, typeof(short));
columns.Add(SchemaTableColumn.IsUnique, typeof(bool));
columns.Add(SchemaTableColumn.IsKey, typeof(bool));
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));
columns.Add(SchemaTableColumn.BaseColumnName, typeof(string));
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string));
columns.Add(SchemaTableColumn.BaseTableName, typeof(string));
columns.Add(SchemaTableColumn.DataType, typeof(Type));
columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool));
columns.Add(SchemaTableColumn.ProviderType, typeof(int));
columns.Add(SchemaTableColumn.IsAliased, typeof(bool));
columns.Add(SchemaTableColumn.IsExpression, typeof(bool));
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(bool));
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool));
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool));
columns.Add(SchemaTableColumn.IsLong, typeof(bool));
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool));
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(string));
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(string));
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string));
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(string));
}
#endregion
@@ -1090,7 +1090,7 @@ namespace Umbraco.Core.Persistence
/// <seealso cref="IDataRecord.GetDecimal(Int32)"/>
public decimal GetDecimal(int i)
{
return (Decimal)GetValue(i);
return (decimal)GetValue(i);
}
/// <summary>
@@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.CompilerServices;
namespace Umbraco.Core.Persistence
{
internal static class DatabaseNodeLockExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ValidateDatabase(IUmbracoDatabase database)
{
if (database == null)
throw new ArgumentNullException("database");
if (database.GetCurrentTransactionIsolationLevel() < IsolationLevel.RepeatableRead)
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
}
// updating a record within a repeatable-read transaction gets an exclusive lock on
// that record which will be kept until the transaction is ended, effectively locking
// out all other accesses to that record - thus obtaining an exclusive lock over the
// protected resources.
public static void AcquireLockNodeWriteLock(this IUmbracoDatabase database, int nodeId)
{
ValidateDatabase(database);
database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id",
new { @id = nodeId });
}
// reading a record within a repeatable-read transaction gets a shared lock on
// that record which will be kept until the transaction is ended, effectively preventing
// other write accesses to that record - thus obtaining a shared lock over the protected
// resources.
public static void AcquireLockNodeReadLock(this IUmbracoDatabase database, int nodeId)
{
ValidateDatabase(database);
database.ExecuteScalar<int>("SELECT value FROM umbracoLock WHERE id=@id",
new { @id = nodeId });
}
}
}
@@ -7,5 +7,12 @@ namespace Umbraco.Core.Persistence.Repositories
public interface IDataTypeRepository : IReadWriteQueryRepository<int, IDataType>
{
IEnumerable<MoveEventInfo<IDataType>> Move(IDataType toMove, EntityContainer container);
/// <summary>
/// Returns a dictionary of content type <see cref="Udi"/>s and the property type aliases that use a <see cref="IDataType"/>
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IReadOnlyDictionary<Udi, IEnumerable<string>> FindUsages(int id);
}
}
@@ -1,4 +1,5 @@
using System;

using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
@@ -218,6 +219,7 @@ AND umbracoNode.nodeObjectType = @objectType",
protected void PersistUpdatedBaseContentType(IContentTypeComposition entity)
{
CorrectPropertyTypeVariations(entity);
ValidateVariations(entity);
var dto = ContentTypeFactory.BuildContentTypeDto(entity);
@@ -410,26 +412,7 @@ AND umbracoNode.id <> @id",
// note: this only deals with *local* property types, we're dealing w/compositions later below
foreach (var propertyType in entity.PropertyTypes)
{
if (contentTypeVariationChanging)
{
// content type is changing
switch (newContentTypeVariation)
{
case ContentVariation.Nothing: // changing to Nothing
// all property types must change to Nothing
propertyType.Variations = ContentVariation.Nothing;
break;
case ContentVariation.Culture: // changing to Culture
// all property types can remain Nothing
break;
case ContentVariation.CultureAndSegment:
case ContentVariation.Segment:
default:
throw new NotSupportedException(); // TODO: Support this
}
}
// then, track each property individually
// track each property individually
if (propertyType.IsPropertyDirty("Variations"))
{
// allocate the list only when needed
@@ -455,23 +438,19 @@ 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)
propertyTypeVariationChanges = propertyTypeVariationChanges ?? new Dictionary<int, (ContentVariation, ContentVariation)>();
foreach (var composedPropertyType in ((ContentTypeCompositionBase)entity).RawComposedPropertyTypes)
{
if (propertyType.VariesBySegment() || newContentTypeVariation.VariesBySegment())
throw new NotSupportedException(); // TODO: support this
if (composedPropertyType.Variations == ContentVariation.Nothing) continue;
if (propertyType.Variations == ContentVariation.Culture)
{
if (propertyTypeVariationChanges == null)
propertyTypeVariationChanges = new Dictionary<int, (ContentVariation, ContentVariation)>();
// Determine target variation of the composed property type.
// The composed property is only considered culture variant when the base content type is also culture variant.
// The composed property is only considered segment variant when the base content type is also segment variant.
// Example: Culture variant content type with a Culture+Segment variant property type will become ContentVariation.Culture
var target = newContentTypeVariation & composedPropertyType.Variations;
// if content type moves to Culture, property type becomes Culture here again
// if content type moves to Nothing, property type becomes Nothing here
if (newContentTypeVariation == ContentVariation.Culture)
propertyTypeVariationChanges[propertyType.Id] = (ContentVariation.Nothing, ContentVariation.Culture);
else if (newContentTypeVariation == ContentVariation.Nothing)
propertyTypeVariationChanges[propertyType.Id] = (ContentVariation.Culture, ContentVariation.Nothing);
}
propertyTypeVariationChanges[composedPropertyType.Id] = (composedPropertyType.Variations, target);
}
}
@@ -512,7 +491,7 @@ AND umbracoNode.id <> @id",
var impacted = GetImpactedContentTypes(entity, all);
// if some property types have actually changed, move their variant data
if (propertyTypeVariationChanges != null)
if (propertyTypeVariationChanges?.Count > 0)
MovePropertyTypeVariantData(propertyTypeVariationChanges, impacted);
// deal with orphan properties: those that were in a deleted tab,
@@ -524,23 +503,40 @@ AND umbracoNode.id <> @id",
CommonRepository.ClearCache(); // always
}
/// <summary>
/// Corrects the property type variations for the given entity
/// to make sure the property type variation is compatible with the
/// variation set on the entity itself.
/// </summary>
/// <param name="entity">Entity to correct properties for</param>
private void CorrectPropertyTypeVariations(IContentTypeComposition entity)
{
// Update property variations based on the content type variation
foreach (var propertyType in entity.PropertyTypes)
{
// Determine variation for the property type.
// The property is only considered culture variant when the base content type is also culture variant.
// The property is only considered segment variant when the base content type is also segment variant.
// Example: Culture variant content type with a Culture+Segment variant property type will become ContentVariation.Culture
propertyType.Variations = entity.Variations & propertyType.Variations;
}
}
/// <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>
/// <param name="entity">The entity for which the property types will be validated</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)
{
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}");
}
// The variation of a property is only allowed if all its variation flags
// are also set on the entity itself. It cannot set anything that is not also set by the content type.
// For example, when entity.Variations is set to Culture a property cannot be set to Segment.
var isValid = entity.Variations.HasFlag(prop.Variations);
if (!isValid)
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)
@@ -661,27 +657,27 @@ 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))
{
var propertyTypeIds = grouping.Select(x => x.Key).ToList();
var toVariation = grouping.Key;
var (FromVariation, ToVariation) = grouping.Key;
switch (toVariation)
var fromCultureEnabled = FromVariation.HasFlag(ContentVariation.Culture);
var toCultureEnabled = ToVariation.HasFlag(ContentVariation.Culture);
if (!fromCultureEnabled && toCultureEnabled)
{
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:
default:
throw new NotSupportedException(); // TODO: Support this
// Culture has been enabled
CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL);
CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL);
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
}
else if (fromCultureEnabled && !toCultureEnabled)
{
// Culture has been disabled
CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL);
CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL);
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
}
}
}
@@ -693,78 +689,72 @@ AND umbracoNode.id <> @id",
{
var defaultLanguageId = GetDefaultLanguageId();
switch (toVariation)
var cultureIsNotEnabled = !fromVariation.HasFlag(ContentVariation.Culture);
var cultureWillBeEnabled = toVariation.HasFlag(ContentVariation.Culture);
if (cultureIsNotEnabled && cultureWillBeEnabled)
{
case ContentVariation.Culture:
//move the names
//first clear out any existing names that might already exists under the default lang
//there's 2x tables to update
//move the names
//first clear out any existing names that might already exists under the default lang
//there's 2x tables to update
//clear out the versionCultureVariation table
var sqlSelect = Sql().Select<ContentVersionCultureVariationDto>(x => x.Id)
.From<ContentVersionCultureVariationDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, ContentVersionCultureVariationDto>(x => x.Id, x => x.VersionId)
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
.Where<ContentVersionCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
var sqlDelete = Sql()
.Delete<ContentVersionCultureVariationDto>()
.WhereIn<ContentVersionCultureVariationDto>(x => x.Id, sqlSelect);
//clear out the versionCultureVariation table
var sqlSelect = Sql().Select<ContentVersionCultureVariationDto>(x => x.Id)
.From<ContentVersionCultureVariationDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, ContentVersionCultureVariationDto>(x => x.Id, x => x.VersionId)
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
.Where<ContentVersionCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
var sqlDelete = Sql()
.Delete<ContentVersionCultureVariationDto>()
.WhereIn<ContentVersionCultureVariationDto>(x => x.Id, sqlSelect);
Database.Execute(sqlDelete);
Database.Execute(sqlDelete);
//clear out the documentCultureVariation table
sqlSelect = Sql().Select<DocumentCultureVariationDto>(x => x.Id)
.From<DocumentCultureVariationDto>()
.InnerJoin<ContentDto>().On<ContentDto, DocumentCultureVariationDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
.Where<DocumentCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
sqlDelete = Sql()
.Delete<DocumentCultureVariationDto>()
.WhereIn<DocumentCultureVariationDto>(x => x.Id, sqlSelect);
//clear out the documentCultureVariation table
sqlSelect = Sql().Select<DocumentCultureVariationDto>(x => x.Id)
.From<DocumentCultureVariationDto>()
.InnerJoin<ContentDto>().On<ContentDto, DocumentCultureVariationDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
.Where<DocumentCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
sqlDelete = Sql()
.Delete<DocumentCultureVariationDto>()
.WhereIn<DocumentCultureVariationDto>(x => x.Id, sqlSelect);
Database.Execute(sqlDelete);
Database.Execute(sqlDelete);
//now we need to insert names into these 2 tables based on the invariant data
//now we need to insert names into these 2 tables based on the invariant data
//insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang
var cols = Sql().Columns<ContentVersionCultureVariationDto>(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId);
sqlSelect = Sql().Select<ContentVersionDto>(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate)
.Append($", {defaultLanguageId}") //default language ID
.From<ContentVersionDto>()
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
//insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang
var cols = Sql().Columns<ContentVersionCultureVariationDto>(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId);
sqlSelect = Sql().Select<ContentVersionDto>(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate)
.Append($", {defaultLanguageId}") //default language ID
.From<ContentVersionDto>()
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
Database.Execute(sqlInsert);
Database.Execute(sqlInsert);
//insert rows into the documentCultureVariation table
cols = Sql().Columns<DocumentCultureVariationDto>(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId);
sqlSelect = Sql().Select<DocumentDto>(x => x.NodeId, x => x.Edited, x => x.Published)
.AndSelect<NodeDto>(x => x.Text)
.Append($", 1, {defaultLanguageId}") //make Available + default language ID
.From<DocumentDto>()
.InnerJoin<NodeDto>().On<NodeDto, DocumentDto>(x => x.NodeId, x => x.NodeId)
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
sqlInsert = Sql($"INSERT INTO {DocumentCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
//insert rows into the documentCultureVariation table
cols = Sql().Columns<DocumentCultureVariationDto>(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId);
sqlSelect = Sql().Select<DocumentDto>(x => x.NodeId, x => x.Edited, x => x.Published)
.AndSelect<NodeDto>(x => x.Text)
.Append($", 1, {defaultLanguageId}") //make Available + default language ID
.From<DocumentDto>()
.InnerJoin<NodeDto>().On<NodeDto, DocumentDto>(x => x.NodeId, x => x.NodeId)
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(x => x.NodeId, x => x.NodeId)
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
sqlInsert = Sql($"INSERT INTO {DocumentCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
Database.Execute(sqlInsert);
}
else
{
//we don't need to move the names! this is because we always keep the invariant names with the name of the default language.
Database.Execute(sqlInsert);
break;
case ContentVariation.Nothing:
//we don't need to move the names! this is because we always keep the invariant names with the name of the default language.
//however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :(
// if we want these SQL statements back, look into GIT history
break;
case ContentVariation.CultureAndSegment:
case ContentVariation.Segment:
default:
throw new NotSupportedException(); // TODO: Support this
//however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :(
// if we want these SQL statements back, look into GIT history
}
}
@@ -279,6 +279,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return moveInfo;
}
public IReadOnlyDictionary<Udi, IEnumerable<string>> FindUsages(int id)
{
if (id == default)
return new Dictionary<Udi, IEnumerable<string>>();
var sql = Sql()
.Select<ContentTypeDto>(ct => ct.Select(node => node.NodeDto))
.AndSelect<PropertyTypeDto>(pt => Alias(pt.Alias, "ptAlias"), pt => Alias(pt.Name, "ptName"))
.From<PropertyTypeDto>()
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, PropertyTypeDto>(ct => ct.NodeId, pt => pt.ContentTypeId)
.InnerJoin<NodeDto>().On<NodeDto, ContentTypeDto>(n => n.NodeId, ct => ct.NodeId)
.Where<PropertyTypeDto>(pt => pt.DataTypeId == id)
.OrderBy<NodeDto>(node => node.NodeId)
.AndBy<PropertyTypeDto>(pt => pt.Alias);
var dtos = Database.FetchOneToMany<ContentTypeReferenceDto>(ct => ct.PropertyTypes, sql);
return dtos.ToDictionary(
x => (Udi)new GuidUdi(ObjectTypes.GetUdiType(x.NodeDto.NodeObjectType.Value), x.NodeDto.UniqueId).EnsureClosed(),
x => (IEnumerable<string>)x.PropertyTypes.Select(p => p.Alias).ToList());
}
private string EnsureUniqueNodeName(string nodeName, int id = 0)
{
var template = SqlContext.Templates.Get("Umbraco.Core.DataTypeDefinitionRepository.EnsureUniqueNodeName", tsql => tsql
@@ -291,5 +313,24 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return SimilarNodeName.GetUniqueName(names, id, nodeName);
}
[TableName(Constants.DatabaseSchema.Tables.ContentType)]
private class ContentTypeReferenceDto : ContentTypeDto
{
[ResultColumn]
[Reference(ReferenceType.Many)]
public List<PropertyTypeReferenceDto> PropertyTypes { get; set; }
}
[TableName(Constants.DatabaseSchema.Tables.PropertyType)]
private class PropertyTypeReferenceDto
{
[Column("ptAlias")]
public string Alias { get; set; }
[Column("ptName")]
public string Name { get; set; }
}
}
}
@@ -248,14 +248,63 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return dto == null ? null : MapDtoToContent(dto);
}
// deletes a specific version
public override void DeleteVersion(int versionId)
{
// TODO: test object node type?
// get the version we want to delete
var template = SqlContext.Templates.Get("Umbraco.Core.DocumentRepository.GetVersion", tsql =>
tsql.Select<ContentVersionDto>()
.AndSelect<DocumentVersionDto>()
.From<ContentVersionDto>()
.InnerJoin<DocumentVersionDto>()
.On<ContentVersionDto, DocumentVersionDto>((c, d) => c.Id == d.Id)
.Where<ContentVersionDto>(x => x.Id == SqlTemplate.Arg<int>("versionId"))
);
var versionDto = Database.Fetch<DocumentVersionDto>(template.Sql(new { versionId })).FirstOrDefault();
// nothing to delete
if (versionDto == null)
return;
// don't delete the current or published version
if (versionDto.ContentVersionDto.Current)
throw new InvalidOperationException("Cannot delete the current version.");
else if (versionDto.Published)
throw new InvalidOperationException("Cannot delete the published version.");
PerformDeleteVersion(versionDto.ContentVersionDto.NodeId, versionId);
}
// deletes all versions of an entity, older than a date.
public override void DeleteVersions(int nodeId, DateTime versionDate)
{
// TODO: test object node type?
// get the versions we want to delete, excluding the current one
var template = SqlContext.Templates.Get("Umbraco.Core.DocumentRepository.GetVersions", tsql =>
tsql.Select<ContentVersionDto>()
.From<ContentVersionDto>()
.InnerJoin<DocumentVersionDto>()
.On<ContentVersionDto, DocumentVersionDto>((c, d) => c.Id == d.Id)
.Where<ContentVersionDto>(x => x.NodeId == SqlTemplate.Arg<int>("nodeId") && !x.Current && x.VersionDate < SqlTemplate.Arg<DateTime>("versionDate"))
.Where<DocumentVersionDto>( x => !x.Published)
);
var versionDtos = Database.Fetch<ContentVersionDto>(template.Sql(new { nodeId, versionDate }));
foreach (var versionDto in versionDtos)
PerformDeleteVersion(versionDto.NodeId, versionDto.Id);
}
protected override void PerformDeleteVersion(int id, int versionId)
{
// raise event first else potential FK issues
OnUowRemovingVersion(new ScopedVersionEventArgs(AmbientScope, id, versionId));
Database.Delete<PropertyDataDto>("WHERE versionId = @versionId", new { versionId });
Database.Delete<ContentVersionDto>("WHERE id = @versionId", new { versionId });
Database.Delete<ContentVersionCultureVariationDto>("WHERE versionId = @versionId", new { versionId });
Database.Delete<DocumentVersionDto>("WHERE id = @versionId", new { versionId });
Database.Delete<ContentVersionDto>("WHERE id = @versionId", new { versionId });
}
#endregion
@@ -42,8 +42,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectType == Constants.ObjectTypes.Media;
var isMember = objectType == Constants.ObjectTypes.Member;
var sql = GetBaseWhere(isContent, isMedia, false, x =>
var sql = GetBaseWhere(isContent, isMedia, isMember, false, x =>
{
if (filter == null) return;
foreach (var filterClause in filter.GetWhereClauses())
@@ -54,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql, ordering.IsEmpty);
sql = AddGroupBy(isContent, isMedia, isMember, sql, ordering.IsEmpty);
if (!ordering.IsEmpty)
{
@@ -81,6 +82,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
dtos = page.Items;
totalRecords = page.TotalItems;
}
else if (isMember)
{
var page = Database.Page<MemberEntityDto>(pageIndexToFetch, pageSize, sql);
dtos = page.Items;
totalRecords = page.TotalItems;
}
else
{
var page = Database.Page<BaseDto>(pageIndexToFetch, pageSize, sql);
@@ -88,7 +95,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
totalRecords = page.TotalItems;
}
var entities = dtos.Select(x => BuildEntity(isContent, isMedia, x)).ToArray();
var entities = dtos.Select(x => BuildEntity(isContent, isMedia, isMember, x)).ToArray();
if (isContent)
BuildVariants(entities.Cast<DocumentEntitySlim>());
@@ -98,13 +105,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public IEntitySlim Get(Guid key)
{
var sql = GetBaseWhere(false, false, false, key);
var sql = GetBaseWhere(false, false, false, false, key);
var dto = Database.FirstOrDefault<BaseDto>(sql);
return dto == null ? null : BuildEntity(false, false, dto);
return dto == null ? null : BuildEntity(false, false, false, dto);
}
private IEntitySlim GetEntity(Sql<ISqlContext> sql, bool isContent, bool isMedia)
private IEntitySlim GetEntity(Sql<ISqlContext> sql, bool isContent, bool isMedia, bool isMember)
{
//isContent is going to return a 1:M result now with the variants so we need to do different things
if (isContent)
@@ -120,7 +127,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (dto == null) return null;
var entity = BuildEntity(false, isMedia, dto);
var entity = BuildEntity(false, isMedia, isMember, dto);
return entity;
}
@@ -129,25 +136,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
var isContent = objectTypeId == Constants.ObjectTypes.Document || objectTypeId == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectTypeId == Constants.ObjectTypes.Media;
var isMember = objectTypeId == Constants.ObjectTypes.Member;
var sql = GetFullSqlForEntityType(isContent, isMedia, objectTypeId, key);
return GetEntity(sql, isContent, isMedia);
var sql = GetFullSqlForEntityType(isContent, isMedia, isMember, objectTypeId, key);
return GetEntity(sql, isContent, isMedia, isMember);
}
public IEntitySlim Get(int id)
{
var sql = GetBaseWhere(false, false, false, id);
var sql = GetBaseWhere(false, false, false, false, id);
var dto = Database.FirstOrDefault<BaseDto>(sql);
return dto == null ? null : BuildEntity(false, false, dto);
return dto == null ? null : BuildEntity(false, false, false, dto);
}
public IEntitySlim Get(int id, Guid objectTypeId)
{
var isContent = objectTypeId == Constants.ObjectTypes.Document || objectTypeId == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectTypeId == Constants.ObjectTypes.Media;
var isMember = objectTypeId == Constants.ObjectTypes.Member;
var sql = GetFullSqlForEntityType(isContent, isMedia, objectTypeId, id);
return GetEntity(sql, isContent, isMedia);
var sql = GetFullSqlForEntityType(isContent, isMedia, isMember, objectTypeId, id);
return GetEntity(sql, isContent, isMedia, isMember);
}
public IEnumerable<IEntitySlim> GetAll(Guid objectType, params int[] ids)
@@ -164,7 +173,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: PerformGetAll(objectType);
}
private IEnumerable<IEntitySlim> GetEntities(Sql<ISqlContext> sql, bool isContent, bool isMedia)
private IEnumerable<IEntitySlim> GetEntities(Sql<ISqlContext> sql, bool isContent, bool isMedia, bool isMember)
{
//isContent is going to return a 1:M result now with the variants so we need to do different things
if (isContent)
@@ -180,7 +189,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
? (IEnumerable<BaseDto>)Database.Fetch<MediaEntityDto>(sql)
: Database.Fetch<BaseDto>(sql);
var entities = dtos.Select(x => BuildEntity(false, isMedia, x)).ToArray();
var entities = dtos.Select(x => BuildEntity(false, isMedia, isMember, x)).ToArray();
return entities;
}
@@ -189,9 +198,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectType == Constants.ObjectTypes.Media;
var isMember = objectType == Constants.ObjectTypes.Member;
var sql = GetFullSqlForEntityType(isContent, isMedia, objectType, filter);
return GetEntities(sql, isContent, isMedia);
var sql = GetFullSqlForEntityType(isContent, isMedia, isMember, objectType, filter);
return GetEntities(sql, isContent, isMedia, isMember);
}
public IEnumerable<TreeEntityPath> GetAllPaths(Guid objectType, params int[] ids)
@@ -218,26 +228,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public IEnumerable<IEntitySlim> GetByQuery(IQuery<IUmbracoEntity> query)
{
var sqlClause = GetBase(false, false, null);
var sqlClause = GetBase(false, false, false, null);
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
var sql = translator.Translate();
sql = AddGroupBy(false, false, sql, true);
sql = AddGroupBy(false, false, false, sql, true);
var dtos = Database.Fetch<BaseDto>(sql);
return dtos.Select(x => BuildEntity(false, false, x)).ToList();
return dtos.Select(x => BuildEntity(false, false, false, x)).ToList();
}
public IEnumerable<IEntitySlim> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectType)
{
var isContent = objectType == Constants.ObjectTypes.Document || objectType == Constants.ObjectTypes.DocumentBlueprint;
var isMedia = objectType == Constants.ObjectTypes.Media;
var isMember = objectType == Constants.ObjectTypes.Member;
var sql = GetBaseWhere(isContent, isMedia, false, null, objectType);
var sql = GetBaseWhere(isContent, isMedia, isMember, false, null, objectType);
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
sql = translator.Translate();
sql = AddGroupBy(isContent, isMedia, sql, true);
sql = AddGroupBy(isContent, isMedia, isMember, sql, true);
return GetEntities(sql, isContent, isMedia);
return GetEntities(sql, isContent, isMedia, isMember);
}
public UmbracoObjectTypes GetObjectType(int id)
@@ -329,29 +340,29 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
// gets the full sql for a given object type and a given unique id
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, Guid uniqueId)
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Guid uniqueId)
{
var sql = GetBaseWhere(isContent, isMedia, false, objectType, uniqueId);
return AddGroupBy(isContent, isMedia, sql, true);
var sql = GetBaseWhere(isContent, isMedia, isMember, false, objectType, uniqueId);
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the full sql for a given object type and a given node id
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, int nodeId)
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, int nodeId)
{
var sql = GetBaseWhere(isContent, isMedia, false, objectType, nodeId);
return AddGroupBy(isContent, isMedia, sql, true);
var sql = GetBaseWhere(isContent, isMedia, isMember, false, objectType, nodeId);
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the full sql for a given object type, with a given filter
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, Guid objectType, Action<Sql<ISqlContext>> filter)
protected Sql<ISqlContext> GetFullSqlForEntityType(bool isContent, bool isMedia, bool isMember, Guid objectType, Action<Sql<ISqlContext>> filter)
{
var sql = GetBaseWhere(isContent, isMedia, false, filter, objectType);
return AddGroupBy(isContent, isMedia, sql, true);
var sql = GetBaseWhere(isContent, isMedia, isMember, false, filter, objectType);
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the base SELECT + FROM [+ filter] sql
// always from the 'current' content version
protected Sql<ISqlContext> GetBase(bool isContent, bool isMedia, Action<Sql<ISqlContext>> filter, bool isCount = false)
protected Sql<ISqlContext> GetBase(bool isContent, bool isMedia, bool isMember, Action<Sql<ISqlContext>> filter, bool isCount = false)
{
var sql = Sql();
@@ -366,7 +377,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
.AndSelect<NodeDto>(x => x.SortOrder, x => x.UniqueId, x => x.Text, x => x.NodeObjectType, x => x.CreateDate)
.Append(", COUNT(child.id) AS children");
if (isContent || isMedia)
if (isContent || isMedia || isMember)
sql
.AndSelect<ContentVersionDto>(x => Alias(x.Id, "versionId"))
.AndSelect<ContentTypeDto>(x => x.Alias, x => x.Icon, x => x.Thumbnail, x => x.IsContainer, x => x.Variations);
@@ -387,7 +398,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
sql
.From<NodeDto>();
if (isContent || isMedia)
if (isContent || isMedia || isMember)
{
sql
.InnerJoin<ContentVersionDto>().On<NodeDto, ContentVersionDto>((left, right) => left.NodeId == right.NodeId && right.Current)
@@ -422,49 +433,49 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// gets the base SELECT + FROM [+ filter] + WHERE sql
// for a given object type, with a given filter
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Action<Sql<ISqlContext>> filter, Guid objectType)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Action<Sql<ISqlContext>> filter, Guid objectType)
{
return GetBase(isContent, isMedia, filter, isCount)
return GetBase(isContent, isMedia, isMember, filter, isCount)
.Where<NodeDto>(x => x.NodeObjectType == objectType);
}
// gets the base SELECT + FROM + WHERE sql
// for a given node id
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, int id)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, int id)
{
var sql = GetBase(isContent, isMedia, null, isCount)
var sql = GetBase(isContent, isMedia, isMember, null, isCount)
.Where<NodeDto>(x => x.NodeId == id);
return AddGroupBy(isContent, isMedia, sql, true);
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the base SELECT + FROM + WHERE sql
// for a given unique id
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid uniqueId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Guid uniqueId)
{
var sql = GetBase(isContent, isMedia, null, isCount)
var sql = GetBase(isContent, isMedia, isMember, null, isCount)
.Where<NodeDto>(x => x.UniqueId == uniqueId);
return AddGroupBy(isContent, isMedia, sql, true);
return AddGroupBy(isContent, isMedia, isMember, sql, true);
}
// gets the base SELECT + FROM + WHERE sql
// for a given object type and node id
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, int nodeId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Guid objectType, int nodeId)
{
return GetBase(isContent, isMedia, null, isCount)
return GetBase(isContent, isMedia, isMember, null, isCount)
.Where<NodeDto>(x => x.NodeId == nodeId && x.NodeObjectType == objectType);
}
// gets the base SELECT + FROM + WHERE sql
// for a given object type and unique id
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isCount, Guid objectType, Guid uniqueId)
protected Sql<ISqlContext> GetBaseWhere(bool isContent, bool isMedia, bool isMember, bool isCount, Guid objectType, Guid uniqueId)
{
return GetBase(isContent, isMedia, null, isCount)
return GetBase(isContent, isMedia, isMember, null, isCount)
.Where<NodeDto>(x => x.UniqueId == uniqueId && x.NodeObjectType == objectType);
}
// gets the GROUP BY / ORDER BY sql
// required in order to count children
protected Sql<ISqlContext> AddGroupBy(bool isContent, bool isMedia, Sql<ISqlContext> sql, bool defaultSort)
protected Sql<ISqlContext> AddGroupBy(bool isContent, bool isMedia, bool isMember, Sql<ISqlContext> sql, bool defaultSort)
{
sql
.GroupBy<NodeDto>(x => x.NodeId, x => x.Trashed, x => x.ParentId, x => x.UserId, x => x.Level, x => x.Path)
@@ -483,7 +494,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
if (isContent || isMedia)
if (isContent || isMedia || isMember)
sql
.AndBy<ContentVersionDto>(x => x.Id)
.AndBy<ContentTypeDto>(x => x.Alias, x => x.Icon, x => x.Thumbnail, x => x.IsContainer, x => x.Variations);
@@ -528,6 +539,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public string MediaPath { get; set; }
}
private class MemberEntityDto : BaseDto
{
}
public class VariantInfoDto
{
public int NodeId { get; set; }
@@ -574,12 +589,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
#region Factory
private EntitySlim BuildEntity(bool isContent, bool isMedia, BaseDto dto)
private EntitySlim BuildEntity(bool isContent, bool isMedia, bool isMember, BaseDto dto)
{
if (isContent)
return BuildDocumentEntity(dto);
if (isMedia)
return BuildMediaEntity(dto);
if (isMember)
return BuildMemberEntity(dto);
// EntitySlim does not track changes
var entity = new EntitySlim();
@@ -644,6 +661,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return entity;
}
private MemberEntitySlim BuildMemberEntity(BaseDto dto)
{
// EntitySlim does not track changes
var entity = new MemberEntitySlim();
BuildEntity(entity, dto);
entity.ContentTypeAlias = dto.Alias;
entity.ContentTypeIcon = dto.Icon;
entity.ContentTypeThumbnail = dto.Thumbnail;
return entity;
}
#endregion
}
}
@@ -102,17 +102,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override IEnumerable<string> GetDeleteClauses()
{
var list = new List<string>
{
//NOTE: There is no constraint between the Language and cmsDictionary/cmsLanguageText tables (?)
// but we still need to remove them
"DELETE FROM cmsLanguageText WHERE languageId = @id",
"DELETE FROM umbracoPropertyData WHERE languageId = @id",
"DELETE FROM umbracoContentVersionCultureVariation WHERE languageId = @id",
"DELETE FROM umbracoDocumentCultureVariation WHERE languageId = @id",
"DELETE FROM umbracoLanguage WHERE id = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Tag + " WHERE languageId = @id"
"DELETE FROM " + Constants.DatabaseSchema.Tables.DictionaryValue + " WHERE languageId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.PropertyData + " WHERE languageId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersionCultureVariation + " WHERE languageId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.DocumentCultureVariation + " WHERE languageId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.TagRelationship + " WHERE tagId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.Tag + " WHERE languageId = @id)",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Tag + " WHERE languageId = @id",
"DELETE FROM " + Constants.DatabaseSchema.Tables.Language + " WHERE id = @id"
};
return list;
}
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// joining the type so we can do a query against the member type - not sure if this adds much overhead or not?
// the execution plan says it doesn't so we'll go with that and in that case, it might be worth joining the content
// types by default on the document and media repo's so we can query by content type there too.
// types by default on the document and media repos so we can query by content type there too.
.InnerJoin<ContentTypeDto>().On<ContentDto, ContentTypeDto>(left => left.ContentTypeId, right => right.NodeId);
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
@@ -546,6 +546,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (ordering.OrderBy.InvariantEquals("userName"))
return SqlSyntax.GetFieldName<MemberDto>(x => x.LoginName);
if (ordering.OrderBy.InvariantEquals("updateDate"))
return SqlSyntax.GetFieldName<ContentVersionDto>(x => x.VersionDate);
if (ordering.OrderBy.InvariantEquals("createDate"))
return SqlSyntax.GetFieldName<NodeDto>(x => x.CreateDate);
if (ordering.OrderBy.InvariantEquals("contentTypeAlias"))
return SqlSyntax.GetFieldName<ContentTypeDto>(x => x.Alias);
return base.ApplySystemOrdering(ref sql, ordering);
}
@@ -225,8 +225,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (builtinProperties.ContainsKey(propertyType.Alias))
{
//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;
var propDefinition = builtinProperties[propertyType.Alias];
if (propDefinition != null)
{
propertyType.DataTypeId = propDefinition.DataTypeId;
propertyType.DataTypeKey = propDefinition.DataTypeKey;
}
else
{
propertyType.DataTypeId = 0;
propertyType.DataTypeKey = default;
}
}
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using NPoco;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
@@ -105,7 +106,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
CreateDateUtc = redirectUrl.CreateDateUtc,
Url = redirectUrl.Url,
Culture = redirectUrl.Culture,
UrlHash = redirectUrl.Url.ToSHA1()
UrlHash = redirectUrl.Url.GenerateHash<SHA1>()
};
}
@@ -134,7 +135,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
public IRedirectUrl Get(string url, Guid contentKey, string culture)
{
var urlHash = url.ToSHA1();
var urlHash = url.GenerateHash<SHA1>();
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey && x.Culture == culture);
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
return dto == null ? null : Map(dto);
@@ -157,7 +158,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
public IRedirectUrl GetMostRecentUrl(string url)
{
var urlHash = url.ToSHA1();
var urlHash = url.GenerateHash<SHA1>();
var sql = GetBaseQuery(false)
.Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash)
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc);
@@ -557,6 +557,16 @@ ORDER BY colName";
}
}
// If userlogin or the email has changed then need to reset security stamp
if (changedCols.Contains("userLogin") || changedCols.Contains("userEmail"))
{
userDto.EmailConfirmedDate = null;
userDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString();
changedCols.Add("emailConfirmedDate");
changedCols.Add("securityStampToken");
}
//only update the changed cols
if (changedCols.Count > 0)
{
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Text.RegularExpressions;
using NPoco;
using Umbraco.Core.Persistence.DatabaseAnnotations;
@@ -76,6 +77,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string ConvertIntegerToOrderableString { get; }
string ConvertDateToOrderableString { get; }
string ConvertDecimalToOrderableString { get; }
/// <summary>
/// Returns the default isolation level for the database
/// </summary>
IsolationLevel DefaultIsolationLevel { get; }
IEnumerable<string> GetTablesInSchema(IDatabase db);
IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db);
@@ -121,5 +127,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// unspecified.</para>
/// </remarks>
bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
void ReadLock(IDatabase db, params int[] lockIds);
void WriteLock(IDatabase db, params int[] lockIds);
}
}
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlServerCe;
using System.Linq;
using NPoco;
using Umbraco.Core.Persistence.DatabaseAnnotations;
@@ -52,6 +54,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return "(" + string.Join("+", args) + ")";
}
public override System.Data.IsolationLevel DefaultIsolationLevel => System.Data.IsolationLevel.RepeatableRead;
public override string FormatColumnRename(string tableName, string oldName, string newName)
{
//NOTE Sql CE doesn't support renaming a column, so a new column needs to be created, then copy data and finally remove old column
@@ -152,6 +156,39 @@ where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault()
return result > 0;
}
public override void WriteLock(IDatabase db, params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (db.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
db.Execute(@"SET LOCK_TIMEOUT 1800;");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
var i = db.Execute(@"UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
if (i == 0) // ensure we are actually locking!
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
}
}
public override void ReadLock(IDatabase db, params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (db.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
var i = db.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id", new { id = lockId });
if (i == null) // ensure we are actually locking!
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
}
}
protected override string FormatIdentity(ColumnDefinition column)
{
return column.IsIdentity ? GetIdentityString(column) : string.Empty;
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using NPoco;
using Umbraco.Core.Logging;
@@ -179,6 +180,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
}
public override IsolationLevel DefaultIsolationLevel => IsolationLevel.ReadCommitted;
public override IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db)
{
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
@@ -246,6 +249,41 @@ where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName)
return result > 0;
}
public override void WriteLock(IDatabase db, params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
db.Execute(@"SET LOCK_TIMEOUT 1800;");
var i = db.Execute(@"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
if (i == 0) // ensure we are actually locking!
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
}
}
public override void ReadLock(IDatabase db, params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
var i = db.ExecuteScalar<int?>("SELECT value FROM umbracoLock WITH (REPEATABLEREAD) WHERE id=@id", new { id = lockId });
if (i == null) // ensure we are actually locking!
throw new ArgumentException($"LockObject with id={lockId} does not exist.", nameof(lockIds));
}
}
public override string FormatColumnRename(string tableName, string oldName, string newName)
{
return string.Format(RenameColumn, tableName, oldName, newName);
@@ -200,7 +200,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return "NVARCHAR";
}
public abstract IsolationLevel DefaultIsolationLevel { get; }
public virtual IEnumerable<string> GetTablesInSchema(IDatabase db)
{
return new List<string>();
@@ -225,6 +227,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public abstract bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
public abstract void ReadLock(IDatabase db, params int[] lockIds);
public abstract void WriteLock(IDatabase db, params int[] lockIds);
public virtual bool DoesTableExist(IDatabase db, string tableName)
{
return false;
@@ -20,9 +20,6 @@ namespace Umbraco.Core.Persistence
/// </remarks>
public class UmbracoDatabase : Database, IUmbracoDatabase
{
// Umbraco's default isolation level is RepeatableRead
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.RepeatableRead;
private readonly ILogger _logger;
private readonly RetryPolicy _connectionRetryPolicy;
private readonly RetryPolicy _commandRetryPolicy;
@@ -38,7 +35,7 @@ namespace Umbraco.Core.Persistence
/// <para>Also used by DatabaseBuilder for creating databases and installing/upgrading.</para>
/// </remarks>
public UmbracoDatabase(string connectionString, ISqlContext sqlContext, DbProviderFactory provider, ILogger logger, RetryPolicy connectionRetryPolicy = null, RetryPolicy commandRetryPolicy = null)
: base(connectionString, sqlContext.DatabaseType, provider, DefaultIsolationLevel)
: base(connectionString, sqlContext.DatabaseType, provider, sqlContext.SqlSyntax.DefaultIsolationLevel)
{
SqlContext = sqlContext;
@@ -54,7 +51,7 @@ namespace Umbraco.Core.Persistence
/// </summary>
/// <remarks>Internal for unit tests only.</remarks>
internal UmbracoDatabase(DbConnection connection, ISqlContext sqlContext, ILogger logger)
: base(connection, sqlContext.DatabaseType, DefaultIsolationLevel)
: base(connection, sqlContext.DatabaseType, sqlContext.SqlSyntax.DefaultIsolationLevel)
{
SqlContext = sqlContext;
_logger = logger;
@@ -18,6 +18,9 @@ namespace Umbraco.Core.PropertyEditors
[JsonProperty("name", Required = Required.Always)]
public string Name { get; set; }
[JsonProperty("nameTemplate")]
public string NameTemplate { get; set; }
[JsonProperty("alias", Required = Required.Always)]
public string Alias { get; set; }
+3 -33
View File
@@ -33,8 +33,6 @@ namespace Umbraco.Core.Scoping
private ICompletable _fscope;
private IEventDispatcher _eventDispatcher;
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.RepeatableRead;
// initializes a new scope
private Scope(ScopeProvider scopeProvider,
ILogger logger, FileSystems fileSystems, Scope parent, ScopeContext scopeContext, bool detachable,
@@ -205,7 +203,7 @@ namespace Umbraco.Core.Scoping
{
if (_isolationLevel != IsolationLevel.Unspecified) return _isolationLevel;
if (ParentScope != null) return ParentScope.IsolationLevel;
return DefaultIsolationLevel;
return Database.SqlContext.SqlSyntax.DefaultIsolationLevel;
}
}
@@ -488,37 +486,9 @@ namespace Umbraco.Core.Scoping
?? (_logUncompletedScopes = Current.Configs.CoreDebug().LogUncompletedScopes)).Value;
/// <inheritdoc />
public void ReadLock(params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
var i = Database.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id", new { id = lockId });
if (i == null) // ensure we are actually locking!
throw new Exception($"LockObject with id={lockId} does not exist.");
}
}
public void ReadLock(params int[] lockIds) => Database.SqlContext.SqlSyntax.ReadLock(Database, lockIds);
/// <inheritdoc />
public void WriteLock(params int[] lockIds)
{
// soon as we get Database, a transaction is started
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
foreach (var lockId in lockIds)
{
var i = Database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
if (i == 0) // ensure we are actually locking!
throw new Exception($"LockObject with id={lockId} does not exist.");
}
}
public void WriteLock(params int[] lockIds) => Database.SqlContext.SqlSyntax.WriteLock(Database, lockIds);
}
}
@@ -60,7 +60,7 @@ namespace Umbraco.Core.Serialization
/// <returns></returns>
public IStreamedResult ToStream(object input)
{
string s = JsonConvert.SerializeObject(input, Formatting.Indented, _settings);
string s = JsonConvert.SerializeObject(input, Formatting.None, _settings);
byte[] bytes = Encoding.UTF8.GetBytes(s);
MemoryStream ms = new MemoryStream(bytes);
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Gets a content type.
/// </summary>
TItem Get(int id);
new TItem Get(int id);
/// <summary>
/// Gets a content type.
@@ -40,6 +40,7 @@ namespace Umbraco.Core.Services
int Count();
IEnumerable<TItem> GetAll(params int[] ids);
IEnumerable<TItem> GetAll(IEnumerable<Guid> ids);
IEnumerable<TItem> GetDescendants(int id, bool andSelf); // parent-child axis
IEnumerable<TItem> GetComposedOf(int id); // composition axis
@@ -10,6 +10,13 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IDataTypeService : IService
{
/// <summary>
/// Returns a dictionary of content type <see cref="Udi"/>s and the property type aliases that use a <see cref="IDataType"/>
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IReadOnlyDictionary<Udi, IEnumerable<string>> GetReferences(int id);
Attempt<OperationResult<OperationResultType, EntityContainer>> CreateContainer(int parentId, string name, int userId = Constants.Security.SuperUserId);
Attempt<OperationResult> SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId);
EntityContainer GetContainer(int containerId);
@@ -3,7 +3,6 @@ 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;
@@ -12,7 +11,6 @@ using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services.Changes;
@@ -1850,7 +1848,7 @@ namespace Umbraco.Core.Services.Implement
scope.WriteLock(Constants.Locks.ContentTree);
var c = _documentRepository.Get(id);
if (c.VersionId != versionId) // don't delete the current version
if (c.VersionId != versionId && c.PublishedVersionId != versionId) // don't delete the current or published version
_documentRepository.DeleteVersion(versionId);
scope.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false,/* specificVersion:*/ versionId));
@@ -2988,8 +2986,22 @@ namespace Umbraco.Core.Services.Implement
content.CreatorId = userId;
content.WriterId = userId;
IEnumerable<string> cultures = ArrayOfOneNullString;
if (blueprint.CultureInfos.Count > 0)
{
cultures = blueprint.CultureInfos.Values.Select(x => x.Culture);
using (var scope = ScopeProvider.CreateScope())
{
if (blueprint.CultureInfos.TryGetValue(_languageRepository.GetDefaultIsoCode(), out var defaultCulture))
{
defaultCulture.Name = name;
}
scope.Complete();
}
}
var now = DateTime.Now;
var cultures = blueprint.CultureInfos.Count > 0 ? blueprint.CultureInfos.Values.Select(x => x.Culture) : ArrayOfOneNullString;
foreach (var culture in cultures)
{
foreach (var property in blueprint.Properties)
@@ -3071,7 +3083,7 @@ namespace Umbraco.Core.Services.Implement
var version = GetVersion(versionId);
//Good ole null checks
if (content == null || version == null)
if (content == null || version == null || content.Trashed)
{
return new OperationResult(OperationResultType.FailedCannot, evtMsgs);
}
@@ -252,12 +252,12 @@ namespace Umbraco.Core.Services.Implement
}
}
public IEnumerable<TItem> GetAll(params Guid[] ids)
public IEnumerable<TItem> GetAll(IEnumerable<Guid> ids)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(ReadLockIds);
return Repository.GetMany(ids);
return Repository.GetMany(ids.ToArray());
}
}
@@ -466,6 +466,14 @@ namespace Umbraco.Core.Services.Implement
}
}
public IReadOnlyDictionary<Udi, IEnumerable<string>> GetReferences(int id)
{
using (var scope = ScopeProvider.CreateScope(autoComplete:true))
{
return _dataTypeRepository.FindUsages(id);
}
}
private void Audit(AuditType type, int userId, int objectId)
{
_auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.DataType)));
@@ -405,6 +405,21 @@ namespace Umbraco.Core.Services.Implement
/// <returns></returns>
public ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = Constants.Security.SuperUserId)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name cannot be empty or contain only white-space characters", nameof(name));
}
if (name.Length > 255)
{
throw new ArgumentOutOfRangeException(nameof(name), "Name cannot be more than 255 characters in length.");
}
// file might already be on disk, if so grab the content to avoid overwriting
var template = new Template(name, alias)
{
@@ -539,6 +554,17 @@ namespace Umbraco.Core.Services.Implement
/// <param name="userId"></param>
public void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId)
{
if (template == null)
{
throw new ArgumentNullException(nameof(template));
}
if (string.IsNullOrWhiteSpace(template.Name) || template.Name.Length > 255)
{
throw new InvalidOperationException("Name cannot be null, empty, contain only white-space characters or be more than 255 characters in length.");
}
using (var scope = ScopeProvider.CreateScope())
{
if (scope.Events.DispatchCancelable(SavingTemplate, this, new SaveEventArgs<ITemplate>(template)))
@@ -816,8 +816,8 @@ namespace Umbraco.Core.Services.Implement
{
//trimming username and email to make sure we have no trailing space
member.Username = member.Username.Trim();
member.Email = member.Email.Trim();
member.Email = member.Email.Trim();
using (var scope = ScopeProvider.CreateScope())
{
var saveEventArgs = new SaveEventArgs<IMember>(member);
@@ -131,6 +131,12 @@ namespace Umbraco.Core.Services
private bool IsPropertyValueValid(PropertyType propertyType, object value)
{
var editor = _propertyEditors[propertyType.PropertyEditorAlias];
if (editor == null)
{
// nothing much we can do validation wise if the property editor has been removed.
// the property will be displayed as a label, so flagging it as invalid would be pointless.
return true;
}
var configuration = _dataTypeService.GetDataType(propertyType.DataTypeId).Configuration;
var valueEditor = editor.GetValueEditor(configuration);
return !valueEditor.Validate(value, propertyType.Mandatory, propertyType.ValidationRegExp).Any();
+28 -39
View File
@@ -724,67 +724,56 @@ namespace Umbraco.Core
/// <summary>
/// Generates a hash of a string based on the FIPS compliance setting.
/// </summary>
/// <param name="str">Refers to itself</param>
/// <returns>The hashed string</returns>
/// <param name="str">The <see cref="string" /> to hash.</param>
/// <returns>
/// The hashed string.
/// </returns>
public static string GenerateHash(this string str)
{
return CryptoConfig.AllowOnlyFipsAlgorithms
? str.ToSHA1()
: str.ToMd5();
return str.GenerateHash(CryptoConfig.AllowOnlyFipsAlgorithms ? "SHA1" : "MD5");
}
/// <summary>
/// Converts the string to MD5
/// Generate a hash of a string based on the specified hash algorithm.
/// </summary>
/// <param name="stringToConvert">Refers to itself</param>
/// <returns>The MD5 hashed string</returns>
[Obsolete("Please use the GenerateHash method instead. This may be removed in future versions")]
internal static string ToMd5(this string stringToConvert)
/// <typeparam name="T">The hash algorithm implementation to use.</typeparam>
/// <param name="str">The <see cref="string" /> to hash.</param>
/// <returns>
/// The hashed string.
/// </returns>
internal static string GenerateHash<T>(this string str)
where T : HashAlgorithm
{
return stringToConvert.GenerateHash("MD5");
return str.GenerateHash(typeof(T).FullName);
}
/// <summary>
/// Converts the string to SHA1
/// Generate a hash of a string based on the specified <paramref name="hashType" />.
/// </summary>
/// <param name="stringToConvert">refers to itself</param>
/// <returns>The SHA1 hashed string</returns>
[Obsolete("Please use the GenerateHash method instead. This may be removed in future versions")]
internal static string ToSHA1(this string stringToConvert)
/// <param name="str">The <see cref="string" /> to hash.</param>
/// <param name="hashType">The hash algorithm implementation to use.</param>
/// <returns>
/// The hashed string.
/// </returns>
/// <exception cref="System.InvalidOperationException">No hashing type found by name <paramref name="hashType" />.</exception>
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.create#System_Security_Cryptography_HashAlgorithm_Create_System_String_" />
internal static string GenerateHash(this string str, string hashType)
{
return stringToConvert.GenerateHash("SHA1");
}
/// <summary>Generate a hash of a string based on the hashType passed in
/// </summary>
/// <param name="str">Refers to itself</param>
/// <param name="hashType">String with the hash type. See remarks section of the CryptoConfig Class in MSDN docs for a list of possible values.</param>
/// <returns>The hashed string</returns>
private static string GenerateHash(this string str, string hashType)
{
//create an instance of the correct hashing provider based on the type passed in
var hasher = HashAlgorithm.Create(hashType);
if (hasher == null) throw new InvalidOperationException("No hashing type found by name " + hashType);
if (hasher == null) throw new InvalidOperationException($"No hashing type found by name {hashType}.");
using (hasher)
{
//convert our string into byte array
var byteArray = Encoding.UTF8.GetBytes(str);
//get the hashed values created by our selected provider
var hashedByteArray = hasher.ComputeHash(byteArray);
//create a StringBuilder object
var stringBuilder = new StringBuilder();
//loop to each byte
var sb = new StringBuilder();
foreach (var b in hashedByteArray)
{
//append it to our StringBuilder
stringBuilder.Append(b.ToString("x2"));
sb.Append(b.ToString("x2"));
}
//return the hashed value
return stringBuilder.ToString();
return sb.ToString();
}
}
+13 -3
View File
@@ -10,6 +10,7 @@
<RootNamespace>Umbraco.Core</RootNamespace>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkProfile />
<AdditionalFileItemNames>$(AdditionalFileItemNames);Content</AdditionalFileItemNames>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -60,6 +61,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="SecurityCodeScan">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Async">
<Version>1.3.0</Version>
</PackageReference>
@@ -245,6 +251,8 @@
<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\ContentEditing\ContentAppBadge.cs" />
<Compile Include="Models\ContentEditing\ContentAppBadgeType.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" />
@@ -263,7 +271,10 @@
<Compile Include="Migrations\Upgrade\V_8_0_0\FixLanguageIsoCodeLength.cs" />
<Compile Include="Models\CultureImpact.cs" />
<Compile Include="Models\Entities\IMediaEntitySlim.cs" />
<Compile Include="Models\Entities\IMemberEntitySlim.cs" />
<Compile Include="Models\Entities\MediaEntitySlim.cs" />
<Compile Include="Models\PagedResult.cs" />
<Compile Include="Models\Entities\MemberEntitySlim.cs" />
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
<Compile Include="Models\PublishedContent\IPublishedPropertyType.cs" />
@@ -837,7 +848,7 @@
<Compile Include="Models\Packaging\InstallationSummary.cs" />
<Compile Include="Models\Packaging\PackageAction.cs" />
<Compile Include="Models\Packaging\PreInstallWarnings.cs" />
<Compile Include="Models\PagedResult.cs" />
<Compile Include="Models\PagedResultOfT.cs" />
<Compile Include="Models\PartialView.cs" />
<Compile Include="Models\PartialViewType.cs" />
<Compile Include="Models\Property.cs" />
@@ -982,7 +993,6 @@
<Compile Include="Persistence\DatabaseModelDefinitions\ModificationType.cs" />
<Compile Include="Persistence\DatabaseModelDefinitions\SystemMethods.cs" />
<Compile Include="Persistence\DatabaseModelDefinitions\TableDefinition.cs" />
<Compile Include="Persistence\DatabaseNodeLockExtensions.cs" />
<Compile Include="Persistence\DbCommandExtensions.cs" />
<Compile Include="Persistence\DbConnectionExtensions.cs" />
<Compile Include="Persistence\EntityNotFoundException.cs" />
@@ -1562,4 +1572,4 @@
<Folder Include="Auditing\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
+1 -1
View File
@@ -236,7 +236,7 @@ namespace Umbraco.Core.Xml
_name = name;
_value = value;
if (value is String)
if (value is string)
_type = XPathResultType.String;
else if (value is bool)
_type = XPathResultType.Boolean;
+3 -3
View File
@@ -15,7 +15,7 @@ namespace Umbraco.Examine
/// <summary>
/// Performs the data lookups required to rebuild a content index
/// </summary>
public class ContentIndexPopulator : IndexPopulator<UmbracoContentIndex>
public class ContentIndexPopulator : IndexPopulator<IUmbracoContentIndex>
{
private readonly IContentService _contentService;
private readonly IValueSetBuilder<IContent> _contentValueSetBuilder;
@@ -36,7 +36,7 @@ namespace Umbraco.Examine
/// <param name="contentValueSetBuilder"></param>
public ContentIndexPopulator(IContentService contentService, ISqlContext sqlContext, IContentValueSetBuilder contentValueSetBuilder)
: this(false, null, contentService, sqlContext, contentValueSetBuilder)
{
{
}
/// <summary>
@@ -52,7 +52,7 @@ namespace Umbraco.Examine
if (sqlContext == null) throw new ArgumentNullException(nameof(sqlContext));
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
_contentValueSetBuilder = contentValueSetBuilder ?? throw new ArgumentNullException(nameof(contentValueSetBuilder));
if (_publishedQuery != null)
if (_publishedQuery == null)
_publishedQuery = sqlContext.Query<IContent>().Where(x => x.Published);
_publishedValuesOnly = publishedValuesOnly;
_parentId = parentId;
@@ -0,0 +1,9 @@
using Examine;
namespace Umbraco.Examine
{
public interface IUmbracoContentIndex : IIndex
{
}
}
@@ -0,0 +1,12 @@
using Examine;
namespace Umbraco.Examine
{
public interface IUmbracoIndexConfig
{
IContentValueSetValidator GetContentValueSetValidator();
IContentValueSetValidator GetPublishedContentValueSetValidator();
IValueSetValidator GetMemberValueSetValidator();
}
}
@@ -0,0 +1,9 @@
using Examine;
namespace Umbraco.Examine
{
public interface IUmbracoMemberIndex : IIndex
{
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Examine
/// <summary>
/// Performs the data lookups required to rebuild a media index
/// </summary>
public class MediaIndexPopulator : IndexPopulator<UmbracoContentIndex>
public class MediaIndexPopulator : IndexPopulator<IUmbracoContentIndex>
{
private readonly int? _parentId;
private readonly IMediaService _mediaService;
@@ -69,6 +69,6 @@ namespace Umbraco.Examine
pageIndex++;
} while (media.Length == pageSize);
}
}
}
+46 -3
View File
@@ -1,9 +1,13 @@
using Examine;
using System;
using Examine;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
@@ -13,14 +17,16 @@ namespace Umbraco.Examine
{
private readonly UrlSegmentProviderCollection _urlSegmentProviders;
private readonly IUserService _userService;
private readonly ILogger _logger;
public MediaValueSetBuilder(PropertyEditorCollection propertyEditors,
UrlSegmentProviderCollection urlSegmentProviders,
IUserService userService)
IUserService userService, ILogger logger)
: base(propertyEditors, false)
{
_urlSegmentProviders = urlSegmentProviders;
_userService = userService;
_logger = logger;
}
/// <inheritdoc />
@@ -29,6 +35,42 @@ namespace Umbraco.Examine
foreach (var m in media)
{
var urlValue = m.GetUrlSegment(_urlSegmentProviders);
var umbracoFilePath = string.Empty;
var umbracoFile = string.Empty;
var umbracoFileSource = m.GetValue<string>(Constants.Conventions.Media.File);
if (umbracoFileSource.DetectIsJson())
{
ImageCropperValue cropper = null;
try
{
cropper = JsonConvert.DeserializeObject<ImageCropperValue>(
m.GetValue<string>(Constants.Conventions.Media.File));
}
catch (Exception ex)
{
_logger.Error<MediaValueSetBuilder>(ex, $"Could not Deserialize ImageCropperValue for item with key {m.Key} ");
}
if (cropper != null)
{
umbracoFilePath = cropper.Src;
}
}
else
{
umbracoFilePath = umbracoFileSource;
}
if (!string.IsNullOrEmpty(umbracoFilePath))
{
// intentional dummy Uri
var uri = new Uri("https://localhost/" + umbracoFilePath);
umbracoFile = uri.Segments.Last();
}
var values = new Dictionary<string, IEnumerable<object>>
{
{"icon", m.ContentType.Icon?.Yield() ?? Enumerable.Empty<string>()},
@@ -44,7 +86,8 @@ namespace Umbraco.Examine
{"urlName", urlValue?.Yield() ?? Enumerable.Empty<string>()},
{"path", m.Path?.Yield() ?? Enumerable.Empty<string>()},
{"nodeType", m.ContentType.Id.ToString().Yield() },
{"creatorName", (m.GetCreatorProfile(_userService)?.Name ?? "??").Yield()}
{"creatorName", (m.GetCreatorProfile(_userService)?.Name ?? "??").Yield()},
{UmbracoExamineIndex.UmbracoFileFieldName, umbracoFile.Yield()}
};
foreach (var property in m.Properties)
+1 -1
View File
@@ -7,7 +7,7 @@ using Umbraco.Core.Services;
namespace Umbraco.Examine
{
public class MemberIndexPopulator : IndexPopulator<UmbracoMemberIndex>
public class MemberIndexPopulator : IndexPopulator<IUmbracoMemberIndex>
{
private readonly IMemberService _memberService;
private readonly IValueSetBuilder<IMember> _valueSetBuilder;
+12 -2
View File
@@ -10,6 +10,7 @@
<RootNamespace>Umbraco.Examine</RootNamespace>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<TargetFrameworkProfile />
<AdditionalFileItemNames>$(AdditionalFileItemNames);Content</AdditionalFileItemNames>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -48,7 +49,7 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="Examine" Version="1.0.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub">
<Version>1.0.0-beta2-19324-01</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -56,6 +57,11 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="NPoco" Version="3.9.4" />
<PackageReference Include="SecurityCodeScan">
<Version>3.3.0</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="BaseValueSetBuilder.cs" />
@@ -64,9 +70,13 @@
<Compile Include="ExamineExtensions.cs" />
<Compile Include="IContentValueSetBuilder.cs" />
<Compile Include="IContentValueSetValidator.cs" />
<Compile Include="IUmbracoContentIndex.cs" />
<Compile Include="IUmbracoIndexConfig.cs" />
<Compile Include="IIndexCreator.cs" />
<Compile Include="IIndexDiagnostics.cs" />
<Compile Include="IIndexPopulator.cs" />
<Compile Include="IUmbracoMemberIndex.cs" />
<Compile Include="UmbracoIndexConfig.cs" />
<Compile Include="IndexPopulator.cs" />
<Compile Include="IndexRebuilder.cs" />
<Compile Include="IPublishedContentValueSetBuilder.cs" />
@@ -102,4 +112,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
+3 -3
View File
@@ -17,13 +17,13 @@ namespace Umbraco.Examine
/// <summary>
/// An indexer for Umbraco content and media
/// </summary>
public class UmbracoContentIndex : UmbracoExamineIndex
public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex
{
public const string VariesByCultureFieldName = SpecialFieldPrefix + "VariesByCulture";
protected ILocalizationService LanguageService { get; }
#region Constructors
/// <summary>
/// Create an index at runtime
/// </summary>
@@ -141,6 +141,6 @@ namespace Umbraco.Examine
base.PerformDeleteFromIndex(idsAsList, onComplete);
}
}
}
@@ -32,6 +32,7 @@ namespace Umbraco.Examine
/// </summary>
public const string IndexPathFieldName = SpecialFieldPrefix + "Path";
public const string NodeKeyFieldName = SpecialFieldPrefix + "Key";
public const string UmbracoFileFieldName = "umbracoFileSrc";
public const string IconFieldName = SpecialFieldPrefix + "Icon";
public const string PublishedFieldName = SpecialFieldPrefix + "Published";
+34
View File
@@ -0,0 +1,34 @@
using Examine;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Examine
{
public class UmbracoIndexConfig : IUmbracoIndexConfig
{
public UmbracoIndexConfig(IPublicAccessService publicAccessService)
{
PublicAccessService = publicAccessService;
}
protected IPublicAccessService PublicAccessService { get; }
public IContentValueSetValidator GetContentValueSetValidator()
{
return new ContentValueSetValidator(false, true, PublicAccessService);
}
public IContentValueSetValidator GetPublishedContentValueSetValidator()
{
return new ContentValueSetValidator(true, false, PublicAccessService);
}
/// <summary>
/// Returns the <see cref="IValueSetValidator"/> for the member indexer
/// </summary>
/// <returns></returns>
public IValueSetValidator GetMemberValueSetValidator()
{
return new MemberValueSetValidator();
}
}
}
+2 -2
View File
@@ -11,7 +11,7 @@ namespace Umbraco.Examine
/// <summary>
/// Custom indexer for members
/// </summary>
public class UmbracoMemberIndex : UmbracoExamineIndex
public class UmbracoMemberIndex : UmbracoExamineIndex, IUmbracoMemberIndex
{
/// <summary>
/// Constructor to allow for creating an indexer at runtime
@@ -32,6 +32,6 @@ namespace Umbraco.Examine
base(name, luceneDirectory, fieldDefinitions, analyzer, profilingLogger, validator)
{
}
}
}
+4 -2
View File
@@ -12,20 +12,22 @@ namespace Umbraco.Tests.Cache
[Test]
public void MediaCacheRefresherCanDeserializeJsonPayload()
{
var source = new[] { new MediaCacheRefresher.JsonPayload(1234, TreeChangeTypes.None) };
var source = new[] { new MediaCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) };
var json = JsonConvert.SerializeObject(source);
var payload = JsonConvert.DeserializeObject<MediaCacheRefresher.JsonPayload[]>(json);
Assert.AreEqual(source[0].Id, payload[0].Id);
Assert.AreEqual(source[0].Key, payload[0].Key);
Assert.AreEqual(source[0].ChangeTypes, payload[0].ChangeTypes);
}
[Test]
public void ContentCacheRefresherCanDeserializeJsonPayload()
{
var source = new[] { new ContentCacheRefresher.JsonPayload(1234, TreeChangeTypes.None) };
var source = new[] { new ContentCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) };
var json = JsonConvert.SerializeObject(source);
var payload = JsonConvert.DeserializeObject<ContentCacheRefresher.JsonPayload[]>(json);
Assert.AreEqual(source[0].Id, payload[0].Id);
Assert.AreEqual(source[0].Key, payload[0].Key);
Assert.AreEqual(source[0].ChangeTypes, payload[0].ChangeTypes);
}
@@ -4,6 +4,7 @@ using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Tests.Composing
@@ -35,7 +36,7 @@ namespace Umbraco.Tests.Composing
.Returns(() => factoryFactory?.Invoke(mockedFactory));
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), IOHelper.MapPath("~/App_Data/TEMP"), logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
// create the factory, ensure it is the mocked factory
@@ -165,7 +165,7 @@ namespace Umbraco.Tests.Composing
Assert.IsTrue(TypeHelper.MatchType(typeof(int?), typeof(Nullable<>)));
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(Object)));
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(object)));
Assert.IsFalse(TypeHelper.MatchType(typeof(Derived<int>), typeof(List<>)));
Assert.IsFalse(TypeHelper.MatchType(typeof(Derived<int>), typeof(IEnumerable<>)));
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(Base<int>)));
@@ -268,7 +268,7 @@ AnotherContentFinder
public void GetDataEditors()
{
var types = _typeLoader.GetDataEditors();
Assert.AreEqual(39, types.Count());
Assert.AreEqual(38, types.Count());
}
/// <summary>
@@ -67,7 +67,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
[Test]
public void PreviewBadge()
{
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>");
}
[Test]
public void ResolveUrlsFromTextString()
@@ -41,9 +41,7 @@
</notifications>
<PreviewBadge>
<![CDATA[
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/preview/end?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
<![CDATA[<div id="umbracoPreviewBadge" class="umbraco-preview-badge"><span class="umbraco-preview-badge__header">Preview mode</span><a href="{0}/preview/end?redir={1}" class="umbraco-preview-badge__end"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><title>Click to end</title><path d="M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z"/><path d="M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z"/><path d="M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z"/><path d="M42.7 2.5h14.6v49.4H42.7z"/></svg></a></div><style type="text/css">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>]]></PreviewBadge>
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
- inline - show an inline error within the macro but allow the page to continue rendering. Historial Umbraco behaviour.
@@ -1087,7 +1087,7 @@ namespace Umbraco.Tests.Integration
[Test]
public void EmptyRecycleBinContent()
{
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var content = CreateContent();
Assert.IsNotNull(content);
@@ -1095,7 +1095,7 @@ namespace Umbraco.Tests.Integration
ServiceContext.ContentService.MoveToRecycleBin(content);
ResetEvents();
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
Assert.AreEqual(2, _msgCount);
Assert.AreEqual(2, _events.Count);
@@ -1109,7 +1109,7 @@ namespace Umbraco.Tests.Integration
[Test]
public void EmptyRecycleBinContents()
{
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var content1 = CreateContent();
Assert.IsNotNull(content1);
@@ -1120,7 +1120,7 @@ namespace Umbraco.Tests.Integration
ServiceContext.ContentService.MoveToRecycleBin(content2);
ResetEvents();
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
Assert.AreEqual(3, _msgCount);
Assert.AreEqual(4, _events.Count);
@@ -1136,7 +1136,7 @@ namespace Umbraco.Tests.Integration
[Test]
public void EmptyRecycleBinBranch()
{
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var content1 = CreateBranch();
Assert.IsNotNull(content1);
@@ -1151,7 +1151,7 @@ namespace Umbraco.Tests.Integration
var content4C = Children(content1C[2]).ToArray();
var content5C = Children(content1C[3]).ToArray();
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
Assert.AreEqual(14, _msgCount);
Assert.AreEqual(14, _events.Count);
@@ -57,6 +57,9 @@ namespace Umbraco.Tests.Models
[TestCase("1,-1", "1", "1")] // was an issue
[TestCase("-1,1", "1", "1")] // was an issue
[TestCase("-1", "", "-1")]
[TestCase("", "-1", "-1")]
public void CombineStartNodes(string groupSn, string userSn, string expected)
{
// 1
+108 -30
View File
@@ -70,50 +70,128 @@ namespace Umbraco.Tests.Models
[Test]
public void ValidateVariationTests()
{
void Assert4A(ContentVariation v, string c, string s, bool xx)
{
Assert4B(v, c, s, xx, xx, xx, xx);
}
void Assert4B(ContentVariation v, string c, string s, bool ew, bool nn, bool en, bool nw)
{
Assert.AreEqual(ew, v.ValidateVariation(c, s, true, true, false));
Assert.AreEqual(nn, v.ValidateVariation(c, s, false, false, false));
Assert.AreEqual(en, v.ValidateVariation(c, s, true, false, false));
Assert.AreEqual(nw, v.ValidateVariation(c, s, false, true, false));
}
// All tests:
// 1. if exact is set to true: culture cannot be null when the ContentVariation.Culture flag is set
// 2. if wildcards is set to false: fail when "*" is passed in as either culture or segment.
// 3. ContentVariation flag is ignored when wildcards are used.
// 4. Empty string is considered the same as null
#region Nothing
// always support invariant,neutral
Assert4A(ContentVariation.Nothing, null, null, true);
// never support culture and/or segment
Assert4A(ContentVariation.Nothing, "culture", null, false);
Assert4A(ContentVariation.Nothing, null, "", true);
Assert4B(ContentVariation.Nothing, null, "*", true, false, false, true);
Assert4A(ContentVariation.Nothing, null, "segment", false);
Assert4A(ContentVariation.Nothing, "", null, true);
Assert4A(ContentVariation.Nothing, "", "", true);
Assert4B(ContentVariation.Nothing, "", "*", true, false, false, true);
Assert4A(ContentVariation.Nothing, "", "segment", false);
Assert4B(ContentVariation.Nothing, "*", null, true, false, false, true);
Assert4B(ContentVariation.Nothing, "*", "", true, false, false, true);
Assert4B(ContentVariation.Nothing, "*", "*", true, false, false, true);
Assert4A(ContentVariation.Nothing, "*", "segment", false);
Assert4A(ContentVariation.Nothing, "culture", null, false);
Assert4A(ContentVariation.Nothing, "culture", "", false);
Assert4A(ContentVariation.Nothing, "culture", "*", false);
Assert4A(ContentVariation.Nothing, "culture", "segment", false);
// support '*' only when wildcards are supported
Assert4B(ContentVariation.Nothing, "*", null, true, false, false, true);
Assert4B(ContentVariation.Nothing, null, "*", true, false, false, true);
Assert4B(ContentVariation.Nothing, "*", "*", true, false, false, true);
#endregion
#region Culture
// support invariant if not exact
Assert4B(ContentVariation.Culture, null, null, false, true, false, true);
// support invariant if not exact, '*' when wildcards are supported
Assert4B(ContentVariation.Culture, "*", null, true, false, false, true);
Assert4B(ContentVariation.Culture, null, "", false, true, false, true);
Assert4B(ContentVariation.Culture, null, "*", false, false, false, true);
Assert4B(ContentVariation.Culture, "*", "*", true, false, false, true);
// never support segment
Assert4A(ContentVariation.Culture, null, "segment", false);
Assert4A(ContentVariation.Culture, "culture", "segment", false);
Assert4B(ContentVariation.Culture, "", null, false, true, false, true);
Assert4B(ContentVariation.Culture, "", "", false, true, false, true);
Assert4B(ContentVariation.Culture, "", "*", false, false, false, true);
Assert4A(ContentVariation.Culture, "", "segment", false);
Assert4B(ContentVariation.Culture, "*", null, true, false, false, true);
Assert4B(ContentVariation.Culture, "*", "", true, false, false, true);
Assert4B(ContentVariation.Culture, "*", "*", true, false, false, true);
Assert4A(ContentVariation.Culture, "*", "segment", false);
Assert4B(ContentVariation.Culture, null, "*", false, false, false, true);
Assert4A(ContentVariation.Culture, "culture", null, true);
Assert4A(ContentVariation.Culture, "culture", "", true);
Assert4B(ContentVariation.Culture, "culture", "*", true, false, false, true);
Assert4A(ContentVariation.Culture, "culture", "segment", false);
// could do the same with .Segment, and .CultureAndSegment
#endregion
#region Segment
Assert4B(ContentVariation.Segment, null, null, true, true, true, true);
Assert4B(ContentVariation.Segment, null, "", true, true, true, true);
Assert4B(ContentVariation.Segment, null, "*", true, false, false, true);
Assert4A(ContentVariation.Segment, null, "segment", true);
Assert4B(ContentVariation.Segment, "", null, true, true, true, true);
Assert4B(ContentVariation.Segment, "", "", true, true, true, true);
Assert4B(ContentVariation.Segment, "", "*", true, false, false, true);
Assert4A(ContentVariation.Segment, "", "segment", true);
Assert4B(ContentVariation.Segment, "*", null, true, false, false, true);
Assert4B(ContentVariation.Segment, "*", "", true, false, false, true);
Assert4B(ContentVariation.Segment, "*", "*", true, false, false, true);
Assert4B(ContentVariation.Segment, "*", "segment", true, false, false, true);
Assert4A(ContentVariation.Segment, "culture", null, false);
Assert4A(ContentVariation.Segment, "culture", "", false);
Assert4A(ContentVariation.Segment, "culture", "*", false);
Assert4A(ContentVariation.Segment, "culture", "segment", false);
#endregion
#region CultureAndSegment
Assert4B(ContentVariation.CultureAndSegment, null, null, false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, null, "", false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, null, "*", false, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, null, "segment", false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, "", null, false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, "", "", false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, "", "*", false, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "", "segment", false, true, false, true);
Assert4B(ContentVariation.CultureAndSegment, "*", null, true, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "*", "", true, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "*", "*", true, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "*", "segment", true, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "culture", null, true, true, true, true);
Assert4B(ContentVariation.CultureAndSegment, "culture", "", true, true, true, true);
Assert4B(ContentVariation.CultureAndSegment, "culture", "*", true, false, false, true);
Assert4B(ContentVariation.CultureAndSegment, "culture", "segment", true, true, true, true);
#endregion
}
/// <summary>
/// Asserts the result of <see cref="ContentVariationExtensions.ValidateVariation(ContentVariation, string, string, bool, bool, bool)"/>
/// </summary>
/// <param name="variation"></param>
/// <param name="culture"></param>
/// <param name="segment"></param>
/// <param name="exactAndWildcards">Validate using Exact + Wildcards flags</param>
/// <param name="nonExactAndNoWildcards">Validate using non Exact + no Wildcard flags</param>
/// <param name="exactAndNoWildcards">Validate using Exact + no Wildcard flags</param>
/// <param name="nonExactAndWildcards">Validate using non Exact + Wildcard flags</param>
private static void Assert4B(ContentVariation variation, string culture, string segment,
bool exactAndWildcards, bool nonExactAndNoWildcards, bool exactAndNoWildcards, bool nonExactAndWildcards)
{
Assert.AreEqual(exactAndWildcards, variation.ValidateVariation(culture, segment, true, true, false));
Assert.AreEqual(nonExactAndNoWildcards, variation.ValidateVariation(culture, segment, false, false, false));
Assert.AreEqual(exactAndNoWildcards, variation.ValidateVariation(culture, segment, true, false, false));
Assert.AreEqual(nonExactAndWildcards, variation.ValidateVariation(culture, segment, false, true, false));
}
/// <summary>
/// Asserts the result of <see cref="ContentVariationExtensions.ValidateVariation(ContentVariation, string, string, bool, bool, bool)"/>
/// where expectedResult matches all combinations of Exact + Wildcard
/// </summary>
/// <param name="variation"></param>
/// <param name="culture"></param>
/// <param name="segment"></param>
/// <param name="expectedResult"></param>
private static void Assert4A(ContentVariation variation, string culture, string segment, bool expectedResult)
{
Assert4B(variation, culture, segment, expectedResult, expectedResult, expectedResult, expectedResult);
}
[Test]
+6 -7
View File
@@ -5,7 +5,6 @@ using System.Threading;
using NPoco;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
@@ -37,7 +36,7 @@ namespace Umbraco.Tests.Persistence
{
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.AcquireLockNodeReadLock(Constants.Locks.Servers);
scope.ReadLock(Constants.Locks.Servers);
scope.Complete();
}
}
@@ -62,7 +61,7 @@ namespace Umbraco.Tests.Persistence
{
try
{
scope.Database.AcquireLockNodeReadLock(Constants.Locks.Servers);
scope.ReadLock(Constants.Locks.Servers);
lock (locker)
{
acquired++;
@@ -131,7 +130,7 @@ namespace Umbraco.Tests.Persistence
if (entered == threadCount) m1.Set();
}
ms[ic].WaitOne();
scope.Database.AcquireLockNodeWriteLock(Constants.Locks.Servers);
scope.WriteLock(Constants.Locks.Servers);
lock (locker)
{
acquired++;
@@ -221,7 +220,7 @@ namespace Umbraco.Tests.Persistence
{
otherEv.WaitOne();
Console.WriteLine($"[{id1}] WAIT {id1}");
scope.Database.AcquireLockNodeWriteLock(id1);
scope.WriteLock(id1);
Console.WriteLine($"[{id1}] GRANT {id1}");
WriteLocks(scope.Database);
myEv.Set();
@@ -232,7 +231,7 @@ namespace Umbraco.Tests.Persistence
Thread.Sleep(200); // cannot wait due to deadlock... just give it a bit of time
Console.WriteLine($"[{id1}] WAIT {id2}");
scope.Database.AcquireLockNodeWriteLock(id2);
scope.WriteLock(id2);
Console.WriteLine($"[{id1}] GRANT {id2}");
WriteLocks(scope.Database);
}
@@ -284,7 +283,7 @@ namespace Umbraco.Tests.Persistence
{
otherEv.WaitOne();
Console.WriteLine($"[{id}] WAIT {id}");
scope.Database.AcquireLockNodeWriteLock(id);
scope.WriteLock(id);
Console.WriteLine($"[{id}] GRANT {id}");
WriteLocks(scope.Database);
myEv.Set();
@@ -28,6 +28,68 @@ namespace Umbraco.Tests.Persistence.Repositories
return new EntityContainerRepository(scopeAccessor, AppCaches.Disabled, Logger, Constants.ObjectTypes.DataTypeContainer);
}
[Test]
public void Can_Find_Usages()
{
var provider = TestObjects.GetScopeProvider(Logger);
using (provider.CreateScope())
{
var dtRepo = CreateRepository();
IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService)) { Name = "dt1" };
dtRepo.Save(dataType1);
IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService)) { Name = "dt2" };
dtRepo.Save(dataType2);
var ctRepo = Factory.GetInstance<IContentTypeRepository>();
IContentType ct = new ContentType(-1)
{
Alias = "ct1",
Name = "CT1",
AllowedAsRoot = true,
Icon = "icon-home",
PropertyGroups = new PropertyGroupCollection
{
new PropertyGroup(true)
{
Name = "PG1",
PropertyTypes = new PropertyTypeCollection(true)
{
new PropertyType(dataType1, "pt1")
{
Name = "PT1"
},
new PropertyType(dataType1, "pt2")
{
Name = "PT2"
},
new PropertyType(dataType2, "pt3")
{
Name = "PT3"
}
}
}
}
};
ctRepo.Save(ct);
var usages = dtRepo.FindUsages(dataType1.Id);
var key = usages.First().Key;
Assert.AreEqual(ct.Key, ((GuidUdi)key).Guid);
Assert.AreEqual(2, usages[key].Count());
Assert.AreEqual("pt1", usages[key].ElementAt(0));
Assert.AreEqual("pt2", usages[key].ElementAt(1));
usages = dtRepo.FindUsages(dataType2.Id);
key = usages.First().Key;
Assert.AreEqual(ct.Key, ((GuidUdi)key).Guid);
Assert.AreEqual(1, usages[key].Count());
Assert.AreEqual("pt3", usages[key].ElementAt(0));
}
}
[Test]
public void Can_Move()
{
@@ -409,6 +409,35 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Can_Invalidate_SecurityStamp_On_Username_Change()
{
// Arrange
var provider = TestObjects.GetScopeProvider(Logger);
using (var scope = provider.CreateScope())
{
var repository = CreateRepository(provider);
var userGroupRepository = CreateUserGroupRepository(provider);
var user = CreateAndCommitUserWithGroup(repository, userGroupRepository);
var originalSecurityStamp = user.SecurityStamp;
// Ensure when user generated a security stamp is present
Assert.That(user.SecurityStamp, Is.Not.Null);
Assert.That(user.SecurityStamp, Is.Not.Empty);
// Update username
user.Username = user.Username + "UPDATED";
repository.Save(user);
// Get the user
var updatedUser = repository.Get(user.Id);
// Ensure the Security Stamp is invalidated & no longer the same
Assert.AreNotEqual(originalSecurityStamp, updatedUser.SecurityStamp);
}
}
private void AssertPropertyValues(IUser updatedItem, IUser originalUser)
{
Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id));
@@ -14,7 +14,7 @@ namespace Umbraco.Tests.Persistence
public void ReadLockNonExisting()
{
var provider = TestObjects.GetScopeProvider(Logger);
Assert.Throws<Exception>(() =>
Assert.Throws<ArgumentException>(() =>
{
using (var scope = provider.CreateScope())
{
@@ -39,7 +39,7 @@ namespace Umbraco.Tests.Persistence
public void WriteLockNonExisting()
{
var provider = TestObjects.GetScopeProvider(Logger);
Assert.Throws<Exception>(() =>
Assert.Throws<ArgumentException>(() =>
{
using (var scope = provider.CreateScope())
{
@@ -466,7 +466,7 @@ namespace Umbraco.Tests.PublishedContent
};
// notify
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(10, TreeChangeTypes.RefreshBranch) }, out _, out _);
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(10, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _);
// changes that *I* make are immediately visible on the current snapshot
var documents = snapshot.Content.GetAtRoot().ToArray();
@@ -508,7 +508,7 @@ namespace Umbraco.Tests.PublishedContent
};
// notify
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, TreeChangeTypes.RefreshBranch) }, out _, out _);
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _);
// changes that *I* make are immediately visible on the current snapshot
var documents = snapshot.Content.GetAtRoot().ToArray();
@@ -588,7 +588,7 @@ namespace Umbraco.Tests.PublishedContent
};
// notify
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(kit.Node.ParentContentId, TreeChangeTypes.RefreshBranch) }, out _, out _);
_snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(kit.Node.ParentContentId, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _);
// changes that *I* make are immediately visible on the current snapshot
var documents = snapshot.Content.GetById(kit.Node.ParentContentId).Children().ToArray();
@@ -685,8 +685,8 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
// removal must come first
new ContentCacheRefresher.JsonPayload(2, TreeChangeTypes.RefreshBranch),
new ContentCacheRefresher.JsonPayload(1, TreeChangeTypes.RefreshBranch)
new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.RefreshBranch),
new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch)
}, out _, out _);
// changes that *I* make are immediately visible on the current snapshot
@@ -881,9 +881,9 @@ namespace Umbraco.Tests.PublishedContent
// notify
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(3, TreeChangeTypes.Remove), // remove last
new ContentCacheRefresher.JsonPayload(5, TreeChangeTypes.Remove), // remove middle
new ContentCacheRefresher.JsonPayload(9, TreeChangeTypes.Remove), // remove first
new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.Remove), // remove last
new ContentCacheRefresher.JsonPayload(5, Guid.Empty, TreeChangeTypes.Remove), // remove middle
new ContentCacheRefresher.JsonPayload(9, Guid.Empty, TreeChangeTypes.Remove), // remove first
}, out _, out _);
documents = snapshot.Content.GetAtRoot().ToArray();
@@ -898,9 +898,9 @@ namespace Umbraco.Tests.PublishedContent
// notify
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(1, TreeChangeTypes.Remove), // remove first
new ContentCacheRefresher.JsonPayload(8, TreeChangeTypes.Remove), // remove
new ContentCacheRefresher.JsonPayload(7, TreeChangeTypes.Remove), // remove
new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.Remove), // remove first
new ContentCacheRefresher.JsonPayload(8, Guid.Empty, TreeChangeTypes.Remove), // remove
new ContentCacheRefresher.JsonPayload(7, Guid.Empty, TreeChangeTypes.Remove), // remove
}, out _, out _);
documents = snapshot.Content.GetAtRoot().ToArray();
@@ -930,8 +930,8 @@ namespace Umbraco.Tests.PublishedContent
// notify
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(1, TreeChangeTypes.RefreshBranch),
new ContentCacheRefresher.JsonPayload(2, TreeChangeTypes.RefreshNode),
new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch),
new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.RefreshNode),
}, out _, out _);
documents = snapshot.Content.GetAtRoot().ToArray();
@@ -987,7 +987,7 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(2, TreeChangeTypes.Remove)
new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.Remove)
}, out _, out _);
parentNodes = contentStore.Test.GetValues(1);
@@ -1046,7 +1046,7 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(3, TreeChangeTypes.Remove) //remove middle child
new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.Remove) //remove middle child
}, out _, out _);
Assert.AreEqual(2, contentStore.Test.LiveGen);
@@ -1114,7 +1114,7 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(1, TreeChangeTypes.RefreshNode)
new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshNode)
}, out _, out _);
Assert.AreEqual(2, contentStore.Test.LiveGen);
@@ -1134,7 +1134,7 @@ namespace Umbraco.Tests.PublishedContent
/// 2) Save and publish it
/// 3) Publish it with descendants
/// 4) Repeat steps 2 and 3
///
///
/// Which has caused an exception. To replicate this test:
/// 1) RefreshBranch with kits for a branch where the top most node is unpublished
/// 2) RefreshBranch with kits for the branch where the top most node is published
@@ -1162,7 +1162,7 @@ namespace Umbraco.Tests.PublishedContent
//children of 1
yield return CreateInvariantKit(20, 1, 1, paths);
yield return CreateInvariantKit(30, 1, 2, paths);
yield return CreateInvariantKit(30, 1, 2, paths);
yield return CreateInvariantKit(40, 1, 3, paths);
}
@@ -1189,7 +1189,7 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(1, changeType)
new ContentCacheRefresher.JsonPayload(1, Guid.Empty, changeType)
}, out _, out _);
Assert.AreEqual(assertGen, contentStore.Test.LiveGen);
@@ -1199,12 +1199,12 @@ namespace Umbraco.Tests.PublishedContent
var (gen, contentNode) = contentStore.Test.GetValues(1)[0];
Assert.AreEqual(assertGen, gen);
//even when unpublishing/re-publishing/etc... the linked list is always maintained
AssertLinkedNode(contentNode, 100, 2, 3, 20, 40);
AssertLinkedNode(contentNode, 100, 2, 3, 20, 40);
}
//unpublish the root
ChangePublishFlagOfRoot(false, 2, TreeChangeTypes.RefreshBranch);
//publish the root (since it's not published, it will cause a RefreshBranch)
ChangePublishFlagOfRoot(true, 3, TreeChangeTypes.RefreshBranch);
@@ -1268,7 +1268,7 @@ namespace Umbraco.Tests.PublishedContent
_snapshotService.Notify(new[]
{
new ContentCacheRefresher.JsonPayload(3, TreeChangeTypes.RefreshBranch) //remove middle child
new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.RefreshBranch) //remove middle child
}, out _, out _);
Assert.AreEqual(2, contentStore.Test.LiveGen);
@@ -1616,7 +1616,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(descendants.All(x => x.Path.StartsWith("-1,-20,")));
Assert.True(descendants.All(x => x.Trashed));
contentService.EmptyRecycleBin();
contentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var trashed = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
Assert.IsEmpty(trashed);
}
@@ -1628,7 +1628,7 @@ namespace Umbraco.Tests.Services
var contentService = ServiceContext.ContentService;
// Act
contentService.EmptyRecycleBin();
contentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
// Assert
@@ -1804,7 +1804,7 @@ namespace Umbraco.Tests.Services
// Act
ServiceContext.ContentService.MoveToRecycleBin(content1);
ServiceContext.ContentService.EmptyRecycleBin();
ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId);
var contents = ServiceContext.ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList();
// Assert
@@ -105,13 +105,26 @@ namespace Umbraco.Tests.Services
}
}
[Test]
public void Change_Content_Type_Variation_Clears_Redirects()
[TestCase(ContentVariation.Nothing, ContentVariation.Nothing, false)]
[TestCase(ContentVariation.Nothing, ContentVariation.Culture, true)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment, true)]
[TestCase(ContentVariation.Nothing, ContentVariation.Segment, true)]
[TestCase(ContentVariation.Culture, ContentVariation.Nothing, true)]
[TestCase(ContentVariation.Culture, ContentVariation.Culture, false)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment, true)]
[TestCase(ContentVariation.Culture, ContentVariation.CultureAndSegment, true)]
[TestCase(ContentVariation.Segment, ContentVariation.Nothing, true)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture, true)]
[TestCase(ContentVariation.Segment, ContentVariation.Segment, false)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment, true)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing, true)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Culture, true)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment, true)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment, false)]
public void Change_Content_Type_Variation_Clears_Redirects(ContentVariation startingContentTypeVariation, ContentVariation changedContentTypeVariation, bool shouldUrlRedirectsBeCleared)
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Nothing;
var properties = CreatePropertyCollection(("title", ContentVariation.Nothing));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = startingContentTypeVariation;
ServiceContext.ContentTypeService.Save(contentType);
var contentType2 = MockedContentTypes.CreateBasicContentType("test");
ServiceContext.ContentTypeService.Save(contentType2);
@@ -119,6 +132,11 @@ namespace Umbraco.Tests.Services
//create some content of this content type
IContent doc = MockedContent.CreateBasicContent(contentType);
doc.Name = "Hello1";
if(startingContentTypeVariation.HasFlag(ContentVariation.Culture))
{
doc.SetCultureName(doc.Name, "en-US");
}
ServiceContext.ContentService.Save(doc);
IContent doc2 = MockedContent.CreateBasicContent(contentType2);
@@ -127,24 +145,27 @@ namespace Umbraco.Tests.Services
ServiceContext.RedirectUrlService.Register("hello/world", doc.Key);
ServiceContext.RedirectUrlService.Register("hello2/world2", doc2.Key);
// These 2 assertions should probably be moved to a test for the Register() method?
Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count());
Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count());
//change variation
contentType.Variations = ContentVariation.Culture;
contentType.Variations = changedContentTypeVariation;
ServiceContext.ContentTypeService.Save(contentType);
Assert.AreEqual(0, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count());
var expectedRedirectUrlCount = shouldUrlRedirectsBeCleared ? 0 : 1;
Assert.AreEqual(expectedRedirectUrlCount, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count());
Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count());
}
[Test]
public void Change_Content_Type_From_Invariant_Variant()
{
[TestCase(ContentVariation.Nothing, ContentVariation.Culture)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)]
public void Change_Content_Type_From_No_Culture_To_Culture(ContentVariation from, ContentVariation to)
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Nothing;
var properties = CreatePropertyCollection(("title", ContentVariation.Nothing));
contentType.Variations = from;
var properties = CreatePropertyCollection(("title", from));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
@@ -159,12 +180,12 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("Hello1", doc.Name);
Assert.AreEqual("hello world", doc.GetValue("title"));
Assert.IsTrue(doc.Edited);
Assert.IsFalse (doc.IsCultureEdited("en-US"));
Assert.IsFalse(doc.IsCultureEdited("en-US"));
//change the content type to be variant, we will also update the name here to detect the copy changes
doc.Name = "Hello2";
ServiceContext.ContentService.Save(doc);
contentType.Variations = ContentVariation.Culture;
contentType.Variations = to;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -176,7 +197,7 @@ namespace Umbraco.Tests.Services
//change back property type to be invariant, we will also update the name here to detect the copy changes
doc.SetCultureName("Hello3", "en-US");
ServiceContext.ContentService.Save(doc);
contentType.Variations = ContentVariation.Nothing;
contentType.Variations = from;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -186,12 +207,15 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(doc.IsCultureEdited("en-US"));
}
[Test]
public void Change_Content_Type_From_Variant_Invariant()
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
public void Change_Content_Type_From_Culture_To_No_Culture(ContentVariation startingContentTypeVariation, ContentVariation changeContentTypeVariationTo)
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Culture;
var properties = CreatePropertyCollection(("title", ContentVariation.Culture));
contentType.Variations = startingContentTypeVariation;
var properties = CreatePropertyCollection(("title", startingContentTypeVariation));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
@@ -210,7 +234,7 @@ namespace Umbraco.Tests.Services
//change the content type to be invariant, we will also update the name here to detect the copy changes
doc.SetCultureName("Hello2", "en-US");
ServiceContext.ContentService.Save(doc);
contentType.Variations = ContentVariation.Nothing;
contentType.Variations = changeContentTypeVariationTo;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -222,19 +246,20 @@ namespace Umbraco.Tests.Services
//change back property type to be variant, we will also update the name here to detect the copy changes
doc.Name = "Hello3";
ServiceContext.ContentService.Save(doc);
contentType.Variations = ContentVariation.Culture;
contentType.Variations = startingContentTypeVariation;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
//at this stage all property types were switched to invariant so even though the variant value
//exists it will not be returned because the property type is invariant,
//so this check proves that null will be returned
Assert.AreEqual("Hello3", doc.Name);
Assert.IsNull(doc.GetValue("title", "en-US"));
Assert.IsTrue(doc.Edited);
Assert.IsTrue(doc.IsCultureEdited("en-US")); // this is true because the name change is copied to the default language
//we can now switch the property type to be variant and the value can be returned again
contentType.PropertyTypes.First().Variations = ContentVariation.Culture;
contentType.PropertyTypes.First().Variations = startingContentTypeVariation;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -242,32 +267,129 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("hello world", doc.GetValue("title", "en-US"));
Assert.IsTrue(doc.Edited);
Assert.IsTrue(doc.IsCultureEdited("en-US"));
}
[Test]
public void Change_Property_Type_From_To_Variant_On_Invariant_Content_Type()
[TestCase(ContentVariation.Nothing, ContentVariation.Nothing)]
[TestCase(ContentVariation.Nothing, ContentVariation.Culture)]
[TestCase(ContentVariation.Nothing, ContentVariation.Segment)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Culture)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.Culture, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Segment, ContentVariation.Nothing)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture)]
[TestCase(ContentVariation.Segment, ContentVariation.Segment)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Culture)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment)]
public void Preserve_Content_Name_After_Content_Type_Variation_Change(ContentVariation contentTypeVariationFrom, ContentVariation contentTypeVariationTo)
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Nothing;
var properties = CreatePropertyCollection(("title", ContentVariation.Nothing));
contentType.Variations = contentTypeVariationFrom;
ServiceContext.ContentTypeService.Save(contentType);
var invariantContentName = "Content Invariant";
var defaultCultureContentName = "Content en-US";
var defaultCulture = "en-US";
var nlContentName = "Content nl-NL";
var nlCulture = "nl-NL";
ServiceContext.LocalizationService.Save(new Language(nlCulture));
var includeCultureNames = contentType.Variations.HasFlag(ContentVariation.Culture);
// Create some content of this content type
IContent doc = MockedContent.CreateBasicContent(contentType);
doc.Name = invariantContentName;
if (includeCultureNames)
{
Assert.DoesNotThrow(() => doc.SetCultureName(defaultCultureContentName, defaultCulture));
Assert.DoesNotThrow(() => doc.SetCultureName(nlContentName, nlCulture));
} else
{
Assert.Throws<NotSupportedException>(() => doc.SetCultureName(defaultCultureContentName, defaultCulture));
Assert.Throws<NotSupportedException>(() => doc.SetCultureName(nlContentName, nlCulture));
}
ServiceContext.ContentService.Save(doc);
doc = ServiceContext.ContentService.GetById(doc.Id);
AssertAll();
// Change variation
contentType.Variations = contentTypeVariationTo;
ServiceContext.ContentService.Save(doc);
doc = ServiceContext.ContentService.GetById(doc.Id);
AssertAll();
void AssertAll()
{
if (includeCultureNames)
{
// Invariant content name is not preserved when content type is set to culture
Assert.AreEqual(defaultCultureContentName, doc.Name);
Assert.AreEqual(doc.Name, doc.GetCultureName(defaultCulture));
Assert.AreEqual(nlContentName, doc.GetCultureName(nlCulture));
}
else
{
Assert.AreEqual(invariantContentName, doc.Name);
Assert.AreEqual(null, doc.GetCultureName(defaultCulture));
Assert.AreEqual(null, doc.GetCultureName(nlCulture));
}
}
}
[TestCase(ContentVariation.Nothing, ContentVariation.Nothing)]
[TestCase(ContentVariation.Nothing, ContentVariation.Culture)]
[TestCase(ContentVariation.Nothing, ContentVariation.Segment)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Culture)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.Culture, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Segment, ContentVariation.Nothing)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture)]
[TestCase(ContentVariation.Segment, ContentVariation.Segment)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Culture)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment)]
public void Verify_If_Property_Type_Variation_Is_Correctly_Corrected_When_Content_Type_Is_Updated(ContentVariation contentTypeVariation, ContentVariation propertyTypeVariation)
{
var contentType = MockedContentTypes.CreateBasicContentType();
// We test an updated content type so it has to be saved first.
ServiceContext.ContentTypeService.Save(contentType);
// Update it
contentType.Variations = contentTypeVariation;
var properties = CreatePropertyCollection(("title", propertyTypeVariation));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
//change the property type to be variant
contentType.PropertyTypes.First().Variations = ContentVariation.Culture;
//Cannot change a property type to be variant if the content type itself is not variant
Assert.Throws<InvalidOperationException>(() => ServiceContext.ContentTypeService.Save(contentType));
// Check if property type variations have been updated correctly
Assert.AreEqual(properties.First().Variations, contentTypeVariation & propertyTypeVariation);
}
[Test]
public void Change_Property_Type_From_Invariant_Variant()
[TestCase(ContentVariation.Nothing, ContentVariation.Culture)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)]
public void Change_Property_Type_From_Invariant_Variant(ContentVariation invariant, ContentVariation variant)
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Culture;
var properties = CreatePropertyCollection(("title", ContentVariation.Nothing));
// content type supports all variations
contentType.Variations = ContentVariation.Culture | ContentVariation.Segment;
var properties = CreatePropertyCollection(("title", invariant));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
@@ -283,7 +405,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(doc.Edited);
//change the property type to be variant
contentType.PropertyTypes.First().Variations = ContentVariation.Culture;
contentType.PropertyTypes.First().Variations = variant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -292,7 +414,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(doc.Edited);
//change back property type to be invariant
contentType.PropertyTypes.First().Variations = ContentVariation.Nothing;
contentType.PropertyTypes.First().Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
@@ -301,13 +423,17 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(doc.Edited);
}
[Test]
public void Change_Property_Type_From_Variant_Invariant()
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
public void Change_Property_Type_From_Variant_Invariant(ContentVariation variant, ContentVariation invariant)
{
//create content type with a property type that varies by culture
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Culture;
var properties = CreatePropertyCollection(("title", ContentVariation.Culture));
// content type supports all variations
contentType.Variations = ContentVariation.Culture | ContentVariation.Segment;
var properties = CreatePropertyCollection(("title", variant));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
@@ -320,33 +446,37 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("hello world", doc.GetValue("title", "en-US"));
//change the property type to be invariant
contentType.PropertyTypes.First().Variations = ContentVariation.Nothing;
contentType.PropertyTypes.First().Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
Assert.AreEqual("hello world", doc.GetValue("title"));
//change back property type to be variant
contentType.PropertyTypes.First().Variations = ContentVariation.Culture;
contentType.PropertyTypes.First().Variations = variant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
Assert.AreEqual("hello world", doc.GetValue("title", "en-US"));
}
[Test]
public void Change_Property_Type_From_Variant_Invariant_On_A_Composition()
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
public void Change_Property_Type_From_Variant_Invariant_On_A_Composition(ContentVariation variant, ContentVariation invariant)
{
//create content type with a property type that varies by culture
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Culture;
var properties = CreatePropertyCollection(("title", ContentVariation.Culture));
// content type supports all variations
contentType.Variations = ContentVariation.Culture | ContentVariation.Segment;
var properties = CreatePropertyCollection(("title", variant));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
//compose this from the other one
var contentType2 = MockedContentTypes.CreateBasicContentType("test");
contentType2.Variations = ContentVariation.Culture;
contentType2.Variations = contentType.Variations;
contentType2.AddContentType(contentType);
ServiceContext.ContentTypeService.Save(contentType2);
@@ -362,7 +492,7 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.Save(doc2);
//change the property type to be invariant
contentType.PropertyTypes.First().Variations = ContentVariation.Nothing;
contentType.PropertyTypes.First().Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get
@@ -371,7 +501,7 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("hello world", doc2.GetValue("title"));
//change back property type to be variant
contentType.PropertyTypes.First().Variations = ContentVariation.Culture;
contentType.PropertyTypes.First().Variations = variant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get
@@ -380,19 +510,22 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("hello world", doc2.GetValue("title", "en-US"));
}
[Test]
public void Change_Content_Type_From_Variant_Invariant_On_A_Composition()
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
public void Change_Content_Type_From_Variant_Invariant_On_A_Composition(ContentVariation variant, ContentVariation invariant)
{
//create content type with a property type that varies by culture
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Variations = ContentVariation.Culture;
contentType.Variations = variant;
var properties = CreatePropertyCollection(("title", ContentVariation.Culture));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
//compose this from the other one
var contentType2 = MockedContentTypes.CreateBasicContentType("test");
contentType2.Variations = ContentVariation.Culture;
contentType2.Variations = contentType.Variations;
contentType2.AddContentType(contentType);
ServiceContext.ContentTypeService.Save(contentType2);
@@ -408,7 +541,7 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.Save(doc2);
//change the content type to be invariant
contentType.Variations = ContentVariation.Nothing;
contentType.Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get
@@ -417,7 +550,7 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("hello world", doc2.GetValue("title"));
//change back content type to be variant
contentType.Variations = ContentVariation.Culture;
contentType.Variations = variant;
ServiceContext.ContentTypeService.Save(contentType);
doc = ServiceContext.ContentService.GetById(doc.Id); //re-get
doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get
@@ -693,22 +826,25 @@ namespace Umbraco.Tests.Services
"{'properties':{'value1':[{'culture':'en','seg':'','val':'v1en'},{'culture':'fr','seg':'','val':'v1fr'}],'value2':[{'culture':'en','seg':'','val':'v2'}]},'cultureData':");
}
[Test]
public void Change_Property_Variations_From_Variant_To_Invariant_And_Ensure_Edited_Values_Are_Renormalized()
[TestCase(ContentVariation.Culture, ContentVariation.Nothing)]
[TestCase(ContentVariation.Culture, ContentVariation.Segment)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Nothing)]
[TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)]
public void Change_Property_Variations_From_Variant_To_Invariant_And_Ensure_Edited_Values_Are_Renormalized(ContentVariation variant, ContentVariation invariant)
{
// one simple content type, variant, with both variant and invariant properties
// can change an invariant property to variant and back
CreateFrenchAndEnglishLangs();
var contentType = CreateContentType(ContentVariation.Culture);
var contentType = CreateContentType(ContentVariation.Culture | ContentVariation.Segment);
var properties = CreatePropertyCollection(("value1", ContentVariation.Culture));
var properties = CreatePropertyCollection(("value1", variant));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
var document = (IContent)new Content("document", -1, contentType);
IContent document = new Content("document", -1, contentType);
document.SetCultureName("doc1en", "en");
document.SetCultureName("doc1fr", "fr");
document.SetValue("value1", "v1en-init", "en");
@@ -737,7 +873,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(document.Edited);
// switch property type to Invariant
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Nothing;
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag
document = ServiceContext.ContentService.GetById(document.Id);
@@ -764,7 +900,7 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(document.Edited);
// switch property back to Culture
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture;
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = variant;
ServiceContext.ContentTypeService.Save(contentType);
document = ServiceContext.ContentService.GetById(document.Id);
@@ -793,17 +929,20 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(document.Edited);
}
[Test]
public void Change_Property_Variations_From_Invariant_To_Variant_And_Ensure_Edited_Values_Are_Renormalized()
[TestCase(ContentVariation.Nothing, ContentVariation.Culture)]
[TestCase(ContentVariation.Nothing, ContentVariation.CultureAndSegment)]
[TestCase(ContentVariation.Segment, ContentVariation.Culture)]
[TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)]
public void Change_Property_Variations_From_Invariant_To_Variant_And_Ensure_Edited_Values_Are_Renormalized(ContentVariation invariant, ContentVariation variant)
{
// one simple content type, variant, with both variant and invariant properties
// can change an invariant property to variant and back
CreateFrenchAndEnglishLangs();
var contentType = CreateContentType(ContentVariation.Culture);
var contentType = CreateContentType(ContentVariation.Culture | ContentVariation.Segment);
var properties = CreatePropertyCollection(("value1", ContentVariation.Nothing));
var properties = CreatePropertyCollection(("value1", invariant));
contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" });
ServiceContext.ContentTypeService.Save(contentType);
@@ -833,7 +972,7 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(document.Edited);
// switch property type to Culture
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture;
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = variant;
ServiceContext.ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag
document = ServiceContext.ContentService.GetById(document.Id);
@@ -858,7 +997,7 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(document.Edited);
// switch property back to Invariant
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Nothing;
contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = invariant;
ServiceContext.ContentTypeService.Save(contentType);
document = ServiceContext.ContentService.GetById(document.Id);
@@ -96,8 +96,7 @@ namespace Umbraco.Tests.Services
var properties = pmember.Properties.ToList();
for (var i = 0; i < aliases.Length; i++)
Assert.AreEqual(properties[i].Alias, aliases[i]);
Assert.IsTrue(properties.Select(x => x.Alias).ContainsAll(aliases));
var email = properties[aliases.IndexOf("Email")];
Assert.AreEqual("xemail", email.GetSourceValue());
@@ -329,6 +329,11 @@ namespace Umbraco.Tests.TestHelpers
{
throw new NotImplementedException();
}
public IReadOnlyDictionary<Udi, IEnumerable<string>> GetReferences(int id)
{
throw new NotImplementedException();
}
}
#endregion
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
@@ -8,6 +9,8 @@ namespace Umbraco.Tests.Testing
{
public abstract class TestOptionAttributeBase : Attribute
{
public static readonly List<Assembly> ScanAssemblies = new List<Assembly>();
public static TOptions GetTestOptions<TOptions>(MethodInfo method)
where TOptions : TestOptionAttributeBase, new()
{
@@ -28,9 +31,18 @@ namespace Umbraco.Tests.Testing
var test = TestContext.CurrentContext.Test;
var typeName = test.ClassName;
var methodName = test.MethodName;
var type = Type.GetType(typeName, true);
var type = Type.GetType(typeName, false);
if (type == null)
throw new PanicException($"Could not resolve the type from type name {typeName}"); // makes no sense
{
type = ScanAssemblies
.Select(assembly => assembly.GetType(typeName, false))
.FirstOrDefault(x => x != null);
if (type == null)
{
throw new PanicException($"Could not resolve the running test fixture from type name {typeName}.\n" +
$"To use base classes from Umbraco.Tests, add your test assembly to TestOptionAttributeBase.ScanAssemblies");
}
}
var methodInfo = type.GetMethod(methodName); // what about overloads?
var options = GetTestOptions<TOptions>(methodInfo);
return options;
@@ -7,10 +7,13 @@ using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Stubs;
@@ -19,6 +22,7 @@ using Umbraco.Web;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using Umbraco.Web.WebApi;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.Testing.TestingTests
@@ -88,5 +92,26 @@ namespace Umbraco.Tests.Testing.TestingTests
Assert.AreEqual("/hello/world/1234", theUrlProvider.GetUrl(publishedContent));
}
[Test]
public void Can_Mock_UmbracoApiController_Dependencies_With_Injected_UmbracoMapper()
{
var umbracoContext = TestObjects.GetUmbracoContextMock();
var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>());
var umbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper);
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }));
// ReSharper disable once UnusedVariable
var umbracoApiController = new FakeUmbracoApiController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), Mock.Of<ISqlContext>(), ServiceContext.CreatePartial(), AppCaches.NoCache, Mock.Of<IProfilingLogger>(), Mock.Of<IRuntimeState>(), umbracoHelper, umbracoMapper);
Assert.Pass();
}
}
internal class FakeUmbracoApiController : UmbracoApiController
{
public FakeUmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { }
public FakeUmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, UmbracoMapper umbracoMapper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, umbracoMapper) { }
}
}
+1 -1
View File
@@ -79,7 +79,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.3.1" />
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="Examine" Version="1.0.1" />
<PackageReference Include="HtmlAgilityPack">
<Version>1.8.14</Version>
</PackageReference>
@@ -7,6 +7,7 @@ using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Store;
using Moq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -44,11 +45,10 @@ namespace Umbraco.Tests.UmbracoExamine
public static MediaIndexPopulator GetMediaIndexRebuilder(PropertyEditorCollection propertyEditors, IMediaService mediaService)
{
var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), GetMockUserService());
var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }), GetMockUserService(), GetMockLogger());
var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder);
return mediaIndexDataSource;
}
public static IContentService GetMockContentService()
{
long longTotalRecs;
@@ -146,6 +146,11 @@ namespace Umbraco.Tests.UmbracoExamine
return mediaTypeServiceMock.Object;
}
public static IProfilingLogger GetMockLogger()
{
return new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
}
public static UmbracoContentIndex GetUmbracoIndexer(
IProfilingLogger profilingLogger,
Directory luceneDir,
+21 -18
View File
@@ -3,26 +3,26 @@
module.exports = {
sources: {
//less files used by backoffice and preview
//processed in the less task
// less files used by backoffice and preview
// processed in the less task
less: {
installer: { files: ["./src/less/installer.less"], out: "installer.css" },
nonodes: { files: ["./src/less/pages/nonodes.less"], out: "nonodes.style.min.css"},
preview: { files: ["./src/less/canvas-designer.less"], out: "canvasdesigner.css" },
umbraco: { files: ["./src/less/belle.less"], out: "umbraco.css" },
rteContent: { files: ["./src/less/rte-content.less"], out: "rte-content.css" }
installer: { files: "./src/less/installer.less", watch: "./src/less/**/*.less", out: "installer.css" },
nonodes: { files: "./src/less/pages/nonodes.less", watch: "./src/less/**/*.less", out: "nonodes.style.min.css"},
preview: { files: "./src/less/canvas-designer.less", watch: "./src/less/**/*.less", out: "canvasdesigner.css" },
umbraco: { files: "./src/less/belle.less", watch: "./src/less/**/*.less", out: "umbraco.css" },
rteContent: { files: "./src/less/rte-content.less", watch: "./src/less/**/*.less", out: "rte-content.css" }
},
//js files for backoffie
//processed in the js task
// js files for backoffice
// processed in the js task
js: {
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
filters: { files: ["./src/common/filters/**/*.js"], out: "umbraco.filters.js" },
resources: { files: ["./src/common/resources/**/*.js"], out: "umbraco.resources.js" },
services: { files: ["./src/common/services/**/*.js"], out: "umbraco.services.js" },
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" },
preview: { files: "./src/preview/**/*.js", out: "umbraco.preview.js" },
installer: { files: "./src/installer/**/*.js", out: "umbraco.installer.js" },
filters: { files: "./src/common/filters/**/*.js", out: "umbraco.filters.js" },
resources: { files: "./src/common/resources/**/*.js", out: "umbraco.resources.js" },
services: { files: "./src/common/services/**/*.js", out: "umbraco.services.js" },
security: { files: "./src/common/interceptors/**/*.js", out: "umbraco.interceptors.js" },
//the controllers for views
controllers: {
files: [
@@ -42,13 +42,16 @@ module.exports = {
],
out: "umbraco.directives.js"
}
},
//selectors for copying all views into the build
//processed in the views task
views:{
umbraco: {files: ["./src/views/**/*.html"], folder: ""},
installer: {files: ["./src/installer/steps/*.html"], folder: "install/"}
views: {files: "./src/views/**/*.html", folder: ""},
directives: {files: "./src/common/directives/**/*.html", folder: ""},
components: {files: "./src/common/components/**/*.html", folder: ""},
installer: {files: "./src/installer/steps/*.html", folder: "install/"}
},
//globs for file-watching
-10
View File
@@ -1,10 +0,0 @@
'use strict';
var fs = require('fs');
var onlyScripts = require('./util/scriptFilter');
var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts);
tasks.forEach(function(task) {
require('./tasks/' + task);
});
@@ -1,10 +0,0 @@
'use strict';
var config = require('../config');
var gulp = require('gulp');
var runSequence = require('run-sequence');
// Build - build the files ready for production
gulp.task('build', function(cb) {
runSequence(["js", "dependencies", "less", "views"], "test:unit", cb);
});
@@ -10,7 +10,7 @@ var imagemin = require('gulp-imagemin');
/**************************
* Task processes and copies all dependencies, either installed by npm or stored locally in the project
**************************/
gulp.task('dependencies', function () {
function dependencies() {
//as we do multiple things in this task, we merge the multiple streams
var stream = new MergeStream();
@@ -42,6 +42,11 @@ gulp.task('dependencies', function () {
"src": ["./node_modules/angular/angular.js"],
"base": "./node_modules/angular"
},
{
"name": "angular-aria",
"src": ["./node_modules/angular-aria/angular-aria.min.js"],
"base": "./node_modules/angular-aria"
},
{
"name": "angular-cookies",
"src": ["./node_modules/angular-cookies/angular-cookies.js"],
@@ -100,7 +105,7 @@ gulp.task('dependencies', function () {
"name": "angular-messages",
"src": ["./node_modules/angular-messages/angular-messages.js"],
"base": "./node_modules/angular-messages"
},
},
{
"name": "angular-mocks",
"src": ["./node_modules/angular-mocks/angular-mocks.js"],
@@ -239,54 +244,55 @@ gulp.task('dependencies', function () {
nodeModules.forEach(module => {
stream.add(
gulp.src(module.src,
{ base: module.base })
{ base: module.base, allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.lib + "/" + module.name))
);
});
//copy over libs which are not on npm (/lib)
stream.add(
gulp.src(config.sources.globs.lib)
gulp.src(config.sources.globs.lib, { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.lib))
);
//Copies all static assets into /root / assets folder
//css, fonts and image files
var assetsTask = gulp.src(config.sources.globs.assets);
if (global.isProd === true) {
assetsTask = assetsTask.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({
plugins: [
{removeViewBox: true},
{cleanupIDs: false}
]
})
]));
}
var assetsTask = gulp.src(config.sources.globs.assets, { allowEmpty: true });
assetsTask = assetsTask.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({
plugins: [
{removeViewBox: true},
{cleanupIDs: false}
]
})
]));
assetsTask = assetsTask.pipe(gulp.dest(config.root + config.targets.assets));
stream.add(assetsTask);
// Copies all the less files related to the preview into their folder
//these are not pre-processed as preview has its own less combiler client side
//these are not pre-processed as preview has its own less compiler client side
stream.add(
gulp.src("src/canvasdesigner/editors/*.less")
gulp.src("src/canvasdesigner/editors/*.less", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.assets + "/less"))
);
// Todo: check if we need these fileSize
// TODO: check if we need these fileSize
stream.add(
gulp.src("src/views/propertyeditors/grid/config/*.*")
gulp.src("src/views/propertyeditors/grid/config/*.*", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.views + "/propertyeditors/grid/config"))
);
stream.add(
gulp.src("src/views/dashboard/default/*.jpg")
gulp.src("src/views/dashboard/default/*.jpg", { allowEmpty: true })
.pipe(gulp.dest(config.root + config.targets.views + "/dashboard/default"))
);
return stream;
});
};
module.exports = { dependencies: dependencies };

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