From 1f51d667e9837982a92985c46983646d2697ed14 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Mon, 18 May 2020 06:43:33 +0200
Subject: [PATCH 01/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated UmbracoWebApiRequireHttpsFilter
---
.../UmbracoAuthorizedApiController.cs | 28 +++++++
.../UmbracoWebApiRequireHttpsAttribute.cs | 73 +++++++++++++++++++
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
.../UmbracoWebApiRequireHttpsAttribute.cs | 56 --------------
4 files changed, 101 insertions(+), 57 deletions(-)
create mode 100644 src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
create mode 100644 src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs
delete mode 100644 src/Umbraco.Web/WebApi/Filters/UmbracoWebApiRequireHttpsAttribute.cs
diff --git a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
new file mode 100644
index 0000000000..071680b325
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
@@ -0,0 +1,28 @@
+using Umbraco.Web.BackOffice.Filters;
+using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Common.Controllers;
+using Umbraco.Web.Common.Filters;
+
+namespace Umbraco.Web.BackOffice.Controllers
+{
+ ///
+ /// Provides a base class for authorized auto-routed Umbraco API controllers.
+ ///
+ ///
+ /// This controller will also append a custom header to the response if the user
+ /// is logged in using forms authentication which indicates the seconds remaining
+ /// before their timeout expires.
+ ///
+ [IsBackOffice]
+ [UmbracoUserTimeoutFilter]
+ [UmbracoAuthorize]
+ [DisableBrowserCache]
+ [UmbracoWebApiRequireHttps]
+ [CheckIfUserTicketDataIsStale]
+ [UnhandedExceptionLoggerConfiguration]
+ [EnableDetailedErrors]
+ public abstract class UmbracoAuthorizedApiController : UmbracoApiController
+ {
+
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs
new file mode 100644
index 0000000000..7c7652c532
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Web.BackOffice.Filters
+{
+ ///
+ /// If Umbraco.Core.UseHttps property in web.config is set to true, this filter will redirect any http access to https.
+ ///
+ ///
+ /// This will only redirect Head/Get requests, otherwise will respond with text
+ ///
+ /// References:
+ /// http://issues.umbraco.org/issue/U4-8542
+ /// https://blogs.msdn.microsoft.com/carlosfigueira/2012/03/09/implementing-requirehttps-with-asp-net-web-api/
+ ///
+ public class UmbracoWebApiRequireHttpsAttribute : TypeFilterAttribute
+ {
+ public UmbracoWebApiRequireHttpsAttribute() : base(typeof(UmbracoWebApiRequireHttpsFilter))
+ {
+ Arguments = Array.Empty
"
+ },
+ {
+ "element": "[data-element='group-add']",
+ "title": "Add group",
+ "content": "Group are used to organize properties on content in the Content section. Click Add Group to add a group.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element='group-name-field']",
+ "title": "Name the group",
+ "content": "
Enter Home in the group name.
You can name a group anything you want and if you have a lot of properties it can be useful to add multiple groups.
Properties are the different input fields on a content page.
On our Home Page we want to add a welcome text.
Click Add property to open the property dialog.
",
+ "event": "click"
+ },
+ {
+ "element": "[data-element='editor-property-settings'] [data-element='property-name']",
+ "title": "Name the property",
+ "content": "Enter Welcome Text as the name for the property.",
+ "view": "propertyname"
+ },
+ {
+ "element": "[data-element~='editor-property-settings'] [data-element='property-description']",
+ "title": "Enter a description",
+ "content": "
A description will help your editor fill in the right content.
Enter a description for the property editor. It could be:
Write a nice introduction text so the visitors feel welcome
"
+ },
+ {
+ "element": "[data-element~='editor-property-settings'] [data-element='editor-add']",
+ "title": "Add editor",
+ "content": "When you add an editor you choose what the input method for this property will be. Click Add editor to open the editor picker dialog.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element~='editor-data-type-picker']",
+ "elementPreventClick": true,
+ "title": "Editor picker",
+ "content": "
In the editor picker dialog we can pick one of the many built-in editors.
You can choose from preconfigured data types (Reuse) or create a new configuration (Available editors).
"
+ },
+ {
+ "element": "[data-element~='editor-data-type-picker'] [data-element='editor-Textarea']",
+ "title": "Select editor",
+ "content": "Select the Textarea editor. This will add a textarea to the Welcome Text property.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element~='editor-data-type-settings']",
+ "elementPreventClick": true,
+ "title": "Editor settings",
+ "content": "Each property editor can have individual settings. For the textarea editor you can set a character limit but in this case it is not needed."
+ },
+ {
+ "element": "[data-element~='editor-data-type-settings'] [data-element='button-submit']",
+ "title": "Save editor",
+ "content": "Click Submit to save the changes.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element~='editor-property-settings'] [data-element='button-submit']",
+ "title": "Add property to document type",
+ "content": "Click Submit to add the property to the document type.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element~='sub-view-permissions']",
+ "title": "Check the document type permissions",
+ "content": "Click Permissions to view the permissions page.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element~='permissions-allow-as-root']",
+ "title": "Allow this document type to work at the root of your site",
+ "content": "Toggle the switch Allow as root to allow new content pages based on this document type to be created at the root of your site",
+ "event": "click"
+ },
+ {
+ "element": "[data-element='button-save']",
+ "title": "Save the document type",
+ "content": "All we need now is to save the document type. Click Save to create and save your new document type.",
+ "event": "click"
+ }
+ ]
+ },
+ {
+ "name": "Create Content",
+ "alias": "umbIntroCreateContent",
+ "group": "Getting Started",
+ "groupOrder": 100,
+ "requiredSections": [
+ "content"
+ ],
+ "steps": [
+ {
+ "title": "Creating your first content node",
+ "content": "
In this tour you will learn how to create the home page for your website. It will use the Home Page Document type you created in the previous tour.
Tip: Click the preview button in the bottom right corner to preview changes without publishing them.
",
+ "event": "click",
+ "eventElement": "[data-element='editor-content'] [data-element='node-info-urls'] a[target='_blank']"
+ }
+ ]
+ },
+ {
+ "name": "The Media library",
+ "alias": "umbIntroMediaSection",
+ "group": "Getting Started",
+ "groupOrder": 100,
+ "requiredSections": [
+ "media"
+ ],
+ "steps": [
+ {
+ "title": "How to use the media library",
+ "content": "
A website would be boring without media content. In Umbraco you can manage all your images, documents, videos etc. in the Media section. Here you can upload and organise your media items and see details about each item.
In this tour you will learn how to upload and organise your Media library in Umbraco. It will also show you how to view details about a specific media item.
",
+ "type": "intro"
+ },
+ {
+ "element": "#applications [data-element='section-media']",
+ "title": "Navigate to the Media section",
+ "content": "The media section is where you manage all your media items.",
+ "event": "click",
+ "backdropOpacity": 0.6
+ },
+ {
+ "element": "#tree [data-element='tree-root']",
+ "title": "Create a new folder",
+ "content": "
First create a folder for your images. Hover over the media root node and click the three small dots on the right side of the item.
In the upload area you can upload your media items.
Click the Click here to choose files button and select a couple of images on your computer and upload them.
",
+ "view": "uploadimages"
+ },
+ {
+ "element": "[data-element='editor-media'] [data-element='media-grid-item-0']",
+ "title": "View media item details",
+ "content": "Hover over the media item and Click the white bar to view details about the media item.",
+ "event": "click",
+ "eventElement": "[data-element='editor-media'] [data-element='media-grid-item-0'] [data-element='media-grid-item-edit']"
+ },
+ {
+ "element": "[data-element='editor-media'] [data-element='property-umbracoFile']",
+ "elementPreventClick": true,
+ "title": "The uploaded image",
+ "content": "
You will also find other details about the image, like the size.
Media items work in much the same way as content. So you can add extra properties to an image by creating or editing the Media types in the Settings section.
"
+ },
+ {
+ "element": "[data-element='editor-media'] [data-element='sub-view-umbInfo']",
+ "title": "Info",
+ "content": "Like the content section you can also find default information about the media item. You will find these under the info app.",
+ "event": "click"
+ },
+ {
+ "element": "[data-element='editor-media'] [data-element='node-info-urls']",
+ "title": "Link to media",
+ "content": "The path to the media item..."
+ },
+ {
+ "element": "[data-element='editor-media'] [data-element='node-info-update-date']",
+ "title": "Last edited",
+ "content": "...and information about when the media item has been created and edited."
+ },
+ {
+ "element": "[data-element='editor-container']",
+ "elementPreventClick": true,
+ "title": "Using media items",
+ "content": "You can reference a media item directly in a template by using the path or try adding a Media Picker to a document type property so you can select media items from the content section."
+ }
+ ]
+ }
+]
diff --git a/src/Umbraco.Web/Editors/TourController.cs b/src/Umbraco.Web/Editors/TourController.cs
index 93ec4252df..8a09673233 100644
--- a/src/Umbraco.Web/Editors/TourController.cs
+++ b/src/Umbraco.Web/Editors/TourController.cs
@@ -21,6 +21,7 @@ using Umbraco.Web.Tour;
namespace Umbraco.Web.Editors
{
+ // Migrated to .NET Core
[PluginController("UmbracoApi")]
public class TourController : UmbracoAuthorizedJsonController
{
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 083e26a755..4858fafa4c 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -145,6 +145,7 @@
+
@@ -264,7 +265,6 @@
-
From 35680bba46fb1e7911c04e9c29a8f780a4d1ba1e Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Tue, 19 May 2020 09:52:58 +0200
Subject: [PATCH 04/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated DashboardController and BackOfficeAssetsController
---
.../Controllers/AuthenticationController.cs | 27 +++++-
.../BackOfficeAssetsController.cs | 5 +-
.../Controllers/BackOfficeController.cs | 10 ++-
.../Controllers}/DashboardController.cs | 87 +++++++++----------
.../Filters/EditorModelEventManager.cs | 74 ++++++++++++++++
.../OutgoingEditorModelEventAttribute.cs | 46 ++++++++++
.../Security/WebSecurity.cs | 33 ++++++-
.../UmbracoContext/UmbracoContextFactory.cs | 2 +-
.../Editors/BackOfficeController.cs | 61 -------------
.../Editors/BackOfficeServerVariables.cs | 18 ++--
src/Umbraco.Web/Umbraco.Web.csproj | 2 -
11 files changed, 241 insertions(+), 124 deletions(-)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/BackOfficeAssetsController.cs (95%)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/DashboardController.cs (68%)
create mode 100644 src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
create mode 100644 src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs
diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
index cb0cb4cc50..8ed4f8368b 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Mvc;
+using Umbraco.Core;
using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Common.Controllers;
using Umbraco.Web.Common.Filters;
+using Umbraco.Web.Security;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.BackOffice.Controllers
@@ -9,8 +12,30 @@ namespace Umbraco.Web.BackOffice.Controllers
//[ValidationFilter] // TODO: I don't actually think this is required with our custom Application Model conventions applied
[TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))] // TODO: This could be applied with our Application Model conventions
[IsBackOffice] // TODO: This could be applied with our Application Model conventions
- public class AuthenticationController : ControllerBase
+ public class AuthenticationController : UmbracoApiController
{
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
// TODO: We need to import the logic from Umbraco.Web.Editors.AuthenticationController and it should not be an auto-routed api controller
+
+ public AuthenticationController(IUmbracoContextAccessor umbracoContextAccessor)
+ {
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
+
+ ///
+ /// Checks if the current user's cookie is valid and if so returns OK or a 400 (BadRequest)
+ ///
+ ///
+ [HttpGet]
+ public bool IsAuthenticated()
+ {
+ var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
+ var attempt = umbracoContext.Security.AuthorizeRequest();
+ if (attempt == ValidateRequestAttempt.Success)
+ {
+ return true;
+ }
+ return false;
+ }
}
}
diff --git a/src/Umbraco.Web/Editors/BackOfficeAssetsController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs
similarity index 95%
rename from src/Umbraco.Web/Editors/BackOfficeAssetsController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs
index d7bfc5c1fa..c549679251 100644
--- a/src/Umbraco.Web/Editors/BackOfficeAssetsController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs
@@ -2,12 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Web.Http;
-using Umbraco.Core.Composing;
+using Microsoft.AspNetCore.Mvc;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
-using Umbraco.Web.Mvc;
+using Umbraco.Web.Common.Attributes;
namespace Umbraco.Web.Editors
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
index 0e244abda2..d8c0216341 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
@@ -31,7 +31,13 @@ namespace Umbraco.Web.BackOffice.Controllers
private readonly ILocalizedTextService _textService;
private readonly IGridConfig _gridConfig;
- public BackOfficeController(IRuntimeMinifier runtimeMinifier, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IGridConfig gridConfig)
+ public BackOfficeController(
+ IRuntimeMinifier runtimeMinifier,
+ IGlobalSettings globalSettings,
+ IHostingEnvironment hostingEnvironment,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ ILocalizedTextService textService,
+ IGridConfig gridConfig)
{
_runtimeMinifier = runtimeMinifier;
_globalSettings = globalSettings;
@@ -107,5 +113,7 @@ namespace Umbraco.Web.BackOffice.Controllers
{
return new JsonNetResult { Data = _gridConfig.EditorsConfig.Editors, Formatting = Formatting.None };
}
+
+
}
}
diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
similarity index 68%
rename from src/Umbraco.Web/Editors/DashboardController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
index 84aad2d0c0..6a8e37a8ec 100644
--- a/src/Umbraco.Web/Editors/DashboardController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
@@ -2,38 +2,39 @@
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Web.Models.ContentEditing;
-using Umbraco.Web.Mvc;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System;
using System.Linq;
-using System.Net;
using System.Text;
+using Microsoft.AspNetCore.Mvc;
using Umbraco.Core.Cache;
-using Umbraco.Web.WebApi;
-using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Dashboards;
-using Umbraco.Core.Strings;
using Umbraco.Web.Services;
-using Umbraco.Core.Mapping;
-using Umbraco.Web.Routing;
+using Umbraco.Web.BackOffice.Filters;
+using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Common.Controllers;
+using Umbraco.Web.Common.Filters;
+using Umbraco.Web.WebApi.Filters;
-namespace Umbraco.Web.Editors
+namespace Umbraco.Web.BackOffice.Controllers
{
//we need to fire up the controller like this to enable loading of remote css directly from this controller
[PluginController("UmbracoApi")]
[ValidationFilter]
- [AngularJsonOnlyConfiguration]
+ [TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))] // TODO: This could be applied with our Application Model conventions
[IsBackOffice]
- [WebApi.UmbracoAuthorize]
-
+ [UmbracoAuthorize]
public class DashboardController : UmbracoApiController
{
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly AppCaches _appCaches;
+ private readonly ILogger _logger;
private readonly IDashboardService _dashboardService;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IShortStringHelper _shortStringHelper;
@@ -47,15 +48,16 @@ namespace Umbraco.Web.Editors
ISqlContext sqlContext,
ServiceContext services,
AppCaches appCaches,
- IProfilingLogger logger,
+ ILogger logger,
IRuntimeState runtimeState,
IDashboardService dashboardService,
IUmbracoVersion umbracoVersion,
- IShortStringHelper shortStringHelper,
- UmbracoMapper umbracoMapper,
- IPublishedUrlProvider publishedUrlProvider)
- : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper,publishedUrlProvider)
+ IShortStringHelper shortStringHelper)
+
{
+ _umbracoContextAccessor = umbracoContextAccessor;
+ _appCaches = appCaches;
+ _logger = logger;
_dashboardService = dashboardService;
_umbracoVersion = umbracoVersion;
_shortStringHelper = shortStringHelper;
@@ -65,10 +67,10 @@ namespace Umbraco.Web.Editors
private static readonly HttpClient HttpClient = new HttpClient();
//we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side
- [ValidateAngularAntiForgeryToken]
+ [TypeFilter(typeof(ValidateAngularAntiForgeryTokenAttribute))]
public async Task GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/")
{
- var user = Security.CurrentUser;
+ var user = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser;
var allowedSections = string.Join(",", user.AllowedSections);
var language = user.Language;
var version = _umbracoVersion.SemanticVersion.ToSemanticString();
@@ -76,7 +78,7 @@ namespace Umbraco.Web.Editors
var url = string.Format(baseUrl + "{0}?section={0}&allowed={1}&lang={2}&version={3}", section, allowedSections, language, version);
var key = "umbraco-dynamic-dashboard-" + language + allowedSections.Replace(",", "-") + section;
- var content = AppCaches.RuntimeCache.GetCacheItem(key);
+ var content = _appCaches.RuntimeCache.GetCacheItem(key);
var result = new JObject();
if (content != null)
{
@@ -92,26 +94,26 @@ namespace Umbraco.Web.Editors
content = JObject.Parse(json);
result = content;
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
}
catch (HttpRequestException ex)
{
- Logger.Error(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url);
+ _logger.Error(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url);
//it's still new JObject() - we return it like this to avoid error codes which triggers UI warnings
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
}
}
return result;
}
- public async Task GetRemoteDashboardCss(string section, string baseUrl = "https://dashboard.umbraco.org/")
+ public async Task GetRemoteDashboardCss(string section, string baseUrl = "https://dashboard.umbraco.org/")
{
var url = string.Format(baseUrl + "css/dashboard.css?section={0}", section);
var key = "umbraco-dynamic-dashboard-css-" + section;
- var content = AppCaches.RuntimeCache.GetCacheItem(key);
+ var content = _appCaches.RuntimeCache.GetCacheItem(key);
var result = string.Empty;
if (content != null)
@@ -130,24 +132,23 @@ namespace Umbraco.Web.Editors
result = content;
//save server content for 30 mins
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
}
catch (HttpRequestException ex)
{
- Logger.Error(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url);
+ _logger.Error(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url);
//it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
}
}
- return new HttpResponseMessage(HttpStatusCode.OK)
- {
- Content = new StringContent(result, Encoding.UTF8, "text/css")
- };
+
+ return Content(result,"text/css", Encoding.UTF8);
+
}
- public async Task GetRemoteXml(string site, string url)
+ public async Task GetRemoteXml(string site, string url)
{
// This is used in place of the old feedproxy.config
// Which was used to grab data from our.umbraco.com, umbraco.com or umbraco.tv
@@ -168,14 +169,14 @@ namespace Umbraco.Web.Editors
break;
default:
- return new HttpResponseMessage(HttpStatusCode.NotFound);
+ return NotFound();
}
//Make remote call to fetch videos or remote dashboard feed data
var key = $"umbraco-XML-feed-{site}-{url.ToCleanString(_shortStringHelper, CleanStringType.UrlSegment)}";
- var content = AppCaches.RuntimeCache.GetCacheItem(key);
+ var content = _appCaches.RuntimeCache.GetCacheItem(key);
var result = string.Empty;
if (content != null)
@@ -194,30 +195,28 @@ namespace Umbraco.Web.Editors
result = content;
//save server content for 30 mins
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0));
}
catch (HttpRequestException ex)
{
- Logger.Error(ex.InnerException ?? ex, "Error getting remote dashboard data from {UrlPrefix}{Url}", urlPrefix, url);
+ _logger.Error(ex.InnerException ?? ex, "Error getting remote dashboard data from {UrlPrefix}{Url}", urlPrefix, url);
//it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings
- AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
+ _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0));
}
}
- return new HttpResponseMessage(HttpStatusCode.OK)
- {
- Content = new StringContent(result, Encoding.UTF8, "text/xml")
- };
+ return Content(result,"text/xml", Encoding.UTF8);
}
// return IDashboardSlim - we don't need sections nor access rules
- [ValidateAngularAntiForgeryToken]
- [OutgoingEditorModelEvent]
+ [TypeFilter(typeof(ValidateAngularAntiForgeryTokenAttribute))]
+ [TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
public IEnumerable> GetDashboard(string section)
{
- return _dashboardService.GetDashboards(section, Security.CurrentUser).Select(x => new Tab
+ var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser;
+ return _dashboardService.GetDashboards(section, currentUser).Select(x => new Tab
{
Id = x.Id,
Alias = x.Alias,
diff --git a/src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs b/src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
new file mode 100644
index 0000000000..7255c91f49
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Umbraco.Core.Dashboards;
+using Umbraco.Core.Events;
+using Umbraco.Web.Models.ContentEditing;
+
+namespace Umbraco.Web.Editors
+{
+ ///
+ /// Used to emit events for editor models in the back office
+ ///
+ public sealed class EditorModelEventManager
+ {
+ public static event TypedEventHandler> SendingContentModel;
+ public static event TypedEventHandler> SendingMediaModel;
+ public static event TypedEventHandler> SendingMemberModel;
+ public static event TypedEventHandler> SendingUserModel;
+
+ public static event TypedEventHandler>>> SendingDashboardSlimModel;
+
+ private static void OnSendingDashboardModel(ActionExecutedContext sender, EditorModelEventArgs>> e)
+ {
+ var handler = SendingDashboardSlimModel;
+ handler?.Invoke(sender, e);
+ }
+
+ private static void OnSendingUserModel(ActionExecutedContext sender, EditorModelEventArgs e)
+ {
+ var handler = SendingUserModel;
+ handler?.Invoke(sender, e);
+ }
+
+ private static void OnSendingContentModel(ActionExecutedContext sender, EditorModelEventArgs e)
+ {
+ var handler = SendingContentModel;
+ handler?.Invoke(sender, e);
+ }
+
+ private static void OnSendingMediaModel(ActionExecutedContext sender, EditorModelEventArgs e)
+ {
+ var handler = SendingMediaModel;
+ handler?.Invoke(sender, e);
+ }
+
+ private static void OnSendingMemberModel(ActionExecutedContext sender, EditorModelEventArgs e)
+ {
+ var handler = SendingMemberModel;
+ handler?.Invoke(sender, e);
+ }
+
+ ///
+ /// Based on the type, emit's a specific event
+ ///
+ ///
+ ///
+ internal static void EmitEvent(ActionExecutedContext sender, EditorModelEventArgs e)
+ {
+ if (e.Model is ContentItemDisplay)
+ OnSendingContentModel(sender, new EditorModelEventArgs(e));
+
+ if (e.Model is MediaItemDisplay)
+ OnSendingMediaModel(sender, new EditorModelEventArgs(e));
+
+ if (e.Model is MemberDisplay)
+ OnSendingMemberModel(sender, new EditorModelEventArgs(e));
+
+ if (e.Model is UserDisplay)
+ OnSendingUserModel(sender, new EditorModelEventArgs(e));
+
+ if (e.Model is IEnumerable>)
+ OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e));
+ }
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs
new file mode 100644
index 0000000000..5c9e646ba0
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs
@@ -0,0 +1,46 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Umbraco.Core;
+using Umbraco.Web.Editors;
+
+namespace Umbraco.Web.WebApi.Filters
+{
+ ///
+ /// Used to emit outgoing editor model events
+ ///
+ internal sealed class OutgoingEditorModelEventAttribute : ActionFilterAttribute
+ {
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+
+ public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor)
+ {
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
+
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ if (context.Result == null) return;
+
+ var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
+ var user = umbracoContext.Security.CurrentUser;
+ if (user == null) return;
+
+ if (context.Result is ObjectResult objectContent)
+ {
+ var model = objectContent.Value;
+
+ if (model != null)
+ {
+ var args = new EditorModelEventArgs(
+ model,
+ umbracoContext);
+ EditorModelEventManager.EmitEvent(context, args);
+ objectContent.Value = args.Model;
+ }
+ }
+
+ base.OnActionExecuted(context);
+ }
+
+ }
+}
diff --git a/src/Umbraco.Web.Common/Security/WebSecurity.cs b/src/Umbraco.Web.Common/Security/WebSecurity.cs
index a52bc68cec..59b4826f46 100644
--- a/src/Umbraco.Web.Common/Security/WebSecurity.cs
+++ b/src/Umbraco.Web.Common/Security/WebSecurity.cs
@@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
+using Microsoft.AspNetCore.Http;
using Umbraco.Composing;
using Umbraco.Core;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Hosting;
using Umbraco.Core.Models.Membership;
+using Umbraco.Core.Services;
using Umbraco.Web.Security;
namespace Umbraco.Web.Common.Security
@@ -12,10 +16,33 @@ namespace Umbraco.Web.Common.Security
public class WebSecurity : IWebSecurity
{
- public IUser CurrentUser => new User(Current.Configs.Global())
- {
+ private readonly IUserService _userService;
- };
+ public WebSecurity(IUserService userService)
+ {
+ _userService = userService;
+ }
+
+ private IUser _currentUser;
+
+ ///
+ /// Gets the current user.
+ ///
+ /// The current user.
+ public IUser CurrentUser
+ {
+ get
+ {
+ //only load it once per instance! (but make sure groups are loaded)
+ if (_currentUser == null)
+ {
+ var id = GetUserId();
+ _currentUser = id ? _userService.GetUserById(id.Result) : null;
+ }
+
+ return _currentUser;
+ }
+ }
public ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false)
{
diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
index ac4b61909c..b2148ea5b3 100644
--- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
+++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
@@ -72,7 +72,7 @@ namespace Umbraco.Web
_variationContextAccessor.VariationContext = new VariationContext(_defaultCultureAccessor.DefaultCulture);
}
- IWebSecurity webSecurity = new WebSecurity();
+ IWebSecurity webSecurity = new WebSecurity(_userService);
return new UmbracoContext(
_publishedSnapshotService,
diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs
index 605690444e..5b3a01052d 100644
--- a/src/Umbraco.Web/Editors/BackOfficeController.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeController.cs
@@ -182,67 +182,6 @@ namespace Umbraco.Web.Editors
() => Redirect("/"));
}
- ///
- /// Get the json localized text for a given culture or the culture for the current user
- ///
- ///
- ///
- /// Migrated already to .Net Core
- [HttpGet]
- public JsonNetResult LocalizedText(string culture = null)
- {
- var cultureInfo = string.IsNullOrWhiteSpace(culture)
- //if the user is logged in, get their culture, otherwise default to 'en'
- ? Security.IsAuthenticated()
- //current culture is set at the very beginning of each request
- ? Thread.CurrentThread.CurrentCulture
- : CultureInfo.GetCultureInfo(GlobalSettings.DefaultUILanguage)
- : CultureInfo.GetCultureInfo(culture);
-
- var allValues = Services.TextService.GetAllStoredValues(cultureInfo);
- var pathedValues = allValues.Select(kv =>
- {
- var slashIndex = kv.Key.IndexOf('/');
- var areaAlias = kv.Key.Substring(0, slashIndex);
- var valueAlias = kv.Key.Substring(slashIndex+1);
- return new
- {
- areaAlias,
- valueAlias,
- value = kv.Value
- };
- });
-
- Dictionary> nestedDictionary = pathedValues
- .GroupBy(pv => pv.areaAlias)
- .ToDictionary(pv => pv.Key, pv =>
- pv.ToDictionary(pve => pve.valueAlias, pve => pve.value));
-
- return new JsonNetResult { Data = nestedDictionary, Formatting = Formatting.None };
- }
-
- ///
- /// Returns the JavaScript main file including all references found in manifests
- ///
- ///
- [MinifyJavaScriptResult(Order = 0)]
- [OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)]
- public async Task Application()
- {
- var result = await _runtimeMinifier.GetScriptForLoadingBackOfficeAsync(GlobalSettings, _hostingEnvironment);
-
- return JavaScript(result);
- }
-
- /// Migrated already to .Net Core
- [UmbracoAuthorize(Order = 0)]
- [HttpGet]
- public JsonNetResult GetGridConfig()
- {
- return new JsonNetResult { Data = _gridConfig.EditorsConfig.Editors, Formatting = Formatting.None };
- }
-
-
///
/// Returns the JavaScript object representing the static server variables javascript object
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index cf63fc2131..c94513684b 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -214,10 +214,11 @@ namespace Umbraco.Web.Editors
"dataTypeApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetById(0))
},
- {
- "dashboardApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetDashboard(null))
- },
+ //TODO Reintroduce
+ // {
+ // "dashboardApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetDashboard(null))
+ // },
{
"logApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetPagedEntityLog(0, 0, 0, Direction.Ascending, null))
@@ -310,10 +311,11 @@ namespace Umbraco.Web.Editors
"helpApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetContextHelpForPage("","",""))
},
- {
- "backOfficeAssetsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetSupportedLocales())
- },
+ //TODO Reintroduce
+ // {
+ // "backOfficeAssetsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetSupportedLocales())
+ // },
{
"languageApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetAllLanguages())
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 4858fafa4c..520b8845b6 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -236,7 +236,6 @@
-
@@ -350,7 +349,6 @@
-
From bff9477c313ae939998773a12d3ff58ccaa3ba49 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Tue, 19 May 2020 14:02:12 +0200
Subject: [PATCH 05/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated ExamineManagementController
---
.../ExamineManagementController.cs | 85 +++++++++++--------
.../Exceptions/HttpResponseException.cs | 18 ++++
.../Extensions/ActionResultExtensions.cs | 20 +++++
.../Extensions/LinkGeneratorExtensions.cs | 2 +-
.../Editors/BackOfficeServerVariables.cs | 9 +-
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
6 files changed, 92 insertions(+), 43 deletions(-)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/ExamineManagementController.cs (73%)
create mode 100644 src/Umbraco.Web.Common/Extensions/ActionResultExtensions.cs
diff --git a/src/Umbraco.Web/Editors/ExamineManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
similarity index 73%
rename from src/Umbraco.Web/Editors/ExamineManagementController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
index bc8590b437..f61b463346 100644
--- a/src/Umbraco.Web/Editors/ExamineManagementController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
@@ -3,15 +3,19 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Web.Http;
using Examine;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Examine;
+using Umbraco.Extensions;
+using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Models.ContentEditing;
-using Umbraco.Web.Mvc;
using Umbraco.Web.Search;
using SearchResult = Umbraco.Web.Models.ContentEditing.SearchResult;
@@ -67,10 +71,10 @@ namespace Umbraco.Web.Editors
return SearchResults.Empty();
var msg = ValidateSearcher(searcherName, out var searcher);
- if (!msg.IsSuccessStatusCode)
+ if (!msg.IsSuccessStatusCode())
throw new HttpResponseException(msg);
- // NativeQuery will work for a single word/phrase too (but depends on the implementation) the lucene one will work.
+ // NativeQuery will work for a single word/phrase too (but depends on the implementation) the lucene one will work.
var results = searcher.CreateQuery().NativeQuery(query).Execute(maxResults: pageSize * (pageIndex + 1));
var pagedResults = results.Skip(pageIndex * pageSize);
@@ -99,18 +103,19 @@ namespace Umbraco.Web.Editors
/// This is kind of rudimentary since there's no way we can know that the index has rebuilt, we
/// have a listener for the index op complete so we'll just check if that key is no longer there in the runtime cache
///
- public ExamineIndexModel PostCheckRebuildIndex(string indexName)
+ public ActionResult PostCheckRebuildIndex(string indexName)
{
var validate = ValidateIndex(indexName, out var index);
- if (!validate.IsSuccessStatusCode)
+
+ if (!validate.IsSuccessStatusCode())
throw new HttpResponseException(validate);
validate = ValidatePopulator(index);
- if (!validate.IsSuccessStatusCode)
+ if (!validate.IsSuccessStatusCode())
throw new HttpResponseException(validate);
var cacheKey = "temp_indexing_op_" + indexName;
- var found = AppCaches.RuntimeCache.Get(cacheKey);
+ var found = _runtimeCache.Get(cacheKey);
//if its still there then it's not done
return found != null
@@ -124,15 +129,15 @@ namespace Umbraco.Web.Editors
///
///
///
- public HttpResponseMessage PostRebuildIndex(string indexName)
+ public IActionResult PostRebuildIndex(string indexName)
{
var validate = ValidateIndex(indexName, out var index);
- if (!validate.IsSuccessStatusCode)
- return validate;
+ if (!validate.IsSuccessStatusCode())
+ throw new HttpResponseException(validate);
validate = ValidatePopulator(index);
- if (!validate.IsSuccessStatusCode)
- return validate;
+ if (!validate.IsSuccessStatusCode())
+ throw new HttpResponseException(validate);
_logger.Info("Rebuilding index '{IndexName}'", indexName);
@@ -146,7 +151,7 @@ namespace Umbraco.Web.Editors
{
var cacheKey = "temp_indexing_op_" + index.Name;
//put temp val in cache which is used as a rudimentary way to know when the indexing is done
- AppCaches.RuntimeCache.Insert(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5));
+ _runtimeCache.Insert(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5));
_indexRebuilder.RebuildIndex(indexName);
@@ -154,18 +159,16 @@ namespace Umbraco.Web.Editors
//foreach (var populator in _populators.Where(x => x.IsRegistered(indexName)))
// populator.Populate(index);
- return Request.CreateResponse(HttpStatusCode.OK);
+ return new OkResult();
}
catch (Exception ex)
{
//ensure it's not listening
index.IndexOperationComplete -= Indexer_IndexOperationComplete;
- Logger.Error(ex, "An error occurred rebuilding index");
- var response = Request.CreateResponse(HttpStatusCode.Conflict);
- response.Content =
- new
- StringContent($"The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {ex}");
- response.ReasonPhrase = "Could Not Rebuild";
+ _logger.Error(ex, "An error occurred rebuilding index");
+ var response = new ConflictObjectResult("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {ex}");
+
+ SetReasonPhrase(response, "Could Not Rebuild");
return response;
}
}
@@ -197,53 +200,61 @@ namespace Umbraco.Web.Editors
return indexerModel;
}
- private HttpResponseMessage ValidateSearcher(string searcherName, out ISearcher searcher)
+ private ActionResult ValidateSearcher(string searcherName, out ISearcher searcher)
{
//try to get the searcher from the indexes
if (_examineManager.TryGetIndex(searcherName, out var index))
{
searcher = index.GetSearcher();
- return Request.CreateResponse(HttpStatusCode.OK);
+ return new OkResult();
}
//if we didn't find anything try to find it by an explicitly declared searcher
if (_examineManager.TryGetSearcher(searcherName, out searcher))
- return Request.CreateResponse(HttpStatusCode.OK);
+ return new OkResult();
- var response1 = Request.CreateResponse(HttpStatusCode.BadRequest);
- response1.Content = new StringContent($"No searcher found with name = {searcherName}");
- response1.ReasonPhrase = "Searcher Not Found";
+ var response1 = new BadRequestObjectResult($"No searcher found with name = {searcherName}");
+ SetReasonPhrase(response1, "Searcher Not Found");
return response1;
}
- private HttpResponseMessage ValidatePopulator(IIndex index)
+ private ActionResult ValidatePopulator(IIndex index)
{
if (_indexRebuilder.CanRebuild(index))
- return Request.CreateResponse(HttpStatusCode.OK);
+ return new OkResult();
- var response = Request.CreateResponse(HttpStatusCode.BadRequest);
- response.Content = new StringContent($"The index {index.Name} cannot be rebuilt because it does not have an associated {typeof(IIndexPopulator)}");
- response.ReasonPhrase = "Index cannot be rebuilt";
+ var response = new BadRequestObjectResult($"The index {index.Name} cannot be rebuilt because it does not have an associated {typeof(IIndexPopulator)}");
+ SetReasonPhrase(response, "Index cannot be rebuilt");
return response;
}
- private HttpResponseMessage ValidateIndex(string indexName, out IIndex index)
+ private ActionResult ValidateIndex(string indexName, out IIndex index)
{
index = null;
if (_examineManager.TryGetIndex(indexName, out index))
{
//return Ok!
- return Request.CreateResponse(HttpStatusCode.OK);
+ return new OkResult();
}
- var response = Request.CreateResponse(HttpStatusCode.BadRequest);
- response.Content = new StringContent($"No index found with name = {indexName}");
- response.ReasonPhrase = "Index Not Found";
+ var response = new BadRequestObjectResult($"No index found with name = {indexName}");
+ SetReasonPhrase(response, "Index Not Found");
return response;
}
+ private void SetReasonPhrase(IActionResult response, string reasonPhrase)
+ {
+ //TODO we should update this behavior, as HTTP2 do not have ReasonPhrase. Could as well be returned in body
+ // https://github.com/aspnet/HttpAbstractions/issues/395
+ var httpResponseFeature = HttpContext.Features.Get();
+ if (!(httpResponseFeature is null))
+ {
+ httpResponseFeature.ReasonPhrase = reasonPhrase;
+ }
+ }
+
private void Indexer_IndexOperationComplete(object sender, EventArgs e)
{
var indexer = (IIndex)sender;
diff --git a/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs b/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs
index d88209fea4..750417fab6 100644
--- a/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs
+++ b/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Net;
using System.Runtime.Serialization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
namespace Umbraco.Web.Common.Exceptions
{
@@ -14,6 +16,22 @@ namespace Umbraco.Web.Common.Exceptions
Value = value;
}
+ public HttpResponseException(ActionResult actionResult)
+ {
+
+ Status = actionResult switch
+ {
+ IStatusCodeActionResult x => (HttpStatusCode)x.StatusCode.GetValueOrDefault((int)HttpStatusCode.InternalServerError),
+ _ => HttpStatusCode.InternalServerError
+ };
+
+ Value = actionResult switch
+ {
+ ObjectResult x => x.Value,
+ _ => null
+ };
+ }
+
public HttpStatusCode Status { get; set; }
public object Value { get; set; }
diff --git a/src/Umbraco.Web.Common/Extensions/ActionResultExtensions.cs b/src/Umbraco.Web.Common/Extensions/ActionResultExtensions.cs
new file mode 100644
index 0000000000..21bfd6f9ba
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/ActionResultExtensions.cs
@@ -0,0 +1,20 @@
+using System.Net;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+
+namespace Umbraco.Extensions
+{
+ public static class ActionResultExtensions
+ {
+ public static bool IsSuccessStatusCode(this ActionResult actionResult)
+ {
+ var statusCode = actionResult switch
+ {
+ IStatusCodeActionResult x => x.StatusCode,
+ _ => (int?)null
+ };
+
+ return statusCode.HasValue && statusCode.Value >= (int)HttpStatusCode.OK && statusCode.Value < (int) HttpStatusCode.Ambiguous;
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs
index aa7700eca0..65b81c7e64 100644
--- a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs
@@ -28,7 +28,7 @@ namespace Umbraco.Extensions
return hostingEnvironment.ApplicationVirtualPath; // this would indicate that the installer is installed without the back office
}
- return linkGenerator.GetPathByAction("Default", ControllerExtensions.GetControllerName(backOfficeControllerType), new { area = Constants.Web.Mvc.BackOfficeApiArea });
+ return linkGenerator.GetPathByAction("Default", ControllerExtensions.GetControllerName(backOfficeControllerType), values: new { area = Constants.Web.Mvc.BackOfficeApiArea });
}
///
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index c94513684b..d639d3a0a8 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -279,10 +279,11 @@ namespace Umbraco.Web.Editors
"tagsDataBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetTags("", "", null))
},
- {
- "examineMgmtBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetIndexerDetails())
- },
+ //TODO reintroduce
+ // {
+ // "examineMgmtBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetIndexerDetails())
+ // },
{
"healthCheckBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetAllHealthChecks())
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 520b8845b6..614df8b29a 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -256,7 +256,6 @@
-
From ea380985dbb3274c50fa6f428c3503bac3d74a49 Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska
Date: Wed, 20 May 2020 00:19:43 +0200
Subject: [PATCH 06/18] Moving files using MailKit nuget package (Smtp
successor) as SmtpClient has been marked as obsolete by Microsoft
---
.../Events/SendEmailEventArgs.cs | 0
.../Users}/EmailSender.cs | 50 ++++++++++++++++---
.../Users}/IEmailSender.cs | 0
3 files changed, 43 insertions(+), 7 deletions(-)
rename src/{Umbraco.Core => Umbraco.Infrastructure}/Events/SendEmailEventArgs.cs (100%)
rename src/{Umbraco.Core => Umbraco.Infrastructure/Users}/EmailSender.cs (58%)
rename src/{Umbraco.Core => Umbraco.Infrastructure/Users}/IEmailSender.cs (100%)
diff --git a/src/Umbraco.Core/Events/SendEmailEventArgs.cs b/src/Umbraco.Infrastructure/Events/SendEmailEventArgs.cs
similarity index 100%
rename from src/Umbraco.Core/Events/SendEmailEventArgs.cs
rename to src/Umbraco.Infrastructure/Events/SendEmailEventArgs.cs
diff --git a/src/Umbraco.Core/EmailSender.cs b/src/Umbraco.Infrastructure/Users/EmailSender.cs
similarity index 58%
rename from src/Umbraco.Core/EmailSender.cs
rename to src/Umbraco.Infrastructure/Users/EmailSender.cs
index 5cfdd765bc..62c45b8f78 100644
--- a/src/Umbraco.Core/EmailSender.cs
+++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs
@@ -1,9 +1,12 @@
using System;
using System.Net.Mail;
using System.Threading.Tasks;
-using Umbraco.Core.Composing;
+using MailKit.Security;
+using MimeKit;
+using MimeKit.Text;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
+using SmtpClient = MailKit.Net.Smtp.SmtpClient;
namespace Umbraco.Core
{
@@ -21,7 +24,7 @@ namespace Umbraco.Core
{
}
- internal EmailSender(IGlobalSettings globalSettings, bool enableEvents)
+ public EmailSender(IGlobalSettings globalSettings, bool enableEvents)
{
_globalSettings = globalSettings;
_enableEvents = enableEvents;
@@ -45,7 +48,9 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- client.Send(message);
+ client.Connect(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
+ client.Send(ConstructEmailMessage(message));
+ client.Disconnect(true);
}
}
}
@@ -65,14 +70,21 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
+ var appSettingsDeliveryMethod = _globalSettings.SmtpSettings.DeliveryMethod;
+ var deliveryMethod = (SmtpDeliveryMethod)Enum.Parse(typeof(SmtpDeliveryMethod), appSettingsDeliveryMethod, true);
+
+ await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
+
+ if (deliveryMethod == SmtpDeliveryMethod.Network)
{
- await client.SendMailAsync(message);
+ await client.SendAsync(ConstructEmailMessage(message));
}
else
{
- client.Send(message);
+ client.Send(ConstructEmailMessage(message));
}
+
+ await client.DisconnectAsync(true);
}
}
}
@@ -83,7 +95,7 @@ namespace Umbraco.Core
///
/// We assume this is possible if either an event handler is registered or an smtp server is configured
///
- internal static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
+ public static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
///
/// returns true if an event handler has been registered
@@ -103,5 +115,29 @@ namespace Umbraco.Core
var handler = SendEmail;
if (handler != null) handler(null, e);
}
+
+ private MimeMessage ConstructEmailMessage(MailMessage mailMessage)
+ {
+ var messageToSend = new MimeMessage
+ {
+ Subject = mailMessage.Subject
+ };
+
+ var fromEmail = mailMessage.From?.Address;
+ if(string.IsNullOrEmpty(fromEmail))
+ fromEmail = _globalSettings.SmtpSettings.From;
+
+ messageToSend.From.Add(new MailboxAddress(fromEmail));
+
+ foreach (var mailAddress in mailMessage.To)
+ messageToSend.To.Add(new MailboxAddress(mailAddress.Address));
+
+ if (mailMessage.IsBodyHtml)
+ messageToSend.Body = new TextPart(TextFormat.Html) { Text = mailMessage.Body };
+ else
+ messageToSend.Body = new TextPart(TextFormat.Plain) { Text = mailMessage.Body };
+
+ return messageToSend;
+ }
}
}
diff --git a/src/Umbraco.Core/IEmailSender.cs b/src/Umbraco.Infrastructure/Users/IEmailSender.cs
similarity index 100%
rename from src/Umbraco.Core/IEmailSender.cs
rename to src/Umbraco.Infrastructure/Users/IEmailSender.cs
From e85ccb0dabd0b488292f566afcbb1640980f5cb6 Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska
Date: Wed, 20 May 2020 00:20:25 +0200
Subject: [PATCH 07/18] Removing TODOs with the actual implementation
---
.../Editors/AuthenticationController.cs | 21 +++++++++++++------
src/Umbraco.Web/Editors/UsersController.cs | 20 +++++++++---------
2 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index fc34a35566..50e9921154 100644
--- a/src/Umbraco.Web/Editors/AuthenticationController.cs
+++ b/src/Umbraco.Web/Editors/AuthenticationController.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Collections.Generic;
+using System.Net.Mail;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Web;
@@ -328,12 +329,20 @@ namespace Umbraco.Web.Editors
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings),
new[] { identityUser.UserName, callbackUrl });
- // TODO: Port email service to ASP.NET Core
- /*await UserManager.SendEmailAsync(identityUser.Id,
- Services.TextService.Localize("login/resetPasswordEmailCopySubject",
- // Ensure the culture of the found user is used for the email!
- UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings)),
- message);*/
+ var subject = Services.TextService.Localize("login/resetPasswordEmailCopySubject",
+ // Ensure the culture of the found user is used for the email!
+ UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings));
+
+ var emailSender = new EmailSender(GlobalSettings, true);
+ var mailMessage = new MailMessage()
+ {
+ Subject = subject,
+ Body = message,
+ IsBodyHtml = true
+ };
+ mailMessage.To.Add(user.Email);
+
+ await emailSender.SendAsync(mailMessage);
UserManager.RaiseForgotPasswordRequestedEvent(user.Id);
}
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index 7aa71b6e2e..029612dc90 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Mail;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Threading.Tasks;
@@ -500,17 +501,16 @@ namespace Umbraco.Web.Editors
UmbracoUserExtensions.GetUserCulture(to.Language, Services.TextService, GlobalSettings),
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
- // TODO: Port email service to ASP.NET Core
- /*await UserManager.EmailService.SendAsync(
- //send the special UmbracoEmailMessage which configures it's own sender
- //to allow for events to handle sending the message if no smtp is configured
- new UmbracoEmailMessage(new EmailSender(GlobalSettings, true))
- {
- Body = emailBody,
- Destination = userDisplay.Email,
- Subject = emailSubject
- });*/
+ var emailSender = new EmailSender(GlobalSettings, true);
+ var mailMessage = new MailMessage()
+ {
+ Subject = emailSubject,
+ Body = emailBody,
+ IsBodyHtml = true
+ };
+ mailMessage.To.Add(to.Email);
+ await emailSender.SendAsync(mailMessage);
}
///
From ad31db9f4afa888a88e5617d25f94d43d856336b Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska
Date: Wed, 20 May 2020 00:21:45 +0200
Subject: [PATCH 08/18] Adding DeliveryMethod option which we make use of in
EmailSender.cs
---
src/Umbraco.Configuration/Legacy/SmtpSettings.cs | 1 +
src/Umbraco.Configuration/Models/GlobalSettings.cs | 5 +++--
src/Umbraco.Core/Configuration/ISmtpSettings.cs | 1 +
.../Builders/SmtpSettingsBuilder.cs | 10 ++++++++++
4 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
index 7e3ff80690..beb6eb9691 100644
--- a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
@@ -8,5 +8,6 @@ namespace Umbraco.Configuration
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
+ public string DeliveryMethod { get; set; }
}
}
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
index 4b30813bd5..646bca0f13 100644
--- a/src/Umbraco.Configuration/Models/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -72,10 +72,10 @@ namespace Umbraco.Configuration.Models
_configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml");
public bool IsSmtpServerConfigured =>
- _configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false;
+ _configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp")?.GetChildren().Any() ?? false;
public ISmtpSettings SmtpSettings =>
- new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp"));
+ new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp"));
private class SmtpSettingsImpl : ISmtpSettings
{
@@ -90,6 +90,7 @@ namespace Umbraco.Configuration.Models
public string Host => _configurationSection.GetValue("Host");
public int Port => _configurationSection.GetValue("Port");
public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation");
+ public string DeliveryMethod => _configurationSection.GetValue("DeliveryMethod");
}
}
}
diff --git a/src/Umbraco.Core/Configuration/ISmtpSettings.cs b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
index c2fb4b2dbe..217e83455b 100644
--- a/src/Umbraco.Core/Configuration/ISmtpSettings.cs
+++ b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
@@ -6,5 +6,6 @@ namespace Umbraco.Core.Configuration
string Host { get; }
int Port{ get; }
string PickupDirectoryLocation { get; }
+ string DeliveryMethod { get; }
}
}
diff --git a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
index 344d7bcf87..140af5f723 100644
--- a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
+++ b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
@@ -16,6 +16,7 @@ namespace Umbraco.Tests.Common.Builders
private string _host;
private int? _port;
private string _pickupDirectoryLocation;
+ private string _deliveryMethod;
public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder)
{
@@ -45,12 +46,19 @@ namespace Umbraco.Tests.Common.Builders
return this;
}
+ public SmtpSettingsBuilder WithDeliveryMethod(string deliveryMethod)
+ {
+ _deliveryMethod = deliveryMethod;
+ return this;
+ }
+
public override ISmtpSettings Build()
{
var from = _from ?? null;
var host = _host ?? null;
var port = _port ?? 25;
var pickupDirectoryLocation = _pickupDirectoryLocation ?? null;
+ var deliveryMethod = _deliveryMethod ?? null;
return new TestSmtpSettings()
{
@@ -58,6 +66,7 @@ namespace Umbraco.Tests.Common.Builders
Host = host,
Port = port,
PickupDirectoryLocation = pickupDirectoryLocation,
+ DeliveryMethod = deliveryMethod
};
}
@@ -67,6 +76,7 @@ namespace Umbraco.Tests.Common.Builders
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
+ public string DeliveryMethod { get; set; }
}
}
}
From 16d805e6f5b7750b5acb52fdd43d8380aae020c6 Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska
Date: Wed, 20 May 2020 00:24:55 +0200
Subject: [PATCH 09/18] Adding Smtp section in appsettings, registering
IEmailSender as an email service and ofc the MailKit nuget in Infrastructure
proj
---
.../Runtime/CoreInitialComposer.cs | 1 +
.../Umbraco.Infrastructure.csproj | 1 +
src/Umbraco.Web.UI.NetCore/appsettings.json | 10 ++++++++++
3 files changed, 12 insertions(+)
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
index 19d3716e1c..34d69c2cd5 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
@@ -320,6 +320,7 @@ namespace Umbraco.Core.Runtime
composition.RegisterUnique();
composition.RegisterUnique();
composition.RegisterUnique();
+ composition.RegisterUnique();
composition.RegisterUnique();
diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
index db3ae1bc25..8da86df6e8 100644
--- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
+++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json
index 46dc20034b..95fdaeec67 100644
--- a/src/Umbraco.Web.UI.NetCore/appsettings.json
+++ b/src/Umbraco.Web.UI.NetCore/appsettings.json
@@ -116,6 +116,16 @@
"Replacement": ""
}
]
+ },
+ "Global": {
+ "Smtp": {
+ "From": "noreply@example.com",
+ "Host": "127.0.0.1",
+ "Port": 25,
+ "UserName": "username",
+ "Password": "password",
+ "DeliveryMethod": "network"
+ }
}
}
}
From 65fa1efc9c7f3dd4fddc3775810a224e35651659 Mon Sep 17 00:00:00 2001
From: Elitsa Marinovska
Date: Wed, 20 May 2020 00:54:28 +0200
Subject: [PATCH 10/18] Changing a var name for better reflection on the origin
of its value
---
src/Umbraco.Infrastructure/Users/EmailSender.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Infrastructure/Users/EmailSender.cs b/src/Umbraco.Infrastructure/Users/EmailSender.cs
index 62c45b8f78..87f27e5097 100644
--- a/src/Umbraco.Infrastructure/Users/EmailSender.cs
+++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs
@@ -70,8 +70,8 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- var appSettingsDeliveryMethod = _globalSettings.SmtpSettings.DeliveryMethod;
- var deliveryMethod = (SmtpDeliveryMethod)Enum.Parse(typeof(SmtpDeliveryMethod), appSettingsDeliveryMethod, true);
+ var smtpSettingsDeliveryMethod = _globalSettings.SmtpSettings.DeliveryMethod;
+ var deliveryMethod = (SmtpDeliveryMethod)Enum.Parse(typeof(SmtpDeliveryMethod), smtpSettingsDeliveryMethod, true);
await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
From ca399c7e894e9cfe7afc219c18ffa8e0c8422a56 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 08:33:00 +0200
Subject: [PATCH 11/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 - removed
old tourcontroller
---
src/Umbraco.Web/Editors/TourController.cs | 227 ----------------------
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
2 files changed, 228 deletions(-)
delete mode 100644 src/Umbraco.Web/Editors/TourController.cs
diff --git a/src/Umbraco.Web/Editors/TourController.cs b/src/Umbraco.Web/Editors/TourController.cs
deleted file mode 100644
index 8a09673233..0000000000
--- a/src/Umbraco.Web/Editors/TourController.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using Newtonsoft.Json;
-using Umbraco.Core;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Configuration.UmbracoSettings;
-using Umbraco.Core.IO;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Mapping;
-using Umbraco.Core.Models.Identity;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Services;
-using Umbraco.Core.Strings;
-using Umbraco.Web.Models;
-using Umbraco.Web.Mvc;
-using Umbraco.Web.Routing;
-using Umbraco.Web.Tour;
-
-namespace Umbraco.Web.Editors
-{
- // Migrated to .NET Core
- [PluginController("UmbracoApi")]
- public class TourController : UmbracoAuthorizedJsonController
- {
- private readonly TourFilterCollection _filters;
- private readonly IIOHelper _ioHelper;
- private readonly ITourSettings _tourSettings;
-
- public TourController(
- IGlobalSettings globalSettings,
- IUmbracoContextAccessor umbracoContextAccessor,
- ISqlContext sqlContext,
- ServiceContext services,
- AppCaches appCaches,
- IProfilingLogger logger,
- IRuntimeState runtimeState,
- IShortStringHelper shortStringHelper,
- UmbracoMapper umbracoMapper,
- TourFilterCollection filters,
- IIOHelper ioHelper,
- IPublishedUrlProvider publishedUrlProvider,
- ITourSettings tourSettings)
- : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
- {
- _filters = filters;
- _ioHelper = ioHelper;
- _tourSettings = tourSettings;
- }
-
- public IEnumerable GetTours()
- {
- var result = new List();
-
- if (_tourSettings.EnableTours == false)
- return result;
-
- var user = UmbracoContext.Security.CurrentUser;
- if (user == null)
- return result;
-
- //get all filters that will be applied to all tour aliases
- var aliasOnlyFilters = _filters.Where(x => x.PluginName == null && x.TourFileName == null).ToList();
-
- //don't pass in any filters for core tours that have a plugin name assigned
- var nonPluginFilters = _filters.Where(x => x.PluginName == null).ToList();
-
- //add core tour files
- var coreToursPath = Path.Combine(_ioHelper.MapPath(Core.Constants.SystemDirectories.Config), "BackOfficeTours");
- if (Directory.Exists(coreToursPath))
- {
- foreach (var tourFile in Directory.EnumerateFiles(coreToursPath, "*.json"))
- {
- TryParseTourFile(tourFile, result, nonPluginFilters, aliasOnlyFilters);
- }
- }
-
- //collect all tour files in packages
- var appPlugins = _ioHelper.MapPath(Core.Constants.SystemDirectories.AppPlugins);
- if (Directory.Exists(appPlugins))
- {
- foreach (var plugin in Directory.EnumerateDirectories(appPlugins))
- {
- var pluginName = Path.GetFileName(plugin.TrimEnd('\\'));
- var pluginFilters = _filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginName))
- .ToList();
-
- //If there is any filter applied to match the plugin only (no file or tour alias) then ignore the plugin entirely
- var isPluginFiltered = pluginFilters.Any(x => x.TourFileName == null && x.TourAlias == null);
- if (isPluginFiltered) continue;
-
- //combine matched package filters with filters not specific to a package
- var combinedFilters = nonPluginFilters.Concat(pluginFilters).ToList();
-
- foreach (var backofficeDir in Directory.EnumerateDirectories(plugin, "backoffice"))
- {
- foreach (var tourDir in Directory.EnumerateDirectories(backofficeDir, "tours"))
- {
- foreach (var tourFile in Directory.EnumerateFiles(tourDir, "*.json"))
- {
- TryParseTourFile(tourFile, result, combinedFilters, aliasOnlyFilters, pluginName);
- }
- }
- }
- }
- }
-
- //Get all allowed sections for the current user
- var allowedSections = user.AllowedSections.ToList();
-
- var toursToBeRemoved = new List();
-
- //Checking to see if the user has access to the required tour sections, else we remove the tour
- foreach (var backOfficeTourFile in result)
- {
- if (backOfficeTourFile.Tours != null)
- {
- foreach (var tour in backOfficeTourFile.Tours)
- {
- if (tour.RequiredSections != null)
- {
- foreach (var toursRequiredSection in tour.RequiredSections)
- {
- if (allowedSections.Contains(toursRequiredSection) == false)
- {
- toursToBeRemoved.Add(backOfficeTourFile);
- break;
- }
- }
- }
- }
- }
- }
-
- return result.Except(toursToBeRemoved).OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
- }
-
- ///
- /// Gets a tours for a specific doctype
- ///
- /// The documenttype alias
- /// A
- public IEnumerable GetToursForDoctype(string doctypeAlias)
- {
- var tourFiles = this.GetTours();
-
- var doctypeAliasWithCompositions = new List
- {
- doctypeAlias
- };
-
- var contentType = this.Services.ContentTypeService.Get(doctypeAlias);
-
- if (contentType != null)
- {
- doctypeAliasWithCompositions.AddRange(contentType.CompositionAliases());
- }
-
- return tourFiles.SelectMany(x => x.Tours)
- .Where(x =>
- {
- if (string.IsNullOrEmpty(x.ContentType))
- {
- return false;
- }
- var contentTypes = x.ContentType.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(ct => ct.Trim());
- return contentTypes.Intersect(doctypeAliasWithCompositions).Any();
- });
- }
-
- private void TryParseTourFile(string tourFile,
- ICollection result,
- List filters,
- List aliasOnlyFilters,
- string pluginName = null)
- {
- var fileName = Path.GetFileNameWithoutExtension(tourFile);
- if (fileName == null) return;
-
- //get the filters specific to this file
- var fileFilters = filters.Where(x => x.TourFileName != null && x.TourFileName.IsMatch(fileName)).ToList();
-
- //If there is any filter applied to match the file only (no tour alias) then ignore the file entirely
- var isFileFiltered = fileFilters.Any(x => x.TourAlias == null);
- if (isFileFiltered) return;
-
- //now combine all aliases to filter below
- var aliasFilters = aliasOnlyFilters.Concat(filters.Where(x => x.TourAlias != null))
- .Select(x => x.TourAlias)
- .ToList();
-
- try
- {
- var contents = File.ReadAllText(tourFile);
- var tours = JsonConvert.DeserializeObject(contents);
-
- var backOfficeTours = tours.Where(x =>
- aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false);
-
- var localizedTours = backOfficeTours.Where(x =>
- string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(Security.CurrentUser.Language,
- StringComparison.InvariantCultureIgnoreCase)).ToList();
-
- var tour = new BackOfficeTourFile
- {
- FileName = Path.GetFileNameWithoutExtension(tourFile),
- PluginName = pluginName,
- Tours = localizedTours
- };
-
- //don't add if all of the tours are filtered
- if (tour.Tours.Any())
- result.Add(tour);
- }
- catch (IOException e)
- {
- throw new IOException("Error while trying to read file: " + tourFile, e);
- }
- catch (JsonReaderException e)
- {
- throw new JsonReaderException("Error while trying to parse content as tour data: " + tourFile, e);
- }
- }
- }
-}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 614df8b29a..048b9f21bd 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -145,7 +145,6 @@
-
From a8f5d21eeb9afcaf88a7c0ee23badd710d15965d Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 08:39:27 +0200
Subject: [PATCH 12/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 - removed
old OutgoingEditorModelEventAttribute and EditorModelEventManager
---
.../Editors/BackOfficeServerVariables.cs | 9 ++-
src/Umbraco.Web/Editors/ContentController.cs | 14 ++--
.../Editors/EditorModelEventManager.cs | 74 -------------------
src/Umbraco.Web/Editors/MediaController.cs | 10 +--
src/Umbraco.Web/Editors/MemberController.cs | 6 +-
src/Umbraco.Web/Editors/UsersController.cs | 4 +-
src/Umbraco.Web/Umbraco.Web.csproj | 2 -
.../OutgoingEditorModelEventAttribute.cs | 40 ----------
8 files changed, 22 insertions(+), 137 deletions(-)
delete mode 100644 src/Umbraco.Web/Editors/EditorModelEventManager.cs
delete mode 100644 src/Umbraco.Web/WebApi/Filters/OutgoingEditorModelEventAttribute.cs
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index d639d3a0a8..3f63ef7516 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -146,10 +146,11 @@ namespace Umbraco.Web.Editors
"redirectUrlManagementApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetEnableState())
},
- {
- "tourApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetTours())
- },
+ //TODO reintroduce
+ // {
+ // "tourApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetTours())
+ // },
{
"embedApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetEmbed("", 0, 0))
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index c1ddb6dba8..0bb9f93b83 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -303,7 +303,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForContent("id")]
public ContentItemDisplay GetById(int id)
{
@@ -322,7 +322,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForContent("id")]
public ContentItemDisplay GetById(Guid id)
{
@@ -342,7 +342,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForContent("id")]
public ContentItemDisplay GetById(Udi id)
{
@@ -360,7 +360,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public ContentItemDisplay GetEmpty(string contentTypeAlias, int parentId)
{
var contentType = Services.ContentTypeService.Get(contentTypeAlias);
@@ -383,7 +383,7 @@ namespace Umbraco.Web.Editors
return mapped;
}
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public ContentItemDisplay GetEmpty(int blueprintId, int parentId)
{
var blueprint = Services.ContentService.GetBlueprintById(blueprintId);
@@ -608,7 +608,7 @@ namespace Umbraco.Web.Editors
///
[FileUploadCleanupFilter]
[ContentSaveValidation]
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public ContentItemDisplay PostSave([ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem)
{
var contentItemDisplay = PostSaveInternal(
@@ -1629,7 +1629,7 @@ namespace Umbraco.Web.Editors
/// The content and variants to unpublish
///
[EnsureUserPermissionForContent("model.Id", 'Z')]
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public ContentItemDisplay PostUnpublish(UnpublishContent model)
{
var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(model.Id));
diff --git a/src/Umbraco.Web/Editors/EditorModelEventManager.cs b/src/Umbraco.Web/Editors/EditorModelEventManager.cs
deleted file mode 100644
index df4c5e4b36..0000000000
--- a/src/Umbraco.Web/Editors/EditorModelEventManager.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.Collections.Generic;
-using System.Web.Http.Filters;
-using Umbraco.Core.Dashboards;
-using Umbraco.Core.Events;
-using Umbraco.Web.Models.ContentEditing;
-
-namespace Umbraco.Web.Editors
-{
- ///
- /// Used to emit events for editor models in the back office
- ///
- public sealed class EditorModelEventManager
- {
- public static event TypedEventHandler> SendingContentModel;
- public static event TypedEventHandler> SendingMediaModel;
- public static event TypedEventHandler> SendingMemberModel;
- public static event TypedEventHandler> SendingUserModel;
-
- public static event TypedEventHandler>>> SendingDashboardSlimModel;
-
- private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e)
- {
- var handler = SendingDashboardSlimModel;
- handler?.Invoke(sender, e);
- }
-
- private static void OnSendingUserModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
- {
- var handler = SendingUserModel;
- handler?.Invoke(sender, e);
- }
-
- private static void OnSendingContentModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
- {
- var handler = SendingContentModel;
- handler?.Invoke(sender, e);
- }
-
- private static void OnSendingMediaModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
- {
- var handler = SendingMediaModel;
- handler?.Invoke(sender, e);
- }
-
- private static void OnSendingMemberModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
- {
- var handler = SendingMemberModel;
- handler?.Invoke(sender, e);
- }
-
- ///
- /// Based on the type, emit's a specific event
- ///
- ///
- ///
- internal static void EmitEvent(HttpActionExecutedContext sender, EditorModelEventArgs e)
- {
- if (e.Model is ContentItemDisplay)
- OnSendingContentModel(sender, new EditorModelEventArgs(e));
-
- if (e.Model is MediaItemDisplay)
- OnSendingMediaModel(sender, new EditorModelEventArgs(e));
-
- if (e.Model is MemberDisplay)
- OnSendingMemberModel(sender, new EditorModelEventArgs(e));
-
- if (e.Model is UserDisplay)
- OnSendingUserModel(sender, new EditorModelEventArgs(e));
-
- if (e.Model is IEnumerable>)
- OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e));
- }
- }
-}
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index 40f00d54e5..73db8bdef4 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -96,7 +96,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MediaItemDisplay GetEmpty(string contentTypeAlias, int parentId)
{
var contentType = Services.MediaTypeService.Get(contentTypeAlias);
@@ -144,7 +144,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
public MediaItemDisplay GetById(int id)
{
@@ -164,7 +164,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
public MediaItemDisplay GetById(Guid id)
{
@@ -184,7 +184,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
public MediaItemDisplay GetById(Udi id)
{
@@ -475,7 +475,7 @@ namespace Umbraco.Web.Editors
///
[FileUploadCleanupFilter]
[MediaItemSaveValidation]
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MediaItemDisplay PostSave(
[ModelBinder(typeof(MediaItemBinder))]
MediaItemSave contentItem)
diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs
index 55a3e29c5c..30d34d4bd6 100644
--- a/src/Umbraco.Web/Editors/MemberController.cs
+++ b/src/Umbraco.Web/Editors/MemberController.cs
@@ -135,7 +135,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MemberDisplay GetByKey(Guid key)
{
var foundMember = Services.MemberService.GetByKey(key);
@@ -151,7 +151,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MemberDisplay GetEmpty(string contentTypeAlias = null)
{
IMember emptyContent;
@@ -178,7 +178,7 @@ namespace Umbraco.Web.Editors
///
///
[FileUploadCleanupFilter]
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[MemberSaveValidation]
public async Task PostSave(
[ModelBinder(typeof(MemberBinder))]
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index e695139b8c..5984a86b15 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -199,7 +199,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[AdminUsersAuthorize]
public UserDisplay GetById(int id)
{
@@ -521,7 +521,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public async Task PostSaveUser(UserSave userSave)
{
if (userSave == null) throw new ArgumentNullException("userSave");
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 048b9f21bd..4072bc9a2c 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -155,7 +155,6 @@
-
@@ -399,7 +398,6 @@
-
diff --git a/src/Umbraco.Web/WebApi/Filters/OutgoingEditorModelEventAttribute.cs b/src/Umbraco.Web/WebApi/Filters/OutgoingEditorModelEventAttribute.cs
deleted file mode 100644
index e2a6f155d0..0000000000
--- a/src/Umbraco.Web/WebApi/Filters/OutgoingEditorModelEventAttribute.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Net.Http;
-using System.Web.Http.Filters;
-using Umbraco.Core;
-using Umbraco.Web.Composing;
-using Umbraco.Web.Editors;
-using Umbraco.Web.Models.ContentEditing;
-
-namespace Umbraco.Web.WebApi.Filters
-{
- ///
- /// Used to emit outgoing editor model events
- ///
- internal sealed class OutgoingEditorModelEventAttribute : ActionFilterAttribute
- {
- public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
- {
- if (actionExecutedContext.Response == null) return;
-
- var user = Current.UmbracoContext.Security.CurrentUser;
- if (user == null) return;
-
- if (actionExecutedContext.Response.Content is ObjectContent objectContent)
- {
- var model = objectContent.Value;
-
- if (model != null)
- {
- var args = new EditorModelEventArgs(
- model,
- Current.UmbracoContext);
- EditorModelEventManager.EmitEvent(actionExecutedContext, args);
- objectContent.Value = args.Model;
- }
- }
-
- base.OnActionExecuted(actionExecutedContext);
- }
- }
-}
From 1c220b492596c80f4c160db7029579af787f6584 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 08:44:02 +0200
Subject: [PATCH 13/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 - Removed
uncommented code, that was removed due to the container needs only a single
valid constructor
---
.../Filters/UmbracoAuthorizeFilter.cs | 28 -------------------
1 file changed, 28 deletions(-)
diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
index 712ece4773..16d4b7ba33 100644
--- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
@@ -54,34 +54,6 @@ namespace Umbraco.Web.BackOffice.Filters
: this(hostingEnvironment, umbracoContext, runtimeState, linkGenerator, false, null)
{
}
- //
- // ///
- // /// Constructor with redirect umbraco login behavior
- // ///
- // ///
- // ///
- // ///
- // /// If true will redirect to the umbraco login page if not authorized
- // public UmbracoAuthorizeFilter(
- // IHostingEnvironment hostingEnvironment, IUmbracoContextAccessor umbracoContext, IRuntimeState runtimeState, LinkGenerator linkGenerator,
- // bool redirectToUmbracoLogin)
- // : this(hostingEnvironment, umbracoContext, runtimeState, linkGenerator, redirectToUmbracoLogin, null)
- // {
- // }
- //
- // ///
- // /// Constructor with redirect url behavior
- // ///
- // ///
- // ///
- // /// ///
- // /// If specified will redirect to this URL if not authorized
- // public UmbracoAuthorizeFilter(
- // IHostingEnvironment hostingEnvironment, IUmbracoContextAccessor umbracoContext, IRuntimeState runtimeState, LinkGenerator linkGenerator,
- // string redirectUrl)
- // : this(hostingEnvironment, umbracoContext, runtimeState, linkGenerator, false, redirectUrl)
- // {
- // }
public void OnAuthorization(AuthorizationFilterContext context)
{
From 2b4dfbca9d44b7415bae5d6582bec35fde37a3b5 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 11:42:23 +0200
Subject: [PATCH 14/18] #8142 - Small cleanup, and bugfix
---
.../Legacy/SmtpSettings.cs | 7 +++-
.../Models/GlobalSettings.cs | 7 +++-
.../Configuration/ISmtpSettings.cs | 6 +++-
.../Events/SendEmailEventArgs.cs | 0
.../Users => Umbraco.Core}/IEmailSender.cs | 0
.../Users/EmailSender.cs | 35 +++++++------------
.../Builders/SmtpSettingsBuilder.cs | 34 ++++++++++++++----
src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 +
.../AuthenticationControllerTests.cs | 3 +-
.../Web/Controllers/UsersControllerTests.cs | 15 +++++---
.../Editors/AuthenticationController.cs | 12 ++++---
src/Umbraco.Web/Editors/UsersController.cs | 12 ++++---
12 files changed, 85 insertions(+), 47 deletions(-)
rename src/{Umbraco.Infrastructure => Umbraco.Core}/Events/SendEmailEventArgs.cs (100%)
rename src/{Umbraco.Infrastructure/Users => Umbraco.Core}/IEmailSender.cs (100%)
diff --git a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
index beb6eb9691..dce3d85840 100644
--- a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
@@ -1,3 +1,4 @@
+using System.Net.Mail;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
@@ -8,6 +9,10 @@ namespace Umbraco.Configuration
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
- public string DeliveryMethod { get; set; }
+ public SmtpDeliveryMethod DeliveryMethod { get; set; }
+
+ public string Username { get; set; }
+
+ public string Password { get; set; }
}
}
diff --git a/src/Umbraco.Configuration/Models/GlobalSettings.cs b/src/Umbraco.Configuration/Models/GlobalSettings.cs
index 646bca0f13..e4995cfb0b 100644
--- a/src/Umbraco.Configuration/Models/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Models/GlobalSettings.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Net.Mail;
using Microsoft.Extensions.Configuration;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -90,7 +91,11 @@ namespace Umbraco.Configuration.Models
public string Host => _configurationSection.GetValue("Host");
public int Port => _configurationSection.GetValue("Port");
public string PickupDirectoryLocation => _configurationSection.GetValue("PickupDirectoryLocation");
- public string DeliveryMethod => _configurationSection.GetValue("DeliveryMethod");
+ public SmtpDeliveryMethod DeliveryMethod => _configurationSection.GetValue("DeliveryMethod");
+
+ public string Username => _configurationSection.GetValue("Username");
+
+ public string Password => _configurationSection.GetValue("Password");
}
}
}
diff --git a/src/Umbraco.Core/Configuration/ISmtpSettings.cs b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
index 217e83455b..ea42ae5567 100644
--- a/src/Umbraco.Core/Configuration/ISmtpSettings.cs
+++ b/src/Umbraco.Core/Configuration/ISmtpSettings.cs
@@ -1,3 +1,5 @@
+using System.Net.Mail;
+
namespace Umbraco.Core.Configuration
{
public interface ISmtpSettings
@@ -6,6 +8,8 @@ namespace Umbraco.Core.Configuration
string Host { get; }
int Port{ get; }
string PickupDirectoryLocation { get; }
- string DeliveryMethod { get; }
+ SmtpDeliveryMethod DeliveryMethod { get; }
+ string Username { get; }
+ string Password { get; }
}
}
diff --git a/src/Umbraco.Infrastructure/Events/SendEmailEventArgs.cs b/src/Umbraco.Core/Events/SendEmailEventArgs.cs
similarity index 100%
rename from src/Umbraco.Infrastructure/Events/SendEmailEventArgs.cs
rename to src/Umbraco.Core/Events/SendEmailEventArgs.cs
diff --git a/src/Umbraco.Infrastructure/Users/IEmailSender.cs b/src/Umbraco.Core/IEmailSender.cs
similarity index 100%
rename from src/Umbraco.Infrastructure/Users/IEmailSender.cs
rename to src/Umbraco.Core/IEmailSender.cs
diff --git a/src/Umbraco.Infrastructure/Users/EmailSender.cs b/src/Umbraco.Infrastructure/Users/EmailSender.cs
index 87f27e5097..315a1748c3 100644
--- a/src/Umbraco.Infrastructure/Users/EmailSender.cs
+++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs
@@ -1,7 +1,7 @@
using System;
+using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
-using MailKit.Security;
using MimeKit;
using MimeKit.Text;
using Umbraco.Core.Configuration;
@@ -70,20 +70,18 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- var smtpSettingsDeliveryMethod = _globalSettings.SmtpSettings.DeliveryMethod;
- var deliveryMethod = (SmtpDeliveryMethod)Enum.Parse(typeof(SmtpDeliveryMethod), smtpSettingsDeliveryMethod, true);
-
await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
- if (deliveryMethod == SmtpDeliveryMethod.Network)
+ var mailMessage = ConstructEmailMessage(message);
+ if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network)
{
- await client.SendAsync(ConstructEmailMessage(message));
+ await client.SendAsync(mailMessage);
}
else
{
- client.Send(ConstructEmailMessage(message));
+ client.Send(mailMessage);
}
-
+
await client.DisconnectAsync(true);
}
}
@@ -118,24 +116,17 @@ namespace Umbraco.Core
private MimeMessage ConstructEmailMessage(MailMessage mailMessage)
{
- var messageToSend = new MimeMessage
- {
- Subject = mailMessage.Subject
- };
-
var fromEmail = mailMessage.From?.Address;
if(string.IsNullOrEmpty(fromEmail))
fromEmail = _globalSettings.SmtpSettings.From;
-
- messageToSend.From.Add(new MailboxAddress(fromEmail));
- foreach (var mailAddress in mailMessage.To)
- messageToSend.To.Add(new MailboxAddress(mailAddress.Address));
-
- if (mailMessage.IsBodyHtml)
- messageToSend.Body = new TextPart(TextFormat.Html) { Text = mailMessage.Body };
- else
- messageToSend.Body = new TextPart(TextFormat.Plain) { Text = mailMessage.Body };
+ var messageToSend = new MimeMessage
+ {
+ Subject = mailMessage.Subject,
+ From = { new MailboxAddress(fromEmail)},
+ Body = new TextPart(mailMessage.IsBodyHtml ? TextFormat.Html : TextFormat.Plain) { Text = mailMessage.Body }
+ };
+ messageToSend.To.AddRange(mailMessage.To.Select(x=>new MailboxAddress(x.Address)));
return messageToSend;
}
diff --git a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
index 140af5f723..bd85807203 100644
--- a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
+++ b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs
@@ -1,4 +1,6 @@
-using Umbraco.Core.Configuration;
+using System.Net.Mail;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Models.Membership;
namespace Umbraco.Tests.Common.Builders
{
@@ -16,7 +18,9 @@ namespace Umbraco.Tests.Common.Builders
private string _host;
private int? _port;
private string _pickupDirectoryLocation;
- private string _deliveryMethod;
+ private SmtpDeliveryMethod? _deliveryMethod;
+ private string _username;
+ private string _password;
public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder)
{
@@ -34,19 +38,31 @@ namespace Umbraco.Tests.Common.Builders
return this;
}
+ public SmtpSettingsBuilder WithUsername(string username)
+ {
+ _username = username;
+ return this;
+ }
+
public SmtpSettingsBuilder WithPost(int port)
{
_port = port;
return this;
}
+ public SmtpSettingsBuilder WithPassword(string password)
+ {
+ _password = password;
+ return this;
+ }
+
public SmtpSettingsBuilder WithPickupDirectoryLocation(string pickupDirectoryLocation)
{
_pickupDirectoryLocation = pickupDirectoryLocation;
return this;
}
- public SmtpSettingsBuilder WithDeliveryMethod(string deliveryMethod)
+ public SmtpSettingsBuilder WithDeliveryMethod(SmtpDeliveryMethod deliveryMethod)
{
_deliveryMethod = deliveryMethod;
return this;
@@ -58,7 +74,9 @@ namespace Umbraco.Tests.Common.Builders
var host = _host ?? null;
var port = _port ?? 25;
var pickupDirectoryLocation = _pickupDirectoryLocation ?? null;
- var deliveryMethod = _deliveryMethod ?? null;
+ var deliveryMethod = _deliveryMethod ?? SmtpDeliveryMethod.Network;
+ var username = _username ?? null;
+ var password = _password ?? null;
return new TestSmtpSettings()
{
@@ -66,7 +84,9 @@ namespace Umbraco.Tests.Common.Builders
Host = host,
Port = port,
PickupDirectoryLocation = pickupDirectoryLocation,
- DeliveryMethod = deliveryMethod
+ DeliveryMethod = deliveryMethod,
+ Username = username,
+ Password = password,
};
}
@@ -76,7 +96,9 @@ namespace Umbraco.Tests.Common.Builders
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
- public string DeliveryMethod { get; set; }
+ public SmtpDeliveryMethod DeliveryMethod { get; set; }
+ public string Username { get; set; }
+ public string Password { get; set; }
}
}
}
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index 80f6ab9c9e..bbc869fc65 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -313,6 +313,7 @@ namespace Umbraco.Tests.Testing
Composition.RegisterUnique();
Composition.RegisterUnique();
+ Composition.RegisterUnique();
Composition.RegisterUnique();
Composition.RegisterUnique();
Composition.RegisterUnique();
diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
index a162b0cd48..f8f02560c4 100644
--- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
@@ -91,7 +91,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
index 4c373b2bc8..ce355180f6 100644
--- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
@@ -103,7 +103,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
@@ -176,7 +177,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -219,7 +221,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -297,7 +300,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -487,7 +491,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance());
+ Factory.GetInstance(),
+ Factory.GetInstance());
var mockOwinContext = new Mock();
var mockUserManagerMarker = new Mock();
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index 50e9921154..01e13ff051 100644
--- a/src/Umbraco.Web/Editors/AuthenticationController.cs
+++ b/src/Umbraco.Web/Editors/AuthenticationController.cs
@@ -48,6 +48,7 @@ namespace Umbraco.Web.Editors
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IRuntimeState _runtimeState;
private readonly ISecuritySettings _securitySettings;
+ private readonly IEmailSender _emailSender;
public AuthenticationController(
IUserPasswordConfiguration passwordConfiguration,
@@ -61,13 +62,15 @@ namespace Umbraco.Web.Editors
IRuntimeState runtimeState,
UmbracoMapper umbracoMapper,
ISecuritySettings securitySettings,
- IPublishedUrlProvider publishedUrlProvider)
+ IPublishedUrlProvider publishedUrlProvider,
+ IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider)
{
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
_securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings));
+ _emailSender = emailSender;
}
protected BackOfficeUserManager UserManager => _userManager
@@ -333,16 +336,15 @@ namespace Umbraco.Web.Editors
// Ensure the culture of the found user is used for the email!
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings));
- var emailSender = new EmailSender(GlobalSettings, true);
var mailMessage = new MailMessage()
{
Subject = subject,
Body = message,
- IsBodyHtml = true
+ IsBodyHtml = true,
+ To = { user.Email}
};
- mailMessage.To.Add(user.Email);
- await emailSender.SendAsync(mailMessage);
+ await _emailSender.SendAsync(mailMessage);
UserManager.RaiseForgotPasswordRequestedEvent(user.Id);
}
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index 029612dc90..3c71245a0a 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -53,6 +53,7 @@ namespace Umbraco.Web.Editors
private readonly ISqlContext _sqlContext;
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly ISecuritySettings _securitySettings;
+ private readonly IEmailSender _emailSender;
public UsersController(
IGlobalSettings globalSettings,
@@ -69,7 +70,8 @@ namespace Umbraco.Web.Editors
IHostingEnvironment hostingEnvironment,
IImageUrlGenerator imageUrlGenerator,
IPublishedUrlProvider publishedUrlProvider,
- ISecuritySettings securitySettings)
+ ISecuritySettings securitySettings,
+ IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_mediaFileSystem = mediaFileSystem;
@@ -78,6 +80,7 @@ namespace Umbraco.Web.Editors
_sqlContext = sqlContext;
_imageUrlGenerator = imageUrlGenerator;
_securitySettings = securitySettings;
+ _emailSender = emailSender;
}
///
@@ -501,16 +504,15 @@ namespace Umbraco.Web.Editors
UmbracoUserExtensions.GetUserCulture(to.Language, Services.TextService, GlobalSettings),
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
- var emailSender = new EmailSender(GlobalSettings, true);
var mailMessage = new MailMessage()
{
Subject = emailSubject,
Body = emailBody,
- IsBodyHtml = true
+ IsBodyHtml = true,
+ To = { to.Email}
};
- mailMessage.To.Add(to.Email);
- await emailSender.SendAsync(mailMessage);
+ await _emailSender.SendAsync(mailMessage);
}
///
From 490ae37b28571996da37cdf0f932318d317a9c21 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 12:38:21 +0200
Subject: [PATCH 15/18] #8142 - Added smtp authentication if username or
password provided
---
src/Umbraco.Infrastructure/Users/EmailSender.cs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/Umbraco.Infrastructure/Users/EmailSender.cs b/src/Umbraco.Infrastructure/Users/EmailSender.cs
index 315a1748c3..9a2f425021 100644
--- a/src/Umbraco.Infrastructure/Users/EmailSender.cs
+++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs
@@ -48,7 +48,15 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
+
client.Connect(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
+
+ if (!(_globalSettings.SmtpSettings.Username is null &&
+ _globalSettings.SmtpSettings.Password is null))
+ {
+ client.Authenticate(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
+ }
+
client.Send(ConstructEmailMessage(message));
client.Disconnect(true);
}
@@ -72,6 +80,12 @@ namespace Umbraco.Core
{
await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
+ if (!(_globalSettings.SmtpSettings.Username is null &&
+ _globalSettings.SmtpSettings.Password is null))
+ {
+ await client.AuthenticateAsync(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
+ }
+
var mailMessage = ConstructEmailMessage(message);
if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network)
{
From a94af8db0342fcfae0ad414f1b543a0394095176 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 13:35:55 +0200
Subject: [PATCH 16/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated HelpController
---
.../Controllers}/HelpController.cs | 13 +++++++++++--
.../Editors/BackOfficeServerVariables.cs | 9 +++++----
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
3 files changed, 16 insertions(+), 7 deletions(-)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/HelpController.cs (81%)
diff --git a/src/Umbraco.Web/Editors/HelpController.cs b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs
similarity index 81%
rename from src/Umbraco.Web/Editors/HelpController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/HelpController.cs
index 39dbbc435c..fe055b5270 100644
--- a/src/Umbraco.Web/Editors/HelpController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs
@@ -3,11 +3,20 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Threading.Tasks;
+using Umbraco.Core.Logging;
+using Umbraco.Web.Editors;
-namespace Umbraco.Web.Editors
+namespace Umbraco.Web.BackOffice.Controllers
{
public class HelpController : UmbracoAuthorizedJsonController
{
+ private readonly ILogger _logger;
+
+ public HelpController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
private static HttpClient _httpClient;
public async Task> GetContextHelpForPage(string section, string tree, string baseUrl = "https://our.umbraco.com")
{
@@ -28,7 +37,7 @@ namespace Umbraco.Web.Editors
}
catch (HttpRequestException rex)
{
- Logger.Info(GetType(), $"Check your network connection, exception: {rex.Message}");
+ _logger.Info(GetType(), $"Check your network connection, exception: {rex.Message}");
}
return new List();
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index 3f63ef7516..edf50ba36b 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -309,10 +309,11 @@ namespace Umbraco.Web.Editors
"publishedSnapshotCacheStatusBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetStatus())
},
- {
- "helpApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetContextHelpForPage("","",""))
- },
+ //TODO Reintroduce
+ // {
+ // "helpApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetContextHelpForPage("","",""))
+ // },
//TODO Reintroduce
// {
// "backOfficeAssetsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 4072bc9a2c..99a165e6fd 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -255,7 +255,6 @@
-
From 0d65fccd52bbb241b3e84571a17fe14f6eca4a78 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 13:51:21 +0200
Subject: [PATCH 17/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated ImagesController
---
.../Controllers}/ImagesController.cs | 18 +++++++++---------
.../Editors/BackOfficeServerVariables.cs | 9 +++++----
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
3 files changed, 14 insertions(+), 14 deletions(-)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/ImagesController.cs (91%)
diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
similarity index 91%
rename from src/Umbraco.Web/Editors/ImagesController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
index bbad627c3b..96eb120b25 100644
--- a/src/Umbraco.Web/Editors/ImagesController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
@@ -2,10 +2,13 @@
using System.IO;
using System.Net;
using System.Net.Http;
+using Microsoft.AspNetCore.Mvc;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Media;
using Umbraco.Core.Models;
+using Umbraco.Web.BackOffice.Controllers;
+using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -36,10 +39,10 @@ namespace Umbraco.Web.Editors
///
/// If there is no original image is found then this will return not found.
///
- public HttpResponseMessage GetBigThumbnail(string originalImagePath)
+ public IActionResult GetBigThumbnail(string originalImagePath)
{
return string.IsNullOrWhiteSpace(originalImagePath)
- ? Request.CreateResponse(HttpStatusCode.OK)
+ ? Ok()
: GetResized(originalImagePath, 500);
}
@@ -52,22 +55,20 @@ namespace Umbraco.Web.Editors
///
/// If there is no media, image property or image file is found then this will return not found.
///
- public HttpResponseMessage GetResized(string imagePath, int width)
+ public IActionResult GetResized(string imagePath, int width)
{
var ext = Path.GetExtension(imagePath);
// we need to check if it is an image by extension
if (_contentSettings.IsImageFile(ext) == false)
- return Request.CreateResponse(HttpStatusCode.NotFound);
+ return NotFound();
//redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file
- var response = Request.CreateResponse(HttpStatusCode.Found);
-
DateTimeOffset? imageLastModified = null;
try
{
imageLastModified = _mediaFileSystem.GetLastModified(imagePath);
-
+
}
catch (Exception)
{
@@ -80,8 +81,7 @@ namespace Umbraco.Web.Editors
var rnd = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath) { UpScale = false, Width = width, AnimationProcessMode = "first", ImageCropMode = "max", CacheBusterValue = rnd });
- response.Headers.Location = new Uri(imageUrl, UriKind.RelativeOrAbsolute);
- return response;
+ return new RedirectResult(imageUrl, false);
}
///
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index edf50ba36b..33d4166112 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -171,10 +171,11 @@ namespace Umbraco.Web.Editors
"mediaApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetRootMedia())
},
- {
- "imagesApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetBigThumbnail(""))
- },
+ //TODO reintroduce
+ // {
+ // "imagesApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetBigThumbnail(""))
+ // },
{
"sectionApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetSections())
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 99a165e6fd..434d5eda88 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -346,7 +346,6 @@
-
From 28c4f8723651c04e36477ce1cecad8cee44f58d0 Mon Sep 17 00:00:00 2001
From: Bjarke Berg
Date: Wed, 20 May 2020 17:39:07 +0200
Subject: [PATCH 18/18]
https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/6586 -
Migrated ImageUrlGeneratorController + Made usage some strings into the enums
in the ImageUrlGenerationOptions
---
.../Models/ImageUrlGenerationOptions.cs | 8 +++++---
.../Media/ImageSharpImageUrlGenerator.cs | 5 +++--
.../Models/UserExtensions.cs | 11 ++++++-----
.../PropertyEditors/RichTextEditorPastedImages.cs | 3 ++-
.../Models/ImageProcessorImageUrlGeneratorTest.cs | 15 ++++++++-------
.../Controllers}/ImageUrlGeneratorController.cs | 11 ++++++++++-
.../Controllers/ImagesController.cs | 5 +++--
.../Editors/BackOfficeServerVariables.cs | 9 +++++----
.../ImageCropperTemplateCoreExtensions.cs | 4 ++--
src/Umbraco.Web/Umbraco.Web.csproj | 1 -
10 files changed, 44 insertions(+), 28 deletions(-)
rename src/{Umbraco.Web/Editors => Umbraco.Web.BackOffice/Controllers}/ImageUrlGeneratorController.cs (75%)
diff --git a/src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs b/src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs
index f87657c33d..369ee9b25b 100644
--- a/src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs
+++ b/src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs
@@ -1,4 +1,6 @@
-namespace Umbraco.Core.Models
+using Umbraco.Web.Models;
+
+namespace Umbraco.Core.Models
{
///
/// These are options that are passed to the IImageUrlGenerator implementation to determine
@@ -17,8 +19,8 @@
public decimal? WidthRatio { get; set; }
public decimal? HeightRatio { get; set; }
public int? Quality { get; set; }
- public string ImageCropMode { get; set; }
- public string ImageCropAnchor { get; set; }
+ public ImageCropMode? ImageCropMode { get; set; }
+ public ImageCropAnchor? ImageCropAnchor { get; set; }
public bool DefaultCrop { get; set; }
public FocalPointPosition FocalPoint { get; set; }
public CropCoordinates Crop { get; set; }
diff --git a/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs b/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs
index 9058123eb3..48ff16f85b 100644
--- a/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs
+++ b/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs
@@ -3,6 +3,7 @@ using System.Text;
using Umbraco.Core;
using Umbraco.Core.Media;
using Umbraco.Core.Models;
+using Umbraco.Web.Models;
namespace Umbraco.Infrastructure.Media
{
@@ -19,9 +20,9 @@ namespace Umbraco.Infrastructure.Media
else if (options.DefaultCrop) imageProcessorUrl.Append("?anchor=center&mode=crop");
else
{
- imageProcessorUrl.Append("?mode=").Append((options.ImageCropMode ?? "crop").ToLower());
+ imageProcessorUrl.Append("?mode=").Append((options.ImageCropMode ?? ImageCropMode.Crop).ToString().ToLower());
- if (options.ImageCropAnchor != null) imageProcessorUrl.Append("&anchor=").Append(options.ImageCropAnchor.ToLower());
+ if (options.ImageCropAnchor != null) imageProcessorUrl.Append("&anchor=").Append(options.ImageCropAnchor.ToString().ToLower());
}
var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&format=");
diff --git a/src/Umbraco.Infrastructure/Models/UserExtensions.cs b/src/Umbraco.Infrastructure/Models/UserExtensions.cs
index 4fefc89d11..668d89a04d 100644
--- a/src/Umbraco.Infrastructure/Models/UserExtensions.cs
+++ b/src/Umbraco.Infrastructure/Models/UserExtensions.cs
@@ -10,6 +10,7 @@ using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Core.Security;
using Umbraco.Core.Media;
+using Umbraco.Web.Models;
namespace Umbraco.Core.Models
{
@@ -78,11 +79,11 @@ namespace Umbraco.Core.Models
var avatarUrl = mediaFileSystem.GetUrl(user.Avatar);
return new[]
{
- imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 30, Height = 30 }),
- imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 60, Height = 60 }),
- imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 90, Height = 90 }),
- imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 150, Height = 150 }),
- imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 300, Height = 300 })
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 30, Height = 30 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 60, Height = 60 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 90, Height = 90 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 150, Height = 150 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 300, Height = 300 })
};
}
diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs
index 38b4611c1e..58a280e5db 100644
--- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs
+++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs
@@ -10,6 +10,7 @@ using Umbraco.Core.Media;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
+using Umbraco.Web.Models;
using Umbraco.Web.Routing;
using Umbraco.Web.Templates;
@@ -120,7 +121,7 @@ namespace Umbraco.Web.PropertyEditors
if (width != int.MinValue && height != int.MinValue)
{
- location = imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(location) { ImageCropMode = "max", Width = width, Height = height });
+ location = imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(location) { ImageCropMode = ImageCropMode.Max, Width = width, Height = height });
}
img.SetAttributeValue("src", location);
diff --git a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs
index 62c82caf66..a5b059cd23 100644
--- a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs
+++ b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs
@@ -20,6 +20,7 @@ using Umbraco.Web;
using Umbraco.Web.PropertyEditors;
using System.Text;
using Umbraco.Infrastructure.Media;
+using Umbraco.Web.Models;
namespace Umbraco.Tests.Models
{
@@ -126,11 +127,11 @@ namespace Umbraco.Tests.Models
[Test]
public void GetCropUrl_SpecifiedCropModeTest()
{
- var urlStringMin = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Min", Width = 300, Height = 150 });
- var urlStringBoxPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "BoxPad", Width = 300, Height = 150 });
- var urlStringPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Pad", Width = 300, Height = 150 });
- var urlStringMax = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Max", Width = 300, Height = 150 });
- var urlStringStretch = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Stretch", Width = 300, Height = 150 });
+ var urlStringMin = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Min, Width = 300, Height = 150 });
+ var urlStringBoxPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.BoxPad, Width = 300, Height = 150 });
+ var urlStringPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 300, Height = 150 });
+ var urlStringMax = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Max, Width = 300, Height = 150 });
+ var urlStringStretch = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Stretch, Width = 300, Height = 150 });
Assert.AreEqual(MediaPath + "?mode=min&width=300&height=150", urlStringMin);
Assert.AreEqual(MediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad);
@@ -145,7 +146,7 @@ namespace Umbraco.Tests.Models
[Test]
public void GetCropUrl_UploadTypeTest()
{
- var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Crop", ImageCropAnchor = "Center", Width = 100, Height = 270 });
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Crop, ImageCropAnchor = ImageCropAnchor.Center, Width = 100, Height = 270 });
Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString);
}
@@ -225,7 +226,7 @@ namespace Umbraco.Tests.Models
[Test]
public void GetCropUrl_BackgroundColorParameter()
{
- var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Pad", Width = 400, Height = 400, FurtherOptions = "&bgcolor=fff" });
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 400, Height = 400, FurtherOptions = "&bgcolor=fff" });
Assert.AreEqual(MediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
}
}
diff --git a/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImageUrlGeneratorController.cs
similarity index 75%
rename from src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/ImageUrlGeneratorController.cs
index e5369fb7a1..bf9b14e86a 100644
--- a/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ImageUrlGeneratorController.cs
@@ -4,6 +4,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Media;
+using Umbraco.Core.Models;
+using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
@@ -20,6 +22,7 @@ namespace Umbraco.Web.Editors
/// building to generate correct URLs
///
///
+ [PluginController("UmbracoApi")]
public class ImageUrlGeneratorController : UmbracoAuthorizedJsonController
{
private readonly IImageUrlGenerator _imageUrlGenerator;
@@ -31,7 +34,13 @@ namespace Umbraco.Web.Editors
public string GetCropUrl(string mediaPath, int? width = null, int? height = null, ImageCropMode? imageCropMode = null, string animationProcessMode = null)
{
- return mediaPath.GetCropUrl(_imageUrlGenerator, null, width: width, height: height, imageCropMode: imageCropMode, animationProcessMode: animationProcessMode);
+ return _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(mediaPath)
+ {
+ Width = width,
+ Height = height,
+ ImageCropMode = imageCropMode,
+ AnimationProcessMode = animationProcessMode
+ });
}
}
}
diff --git a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
index 96eb120b25..90b52b845f 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
@@ -9,6 +9,7 @@ using Umbraco.Core.Media;
using Umbraco.Core.Models;
using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -79,7 +80,7 @@ namespace Umbraco.Web.Editors
}
var rnd = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
- var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath) { UpScale = false, Width = width, AnimationProcessMode = "first", ImageCropMode = "max", CacheBusterValue = rnd });
+ var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath) { UpScale = false, Width = width, AnimationProcessMode = "first", ImageCropMode = ImageCropMode.Max, CacheBusterValue = rnd });
return new RedirectResult(imageUrl, false);
}
@@ -105,7 +106,7 @@ namespace Umbraco.Web.Editors
int? focalPointLeft = null,
int? focalPointTop = null,
string animationProcessMode = "first",
- string mode = "max",
+ ImageCropMode mode = ImageCropMode.Max,
bool upscale = false,
string cacheBusterValue = "")
{
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index 33d4166112..6441f6ad6a 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -340,10 +340,11 @@ namespace Umbraco.Web.Editors
"tinyMceApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.UploadImage())
},
- {
- "imageUrlGeneratorApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetCropUrl(null, null, null, null, null))
- },
+ //TODO Reintroduce
+ // {
+ // "imageUrlGeneratorApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetCropUrl(null, null, null, null, null))
+ // },
}
},
{
diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
index 68bbb26784..0b7e065c59 100644
--- a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
+++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
@@ -346,8 +346,8 @@ namespace Umbraco.Web
{
options = new ImageUrlGenerationOptions (imageUrl)
{
- ImageCropMode = (imageCropMode ?? ImageCropMode.Pad).ToString().ToLowerInvariant(),
- ImageCropAnchor = imageCropAnchor?.ToString().ToLowerInvariant()
+ ImageCropMode = (imageCropMode ?? ImageCropMode.Pad),
+ ImageCropAnchor = imageCropAnchor
};
}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 434d5eda88..2db3dcd909 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -158,7 +158,6 @@
-