From 0afce3d2fcacb599f4cd80c8677edf1a851b72c4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Biel - bielu Date: Thu, 18 Jan 2024 21:40:55 +0000 Subject: [PATCH 1/5] feat: made domain button functional --- .../Composition/CdnComposition.cs | 3 +- .../ContentApp/BieluCDNApp.cs | 34 +++++ .../BieluCdnManagmentController.cs | 24 ++++ .../BieluCdnUIManifestFilter.cs | 1 + ...elu.cdn.ui.angularController.contentApp.js | 32 +++++ .../App_Plugins/bielu.cdn.ui/contentApp.html | 5 + .../generated/api.generated.clients.ts | 45 +++++++ .../src/components/CdnContentApp.vue | 122 ++++++++++++++++++ .../src/components/CdnDashboard.ce.vue | 34 +---- .../src/components/CdnProviderCard.vue | 86 ++++++++++++ ...freshNode.ce.vue => CdnRefreshNode.ce.vue} | 2 +- src/bielu.cdn.ui/src/main.ts | 12 +- .../src/stories/RefreshNode.stories.ts | 2 +- src/bielu.cdn.ui/vite.config.ts | 4 +- 14 files changed, 367 insertions(+), 39 deletions(-) create mode 100644 src/bielu.Umbraco.Cdn.Core/ContentApp/BieluCDNApp.cs create mode 100644 src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.contentApp.js create mode 100644 src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/contentApp.html create mode 100644 src/bielu.cdn.ui/src/components/CdnContentApp.vue create mode 100644 src/bielu.cdn.ui/src/components/CdnProviderCard.vue rename src/bielu.cdn.ui/src/components/{RefreshNode.ce.vue => CdnRefreshNode.ce.vue} (99%) diff --git a/src/bielu.Umbraco.Cdn.Core/Composition/CdnComposition.cs b/src/bielu.Umbraco.Cdn.Core/Composition/CdnComposition.cs index 70134ca..16c86b5 100644 --- a/src/bielu.Umbraco.Cdn.Core/Composition/CdnComposition.cs +++ b/src/bielu.Umbraco.Cdn.Core/Composition/CdnComposition.cs @@ -6,6 +6,7 @@ using bielu.Umbraco.Cdn.Core.NotitificationHandlers.Tree; using bielu.Umbraco.Cdn.Core.Services; using bielu.Umbraco.Cdn.Services; +using bielu.Umbraco.Cdn.Core.ContentApp; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.DependencyInjection; @@ -22,7 +23,7 @@ public void Compose(IUmbracoBuilder composition) { composition.Services.AddOptions().BindConfiguration(BieluCdnOptions.SectionName); composition.ManifestFilters().Append(); - + composition.ContentApps().Append(); //services composition.Services.AddTransient(typeof(IUmbracoUrlDeliveryService), typeof(UmbracoUrlDeliveryService)); composition.Services.AddSingleton(); diff --git a/src/bielu.Umbraco.Cdn.Core/ContentApp/BieluCDNApp.cs b/src/bielu.Umbraco.Cdn.Core/ContentApp/BieluCDNApp.cs new file mode 100644 index 0000000..dabc207 --- /dev/null +++ b/src/bielu.Umbraco.Cdn.Core/ContentApp/BieluCDNApp.cs @@ -0,0 +1,34 @@ +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Models.Membership; + +namespace bielu.Umbraco.Cdn.Core.ContentApp; + +public class BieluCdnApp : IContentAppFactory +{ + public global::Umbraco.Cms.Core.Models.ContentEditing.ContentApp? GetContentAppFor(object source, IEnumerable userGroups) + { + // Can implement some logic with userGroups if needed + // Allowing us to display the content app with some restrictions for certain groups + if (userGroups.All(x => x.Alias.ToLowerInvariant() != global::Umbraco.Cms.Core.Constants.Security.AdminGroupAlias)) + return null; + + // Only show app on content items + if (!(source is IContent)) + return null; + // Only show app on content with certain content type alias + // if (!content.ContentType.Alias.Equals("aliasName")) + // return null; + + + + return new global::Umbraco.Cms.Core.Models.ContentEditing.ContentApp + { + Alias = "bieluCdnApp", + Name = "CDN", + Icon = "icon-hard-drive", + View = "/App_Plugins/bielu.cdn.ui/contentApp.html", + Weight = 900 + }; + } +} \ No newline at end of file diff --git a/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs b/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs index 3caeff1..c58da71 100644 --- a/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs +++ b/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs @@ -51,6 +51,30 @@ public async Task> GetProviders(int id = -1) return await _manager.GetProviders(id); } + public async Task RefreshDomain( string providerId = null, string domain = null) + { + List statuses = new List(); + using (var contextReference = _contextFactory.EnsureUmbracoContext()) + { + + var hostnames = new List { domain }; + + if (!string.IsNullOrEmpty(providerId)) + { + var service = await _manager.GetService(providerId); + statuses.AddRange(await service.PurgeByAssignedHostnames(hostnames)); + return statuses.Merge(); + } + + + foreach (var service in (await _manager.GetServices()).Where(x=>x.IsEnabled())) + { + statuses.AddRange(await service.PurgeByAssignedHostnames(hostnames)); + } + } + + return statuses.Merge(); + } public async Task RefreshForNode(int id,bool descandants,bool references, string providerId = null, string domain = null) { List statuses = new List(); diff --git a/src/bielu.Umbraco.Cdn.Core/ManifestFilters/BieluCdnUIManifestFilter.cs b/src/bielu.Umbraco.Cdn.Core/ManifestFilters/BieluCdnUIManifestFilter.cs index 0d98629..b85e9b4 100644 --- a/src/bielu.Umbraco.Cdn.Core/ManifestFilters/BieluCdnUIManifestFilter.cs +++ b/src/bielu.Umbraco.Cdn.Core/ManifestFilters/BieluCdnUIManifestFilter.cs @@ -28,6 +28,7 @@ public void Filter(List manifests) { $"/App_Plugins/bielu.cdn.ui/{(_options.DevMode ? "dev-bootstrapper" : "bootstrapper")}.js", "/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.js", + "/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.contentApp.js", }, Version = assembly.GetName()?.Version?.ToString(3) ?? "0.1.0", diff --git a/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.contentApp.js b/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.contentApp.js new file mode 100644 index 0000000..73fa2a4 --- /dev/null +++ b/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/bielu.cdn.ui.angularController.contentApp.js @@ -0,0 +1,32 @@ + +angular.module('umbraco') + .controller('bielu.cdn.ui.controller.contentApp', + function ( + $scope, + $compile, + $filter, + $http, + $routeParams, + editorService, + editorState, + contentResource, + notificationsService, + navigationService, + appState, + $timeout) { + var vm = this; + vm.nodeId = editorState.current.id; + vm.nodeAlias = editorState.current.contentTypeAlias; + + var wrapper = document.querySelector("#refreshNodeModalWrapper"); + var todo = document.createElement("content-app-cdn-node"); + todo.setAttribute("node-id", $scope.nodeId); + wrapper.appendChild(todo); + + }); +angular.module('umbraco') + .filter('to_trusted', ['$sce', function ($sce) { + return function (text) { + return $sce.trustAsHtml(text); + }; + }]); \ No newline at end of file diff --git a/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/contentApp.html b/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/contentApp.html new file mode 100644 index 0000000..74554ff --- /dev/null +++ b/src/bielu.cdn.ui/App_Plugins/bielu.cdn.ui/contentApp.html @@ -0,0 +1,5 @@ + +
+
+
+ diff --git a/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts b/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts index 866240b..97f438c 100644 --- a/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts +++ b/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts @@ -16,6 +16,8 @@ export interface IManagementClient { getProviders(id?: number | undefined): Promise; + refreshDomain(providerId?: string | undefined, domain?: string | undefined): Promise; + refreshForNode(id: number, descandants: boolean, references: boolean, providerId?: string | undefined, domain?: string | undefined): Promise; } @@ -117,6 +119,49 @@ export class ManagementClient implements IManagementClient { return Promise.resolve(null as any); } + refreshDomain(providerId?: string | undefined, domain?: string | undefined): Promise { + let url_ = this.baseUrl + "/cdn/api/management/RefreshDomain?"; + if (providerId === null) + throw new Error("The parameter 'providerId' cannot be null."); + else if (providerId !== undefined) + url_ += "providerId=" + encodeURIComponent("" + providerId) + "&"; + if (domain === null) + throw new Error("The parameter 'domain' cannot be null."); + else if (domain !== undefined) + url_ += "domain=" + encodeURIComponent("" + domain) + "&"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processRefreshDomain(_response); + }); + } + + protected processRefreshDomain(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + let _mappings: { source: any, target: any }[] = []; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : jsonParse(_responseText, this.jsonParseReviver); + result200 = resultData200 ? Status.fromJS(resultData200, _mappings) : null; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } + refreshForNode(id: number, descandants: boolean, references: boolean, providerId?: string | undefined, domain?: string | undefined): Promise { let url_ = this.baseUrl + "/cdn/api/management/RefreshForNode?"; if (id === undefined || id === null) diff --git a/src/bielu.cdn.ui/src/components/CdnContentApp.vue b/src/bielu.cdn.ui/src/components/CdnContentApp.vue new file mode 100644 index 0000000..e7357db --- /dev/null +++ b/src/bielu.cdn.ui/src/components/CdnContentApp.vue @@ -0,0 +1,122 @@ + + + + + \ No newline at end of file diff --git a/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue b/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue index 18d0e81..45c113d 100644 --- a/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue +++ b/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue @@ -6,9 +6,11 @@ import {serviceContainer} from "../Services/service-container"; import {Provider} from "../Services/umbraco/generated/api.generated.clients"; import {defineComponent, PropType} from 'vue' +import CdnProviderCard from "./CdnProviderCard.vue"; export default defineComponent({ - name: 'CdnDashboard', + name: 'umbraco-CdnDashboard', + components: {CdnProviderCard}, mounted: function () { console.log("mounted"); this.fetchData() @@ -73,35 +75,7 @@ export default defineComponent({ />
- - Enabled - Disabled - -
-

Domains

-
    - -
  • -
    - {{ domain }} - -
    -
  • -
-
-
- This provider is disabled, which means that all operation will be ignored. -
-
+
diff --git a/src/bielu.cdn.ui/src/components/CdnProviderCard.vue b/src/bielu.cdn.ui/src/components/CdnProviderCard.vue new file mode 100644 index 0000000..df950d1 --- /dev/null +++ b/src/bielu.cdn.ui/src/components/CdnProviderCard.vue @@ -0,0 +1,86 @@ + + + + + \ No newline at end of file diff --git a/src/bielu.cdn.ui/src/components/RefreshNode.ce.vue b/src/bielu.cdn.ui/src/components/CdnRefreshNode.ce.vue similarity index 99% rename from src/bielu.cdn.ui/src/components/RefreshNode.ce.vue rename to src/bielu.cdn.ui/src/components/CdnRefreshNode.ce.vue index ed3a190..dfef2fc 100644 --- a/src/bielu.cdn.ui/src/components/RefreshNode.ce.vue +++ b/src/bielu.cdn.ui/src/components/CdnRefreshNode.ce.vue @@ -6,7 +6,7 @@ import {defineComponent, PropType, ref, watch} from 'vue' import {serviceContainer} from "../Services/service-container"; import {Provider, Status} from "../Services/umbraco/generated/api.generated.clients"; export default defineComponent({ - name: 'RefreshNode', + name: 'umbraco-RefreshNode', created: function () { }, diff --git a/src/bielu.cdn.ui/src/main.ts b/src/bielu.cdn.ui/src/main.ts index e91168e..819f88c 100644 --- a/src/bielu.cdn.ui/src/main.ts +++ b/src/bielu.cdn.ui/src/main.ts @@ -1,9 +1,11 @@ -import refreshNode from './components/RefreshNode.ce.vue' +import refreshNode from './components/CdnRefreshNode.ce.vue' import CdnDashboard from './components/CdnDashboard.ce.vue' import { defineCustomElement } from '@vue/runtime-dom' //todo: this is a hack to get the custom elements to work in umbraco backoffice, i need to figure out how to get vite to do this for me -const myCustomElement = defineCustomElement(refreshNode); -const myCustomElement2 = defineCustomElement(CdnDashboard); -window.customElements.define(`refresh-node`, myCustomElement); -window.customElements.define(`cdn-dashboard`, myCustomElement2); +const refreshNodeActionMenu = defineCustomElement(refreshNode); +const cdnManagmentDashboard = defineCustomElement(CdnDashboard); +const cdnContentApp = defineCustomElement(CdnDashboard); +window.customElements.define(`refresh-node`, refreshNodeActionMenu); +window.customElements.define(`cdn-dashboard`, cdnManagmentDashboard); +window.customElements.define(`content-app-cdn-node`, cdnContentApp); diff --git a/src/bielu.cdn.ui/src/stories/RefreshNode.stories.ts b/src/bielu.cdn.ui/src/stories/RefreshNode.stories.ts index 21d3b41..75b5a10 100644 --- a/src/bielu.cdn.ui/src/stories/RefreshNode.stories.ts +++ b/src/bielu.cdn.ui/src/stories/RefreshNode.stories.ts @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/vue3'; -import RefreshNode from "../components/RefreshNode.ce.vue"; +import RefreshNode from "../components/CdnRefreshNode.ce.vue"; // More on how to set up stories at: https://storybook.js.org/docs/vue/writing-stories/introduction const meta = { diff --git a/src/bielu.cdn.ui/vite.config.ts b/src/bielu.cdn.ui/vite.config.ts index 56af927..97692e9 100644 --- a/src/bielu.cdn.ui/vite.config.ts +++ b/src/bielu.cdn.ui/vite.config.ts @@ -9,7 +9,9 @@ export default defineConfig({ template: { compilerOptions: { // treat all tags with a dash as custom elements - isCustomElement: (tag) => true + isCustomElement: (tag) => { + return tag.startsWith('umbraco-') // (return true) + } } } })], From 1112bd5da03430f2b7ff1480de517c0affa22a2d Mon Sep 17 00:00:00 2001 From: Arkadiusz Biel - bielu Date: Thu, 18 Jan 2024 21:48:25 +0000 Subject: [PATCH 2/5] feat: refresh all providers --- .../BieluCdnManagmentController.cs | 37 ++++++++++++------- .../generated/api.generated.clients.ts | 37 +++++++++++++++++++ .../src/components/CdnDashboard.ce.vue | 12 +++--- .../src/components/CdnProviderCard.vue | 15 ++++---- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs b/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs index c58da71..4c36c97 100644 --- a/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs +++ b/src/bielu.Umbraco.Cdn.Core/Controllers/BieluCdnManagmentController.cs @@ -28,17 +28,15 @@ public class BieluCdnManagmentController : UmbracoApiController private BieluCdnOptions _optionsMonitor; public BieluCdnManagmentController(ICdnManager manager, IUmbracoContextFactory contextFactory, - Services.ICdnAuditService auditService, IUmbracoUrlDeliveryService urlDeliveryService, IOptionsMonitor optionsMonitor) + Services.ICdnAuditService auditService, IUmbracoUrlDeliveryService urlDeliveryService, + IOptionsMonitor optionsMonitor) { _manager = manager; _contextFactory = contextFactory; _auditService = auditService; _urlDeliveryService = urlDeliveryService; _optionsMonitor = optionsMonitor.CurrentValue; - optionsMonitor.OnChange((options, name) => - { - _optionsMonitor = options; - }); + optionsMonitor.OnChange((options, name) => { _optionsMonitor = options; }); } public async Task> GetAuditHistory() @@ -51,14 +49,13 @@ public async Task> GetProviders(int id = -1) return await _manager.GetProviders(id); } - public async Task RefreshDomain( string providerId = null, string domain = null) + public async Task RefreshDomain(string providerId = null, string domain = null) { List statuses = new List(); using (var contextReference = _contextFactory.EnsureUmbracoContext()) { - var hostnames = new List { domain }; - + if (!string.IsNullOrEmpty(providerId)) { var service = await _manager.GetService(providerId); @@ -66,8 +63,8 @@ public async Task RefreshDomain( string providerId = null, string domain return statuses.Merge(); } - - foreach (var service in (await _manager.GetServices()).Where(x=>x.IsEnabled())) + + foreach (var service in (await _manager.GetServices()).Where(x => x.IsEnabled())) { statuses.AddRange(await service.PurgeByAssignedHostnames(hostnames)); } @@ -75,7 +72,9 @@ public async Task RefreshDomain( string providerId = null, string domain return statuses.Merge(); } - public async Task RefreshForNode(int id,bool descandants,bool references, string providerId = null, string domain = null) + + public async Task RefreshForNode(int id, bool descandants, bool references, string providerId = null, + string domain = null) { List statuses = new List(); using (var contextReference = _contextFactory.EnsureUmbracoContext()) @@ -87,6 +86,7 @@ public async Task RefreshForNode(int id,bool descandants,bool references { urls.AddRange(_urlDeliveryService.GetUrlsByReferences(content)); } + if (!string.IsNullOrEmpty(providerId)) { var service = await _manager.GetService(providerId); @@ -94,8 +94,8 @@ public async Task RefreshForNode(int id,bool descandants,bool references return statuses.Merge(); } - - foreach (var service in (await _manager.GetServices()).Where(x=>x.IsEnabled())) + + foreach (var service in (await _manager.GetServices()).Where(x => x.IsEnabled())) { statuses.AddRange(await service.PurgePages(urls)); } @@ -104,4 +104,15 @@ public async Task RefreshForNode(int id,bool descandants,bool references return statuses.Merge(); } + public async Task RefreshAll() + { + List statuses = new List(); + + foreach (var service in (await _manager.GetServices()).Where(x => x.IsEnabled())) + { + statuses.AddRange(await service.PurgeAll()); + } + + return statuses.Merge(); + } } \ No newline at end of file diff --git a/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts b/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts index 97f438c..71ba11a 100644 --- a/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts +++ b/src/bielu.cdn.ui/src/Services/umbraco/generated/api.generated.clients.ts @@ -19,6 +19,8 @@ export interface IManagementClient { refreshDomain(providerId?: string | undefined, domain?: string | undefined): Promise; refreshForNode(id: number, descandants: boolean, references: boolean, providerId?: string | undefined, domain?: string | undefined): Promise; + + refreshAll(): Promise; } export class ManagementClient implements IManagementClient { @@ -216,6 +218,41 @@ export class ManagementClient implements IManagementClient { } return Promise.resolve(null as any); } + + refreshAll(): Promise { + let url_ = this.baseUrl + "/cdn/api/management/RefreshAll"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processRefreshAll(_response); + }); + } + + protected processRefreshAll(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + let _mappings: { source: any, target: any }[] = []; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : jsonParse(_responseText, this.jsonParseReviver); + result200 = resultData200 ? Status.fromJS(resultData200, _mappings) : null; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } } export class AuditRecord implements IAuditRecord { diff --git a/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue b/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue index 45c113d..08c8a48 100644 --- a/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue +++ b/src/bielu.cdn.ui/src/components/CdnDashboard.ce.vue @@ -39,14 +39,12 @@ export default defineComponent({ }, methods: { async refreshAllProviders() { - - }, - async refreshProvider(provider: Provider) { - console.log(provider) - }, - async refreshDomain(domain: string) { - console.log(domain) + var service = serviceContainer.managmentApiClient; + service.refreshAll().then((result: any) => { + console.log(result); + }); }, + async fetchData() { var service = serviceContainer.managmentApiClient; service.getProviders().then((result: any) => { diff --git a/src/bielu.cdn.ui/src/components/CdnProviderCard.vue b/src/bielu.cdn.ui/src/components/CdnProviderCard.vue index df950d1..aec7828 100644 --- a/src/bielu.cdn.ui/src/components/CdnProviderCard.vue +++ b/src/bielu.cdn.ui/src/components/CdnProviderCard.vue @@ -35,13 +35,14 @@ export default defineComponent({ console.log(provider) }, async refreshDomain(domain: string, provider: Provider) { - if(this.nodeId == -1) { - service.refreshDomain(provider.id,domain).then((result: any) => { - console.log(result); - }); - return;} var service = serviceContainer.managmentApiClient; - service.refreshForNode(this.nodeId, false,false, provider.id,domain).then((result: any) => { + if (this.nodeId == -1) { + service.refreshDomain(provider.id, domain).then((result: any) => { + console.log(result); + }); + return; + } + service.refreshForNode(this.nodeId, false, false, provider.id, domain).then((result: any) => { console.log(result); }); }, @@ -51,7 +52,7 @@ export default defineComponent({