From 2761f5cd20622a1e8c1d2f20a9b161582573244d Mon Sep 17 00:00:00 2001 From: mcl-sz Date: Tue, 30 Jul 2024 08:38:06 +0200 Subject: [PATCH 1/6] Combining OpenId and OfflineAccess scope (#16220) * Combining OpenId and OfflineAccess scope When the client scope is set to "openid offline_access", the returned scope only has the "offline_access" scope. The "openid" scope and the "id_token" are missing. By combining the OpenId and OfflineAccess as return scope, the refresh_token and id_token are returned. * Update MemberController.cs Cleaner way, provided by @kjac, to check if the scope has openid and/or offiline_access set. (cherry picked from commit 55f9b09ab754702ceaabdbb57d4f532f5fbabca5) --- .../Controllers/Security/MemberController.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/Security/MemberController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Security/MemberController.cs index a9c670b7ad..102bf16224 100644 --- a/src/Umbraco.Cms.Api.Delivery/Controllers/Security/MemberController.cs +++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Security/MemberController.cs @@ -160,11 +160,12 @@ public class MemberController : DeliveryApiControllerBase claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); } - if (request.GetScopes().Contains(OpenIddictConstants.Scopes.OfflineAccess)) - { - // "offline_access" scope is required to use refresh tokens - memberPrincipal.SetScopes(OpenIddictConstants.Scopes.OfflineAccess); - } + // "openid" and "offline_access" are the only scopes allowed for members; explicitly ensure we only add those + // NOTE: the "offline_access" scope is required to use refresh tokens + IEnumerable allowedScopes = request + .GetScopes() + .Intersect(new[] { OpenIddictConstants.Scopes.OpenId, OpenIddictConstants.Scopes.OfflineAccess }); + memberPrincipal.SetScopes(allowedScopes); return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, memberPrincipal); } From 212b2c999f54f5521c5fea452faf373ad0afdc37 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 7 Aug 2024 10:17:00 +0200 Subject: [PATCH 2/6] Updated to lastest nuget minor or patch versions (#16871) --- Directory.Packages.props | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ccd1e91a2e..aff37a4b02 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,30 +5,30 @@ - + - + - - - - - - - + + + + + + + - + - - + + @@ -45,13 +45,13 @@ - - - + + + - + - + @@ -62,22 +62,22 @@ - + - + - - + + - + From 2e3369a09a16999e5536cd17f0f83a7bdefbe16e Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Wed, 7 Aug 2024 15:20:28 +0200 Subject: [PATCH 3/6] Upgrade imagesharp2 dependency (#16883) --- .../Umbraco.Cms.Imaging.ImageSharp2.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Cms.Imaging.ImageSharp2/Umbraco.Cms.Imaging.ImageSharp2.csproj b/src/Umbraco.Cms.Imaging.ImageSharp2/Umbraco.Cms.Imaging.ImageSharp2.csproj index 724c5b5e34..c513082675 100644 --- a/src/Umbraco.Cms.Imaging.ImageSharp2/Umbraco.Cms.Imaging.ImageSharp2.csproj +++ b/src/Umbraco.Cms.Imaging.ImageSharp2/Umbraco.Cms.Imaging.ImageSharp2.csproj @@ -5,7 +5,7 @@ - + From 81f36df066f06b9f9ae642972fa993c66f39b5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 13 Aug 2024 10:25:24 +0200 Subject: [PATCH 4/6] V13: fix 15516 (#16864) * fix unit testing * fix server value update case * re initialize Block if it was offloaded --- .../blockeditormodelobject.service.js | 3 ++- .../src/common/services/tinymce.service.js | 20 +++++++++++++++++-- .../rte/blocks/umb-rte-block.component.js | 10 +++++++++- .../propertyeditors/rte/rte.component.js | 20 +++++++++++++++++-- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js index ab6c176c85..85ca297e69 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js @@ -401,8 +401,9 @@ // If we are in the document type editor, we need to use -20 as the current page id. // If we are in the content editor, we need to use the current page id or parent id if the current page is new. // We can recognize a content editor context by checking if the current editor state has a contentTypeKey. + // If no current is represented, we will use null. const currentEditorState = editorState.getCurrent(); - const currentPageId = currentEditorState.contentTypeKey ? currentEditorState.id || currentEditorState.parentId || -20 : -20; + const currentPageId = currentEditorState ? currentEditorState.contentTypeKey ? currentEditorState.id || currentEditorState.parentId || -20 : -20 : null; // Load all scaffolds for the block types. // The currentPageId is used to determine the access level for the current user. diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index ebf759c20c..df5b0d51bb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -1457,12 +1457,13 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s function syncContent() { - const content = args.editor.getContent() + const content = args.editor.getContent(); if (getPropertyValue() === content) { return; } + //stop watching before we update the value stopWatch(); angularHelper.safeApply($rootScope, function () { @@ -1493,8 +1494,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s const blockEls = args.editor.contentDocument.querySelectorAll('umb-rte-block, umb-rte-block-inline'); for (var blockEl of blockEls) { if(!blockEl._isInitializedUmbBlock) { + // First time we initialize this block element const blockContentUdi = blockEl.getAttribute('data-content-udi'); - if(blockContentUdi && !blockEl.$block) { + if(blockContentUdi) { const block = args.blockEditorApi.getBlockByContentUdi(blockContentUdi); if(block) { blockEl.removeAttribute('contenteditable'); @@ -1533,9 +1535,23 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s } else { args.editor.dom.remove(blockEl); } + } else { + // Second time we initialize this block element, cause by a new Block Model Object has been initiated. (Mainly cause we re initiate all blocks when there is a value update) + const blockContentUdi = blockEl.getAttribute('data-content-udi'); + const block = args.blockEditorApi.getBlockByContentUdi(blockContentUdi); + if(block) { + blockEl.$index = block.index; + blockEl.$block = block; + blockEl.update(); + } else { + console.error('Could not find block with content udi: ' + blockContentUdi); + } } } } + args.editor.on('updateBlocks', function () { + initBlocks(); + }); // If we can not find the insert image/media toolbar button // Then we need to add an event listener to the editor diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block.component.js index 0c4c8e2e50..7738a73c9f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block.component.js @@ -18,7 +18,8 @@ } function onInit() { - $element[0]._isInitializedUmbBlock = true; + + // We might call onInit multiple times(via the update method), so parsing the latest values is needed no matter if it has been initialized before. $scope.block = $element[0].$block; $scope.api = $element[0].$api; $scope.index = $element[0].$index; @@ -27,6 +28,13 @@ $scope.parentForm = $element[0].$parentForm; $scope.valFormManager = $element[0].$valFormManager; + if($element[0]._isInitializedUmbBlock === true) { + return; + } + $element[0]._isInitializedUmbBlock = true; + $element[0].update = onInit; + + const stylesheet = $scope.block.config.stylesheet; var shadowRoot = $element[0].attachShadow({ mode: 'open' }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.component.js index 7f06215148..d499f47a9c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.component.js @@ -264,7 +264,7 @@ }, culture: vm.umbProperty?.culture ?? null, segment: vm.umbProperty?.segment ?? null, - blockEditorApi: vm.noBlocksMode ? undefined : vm.blockEditorApi, + blockEditorApi: vm.noBlocksMode ? undefined : vm.blockEditorApi, parentForm: vm.propertyForm, valFormManager: vm.valFormManager, currentFormInput: $scope.rteForm.modelValue @@ -341,10 +341,14 @@ // we need to deal with that here so that our model values are all in sync so we basically re-initialize. function onServerValueChanged(newVal, oldVal) { + ensurePropertyValue(newVal); + // updating the modelObject with the new value cause a angular compile issue. + // But I'm not sure it's needed, as this does not trigger the RTE if(modelObject) { modelObject.update(vm.model.value.blocks, $scope); + vm.tinyMceEditor.fire('updateBlocks'); } onLoaded(); } @@ -944,7 +948,19 @@ return undefined; } - return vm.layout[layoutIndex].$block; + var layoutEntry = vm.layout[layoutIndex]; + if(layoutEntry.$block === undefined || layoutEntry.$block.config === undefined) { + // make block model + var blockObject = getBlockObject(layoutEntry); + if (blockObject === null) { + // Initialization of the Block Object didn't go well, therefor we will fail the paste action. + return false; + } + + // set the BlockObject on our layout entry. + layoutEntry.$block = blockObject; + } + return layoutEntry.$block; } vm.blockEditorApi = { From 9d94658372f9af21985e5579f1d0d21c1438e311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 13 Aug 2024 10:43:20 +0200 Subject: [PATCH 5/6] V13: fix 16663 (#16866) * fix unit testing * fix server value update case * PastePropertyResolver for RTE Blocks --------- Co-authored-by: leekelleher --- .../umb-rte-block-clipboard.component.js | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block-clipboard.component.js diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block-clipboard.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block-clipboard.component.js new file mode 100644 index 0000000000..216b7fe1e8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/blocks/umb-rte-block-clipboard.component.js @@ -0,0 +1,95 @@ +/** + * @ngdoc service + * @name umbraco.services.rte-block-clipboard-service + * + * Handles clipboard resolvers for Block of RTE properties. + * + */ +(function () { + 'use strict'; + + + + /** + * When performing a runtime copy of Block Editors entries, we copy the ElementType Data Model and inner IDs are kept identical, to ensure new IDs are changed on paste we need to provide a resolver for the ClipboardService. + */ + angular.module('umbraco').run(['clipboardService', 'udiService', function (clipboardService, udiService) { + + function replaceUdi(obj, key, dataObject, markup) { + var udi = obj[key]; + var newUdi = udiService.create("element"); + obj[key] = newUdi; + dataObject.forEach((data) => { + if (data.udi === udi) { + data.udi = newUdi; + } + }); + // make a attribute name of the key, by kebab casing it: + var attrName = key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); + // replace the udi in the markup as well. + var regex = new RegExp('data-'+attrName+'="'+udi+'"', "g"); + markup = markup.replace(regex, 'data-'+attrName+'="'+newUdi+'"'); + return markup; + } + function replaceUdisOfObject(obj, propValue, markup) { + for (var k in obj) { + if(k === "contentUdi") { + markup = replaceUdi(obj, k, propValue.contentData, markup); + } else if(k === "settingsUdi") { + markup = replaceUdi(obj, k, propValue.settingsData, markup); + } else { + // lets crawl through all properties of layout to make sure get captured all `contentUdi` and `settingsUdi` properties. + var propType = typeof obj[k]; + if(propType != null && (propType === "object" || propType === "array")) { + markup = replaceUdisOfObject(obj[k], propValue, markup); + } + } + } + return markup + } + + + function rawRteBlockResolver(propertyValue, propPasteResolverMethod) { + if (propertyValue != null && typeof propertyValue === "object") { + + // object property of 'blocks' holds the data for the Block Editor. + var value = propertyValue.blocks; + + // we got an object, and it has these three props then we are most likely dealing with a Block Editor. + if ((value.layout !== undefined && value.contentData !== undefined && value.settingsData !== undefined)) { + + // replaceUdisOfObject replaces udis of the value object(by instance reference), but also returns the updated markup (as we cant update the reference of a string). + propertyValue.markup = replaceUdisOfObject(value.layout, value, propertyValue.markup); + + // run resolvers for inner properties of this Blocks content data. + if(value.contentData.length > 0) { + value.contentData.forEach((item) => { + for (var k in item) { + propPasteResolverMethod(item[k], clipboardService.TYPES.RAW); + } + }); + } + // run resolvers for inner properties of this Blocks settings data. + if(value.settingsData.length > 0) { + value.settingsData.forEach((item) => { + for (var k in item) { + propPasteResolverMethod(item[k], clipboardService.TYPES.RAW); + } + }); + } + + } + } + } + + function elementTypeBlockResolver(obj, propPasteResolverMethod) { + // we could filter for specific Property Editor Aliases, but as the Block Editor structure can be used by many Property Editor we do not in this code know a good way to detect that this is a Block Editor and will therefor leave it to the value structure to determin this. + rawRteBlockResolver(obj.value, propPasteResolverMethod); + } + + clipboardService.registerPastePropertyResolver(elementTypeBlockResolver, clipboardService.TYPES.ELEMENT_TYPE); + clipboardService.registerPastePropertyResolver(rawRteBlockResolver, clipboardService.TYPES.RAW); + + }]); + +})(); From bb1c36f59147d1c383703fc40bf953b55a5f156b Mon Sep 17 00:00:00 2001 From: Peter <45105665+PeterKvayt@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:07:36 +0200 Subject: [PATCH 6/6] Making method ExecuteAsync virtual. (#16496) Co-authored-by: Kvyatkovsky, Petr (cherry picked from commit 3a9ef3810bdc063be16bded4877957065e964dbc) --- .../HostedServices/RecurringHostedServiceBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs index a35f7aa956..c6f21738c2 100644 --- a/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs +++ b/src/Umbraco.Infrastructure/HostedServices/RecurringHostedServiceBase.cs @@ -129,7 +129,7 @@ public abstract class RecurringHostedServiceBase : IHostedService, IDisposable /// Executes the task. /// /// The task state. - public async void ExecuteAsync(object? state) + public virtual async void ExecuteAsync(object? state) { try {