From c478945373e88aed3b51cc03a7a2d794d4be438e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Aug 2020 12:14:35 +0200 Subject: [PATCH 01/37] Ability to put property label on top of editor --- .../PropertyEditors/DataValueEditor.cs | 6 ++++++ .../PropertyEditors/IDataValueEditor.cs | 5 +++++ src/Umbraco.Web.UI.Client/src/less/main.less | 20 ++++++++++++++++++- .../components/property/umb-property.html | 2 +- .../ContentEditing/ContentPropertyDisplay.cs | 3 +++ .../Mapping/ContentPropertyDisplayMapper.cs | 1 + .../BlockEditorPropertyEditor.cs | 19 +++++++++++++++++- .../PropertyEditors/BlockListConfiguration.cs | 3 +++ 8 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index c4380f032c..51b6fbde76 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -133,6 +133,12 @@ namespace Umbraco.Core.PropertyEditors [JsonProperty("hideLabel")] public bool HideLabel { get; set; } + /// + /// If this is true the associated label will be placed on top to provide full width for the editor. + /// + [JsonProperty("labelOnTop")] + public bool LabelOnTop { get; set; } + /// /// Set this to true if the property editor is for display purposes only /// diff --git a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs index a02fa71ec7..f9e82d8bd0 100644 --- a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs @@ -35,6 +35,11 @@ namespace Umbraco.Core.PropertyEditors /// bool HideLabel { get; } + /// + /// Gets a value indicating whether to display the associated label on top of the controls. + /// + bool LabelOnTop { get; } + /// /// Validates a property value. /// diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 2354e96d38..1791c26d5b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -238,9 +238,27 @@ umb-property:last-of-type .umb-control-group { .form-horizontal .umb-control-group .control-header { float: none; width: 100%; + &::after { + content: ""; + display: table; + clear: both; + } } - +} +.form-horizontal .umb-control-group.--label-on-top > .umb-el-wrap { + & > .control-header { + float: none; + width: 100%; + &::after { + content: ""; + display: table; + clear: both; + } + } + & > .controls { + margin-left: 0; + } } /* LABELS*/ diff --git a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html index 14ca023046..45107748f0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/property/umb-property.html @@ -1,7 +1,7 @@
+ ng-class="{'hidelabel':vm.property.hideLabel, '--label-on-top':vm.property.labelOnTop, 'umb-control-group__listview': vm.property.alias === '_umb_containerView'}"> diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs index 39a4718dd0..9a07d29a02 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs @@ -33,6 +33,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "hideLabel")] public bool HideLabel { get; set; } + [DataMember(Name = "labelOnTop")] + public bool LabelOnTop { get; set; } + [DataMember(Name = "validation")] public PropertyTypeValidation Validation { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs index d81f81abe2..22d85c1aca 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs @@ -39,6 +39,7 @@ namespace Umbraco.Web.Models.Mapping dest.Description = originalProp.PropertyType.Description; dest.Label = originalProp.PropertyType.Name; dest.HideLabel = valEditor.HideLabel; + dest.LabelOnTop = valEditor.LabelOnTop; //add the validation information dest.Validation.Mandatory = originalProp.PropertyType.Mandatory; diff --git a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs index 18ea3e1e9d..b99ff06223 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors internal class BlockEditorPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly PropertyEditorCollection _propertyEditors; - private readonly IDataTypeService _dataTypeService; + private readonly IDataTypeService _dataTypeService; private readonly ILogger _logger; private readonly BlockEditorValues _blockEditorValues; @@ -91,6 +91,23 @@ namespace Umbraco.Web.PropertyEditors return result; } + + /// + public override object Configuration + { + get => base.Configuration; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + if (!(value is BlockListConfiguration configuration)) + throw new ArgumentException($"Expected a {typeof(BlockListConfiguration).Name}, but got {value.GetType().Name}.", nameof(value)); + base.Configuration = value; + + LabelOnTop = configuration.LabelOnTop.TryConvertTo().Result; + } + } + #region Convert database // editor // note: there is NO variant support here diff --git a/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs b/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs index e461da40dc..11abca529d 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs @@ -70,6 +70,9 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("maxPropertyWidth", "Property editor width", "textstring", Description = "optional css overwrite, example: 800px or 100%")] public string MaxPropertyWidth { get; set; } + [ConfigurationField("labelOnTop", "Label on top", "boolean", Description = "Move the property label on top to provide move space for the editor.")] + public bool LabelOnTop { get; set; } + } } From 41359a6544424656ef12c9525640c5b454ae7b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 14 Aug 2020 14:55:31 +0200 Subject: [PATCH 02/37] adjust spacing --- src/Umbraco.Web.UI.Client/src/less/main.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 1791c26d5b..45d61c167e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -221,6 +221,7 @@ umb-property:last-of-type .umb-control-group { padding-top: 5px; padding-bottom: 0; text-align: left; + margin-bottom: 5px; .control-label { width: auto; @@ -230,7 +231,7 @@ umb-property:last-of-type .umb-control-group { .control-description { max-width:480px;// avoiding description becoming too wide when its placed on top of property. - margin-bottom: 10px; + margin-bottom: 5px; } } @media (max-width: 767px) { From d14e9ee3b422d3a52773c44324f448d3510c8952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 1 Oct 2020 17:29:52 +0200 Subject: [PATCH 03/37] revert POC approach --- .../PropertyEditors/DataValueEditor.cs | 8 +------- .../PropertyEditors/IDataValueEditor.cs | 5 ----- .../BlockEditorPropertyEditor.cs | 17 ----------------- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index 51b6fbde76..eebe5f5722 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -133,12 +133,6 @@ namespace Umbraco.Core.PropertyEditors [JsonProperty("hideLabel")] public bool HideLabel { get; set; } - /// - /// If this is true the associated label will be placed on top to provide full width for the editor. - /// - [JsonProperty("labelOnTop")] - public bool LabelOnTop { get; set; } - /// /// Set this to true if the property editor is for display purposes only /// @@ -210,7 +204,7 @@ namespace Umbraco.Core.PropertyEditors /// /// /// By default this will attempt to automatically convert the string value to the value type supplied by ValueType. - /// + /// /// If overridden then the object returned must match the type supplied in the ValueType, otherwise persisting the /// value to the DB will fail when it tries to validate the value type. /// diff --git a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs index f9e82d8bd0..a02fa71ec7 100644 --- a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs @@ -35,11 +35,6 @@ namespace Umbraco.Core.PropertyEditors /// bool HideLabel { get; } - /// - /// Gets a value indicating whether to display the associated label on top of the controls. - /// - bool LabelOnTop { get; } - /// /// Validates a property value. /// diff --git a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs index b99ff06223..8c4ebf49c3 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockEditorPropertyEditor.cs @@ -91,23 +91,6 @@ namespace Umbraco.Web.PropertyEditors return result; } - - /// - public override object Configuration - { - get => base.Configuration; - set - { - if (value == null) - throw new ArgumentNullException(nameof(value)); - if (!(value is BlockListConfiguration configuration)) - throw new ArgumentException($"Expected a {typeof(BlockListConfiguration).Name}, but got {value.GetType().Name}.", nameof(value)); - base.Configuration = value; - - LabelOnTop = configuration.LabelOnTop.TryConvertTo().Result; - } - } - #region Convert database // editor // note: there is NO variant support here From c264cc9691e637f13db9b1835343e67ab81a7b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 1 Oct 2020 17:30:03 +0200 Subject: [PATCH 04/37] configure label position on Property level --- src/Umbraco.Core/Models/PropertyType.cs | 13 ++++++- .../components/umbgroupsbuilder.directive.js | 7 ++-- .../services/umbdataformatter.service.js | 6 ++-- .../propertysettings.controller.js | 36 +++++++++++-------- .../propertysettings/propertysettings.html | 15 ++++++++ src/Umbraco.Web.UI/Umbraco/config/lang/da.xml | 2 ++ src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 4 ++- .../Umbraco/config/lang/en_us.xml | 2 ++ .../ContentEditing/PropertyTypeBasic.cs | 3 ++ .../Mapping/ContentPropertyDisplayMapper.cs | 2 +- .../Mapping/ContentTypeMapDefinition.cs | 3 ++ 11 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 75c2a7cc00..abdbbfd8db 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -31,6 +31,7 @@ namespace Umbraco.Core.Models private string _validationRegExp; private string _validationRegExpMessage; private ContentVariation _variations; + private bool _labelOnTop; /// /// Initializes a new instance of the class. @@ -205,6 +206,16 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _mandatoryMessage, nameof(MandatoryMessage)); } + /// + /// Gets or sets a value indicating whether the label of this property type should be displayed on top. + /// + [DataMember] + public bool LabelOnTop + { + get => _labelOnTop; + set => SetPropertyValueAndDetectChanges(value, ref _labelOnTop, nameof(LabelOnTop)); + } + /// /// Gets of sets the sort order of the property type. /// @@ -438,7 +449,7 @@ namespace Umbraco.Core.Models base.PerformDeepClone(clone); var clonedEntity = (PropertyType)clone; - + //need to manually assign the Lazy value as it will not be automatically mapped if (PropertyGroupId != null) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 92d2df43e5..5b3468bcfe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -323,12 +323,12 @@ filterAvailableCompositions(selectedContentType, newSelection).then(function () { deferred.resolve({ selectedContentType, newSelection }); // TODO: Here we could probably re-enable selection if we previously showed a throbber or something - }, function () { + }, function () { deferred.reject(); }); } - return deferred.promise; + return deferred.promise; } }; @@ -353,7 +353,7 @@ }), //get where used document types whereUsedContentTypeResource(scope.model.id).then(function (whereUsed) { - //pass to the dialog model the content type eg documentType or mediaType + //pass to the dialog model the content type eg documentType or mediaType scope.compositionsDialogModel.section = scope.contentType; //pass the list of 'where used' document types scope.compositionsDialogModel.whereCompositionUsed = whereUsed; @@ -566,6 +566,7 @@ property.isSensitiveValue = propertyModel.isSensitiveValue; property.allowCultureVariant = propertyModel.allowCultureVariant; property.allowSegmentVariant = propertyModel.allowSegmentVariant; + property.labelOnTop = propertyModel.labelOnTop; // update existing data types if (model.updateSameDataTypes) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index 109fff0919..c646c4833f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -83,7 +83,7 @@ }); var saveProperties = _.map(realProperties, function (p) { - var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile', 'isSensitiveData', 'allowCultureVariant', 'allowSegmentVariant'); + var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile', 'isSensitiveData', 'allowCultureVariant', 'allowSegmentVariant', 'labelOnTop'); return saveProperty; }); @@ -404,7 +404,7 @@ if (displayModel.variants && displayModel.variants.length > 1) { // Collect all invariant properties from the variants that are either the // default language variant or the default segment variant. - var defaultVariants = _.filter(displayModel.variants, function (variant) { + var defaultVariants = _.filter(displayModel.variants, function (variant) { var isDefaultLanguage = variant.language && variant.language.isDefault; var isDefaultSegment = variant.segment == null; @@ -433,7 +433,7 @@ return variant !== defaultVariant; }); - // now assign this same invariant property instance to the same index of the other variants property array + // now assign this same invariant property instance to the same index of the other variants property array _.each(otherVariants, function (variant) { _.each(invariantProps, function (invProp) { var tab = variant.tabs[invProp.tabIndex]; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js index 6310545b20..3c09745f15 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js @@ -35,6 +35,7 @@ vm.toggleShowOnMemberProfile = toggleShowOnMemberProfile; vm.toggleMemberCanEdit = toggleMemberCanEdit; vm.toggleIsSensitiveData = toggleIsSensitiveData; + vm.toggleLabelOnTop = toggleLabelOnTop; function onInit() { @@ -42,23 +43,24 @@ vm.showSensitiveData = user.userGroups.indexOf("sensitiveData") != -1; }); - //make the default the same as the content type + //make the default the same as the content type if (!$scope.model.property.dataTypeId) { $scope.model.property.allowCultureVariant = $scope.model.contentTypeAllowCultureVariant; } - + loadValidationTypes(); - + } function loadValidationTypes() { var labels = [ - "validation_validateAsEmail", - "validation_validateAsNumber", - "validation_validateAsUrl", + "validation_validateAsEmail", + "validation_validateAsNumber", + "validation_validateAsUrl", "validation_enterCustomValidation", - "validation_fieldIsMandatory" + "validation_fieldIsMandatory", + "contentTypeEditor_displaySettingsLabelOnTop" ]; localizationService.localizeMany(labels) @@ -69,6 +71,7 @@ vm.labels.validateAsUrl = data[2]; vm.labels.customValidation = data[3]; vm.labels.fieldIsMandatory = data[4]; + vm.labels.displaySettingsLabelOnTop = data[5]; vm.validationTypes = [ { @@ -121,7 +124,7 @@ $scope.model.updateSameDataTypes = model.updateSameDataTypes; vm.focusOnMandatoryField = true; - + // update property property.config = model.property.config; property.editor = model.property.editor; @@ -179,7 +182,7 @@ if(event && event.keyCode === 13) { submit(); } - } + } function submit() { if($scope.model.submit) { @@ -245,28 +248,31 @@ return !settingValue; } - function toggleAllowCultureVariants() { + function toggleAllowCultureVariants() { $scope.model.property.allowCultureVariant = toggleValue($scope.model.property.allowCultureVariant); } - function toggleAllowSegmentVariants() { + function toggleAllowSegmentVariants() { $scope.model.property.allowSegmentVariant = toggleValue($scope.model.property.allowSegmentVariant); } function toggleValidation() { - $scope.model.property.validation.mandatory = toggleValue($scope.model.property.validation.mandatory); + $scope.model.property.validation.mandatory = toggleValue($scope.model.property.validation.mandatory); } function toggleShowOnMemberProfile() { - $scope.model.property.showOnMemberProfile = toggleValue($scope.model.property.showOnMemberProfile); + $scope.model.property.showOnMemberProfile = toggleValue($scope.model.property.showOnMemberProfile); } function toggleMemberCanEdit() { - $scope.model.property.memberCanEdit = toggleValue($scope.model.property.memberCanEdit); + $scope.model.property.memberCanEdit = toggleValue($scope.model.property.memberCanEdit); } function toggleIsSensitiveData() { - $scope.model.property.isSensitiveData = toggleValue($scope.model.property.isSensitiveData); + $scope.model.property.isSensitiveData = toggleValue($scope.model.property.isSensitiveData); + } + function toggleLabelOnTop() { + $scope.model.property.labelOnTop = toggleValue($scope.model.property.labelOnTop); } onInit(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index af9295f1ed..482345c3b3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -135,6 +135,21 @@ ng-if="vm.showValidationPattern" ng-keypress="vm.submitOnEnter($event)" /> +
+
+ +
+ + + +
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml index 52f4dc1392..c85399e091 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/da.xml @@ -1437,6 +1437,8 @@ Mange hilsner fra Umbraco robotten En Element-type er tiltænkt brug i f.eks. Nested Content, ikke i indholdstræet. Dette benyttes ikke for en Element-type Du har lavet ændringer til denne egenskab. Er du sikker på at du vil kassere dem? + Visning + Flyt label over editoren Tilføj sprog diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 07cec3dff7..020b256c60 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -515,7 +515,7 @@ Select snippet This will delete the node and all its languages. If you only want to delete one language, you should unpublish the node in that language instead. %0%.]]> - %0% from the %1% group]]> + %0% from the %1% group]]> Yes, remove @@ -1695,6 +1695,8 @@ To manage your website, simply open the Umbraco back office and start adding con A document type cannot be changed to an Element type once it has been used to create one or more content items. This is not applicable for an Element type You have made changes to this property. Are you sure you want to discard them? + Appearance + Display label on top of editor. Add language diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index cdb2137e7b..d8833558e8 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1715,6 +1715,8 @@ To manage your website, simply open the Umbraco back office and start adding con A document type cannot be changed to an element type once it has been used to create one or more content items. This is not applicable for an element type You have made changes to this property. Are you sure you want to discard them? + Appearance + Display label on top of editor. Add language diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs index 4252a29567..793e4e391d 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeBasic.cs @@ -65,5 +65,8 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "allowSegmentVariant")] public bool AllowSegmentVariant { get; set; } + + [DataMember(Name = "labelOnTop")] + public bool LabelOnTop { get; set; } } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs index 22d85c1aca..37fd2b2e28 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs @@ -39,7 +39,7 @@ namespace Umbraco.Web.Models.Mapping dest.Description = originalProp.PropertyType.Description; dest.Label = originalProp.PropertyType.Name; dest.HideLabel = valEditor.HideLabel; - dest.LabelOnTop = valEditor.LabelOnTop; + dest.LabelOnTop = originalProp.PropertyType.LabelOnTop; //add the validation information dest.Validation.Mandatory = originalProp.PropertyType.Mandatory; diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs index b0d4c6b2e0..f67a5df56c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs @@ -242,6 +242,7 @@ namespace Umbraco.Web.Models.Mapping target.Alias = source.Alias; target.Description = source.Description; target.SortOrder = source.SortOrder; + target.LabelOnTop = source.LabelOnTop; } // no MapAll - take care @@ -353,6 +354,7 @@ namespace Umbraco.Web.Models.Mapping target.Label = source.Label; target.SortOrder = source.SortOrder; target.Validation = source.Validation; + target.LabelOnTop = source.LabelOnTop; } // Umbraco.Code.MapAll -Editor -View -Config -ContentTypeId -ContentTypeName -Locked -DataTypeIcon -DataTypeName @@ -373,6 +375,7 @@ namespace Umbraco.Web.Models.Mapping target.MemberCanViewProperty = source.MemberCanViewProperty; target.SortOrder = source.SortOrder; target.Validation = source.Validation; + target.LabelOnTop = source.LabelOnTop; } // Umbraco.Code.MapAll -CreatorId -Level -SortOrder -Variations From 433d9ac186cc2bbceb6af1ad85bc07ee60cb382f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 2 Oct 2020 09:49:25 +0200 Subject: [PATCH 05/37] init labelOnTop --- .../common/directives/components/umbgroupsbuilder.directive.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 5b3468bcfe..06e1c61f1e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -648,7 +648,8 @@ mandatoryMessage: null, pattern: null, patternMessage: null - } + }, + labelOnTop: false }; // check if there already is an init property From e5ba2ca78cbad73e192f92965a5e0b7115846a2c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 2 Oct 2020 11:36:50 +0100 Subject: [PATCH 06/37] Migration to add new DB column to PropertyTypeDto for LabelOnTop --- .../Migrations/Upgrade/UmbracoPlan.cs | 5 ++++- .../AddPropertyTypeLabelOnTopColumn.cs | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 03ba58d15e..f48622b8da 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -193,7 +193,10 @@ namespace Umbraco.Core.Migrations.Upgrade // to 8.7.0... To("{a78e3369-8ea3-40ec-ad3f-5f76929d2b20}"); - + + // to 8.10.0... + To("{D6A8D863-38EC-44FB-91EC-ACD6A668BD18}"); + //FINAL } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs new file mode 100644 index 0000000000..a9fcdd8f98 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs @@ -0,0 +1,20 @@ +using System.Linq; +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0 +{ + + public class AddPropertyTypeLabelOnTopColumn : MigrationBase + { + public AddPropertyTypeLabelOnTopColumn(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList(); + + AddColumnIfNotExists(columns, "labelOnTop"); + } + } +} From 1b7f095048f0abac7f0d0ef3f47da8c8123f3234 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 2 Oct 2020 13:32:23 +0100 Subject: [PATCH 07/37] Trying to get the model mapping done correctly - but still stuggling. This can be persisited to DB correctly but does not hydrate model correctly back to a model --- .../Persistence/Dtos/PropertyTypeDto.cs | 4 ++++ .../Factories/PropertyGroupFactory.cs | 3 ++- .../Persistence/Mappers/PropertyTypeMapper.cs | 1 + src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Mapping/ContentTypeModelMappingTests.cs | 17 ++++++++++++----- .../Repositories/ContentTypeRepositoryTest.cs | 14 ++++++++++++-- .../TestHelpers/Entities/MockedContentTypes.cs | 6 +++--- .../Mapping/ContentPropertyMapDefinition.cs | 2 +- .../Models/Mapping/PropertyTypeGroupMapper.cs | 1 + 9 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs index 3e8d6e7496..572201c94a 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs @@ -62,6 +62,10 @@ namespace Umbraco.Core.Persistence.Dtos [Length(2000)] public string Description { get; set; } + [Column("labelOnTop")] + [Constraint(Default = "0")] + public bool LabelOnTop { get; set; } + [Column("variations")] [Constraint(Default = "1" /*ContentVariation.InvariantNeutral*/)] public byte Variations { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index dc1629e8f7..f139619302 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -132,7 +132,8 @@ namespace Umbraco.Core.Persistence.Factories ValidationRegExp = propertyType.ValidationRegExp, ValidationRegExpMessage = propertyType.ValidationRegExpMessage, UniqueId = propertyType.Key, - Variations = (byte)propertyType.Variations + Variations = (byte)propertyType.Variations, + LabelOnTop = propertyType.LabelOnTop }; if (tabId != default) diff --git a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs index 6f22b61f9a..d44618cc96 100644 --- a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs @@ -29,6 +29,7 @@ namespace Umbraco.Core.Persistence.Mappers DefineMap(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder)); DefineMap(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp)); DefineMap(nameof(PropertyType.ValidationRegExpMessage), nameof(PropertyTypeDto.ValidationRegExpMessage)); + DefineMap(nameof(PropertyType.LabelOnTop), nameof(PropertyTypeDto.LabelOnTop)); DefineMap(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias)); DefineMap(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType)); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b7b9867618..e9d6d31955 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -132,6 +132,7 @@ + diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index eee7446823..679f053c5c 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -215,6 +215,7 @@ namespace Umbraco.Tests.Models.Mapping { Assert.AreEqual(propTypes.ElementAt(j).Id, result.PropertyTypes.ElementAt(j).Id); Assert.AreEqual(propTypes.ElementAt(j).DataTypeId, result.PropertyTypes.ElementAt(j).DataTypeId); + Assert.AreEqual(propTypes.ElementAt(j).LabelOnTop, result.PropertyTypes.ElementAt(j).LabelOnTop); } } @@ -449,6 +450,7 @@ namespace Umbraco.Tests.Models.Mapping { Assert.AreEqual(propTypes[j].Id, result.Groups.ElementAt(i).Properties.ElementAt(j).Id); Assert.AreEqual(propTypes[j].DataTypeId, result.Groups.ElementAt(i).Properties.ElementAt(j).DataTypeId); + Assert.AreEqual(propTypes[j].LabelOnTop, result.Groups.ElementAt(i).Properties.ElementAt(j).LabelOnTop); } } @@ -1074,7 +1076,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } } @@ -1120,7 +1123,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } }, @@ -1144,7 +1148,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = false } } @@ -1198,7 +1203,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = true } } }, @@ -1222,7 +1228,8 @@ namespace Umbraco.Tests.Models.Mapping Pattern = string.Empty }, SortOrder = 0, - DataTypeId = 555 + DataTypeId = 555, + LabelOnTop = false } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index e592c5171a..970201bc62 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -348,6 +348,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(contentType.Path.Contains(","), Is.True); Assert.That(contentType.SortOrder, Is.GreaterThan(0)); + Assert.That(contentType.PropertyGroups.ElementAt(0).Name == "testGroup", Is.True); var groupId = contentType.PropertyGroups.ElementAt(0).Id; @@ -355,6 +356,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual("gen", propertyTypes[0].Alias); // just to be sure Assert.IsNull(propertyTypes[0].PropertyGroupId); Assert.IsTrue(propertyTypes.Skip(1).All((x => x.PropertyGroupId.Value == groupId))); + Assert.That(propertyTypes[0].LabelOnTop, Is.True); } } @@ -377,7 +379,8 @@ namespace Umbraco.Tests.Persistence.Repositories Description = "Optional Subtitle", Mandatory = false, SortOrder = 1, - DataTypeId = -88 + DataTypeId = -88, + LabelOnTop = true }); repository.Save(contentType); @@ -389,6 +392,8 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(dirty, Is.False); Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png")); Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True); + Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True); + } @@ -467,7 +472,8 @@ namespace Umbraco.Tests.Persistence.Repositories Pattern = "" }, SortOrder = 1, - DataTypeId = -88 + DataTypeId = -88, + LabelOnTop = true } }); @@ -476,6 +482,7 @@ namespace Umbraco.Tests.Persistence.Repositories // just making sure Assert.AreEqual(mapped.Thumbnail, "Doc2.png"); Assert.IsTrue(mapped.PropertyTypes.Any(x => x.Alias == "subtitle")); + Assert.IsTrue(mapped.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop); repository.Save(mapped); @@ -490,6 +497,9 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(dirty, Is.False); Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png")); Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True); + + Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True); + foreach (var propertyType in contentType.PropertyTypes) { Assert.IsTrue(propertyType.HasIdentity); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index b4cd4ab05e..e3bb012dae 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -41,8 +41,8 @@ namespace Umbraco.Tests.TestHelpers.Entities }; var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox }); - contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.RichtextEditor }); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox, LabelOnTop = true }); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.RichtextEditor, LabelOnTop = false }); var metaCollection = new PropertyTypeCollection(true); metaCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { Alias = "keywords", Name = "Meta Keywords", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox }); @@ -213,7 +213,7 @@ namespace Umbraco.Tests.TestHelpers.Entities contentType.Trashed = false; var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88, LabelOnTop = true }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("author", randomizeAliases) , Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs index e6290cc19e..baa9b7be69 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapDefinition.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Models.Mapping target.Id = source.Id; target.IsActive = true; target.Label = source.Name; -} + } private void Map(Property source, ContentPropertyBasic target, MapperContext context) { diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs index adee6c6928..33fce221b4 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs @@ -222,6 +222,7 @@ namespace Umbraco.Web.Models.Mapping Id = p.Id, Alias = p.Alias, Description = p.Description, + LabelOnTop = p.LabelOnTop, Editor = p.PropertyEditorAlias, Validation = new PropertyTypeValidation { From 7e34dda1311ce027117f85b29802dcfad67a64c9 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 2 Oct 2020 15:08:24 +0100 Subject: [PATCH 08/37] Trying more things & prep for dealing with package XML for Label On Top --- src/Umbraco.Core/Packaging/PackageDataInstallation.cs | 5 ++++- src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs | 3 +++ src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs | 1 + src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 6a5acb0dc7..fac1a1d88f 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -798,7 +798,10 @@ namespace Umbraco.Core.Packaging SortOrder = sortOrder, Variations = property.Element("Variations") != null ? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value) - : ContentVariation.Nothing + : ContentVariation.Nothing, + LabelOnTop = property.Element("LabelOnTop") != null + ? property.Element("LabelOnTop").Value.ToLowerInvariant().Equals("true") + : false }; var tab = (string)property.Element("Tab"); diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs index 4c352a0134..d2001c00d5 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs @@ -44,6 +44,9 @@ namespace Umbraco.Core.Persistence.Dtos [Column("Description")] public string Description { get; set; } + [Column("labelOnTop")] + public bool LabelOnTop { get; set; } + /* cmsMemberType */ [Column("memberCanEdit")] public bool CanEdit { get; set; } diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 5189b3422e..cc329802ee 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -363,6 +363,7 @@ namespace Umbraco.Core.Services.Implement new XElement("MandatoryMessage", propertyType.MandatoryMessage), new XElement("Validation", propertyType.ValidationRegExp), new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage), + new XElement("LabelOnTop", propertyType.LabelOnTop), new XElement("Description", new XCData(propertyType.Description))); genericProperties.Add(genericProperty); } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs index 83e5e2a9b2..9702202294 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs @@ -18,6 +18,8 @@ namespace Umbraco.Web.Models.ContentEditing public bool IsRequired { get; set; } + public bool LabelOnTop { get; set; } + public string IsRequiredMessage { get; set; } public string ValidationRegExp { get; set; } From cf7b7a7ed1bb155e67a384d1320a3c897e6ebb8d Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 7 Oct 2020 20:20:13 +0100 Subject: [PATCH 09/37] More mappings - this seems to have fixed it. Got to update tests & verify export/import doctype to UDA & package.xml export/import --- .../Repositories/Implement/ContentTypeCommonRepository.cs | 3 ++- src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs index 7781e2e38a..90774e4c0b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs @@ -303,7 +303,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement SortOrder = dto.SortOrder, ValidationRegExp = dto.ValidationRegExp, ValidationRegExpMessage = dto.ValidationRegExpMessage, - Variations = (ContentVariation)dto.Variations + Variations = (ContentVariation)dto.Variations, + LabelOnTop = dto.LabelOnTop }; } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs index fd57e4dd2e..64e2ea22a3 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs @@ -27,6 +27,7 @@ namespace Umbraco.Web.Models.Mapping dest.Description = property.PropertyType.Description; dest.Label = property.PropertyType.Name; dest.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId); + dest.LabelOnTop = property.PropertyType.LabelOnTop; } } } From fe929b95fdaaf9895b1b6e5998dbb2ae8c5a7dbc Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 7 Oct 2020 20:21:12 +0100 Subject: [PATCH 10/37] When generating XML for UDA & or package.xml ensure LabelOnTop prop is added --- src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index cc329802ee..441b9b25f3 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -490,6 +490,7 @@ namespace Umbraco.Core.Services.Implement new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), + new XElement("LabelOnTop", propertyType.LabelOnTop.ToString()), propertyType.MandatoryMessage != null ? new XElement("MandatoryMessage", propertyType.MandatoryMessage) : null, propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, propertyType.ValidationRegExpMessage != null ? new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage) : null, From f569200272235352abb8283c5770436a64225f60 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 7 Oct 2020 21:20:53 +0100 Subject: [PATCH 11/37] Fix & update tests --- .../Models/Mapping/ContentTypeModelMappingTests.cs | 2 ++ .../Persistence/Repositories/ContentTypeRepositoryTest.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index 679f053c5c..1480253958 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -641,6 +641,7 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); + Assert.AreEqual(basic.LabelOnTop, result.LabelOnTop); } [Test] @@ -679,6 +680,7 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); + Assert.AreEqual(basic.LabelOnTop, result.LabelOnTop); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index 970201bc62..e8fc94e962 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -356,7 +356,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual("gen", propertyTypes[0].Alias); // just to be sure Assert.IsNull(propertyTypes[0].PropertyGroupId); Assert.IsTrue(propertyTypes.Skip(1).All((x => x.PropertyGroupId.Value == groupId))); - Assert.That(propertyTypes[0].LabelOnTop, Is.True); + Assert.That(propertyTypes.Single(x=> x.Alias == "title").LabelOnTop, Is.True); } } From 8ac0122e203d6e473900b1d66e44518a3105b71c Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 23 Oct 2020 15:52:40 +0100 Subject: [PATCH 12/37] Add migration to marker file & background reporter component to POST to telemetry service --- src/Umbraco.Core/IO/SystemFiles.cs | 2 + .../Migrations/Upgrade/UmbracoPlan.cs | 6 +- .../V_8_10_0/SetupAnonInstallTracker.cs | 49 ++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 109 ++++++++++++++++++ .../Telemetry/TelemetryComponent.cs | 35 ++++++ .../Telemetry/TelemetryComposer.cs | 10 ++ src/Umbraco.Web/Umbraco.Web.csproj | 3 + 8 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs create mode 100644 src/Umbraco.Web/Telemetry/ReportSiteTask.cs create mode 100644 src/Umbraco.Web/Telemetry/TelemetryComponent.cs create mode 100644 src/Umbraco.Web/Telemetry/TelemetryComposer.cs diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 12e3f57d99..5e38737dd2 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -7,6 +7,8 @@ namespace Umbraco.Core.IO { public static string TinyMceConfig => SystemDirectories.Config + "/tinyMceConfig.config"; + public static string TelemetricsIdentifier => SystemDirectories.Umbraco + "/telemetrics-id.umb"; + // TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache public static string GetContentCacheXml(IGlobalSettings globalSettings) { diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 723675ca1a..f97fcda49c 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.Common; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_1; using Umbraco.Core.Migrations.Upgrade.V_8_1_0; +using Umbraco.Core.Migrations.Upgrade.V_8_10_0; using Umbraco.Core.Migrations.Upgrade.V_8_6_0; using Umbraco.Core.Migrations.Upgrade.V_8_8_0; @@ -197,7 +198,10 @@ namespace Umbraco.Core.Migrations.Upgrade // to 8.8.0 To("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}"); - + + // to 8.10.0 + To("{DCBA2C6A-01B3-411E-9CDE-0AB9C69EFF33}"); + //FINAL } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs new file mode 100644 index 0000000000..6eded30312 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; + + +namespace Umbraco.Core.Migrations.Upgrade.V_8_10_0 +{ + + public class SetupAnonInstallTracker : MigrationBase + { + public SetupAnonInstallTracker(IMigrationContext context) + : base(context) + { + } + + /// + /// Adds a new file 'telemetrics-id.umb' at /umbraco + /// Which will add a GUID inside the file as JSON + /// + public override void Migrate() + { + var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); + + // Verify file does not exist already + if (File.Exists(telemetricsFilePath)) + { + Logger.Warn("When migrating to 8.10.0 the anonymous telemetry file already existsed on disk at {filePath}", telemetricsFilePath); + return; + } + + // Generate GUID + var telemetrySiteIdentifier = Guid.NewGuid(); + + // Write file contents + try + { + File.WriteAllText(telemetricsFilePath, telemetrySiteIdentifier.ToString()); + } + catch (Exception ex) + { + Logger.Error(ex, "Unable to create telemetry file at {filePath}", telemetricsFilePath); + } + + Logger.Info("This site has been identified with an anynomous id {telemetrySiteId} for telemetrics and written to {filePath}", telemetrySiteIdentifier, telemetricsFilePath); + + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 71b2a7be4a..821ddb3dc9 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -132,6 +132,7 @@ + diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs new file mode 100644 index 0000000000..8d777b73db --- /dev/null +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -0,0 +1,109 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Net.Http.Formatting; +using System.Threading; +using System.Threading.Tasks; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Web.Scheduling; + +namespace Umbraco.Web.Telemetry +{ + public class ReportSiteTask : RecurringTaskBase + { + private IRuntimeState _runtime; + private IProfilingLogger _logger; + private static HttpClient _httpClient; + + public ReportSiteTask(IBackgroundTaskRunner runner, int delayBeforeWeStart, int howOftenWeRepeat, IRuntimeState runtime, IProfilingLogger logger) + : base(runner, delayBeforeWeStart, howOftenWeRepeat) + { + _runtime = runtime; + _logger = logger; + + if (_httpClient == null) + _httpClient = new HttpClient(); + } + + /// + /// Runs the background task to send the anynomous ID + /// to telemetry service + /// + /// A value indicating whether to repeat the task. + public override async Task PerformRunAsync(CancellationToken token) + { + // Try & find file at '/umbraco/telemetrics-id.umb' + var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); + + if (File.Exists(telemetricsFilePath) == false) + { + // Some users may have decided to not be tracked by deleting/removing the marker file + _logger.Warn("No telemetry marker file found at '{filePath}' and will not report site to telemetry service", telemetricsFilePath); + + // Stop repeating this task (no need to keep checking) + // The only time it will recheck when the site is recycled + return false; + } + + + var telemetricsFileContents = string.Empty; + try + { + // Open file & read its contents + // It may throw due to file permissions or file locking + telemetricsFileContents = File.ReadAllText(telemetricsFilePath); + } + catch (Exception ex) + { + // Silently swallow ex - but lets log it (ReadAllText throws a ton of different types of ex) + // Hence the use of general exception type + _logger.Error(ex, "Error in reading file contents of telemetry marker file found at '{filePath}'", telemetricsFilePath); + } + + + // Parse as a GUID & verify its a GUID and not some random string + // In case of users may have messed or decided to empty the file contents or put in something random + if (Guid.TryParse(telemetricsFileContents, out var telemetrySiteIdentifier) == false) + { + // Some users may have decided to mess with file contents + _logger.Warn("The telemetry marker file found at '{filePath}' with '{telemetrySiteId}' is not a valid identifier for the telemetry service", telemetricsFilePath, telemetrySiteIdentifier); + + // Stop repeating this task (no need to keep checking) + // The only time it will recheck when the site is recycled + return false; + } + + + try + { + // Make a HTTP Post to telemetry service + // https://telemetry.umbraco.com/installs + // Fire & Forget, do not need to know if its a 200, 500 etc + var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; + var result = await _httpClient.PostAsync("https://webhook.site/9c38527a-eca4-4ad6-9847-202f2b37c07d", postData, new JsonMediaTypeFormatter()); + } + catch (Exception ex) + { + // Silently swallow + // The user does need logs being polluted if our service has fallen over or is down etc + } + + // Keep recurring this task & pinging the telemetry service + return true; + } + + public override bool IsAsync => true; + + + private class TelemetryReportData + { + public Guid Id { get; set; } + + public string Version { get; set; } + } + } +} + diff --git a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs new file mode 100644 index 0000000000..c8113df58b --- /dev/null +++ b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs @@ -0,0 +1,35 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Logging; +using Umbraco.Web.Scheduling; + +namespace Umbraco.Web.Telemetry +{ + public class TelemetryComponent : IComponent + { + private IProfilingLogger _logger; + private IRuntimeState _runtime; + private BackgroundTaskRunner _telemetryReporterRunner; + + public TelemetryComponent(IProfilingLogger logger, IRuntimeState runtime) + { + _logger = logger; + _runtime = runtime; + _telemetryReporterRunner = new BackgroundTaskRunner("TelemetryReporter", _logger); + } + + public void Initialize() + { + int delayBeforeWeStart = 60 * 1000; // 60 * 1000ms = 1min (60,000) + int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000) + + // As soon as we add our task to the runner it will start to run (after its delay period) + var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _runtime, _logger); + _telemetryReporterRunner.TryAdd(task); + } + + public void Terminate() + { + } + } +} diff --git a/src/Umbraco.Web/Telemetry/TelemetryComposer.cs b/src/Umbraco.Web/Telemetry/TelemetryComposer.cs new file mode 100644 index 0000000000..933b302e1c --- /dev/null +++ b/src/Umbraco.Web/Telemetry/TelemetryComposer.cs @@ -0,0 +1,10 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Telemetry +{ + + [RuntimeLevel(MinLevel = RuntimeLevel.Run)] + public class TelemetryComposer : ComponentComposer, ICoreComposer + { } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 1b48b9ca0d..90088fe552 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -296,6 +296,9 @@ + + + From c93a5a5cd1a455908a4a498feb271e5d25fd95ad Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 4 Nov 2020 14:07:56 +0000 Subject: [PATCH 13/37] Remove as an upgrade migration step as new installs will never get the marker file --- .../Migrations/Upgrade/UmbracoPlan.cs | 4 -- .../V_8_10_0/SetupAnonInstallTracker.cs | 49 ------------------- src/Umbraco.Core/Umbraco.Core.csproj | 1 - 3 files changed, 54 deletions(-) delete mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index f97fcda49c..ef1f038f04 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -6,7 +6,6 @@ using Umbraco.Core.Migrations.Upgrade.Common; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_1; using Umbraco.Core.Migrations.Upgrade.V_8_1_0; -using Umbraco.Core.Migrations.Upgrade.V_8_10_0; using Umbraco.Core.Migrations.Upgrade.V_8_6_0; using Umbraco.Core.Migrations.Upgrade.V_8_8_0; @@ -199,9 +198,6 @@ namespace Umbraco.Core.Migrations.Upgrade // to 8.8.0 To("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}"); - // to 8.10.0 - To("{DCBA2C6A-01B3-411E-9CDE-0AB9C69EFF33}"); - //FINAL } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs deleted file mode 100644 index 6eded30312..0000000000 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/SetupAnonInstallTracker.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.IO; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; - - -namespace Umbraco.Core.Migrations.Upgrade.V_8_10_0 -{ - - public class SetupAnonInstallTracker : MigrationBase - { - public SetupAnonInstallTracker(IMigrationContext context) - : base(context) - { - } - - /// - /// Adds a new file 'telemetrics-id.umb' at /umbraco - /// Which will add a GUID inside the file as JSON - /// - public override void Migrate() - { - var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); - - // Verify file does not exist already - if (File.Exists(telemetricsFilePath)) - { - Logger.Warn("When migrating to 8.10.0 the anonymous telemetry file already existsed on disk at {filePath}", telemetricsFilePath); - return; - } - - // Generate GUID - var telemetrySiteIdentifier = Guid.NewGuid(); - - // Write file contents - try - { - File.WriteAllText(telemetricsFilePath, telemetrySiteIdentifier.ToString()); - } - catch (Exception ex) - { - Logger.Error(ex, "Unable to create telemetry file at {filePath}", telemetricsFilePath); - } - - Logger.Info("This site has been identified with an anynomous id {telemetrySiteId} for telemetrics and written to {filePath}", telemetrySiteIdentifier, telemetricsFilePath); - - } - } -} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 821ddb3dc9..71b2a7be4a 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -132,7 +132,6 @@ - From 17249d226f3e1ed55085279cb312353cb4db1261 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 4 Nov 2020 14:24:48 +0000 Subject: [PATCH 14/37] Add new composer/component to add marker file only when clean install or an upgrade runtime state --- .../Telemetry/TelemetryMarkerComponent.cs | 52 +++++++++++++++++++ .../Telemetry/TelemetryMarkerComposer.cs | 9 ++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + 3 files changed, 63 insertions(+) create mode 100644 src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs create mode 100644 src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs new file mode 100644 index 0000000000..0426fe777e --- /dev/null +++ b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; + +namespace Umbraco.Web.Telemetry +{ + public class TelemetryMarkerComponent : IComponent + { + private IProfilingLogger _logger; + private IRuntimeState _runtime; + + public TelemetryMarkerComponent(IProfilingLogger logger, IRuntimeState runtime) + { + _logger = logger; + _runtime = runtime; + } + + public void Initialize() + { + var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); + + // Verify file does not exist already + // If the site is upgraded and the file was removed it would re-create one + if (File.Exists(telemetricsFilePath)) + { + _logger.Warn("When installing or upgrading the anonymous telemetry file already existsed on disk at {filePath} with the runtime state {runtimeStateLevel}", telemetricsFilePath, _runtime.Level); + return; + } + + // Generate GUID + var telemetrySiteIdentifier = Guid.NewGuid(); + + // Write file contents + try + { + File.WriteAllText(telemetricsFilePath, telemetrySiteIdentifier.ToString()); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to create telemetry file at {filePath}", telemetricsFilePath); + } + + } + + public void Terminate() + { + } + } +} diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs new file mode 100644 index 0000000000..e01b4a7f10 --- /dev/null +++ b/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs @@ -0,0 +1,9 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Telemetry +{ + [RuntimeLevel(MinLevel = RuntimeLevel.Install, MaxLevel = RuntimeLevel.Upgrade)] + public class TelemetryMarkerComposer : ComponentComposer, ICoreComposer + { } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 90088fe552..1f7158b2b1 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -297,8 +297,10 @@ + + From b1051a882d8196d5f9b15b0b363e4eb8d64a80dd Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 5 Nov 2020 11:52:50 +0000 Subject: [PATCH 15/37] git ignore telemetry file when doing local dev --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index eee2a46a44..3ae099a82f 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,4 @@ cypress.env.json /src/Umbraco.Tests.AcceptanceTest/package-lock.json /src/Umbraco.Tests.AcceptanceTest/cypress/videos/ /src/Umbraco.Tests.AcceptanceTest/cypress/screenshots/ +src/Umbraco.Web.UI/Umbraco/telemetrics-id.umb From a28f3475eb7032772cec9ddc3a1ca5649f1d98ab Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 5 Nov 2020 11:55:18 +0000 Subject: [PATCH 16/37] Only add something to the log when upgrading that the file is missing - during install it would loop over this component serveral times --- src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs index 0426fe777e..660ed18fba 100644 --- a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs +++ b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs @@ -22,14 +22,17 @@ namespace Umbraco.Web.Telemetry { var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); - // Verify file does not exist already + // Verify file does not exist already (if we are upgrading) + // In a clean install we know it would not exist // If the site is upgraded and the file was removed it would re-create one - if (File.Exists(telemetricsFilePath)) + // NOTE: If user removed the marker file to opt out it would re-create a new guid marker file & potentially skew + if (_runtime.Level == RuntimeLevel.Upgrade && File.Exists(telemetricsFilePath)) { - _logger.Warn("When installing or upgrading the anonymous telemetry file already existsed on disk at {filePath} with the runtime state {runtimeStateLevel}", telemetricsFilePath, _runtime.Level); + _logger.Warn("When upgrading the anonymous telemetry file already existsed on disk at {filePath}", telemetricsFilePath); return; } + // We are a clean install or an upgrade without the marker file // Generate GUID var telemetrySiteIdentifier = Guid.NewGuid(); From 918529748494461e0ebb0d20054ad2b3d48a19ed Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 5 Nov 2020 11:55:30 +0000 Subject: [PATCH 17/37] Post to dev env --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 8d777b73db..a3f9e0991d 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -83,7 +83,7 @@ namespace Umbraco.Web.Telemetry // https://telemetry.umbraco.com/installs // Fire & Forget, do not need to know if its a 200, 500 etc var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; - var result = await _httpClient.PostAsync("https://webhook.site/9c38527a-eca4-4ad6-9847-202f2b37c07d", postData, new JsonMediaTypeFormatter()); + var result = await _httpClient.PostAsync("https://telemetry.rainbowsrock.net/installs", postData, new JsonMediaTypeFormatter()); } catch (Exception ex) { From 69b3feb0ea575a184e49843b35c1561a122d9fc9 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 5 Nov 2020 12:17:46 +0000 Subject: [PATCH 18/37] Correct dev URL note the trailing slash --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index a3f9e0991d..df0bed0830 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -83,7 +83,7 @@ namespace Umbraco.Web.Telemetry // https://telemetry.umbraco.com/installs // Fire & Forget, do not need to know if its a 200, 500 etc var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; - var result = await _httpClient.PostAsync("https://telemetry.rainbowsrock.net/installs", postData, new JsonMediaTypeFormatter()); + var result = await _httpClient.PostAsync("https://telemetry.rainbowsrock.net/installs/", postData, new JsonMediaTypeFormatter()); } catch (Exception ex) { From 191d86e27cd258aca12d0e7b641a88dc34b4e48e Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 10 Nov 2020 08:25:32 +0000 Subject: [PATCH 19/37] Do not log that marker file exists already during the serval install boot cycles --- src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs index 660ed18fba..36cae322ce 100644 --- a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs +++ b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs @@ -31,6 +31,11 @@ namespace Umbraco.Web.Telemetry _logger.Warn("When upgrading the anonymous telemetry file already existsed on disk at {filePath}", telemetricsFilePath); return; } + else if (_runtime.Level == RuntimeLevel.Install && File.Exists(telemetricsFilePath)) + { + // No need to log for when level is install if file exists (As this component hit several times during install process) + return; + } // We are a clean install or an upgrade without the marker file // Generate GUID From 59a03115ea808f0fd4730f53ccfc7d803433201b Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Tue, 10 Nov 2020 09:58:15 +0000 Subject: [PATCH 20/37] Posting to service needed lowercase properties --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 29 ++++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index df0bed0830..1905e51540 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -1,7 +1,8 @@ -using System; +using Newtonsoft.Json; +using System; using System.IO; using System.Net.Http; -using System.Net.Http.Formatting; +using System.Text; using System.Threading; using System.Threading.Tasks; using Umbraco.Core; @@ -76,14 +77,26 @@ namespace Umbraco.Web.Telemetry return false; } - try { - // Make a HTTP Post to telemetry service - // https://telemetry.umbraco.com/installs - // Fire & Forget, do not need to know if its a 200, 500 etc + // Send data to LIVE telemetry + _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); + +//#if DEBUG +// // Send data to DEBUG telemetry service +// _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); +//#endif + + _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; - var result = await _httpClient.PostAsync("https://telemetry.rainbowsrock.net/installs/", postData, new JsonMediaTypeFormatter()); + var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); + request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header + + // Make a HTTP Post to telemetry service + // https://telemetry.umbraco.com/installs/ + // Fire & Forget, do not need to know if its a 200, 500 etc + var result = await _httpClient.SendAsync(request); + } catch (Exception ex) { @@ -100,8 +113,10 @@ namespace Umbraco.Web.Telemetry private class TelemetryReportData { + [JsonProperty("id")] public Guid Id { get; set; } + [JsonProperty("version")] public string Version { get; set; } } } From b4c65fe12a05c21814c6964fe4ab475f8957d6ad Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Fri, 27 Nov 2020 11:19:37 +0000 Subject: [PATCH 21/37] Update src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs Co-authored-by: Bjarke Berg --- .../Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs index a9fcdd8f98..206ea2be02 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_10_0/AddPropertyTypeLabelOnTopColumn.cs @@ -1,7 +1,7 @@ using System.Linq; using Umbraco.Core.Persistence.Dtos; -namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0 +namespace Umbraco.Core.Migrations.Upgrade.V_8_10_0 { public class AddPropertyTypeLabelOnTopColumn : MigrationBase From 855bef8c59a3849bcc1ea75f6b66b431de62f33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 30 Nov 2020 09:56:01 +0100 Subject: [PATCH 22/37] remove this class, should not have been added here. --- src/Umbraco.Web.UI.Client/src/views/membergroups/edit.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/membergroups/edit.html b/src/Umbraco.Web.UI.Client/src/views/membergroups/edit.html index aafaaa3bd4..63089de20c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/membergroups/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/membergroups/edit.html @@ -19,7 +19,7 @@ setpagetitle="header.setPageTitle"> - + From 8a6db7f71f930f423f76baeefaead17ca5d2990d Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:05:03 +0000 Subject: [PATCH 23/37] Uncomment out the DEBUG lines --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 1905e51540..074322e126 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -83,8 +83,8 @@ namespace Umbraco.Web.Telemetry _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); //#if DEBUG -// // Send data to DEBUG telemetry service -// _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); + // Send data to DEBUG telemetry service + _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); //#endif _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); From 36cd06b952e12d7fc6cc79501c50314b27102b2d Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:05:38 +0000 Subject: [PATCH 24/37] Add Debug logging and dont set type for ex as we are not using it --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 074322e126..373a1765c8 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -92,16 +92,19 @@ namespace Umbraco.Web.Telemetry var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header + // Make a HTTP Post to telemetry service // https://telemetry.umbraco.com/installs/ // Fire & Forget, do not need to know if its a 200, 500 etc var result = await _httpClient.SendAsync(request); } - catch (Exception ex) + catch { // Silently swallow - // The user does need logs being polluted if our service has fallen over or is down etc + // The user does not need the logs being polluted if our service has fallen over or is down etc + // Hence only loggigng this at a more verbose level (Which users should not be using in prod) + _logger.Debug("There was a problem sending a request to the Umbraco telemetry service"); } // Keep recurring this task & pinging the telemetry service From c5afcf1c9c394c156e791cb7b6d03ea37ac571f3 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:08:24 +0000 Subject: [PATCH 25/37] Move marker file into App_Data a folder that can never be served --- src/Umbraco.Core/IO/SystemFiles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 5e38737dd2..d33e9dfdfc 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.IO { public static string TinyMceConfig => SystemDirectories.Config + "/tinyMceConfig.config"; - public static string TelemetricsIdentifier => SystemDirectories.Umbraco + "/telemetrics-id.umb"; + public static string TelemetricsIdentifier => SystemDirectories.Data + "/telemetrics-id.umb"; // TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache public static string GetContentCacheXml(IGlobalSettings globalSettings) From 5dcb488d2cc5bb6214936d53548f163cf6a68995 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:12:27 +0000 Subject: [PATCH 26/37] Update src/Umbraco.Web/Telemetry/ReportSiteTask.cs Co-authored-by: Bjarke Berg --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 373a1765c8..0613e37bab 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -114,14 +114,14 @@ namespace Umbraco.Web.Telemetry public override bool IsAsync => true; + [DataContract] private class TelemetryReportData { - [JsonProperty("id")] + [DataMember(Name = "id")] public Guid Id { get; set; } - [JsonProperty("version")] + [DataMember(Name = "version")] public string Version { get; set; } } } } - From f747e2a2dcc3a2a91083034de7e10973b98fa273 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:17:39 +0000 Subject: [PATCH 27/37] Missing namespace from Bjarkes suggestion to move to DataMember --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 0613e37bab..7c2913a465 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Net.Http; +using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; From 1394387d4360452de29f154320f0c0555538fbad Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 09:18:13 +0000 Subject: [PATCH 28/37] Move the backgroundtask runner into Initialize method to follow same practise as SchedulerComponent --- src/Umbraco.Web/Telemetry/TelemetryComponent.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs index c8113df58b..bb26ae5f8d 100644 --- a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs +++ b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs @@ -15,11 +15,13 @@ namespace Umbraco.Web.Telemetry { _logger = logger; _runtime = runtime; - _telemetryReporterRunner = new BackgroundTaskRunner("TelemetryReporter", _logger); } public void Initialize() { + // backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly + _telemetryReporterRunner = new BackgroundTaskRunner("TelemetryReporter", _logger); + int delayBeforeWeStart = 60 * 1000; // 60 * 1000ms = 1min (60,000) int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000) From b29ed4c9c36e6e8ac6acc99a6002ddd11a7a82f2 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:04:21 +0000 Subject: [PATCH 29/37] Set a low 1 second timeout, no need to be a BIG timeout on this request --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 7c2913a465..5f3dbcb70c 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -93,6 +93,8 @@ namespace Umbraco.Web.Telemetry var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header + // Set a low timeout - no need to use a larger default timeout for this POST request + _httpClient.Timeout = new TimeSpan(0,0,1); // Make a HTTP Post to telemetry service // https://telemetry.umbraco.com/installs/ From 53282686450418d55b0c26f6e985b20c06d64628 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:08:48 +0000 Subject: [PATCH 30/37] Uncomment #ifdef --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 5f3dbcb70c..34c5932081 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -83,10 +83,10 @@ namespace Umbraco.Web.Telemetry // Send data to LIVE telemetry _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); -//#if DEBUG +#if DEBUG // Send data to DEBUG telemetry service _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); -//#endif +#endif _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; From fc2ff2525d23dbd2bbe6b4977dc5a1eafd405c84 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:15:06 +0000 Subject: [PATCH 31/37] No need for the if null check as it will always be null in the ctor --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 34c5932081..a9c6ea7bde 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -25,9 +25,7 @@ namespace Umbraco.Web.Telemetry { _runtime = runtime; _logger = logger; - - if (_httpClient == null) - _httpClient = new HttpClient(); + _httpClient = new HttpClient(); } /// From 3e6830e1736a68d2b0a71a21eaf84e6726170424 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:18:11 +0000 Subject: [PATCH 32/37] Exit out of function but set to repeat if we are unable to read the file (perhaps a file lock) --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index a9c6ea7bde..2f6c348414 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -61,6 +61,9 @@ namespace Umbraco.Web.Telemetry // Silently swallow ex - but lets log it (ReadAllText throws a ton of different types of ex) // Hence the use of general exception type _logger.Error(ex, "Error in reading file contents of telemetry marker file found at '{filePath}'", telemetricsFilePath); + + // Exit out early, but mark this task to be repeated in case its a file lock so it can be rechecked the next time round + return true; } From 4de3c05e83aa4cbb0f877a691039828bc05c39e7 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:33:07 +0000 Subject: [PATCH 33/37] Wrap use of httpClient in a usings due to it being IDisposable --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 24 +++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 2f6c348414..725f0e431f 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -89,19 +89,21 @@ namespace Umbraco.Web.Telemetry _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); #endif - _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); - var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; - var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); - request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header + using (_httpClient) + { + _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); + var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; + var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); + request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header - // Set a low timeout - no need to use a larger default timeout for this POST request - _httpClient.Timeout = new TimeSpan(0,0,1); - - // Make a HTTP Post to telemetry service - // https://telemetry.umbraco.com/installs/ - // Fire & Forget, do not need to know if its a 200, 500 etc - var result = await _httpClient.SendAsync(request); + // Set a low timeout - no need to use a larger default timeout for this POST request + _httpClient.Timeout = new TimeSpan(0, 0, 1); + // Make a HTTP Post to telemetry service + // https://telemetry.umbraco.com/installs/ + // Fire & Forget, do not need to know if its a 200, 500 etc + var result = await _httpClient.SendAsync(request); + } } catch { From fa931416a459de1cdea9eea0c3c746c2ea27d6e5 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 10:34:10 +0000 Subject: [PATCH 34/37] Forgot to move the baseaddress set inside the usings --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 725f0e431f..74342a2bf3 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -81,16 +81,16 @@ namespace Umbraco.Web.Telemetry try { - // Send data to LIVE telemetry - _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); - -#if DEBUG - // Send data to DEBUG telemetry service - _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); -#endif - using (_httpClient) { + // Send data to LIVE telemetry + _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); + +#if DEBUG + // Send data to DEBUG telemetry service + _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); +#endif + _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); From ee89610559e77c86716e17a7dea8e489bc2446c8 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 12:23:28 +0000 Subject: [PATCH 35/37] Remove unused RuntimeState --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 4 +--- src/Umbraco.Web/Telemetry/TelemetryComponent.cs | 9 +++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index 74342a2bf3..aa5aefe218 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -16,14 +16,12 @@ namespace Umbraco.Web.Telemetry { public class ReportSiteTask : RecurringTaskBase { - private IRuntimeState _runtime; private IProfilingLogger _logger; private static HttpClient _httpClient; - public ReportSiteTask(IBackgroundTaskRunner runner, int delayBeforeWeStart, int howOftenWeRepeat, IRuntimeState runtime, IProfilingLogger logger) + public ReportSiteTask(IBackgroundTaskRunner runner, int delayBeforeWeStart, int howOftenWeRepeat, IProfilingLogger logger) : base(runner, delayBeforeWeStart, howOftenWeRepeat) { - _runtime = runtime; _logger = logger; _httpClient = new HttpClient(); } diff --git a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs index bb26ae5f8d..4ea4c6573a 100644 --- a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs +++ b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Web.Scheduling; @@ -8,13 +7,11 @@ namespace Umbraco.Web.Telemetry public class TelemetryComponent : IComponent { private IProfilingLogger _logger; - private IRuntimeState _runtime; private BackgroundTaskRunner _telemetryReporterRunner; - public TelemetryComponent(IProfilingLogger logger, IRuntimeState runtime) + public TelemetryComponent(IProfilingLogger logger) { _logger = logger; - _runtime = runtime; } public void Initialize() @@ -26,7 +23,7 @@ namespace Umbraco.Web.Telemetry int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000) // As soon as we add our task to the runner it will start to run (after its delay period) - var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _runtime, _logger); + var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _logger); _telemetryReporterRunner.TryAdd(task); } From 6d120322e5154bd60bf7a37e8c9e3f5d9aaebdb4 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 30 Nov 2020 13:35:55 +0100 Subject: [PATCH 36/37] Do not dispose the static httpClient, but the HttpRequestMessage --- src/Umbraco.Web/Telemetry/ReportSiteTask.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index aa5aefe218..fcac8570d2 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -79,19 +79,20 @@ namespace Umbraco.Web.Telemetry try { - using (_httpClient) - { - // Send data to LIVE telemetry - _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); + + // Send data to LIVE telemetry + _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); #if DEBUG - // Send data to DEBUG telemetry service - _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); + // Send data to DEBUG telemetry service + _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); #endif - _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); + _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); + + using (var request = new HttpRequestMessage(HttpMethod.Post, "installs/")) + { var postData = new TelemetryReportData { Id = telemetrySiteIdentifier, Version = UmbracoVersion.SemanticVersion.ToSemanticString() }; - var request = new HttpRequestMessage(HttpMethod.Post, "installs/"); request.Content = new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json"); //CONTENT-TYPE header // Set a low timeout - no need to use a larger default timeout for this POST request From 7ff0f9ee2098914f5fa68252a3e6846c62997bcb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 30 Nov 2020 13:27:33 +0000 Subject: [PATCH 37/37] Bump version to 8.10.0-rc .\build SetUmbracoVersion 8.10.0-rc --- src/SolutionInfo.cs | 4 ++-- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 1c59137aac..89997c0a01 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -18,5 +18,5 @@ using System.Resources; [assembly: AssemblyVersion("8.0.0")] // these are FYI and changed automatically -[assembly: AssemblyFileVersion("8.9.1")] -[assembly: AssemblyInformationalVersion("8.9.1")] +[assembly: AssemblyFileVersion("8.10.0")] +[assembly: AssemblyInformationalVersion("8.10.0-rc")] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index aece40a4c4..6e4a4b780e 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -347,9 +347,9 @@ False True - 8910 + 8100 / - http://localhost:8910 + http://localhost:8100 False False