diff --git a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs
index 7e3ff80690..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,5 +9,10 @@ namespace Umbraco.Configuration
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { 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 4b30813bd5..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;
@@ -72,10 +73,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 +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 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 c2fb4b2dbe..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,5 +8,8 @@ namespace Umbraco.Core.Configuration
string Host { get; }
int Port{ get; }
string PickupDirectoryLocation { get; }
+ SmtpDeliveryMethod DeliveryMethod { get; }
+ string Username { get; }
+ string Password { get; }
}
}
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.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs
index ca5f63ee8e..295b764834 100644
--- a/src/Umbraco.Core/Models/UserExtensions.cs
+++ b/src/Umbraco.Core/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/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/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.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
index f28a97303e..332813faf8 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
@@ -321,6 +321,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 aaac2324ae..1af8ce9119 100644
--- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
+++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
@@ -11,6 +11,7 @@
+
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 7b07a4bdf7..9a2f425021 100644
--- a/src/Umbraco.Core/EmailSender.cs
+++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs
@@ -1,9 +1,12 @@
using System;
+using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
-using Umbraco.Core.Composing;
+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,17 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- client.Send(message);
+
+ 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);
}
}
}
@@ -65,14 +78,25 @@ namespace Umbraco.Core
{
using (var client = new SmtpClient())
{
- if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
+ await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
+
+ if (!(_globalSettings.SmtpSettings.Username is null &&
+ _globalSettings.SmtpSettings.Password is null))
{
- await client.SendMailAsync(message);
+ await client.AuthenticateAsync(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
+ }
+
+ var mailMessage = ConstructEmailMessage(message);
+ if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network)
+ {
+ await client.SendAsync(mailMessage);
}
else
{
- client.Send(message);
+ client.Send(mailMessage);
}
+
+ await client.DisconnectAsync(true);
}
}
}
@@ -103,5 +127,22 @@ namespace Umbraco.Core
var handler = SendEmail;
if (handler != null) handler(null, e);
}
+
+ private MimeMessage ConstructEmailMessage(MailMessage mailMessage)
+ {
+ var fromEmail = mailMessage.From?.Address;
+ if(string.IsNullOrEmpty(fromEmail))
+ fromEmail = _globalSettings.SmtpSettings.From;
+
+ 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 344d7bcf87..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,6 +18,9 @@ namespace Umbraco.Tests.Common.Builders
private string _host;
private int? _port;
private string _pickupDirectoryLocation;
+ private SmtpDeliveryMethod? _deliveryMethod;
+ private string _username;
+ private string _password;
public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder)
{
@@ -33,24 +38,45 @@ 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(SmtpDeliveryMethod 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 ?? SmtpDeliveryMethod.Network;
+ var username = _username ?? null;
+ var password = _password ?? null;
return new TestSmtpSettings()
{
@@ -58,6 +84,9 @@ namespace Umbraco.Tests.Common.Builders
Host = host,
Port = port,
PickupDirectoryLocation = pickupDirectoryLocation,
+ DeliveryMethod = deliveryMethod,
+ Username = username,
+ Password = password,
};
}
@@ -67,6 +96,9 @@ namespace Umbraco.Tests.Common.Builders
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
+ public SmtpDeliveryMethod DeliveryMethod { get; set; }
+ public string Username { get; set; }
+ public string Password { get; set; }
}
}
}
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.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 652541da0c..a35e891c1c 100644
--- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
@@ -93,7 +93,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 6905c749e6..1158d00b4e 100644
--- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
@@ -104,7 +104,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
@@ -178,7 +179,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -222,7 +224,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -301,7 +304,8 @@ namespace Umbraco.Tests.Web.Controllers
Factory.GetInstance(),
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -492,7 +496,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.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 38c6c40da2..aecad8c4e4 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
@@ -33,7 +33,6 @@ namespace Umbraco.Web.BackOffice.Controllers
private readonly IRuntimeMinifier _runtimeMinifier;
private readonly IGlobalSettings _globalSettings;
private readonly IHostingEnvironment _hostingEnvironment;
- private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ILocalizedTextService _textService;
private readonly IGridConfig _gridConfig;
@@ -46,7 +45,7 @@ namespace Umbraco.Web.BackOffice.Controllers
IRuntimeMinifier runtimeMinifier,
IGlobalSettings globalSettings,
IHostingEnvironment hostingEnvironment,
- IUmbracoApplicationLifetime umbracoApplicationLifetime,
+
IUmbracoContextAccessor umbracoContextAccessor,
ILocalizedTextService textService,
IGridConfig gridConfig,
@@ -59,7 +58,6 @@ namespace Umbraco.Web.BackOffice.Controllers
_runtimeMinifier = runtimeMinifier;
_globalSettings = globalSettings;
_hostingEnvironment = hostingEnvironment;
- _umbracoApplicationLifetime = umbracoApplicationLifetime;
_umbracoContextAccessor = umbracoContextAccessor;
_textService = textService;
_gridConfig = gridConfig ?? throw new ArgumentNullException(nameof(gridConfig));
@@ -130,7 +128,7 @@ namespace Umbraco.Web.BackOffice.Controllers
return new JsonNetResult { Data = nestedDictionary, Formatting = Formatting.None };
}
- [UmbracoAuthorize(Order = 0)] // TODO: Re-implement UmbracoAuthorizeAttribute
+ [UmbracoAuthorize(Order = 0)]
[HttpGet]
public JsonNetResult GetGridConfig()
{
@@ -223,5 +221,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
return Redirect("/");
}
+
+
}
}
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/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/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/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/Editors/ImagesController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
similarity index 88%
rename from src/Umbraco.Web/Editors/ImagesController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
index bbad627c3b..90b52b845f 100644
--- a/src/Umbraco.Web/Editors/ImagesController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs
@@ -2,10 +2,14 @@
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.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -36,10 +40,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 +56,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)
{
@@ -78,10 +80,9 @@ 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 });
- response.Headers.Location = new Uri(imageUrl, UriKind.RelativeOrAbsolute);
- return response;
+ 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/TourController.cs b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs
similarity index 84%
rename from src/Umbraco.Web/Editors/TourController.cs
rename to src/Umbraco.Web.BackOffice/Controllers/TourController.cs
index 93ec4252df..528a67fdff 100644
--- a/src/Umbraco.Web/Editors/TourController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs
@@ -3,20 +3,12 @@ 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.Hosting;
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.Common.Attributes;
using Umbraco.Web.Models;
-using Umbraco.Web.Mvc;
-using Umbraco.Web.Routing;
using Umbraco.Web.Tour;
namespace Umbraco.Web.Editors
@@ -25,28 +17,24 @@ namespace Umbraco.Web.Editors
public class TourController : UmbracoAuthorizedJsonController
{
private readonly TourFilterCollection _filters;
- private readonly IIOHelper _ioHelper;
+ private readonly IHostingEnvironment _hostingEnvironment;
private readonly ITourSettings _tourSettings;
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+ private readonly IContentTypeService _contentTypeService;
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)
+ IHostingEnvironment hostingEnvironment,
+ ITourSettings tourSettings,
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IContentTypeService contentTypeService)
{
_filters = filters;
- _ioHelper = ioHelper;
+ _hostingEnvironment = hostingEnvironment;
+
_tourSettings = tourSettings;
+ _umbracoContextAccessor = umbracoContextAccessor;
+ _contentTypeService = contentTypeService;
}
public IEnumerable GetTours()
@@ -56,7 +44,7 @@ namespace Umbraco.Web.Editors
if (_tourSettings.EnableTours == false)
return result;
- var user = UmbracoContext.Security.CurrentUser;
+ var user = _umbracoContextAccessor.UmbracoContext.Security.CurrentUser;
if (user == null)
return result;
@@ -67,7 +55,7 @@ namespace Umbraco.Web.Editors
var nonPluginFilters = _filters.Where(x => x.PluginName == null).ToList();
//add core tour files
- var coreToursPath = Path.Combine(_ioHelper.MapPath(Core.Constants.SystemDirectories.Config), "BackOfficeTours");
+ var coreToursPath = Path.Combine(_hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.Config), "BackOfficeTours");
if (Directory.Exists(coreToursPath))
{
foreach (var tourFile in Directory.EnumerateFiles(coreToursPath, "*.json"))
@@ -77,7 +65,7 @@ namespace Umbraco.Web.Editors
}
//collect all tour files in packages
- var appPlugins = _ioHelper.MapPath(Core.Constants.SystemDirectories.AppPlugins);
+ var appPlugins = _hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.AppPlugins);
if (Directory.Exists(appPlugins))
{
foreach (var plugin in Directory.EnumerateDirectories(appPlugins))
@@ -150,7 +138,7 @@ namespace Umbraco.Web.Editors
doctypeAlias
};
- var contentType = this.Services.ContentTypeService.Get(doctypeAlias);
+ var contentType = _contentTypeService.Get(doctypeAlias);
if (contentType != null)
{
@@ -192,14 +180,16 @@ namespace Umbraco.Web.Editors
try
{
- var contents = File.ReadAllText(tourFile);
+ var contents = System.IO.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 user = _umbracoContextAccessor.UmbracoContext.Security.CurrentUser;
+
var localizedTours = backOfficeTours.Where(x =>
- string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(Security.CurrentUser.Language,
+ string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(user.Language,
StringComparison.InvariantCultureIgnoreCase)).ToList();
var tour = new BackOfficeTourFile
diff --git a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
new file mode 100644
index 0000000000..c3e1a71b86
--- /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] //TODO reintroduce
+ [UmbracoAuthorize]
+ [DisableBrowserCache]
+ [UmbracoWebApiRequireHttps]
+ //[CheckIfUserTicketDataIsStale] //TODO reintroduce
+ //[UnhandedExceptionLoggerConfiguration] //TODO reintroduce
+ //[EnableDetailedErrors] //TODO reintroduce
+ public abstract class UmbracoAuthorizedApiController : UmbracoApiController
+ {
+
+ }
+}
diff --git a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedJsonController.cs
new file mode 100644
index 0000000000..70d3155f23
--- /dev/null
+++ b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedJsonController.cs
@@ -0,0 +1,21 @@
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Web.BackOffice.Controllers;
+using Umbraco.Web.BackOffice.Filters;
+using Umbraco.Web.Common.Filters;
+
+namespace Umbraco.Web.Editors
+{
+ ///
+ /// An abstract API controller that only supports JSON and all requests must contain the correct csrf header
+ ///
+ ///
+ /// Inheriting from this controller means that ALL of your methods are JSON methods that are called by Angular,
+ /// methods that are not called by Angular or don't contain a valid csrf header will NOT work.
+ ///
+ [TypeFilter(typeof(ValidateAngularAntiForgeryTokenAttribute))]
+ [TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))] // TODO: This could be applied with our Application Model conventions
+ public abstract class UmbracoAuthorizedJsonController : UmbracoAuthorizedApiController
+ {
+
+ }
+}
diff --git a/src/Umbraco.Web/Editors/EditorModelEventManager.cs b/src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
similarity index 55%
rename from src/Umbraco.Web/Editors/EditorModelEventManager.cs
rename to src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
index df4c5e4b36..7255c91f49 100644
--- a/src/Umbraco.Web/Editors/EditorModelEventManager.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/EditorModelEventManager.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
-using System.Web.Http.Filters;
+using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core.Dashboards;
using Umbraco.Core.Events;
using Umbraco.Web.Models.ContentEditing;
@@ -11,38 +11,38 @@ namespace Umbraco.Web.Editors
///
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> SendingContentModel;
+ public static event TypedEventHandler> SendingMediaModel;
+ public static event TypedEventHandler> SendingMemberModel;
+ public static event TypedEventHandler> SendingUserModel;
- public static event TypedEventHandler>>> SendingDashboardSlimModel;
+ public static event TypedEventHandler>>> SendingDashboardSlimModel;
- private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e)
+ private static void OnSendingDashboardModel(ActionExecutedContext sender, EditorModelEventArgs>> e)
{
var handler = SendingDashboardSlimModel;
handler?.Invoke(sender, e);
}
- private static void OnSendingUserModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
+ private static void OnSendingUserModel(ActionExecutedContext sender, EditorModelEventArgs e)
{
var handler = SendingUserModel;
handler?.Invoke(sender, e);
}
- private static void OnSendingContentModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
+ private static void OnSendingContentModel(ActionExecutedContext sender, EditorModelEventArgs e)
{
var handler = SendingContentModel;
handler?.Invoke(sender, e);
}
- private static void OnSendingMediaModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
+ private static void OnSendingMediaModel(ActionExecutedContext sender, EditorModelEventArgs e)
{
var handler = SendingMediaModel;
handler?.Invoke(sender, e);
}
- private static void OnSendingMemberModel(HttpActionExecutedContext sender, EditorModelEventArgs e)
+ private static void OnSendingMemberModel(ActionExecutedContext sender, EditorModelEventArgs e)
{
var handler = SendingMemberModel;
handler?.Invoke(sender, e);
@@ -53,7 +53,7 @@ namespace Umbraco.Web.Editors
///
///
///
- internal static void EmitEvent(HttpActionExecutedContext sender, EditorModelEventArgs e)
+ internal static void EmitEvent(ActionExecutedContext sender, EditorModelEventArgs e)
{
if (e.Model is ContentItemDisplay)
OnSendingContentModel(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.BackOffice/Filters/UmbracoAuthorizeFilter.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
index 5aec94e70a..16d4b7ba33 100644
--- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs
@@ -52,34 +52,6 @@ namespace Umbraco.Web.BackOffice.Filters
public UmbracoAuthorizeFilter(
IHostingEnvironment hostingEnvironment, IUmbracoContextAccessor umbracoContext, IRuntimeState runtimeState, LinkGenerator linkGenerator)
: 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)
{
}
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/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index e2dff57cca..81d714926f 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;
@@ -47,6 +48,7 @@ namespace Umbraco.Web.Editors
private readonly IRuntimeState _runtimeState;
private readonly ISecuritySettings _securitySettings;
private readonly IRequestAccessor _requestAccessor;
+ private readonly IEmailSender _emailSender;
public AuthenticationController(
IUserPasswordConfiguration passwordConfiguration,
@@ -61,7 +63,8 @@ namespace Umbraco.Web.Editors
UmbracoMapper umbracoMapper,
ISecuritySettings securitySettings,
IPublishedUrlProvider publishedUrlProvider,
- IRequestAccessor requestAccessor)
+ IRequestAccessor requestAccessor,
+ IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider)
{
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
@@ -69,6 +72,7 @@ namespace Umbraco.Web.Editors
_runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
_securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings));
_requestAccessor = requestAccessor ?? throw new ArgumentNullException(nameof(securitySettings));
+ _emailSender = emailSender;
}
protected BackOfficeOwinUserManager UserManager => _userManager
@@ -330,12 +334,19 @@ 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 mailMessage = new MailMessage()
+ {
+ Subject = subject,
+ Body = message,
+ IsBodyHtml = true,
+ To = { user.Email}
+ };
+
+ await _emailSender.SendAsync(mailMessage);
UserManager.RaiseForgotPasswordRequestedEvent(user.Id);
}
diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs
index ad05f404b3..6dff99b7ba 100644
--- a/src/Umbraco.Web/Editors/BackOfficeController.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeController.cs
@@ -184,70 +184,6 @@ namespace Umbraco.Web.Editors
}
- // NOTE: Migrated
- /////
- ///// 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 };
- //}
-
- // NOTE: Migrated
- /////
- ///// 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);
- //}
-
- // NOTE: Migrated
- //[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 e1122145a2..909fd0ca83 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -143,10 +143,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))
@@ -167,10 +168,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())
@@ -211,10 +213,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))
@@ -275,10 +278,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())
@@ -303,14 +307,16 @@ namespace Umbraco.Web.Editors
"publishedSnapshotCacheStatusBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetStatus())
},
- {
- "helpApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetContextHelpForPage("","",""))
- },
- {
- "backOfficeAssetsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
- controller => controller.GetSupportedLocales())
- },
+ //TODO Reintroduce
+ // {
+ // "helpApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetContextHelpForPage("","",""))
+ // },
+ //TODO Reintroduce
+ // {
+ // "backOfficeAssetsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ // controller => controller.GetSupportedLocales())
+ // },
{
"languageApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.GetAllLanguages())
@@ -331,10 +337,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/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/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 4cf19af968..073929b7a7 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;
@@ -53,6 +54,7 @@ namespace Umbraco.Web.Editors
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly ISecuritySettings _securitySettings;
private readonly IRequestAccessor _requestAccessor;
+ private readonly IEmailSender _emailSender;
public UsersController(
IGlobalSettings globalSettings,
@@ -70,7 +72,8 @@ namespace Umbraco.Web.Editors
IImageUrlGenerator imageUrlGenerator,
IPublishedUrlProvider publishedUrlProvider,
ISecuritySettings securitySettings,
- IRequestAccessor requestAccessor)
+ IRequestAccessor requestAccessor,
+ IEmailSender emailSender)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_mediaFileSystem = mediaFileSystem;
@@ -80,6 +83,7 @@ namespace Umbraco.Web.Editors
_imageUrlGenerator = imageUrlGenerator;
_securitySettings = securitySettings;
_requestAccessor = requestAccessor;
+ _emailSender = emailSender;
}
///
@@ -199,7 +203,7 @@ namespace Umbraco.Web.Editors
///
///
///
- [OutgoingEditorModelEvent]
+ // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[AdminUsersAuthorize]
public UserDisplay GetById(int id)
{
@@ -503,17 +507,15 @@ 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 mailMessage = new MailMessage()
+ {
+ Subject = emailSubject,
+ Body = emailBody,
+ IsBodyHtml = true,
+ To = { to.Email}
+ };
+ await _emailSender.SendAsync(mailMessage);
}
///
@@ -521,7 +523,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/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 8b25c82681..2f70515426 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -155,11 +155,9 @@
-
-
@@ -225,7 +223,6 @@
-
@@ -246,15 +243,12 @@
-
-
-
@@ -340,9 +334,7 @@
-
-
@@ -393,11 +385,9 @@
-
-
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);
- }
- }
-}
diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoWebApiRequireHttpsAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoWebApiRequireHttpsAttribute.cs
deleted file mode 100644
index fbe7d5b1b4..0000000000
--- a/src/Umbraco.Web/WebApi/Filters/UmbracoWebApiRequireHttpsAttribute.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System;
-using System.Net;
-using System.Net.Http;
-using System.Text;
-using System.Web.Http.Controllers;
-using System.Web.Http.Filters;
-using Umbraco.Core;
-using Umbraco.Web.Composing;
-
-namespace Umbraco.Web.WebApi.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 : AuthorizationFilterAttribute
- {
- public override void OnAuthorization(HttpActionContext actionContext)
- {
- var request = actionContext.Request;
- if (Current.Configs.Global().UseHttps && request.RequestUri.Scheme != Uri.UriSchemeHttps)
- {
- HttpResponseMessage response;
- var uri = new UriBuilder(request.RequestUri)
- {
- Scheme = Uri.UriSchemeHttps,
- Port = 443
- };
- var body = string.Format("