diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index 46636483b6..f1e2bf20d6 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Web.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Web; namespace Umbraco.Tests.PublishedContent { @@ -39,7 +40,7 @@ namespace Umbraco.Tests.PublishedContent var converters = Factory.GetInstance(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new RichTextPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); + new DataType(new RichTextPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index e98e28c3dd..6ef632bf90 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -44,11 +44,12 @@ namespace Umbraco.Tests.PublishedContent var logger = Mock.Of(); var mediaService = Mock.Of(); var contentTypeBaseServiceProvider = Mock.Of(); + var umbracoContextAccessor = Mock.Of(); var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new VoidEditor(logger)) { Id = 1 }, new DataType(new TrueFalsePropertyEditor(logger)) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider)) { Id = 1002 }, + new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor)) { Id = 1002 }, new DataType(new IntegerPropertyEditor(logger)) { Id = 1003 }, new DataType(new TextboxPropertyEditor(logger)) { Id = 1004 }, new DataType(new MediaPickerPropertyEditor(logger)) { Id = 1005 }); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 92a2389054..8f37f872b1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -523,10 +523,10 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s if (editor.settings.maxImageSize && editor.settings.maxImageSize !== 0) { var newSize = imageHelper.scaleToMaxSize(editor.settings.maxImageSize, size.w, size.h); - - var s = "width: " + newSize.width + "px; height:" + newSize.height + "px;"; - editor.dom.setAttrib(imgElm, 'style', s); - + + editor.dom.setAttrib(imgElm, 'width', newSize.width); + editor.dom.setAttrib(imgElm, 'height', newSize.height); + if (img.url) { var src = img.url + "?width=" + newSize.width + "&height=" + newSize.height; editor.dom.setAttrib(imgElm, 'data-mce-src', src); diff --git a/src/Umbraco.Web/Editors/TinyMceController.cs b/src/Umbraco.Web/Editors/TinyMceController.cs index 7ed71f0268..5bed080f7f 100644 --- a/src/Umbraco.Web/Editors/TinyMceController.cs +++ b/src/Umbraco.Web/Editors/TinyMceController.cs @@ -1,26 +1,34 @@ -using System.Net; -using System.Net.Http; -using System.Web.Http; -using Umbraco.Core.Services; -using Umbraco.Web.WebApi; -using Umbraco.Core; -using Umbraco.Web.Mvc; -using Umbraco.Core.IO; +using System; using System.IO; -using System.Threading.Tasks; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; using System.Linq; -using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using System.Web.Http; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Services; +using Umbraco.Web.Composing; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors { [PluginController("UmbracoApi")] + [UmbracoApplicationAuthorize( + Constants.Applications.Content, + Constants.Applications.Media, + Constants.Applications.Members)] public class TinyMceController : UmbracoAuthorizedApiController { private IMediaService _mediaService; private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; + public TinyMceController(IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) { _mediaService = mediaService; @@ -91,9 +99,28 @@ namespace Umbraco.Web.Editors } catch (Exception ex) { - // Could be a file permission ex - throw; - } + // IOException, PathTooLong, DirectoryNotFound, UnathorizedAccess + Logger.Error(ex, "Error when trying to move {CurrentFilePath} to {NewFilePath}", currentFile, newFilePath); + return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, $"Error when trying to move {currentFile} to {newFilePath}", ex); + } + + // Now remove all old files so that the temp folder(s) never grow + // Anything older than one day gets deleted + var tempFiles = Directory.GetFiles(SystemDirectories.TempFileUploads, "*", SearchOption.AllDirectories); + foreach (var tempFile in tempFiles) + { + if (DateTime.UtcNow - File.GetLastWriteTimeUtc(tempFile) > TimeSpan.FromDays(1)) + { + try + { + File.Delete(tempFile); + } + catch (Exception ex) + { + Logger.Error(ex, "Could not delete temp file {FileName}", tempFile); + } + } + } return Request.CreateResponse(HttpStatusCode.OK, new { tmpLocation = relativeNewFilePath }); } diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 24ab2edbb3..ebb9b67f0d 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -1,14 +1,13 @@ -using System.Linq; -using Umbraco.Core.Logging; +using Newtonsoft.Json; +using System; +using System.Linq; using Umbraco.Core; -using Umbraco.Core.PropertyEditors; -using Newtonsoft.Json; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; -using Umbraco.Web.Templates; -using Umbraco.Web.Composing; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using System; +using Umbraco.Web.Templates; namespace Umbraco.Web.PropertyEditors { @@ -27,12 +26,16 @@ namespace Umbraco.Web.PropertyEditors { private IMediaService _mediaService; private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; + private IUmbracoContextAccessor _umbracoContextAccessor; + private ILogger _logger; - public GridPropertyEditor(ILogger logger, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) + public GridPropertyEditor(ILogger logger, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor) : base(logger) { _mediaService = mediaService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; + _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger; } public override IPropertyIndexValueFactory PropertyIndexValueFactory => new GridPropertyIndexValueFactory(); @@ -41,7 +44,7 @@ namespace Umbraco.Web.PropertyEditors /// Overridden to ensure that the value is validated /// /// - protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider); + protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider, _umbracoContextAccessor, _logger); protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor(); @@ -49,12 +52,16 @@ namespace Umbraco.Web.PropertyEditors { private IMediaService _mediaService; private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; + private IUmbracoContextAccessor _umbracoContextAccessor; + private ILogger _logger; - public GridPropertyValueEditor(DataEditorAttribute attribute, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) + public GridPropertyValueEditor(DataEditorAttribute attribute, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) : base(attribute) { _mediaService = mediaService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; + _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger; } /// @@ -91,10 +98,10 @@ namespace Umbraco.Web.PropertyEditors { // Parse the HTML var html = rte.Value?.ToString(); - - var userId = Current.UmbracoContext.Security.CurrentUser.Id; - var parsedHtml = TemplateUtilities.FindAndPersistPastedTempImages(html, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider); + var userId = _umbracoContextAccessor.UmbracoContext?.Security.CurrentUser.Id ?? -1; + + var parsedHtml = TemplateUtilities.FindAndPersistPastedTempImages(html, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); rte.Value = parsedHtml; } diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index 1455ad73e7..60f68c3606 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -1,15 +1,11 @@ -using HtmlAgilityPack; -using System; +using System; using System.Collections.Generic; -using System.IO; using Umbraco.Core; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Examine; -using Umbraco.Web.Composing; using Umbraco.Web.Macros; using Umbraco.Web.Templates; @@ -30,21 +26,25 @@ namespace Umbraco.Web.PropertyEditors { private IMediaService _mediaService; private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; + private IUmbracoContextAccessor _umbracoContextAccessor; + private ILogger _logger; /// /// The constructor will setup the property editor based on the attribute if one is found /// - public RichTextPropertyEditor(ILogger logger, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) : base(logger) + public RichTextPropertyEditor(ILogger logger, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor) : base(logger) { _mediaService = mediaService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; + _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger; } /// /// Create a custom value editor /// /// - protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider); + protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider, _umbracoContextAccessor, _logger); protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor(); @@ -57,12 +57,16 @@ namespace Umbraco.Web.PropertyEditors { private IMediaService _mediaService; private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; + private IUmbracoContextAccessor _umbracoContextAccessor; + private ILogger _logger; - public RichTextPropertyValueEditor(DataEditorAttribute attribute, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) + public RichTextPropertyValueEditor(DataEditorAttribute attribute, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) : base(attribute) { _mediaService = mediaService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; + _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger; } /// @@ -113,7 +117,7 @@ namespace Umbraco.Web.PropertyEditors var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(editorValue.Value.ToString()); var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved); - var userId = Current.UmbracoContext.Security.CurrentUser.Id; + var userId = _umbracoContextAccessor.UmbracoContext?.Security.CurrentUser.Id ?? -1; var config = editorValue.DataTypeConfiguration as RichTextConfiguration; var mediaParent = config?.MediaParentId; @@ -124,7 +128,7 @@ namespace Umbraco.Web.PropertyEditors else mediaParentId = mediaParent.Guid; - parsed = TemplateUtilities.FindAndPersistPastedTempImages(parsed, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider); + parsed = TemplateUtilities.FindAndPersistPastedTempImages(parsed, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); return parsed; } } diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index 0fd3b93fef..56225df3d3 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -3,13 +3,14 @@ using System; using System.IO; using System.Text.RegularExpressions; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using File = System.IO.File; namespace Umbraco.Web.Templates { @@ -190,7 +191,7 @@ namespace Umbraco.Web.Templates // see comment in ResolveMediaFromTextString for group reference => ResolveImgPattern.Replace(text, "$1$3$4$5"); - internal static string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) + internal static string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, ILogger logger) { // Find all img's that has data-tmpimg attribute // Use HTML Agility Pack - https://html-agility-pack.net @@ -243,6 +244,21 @@ namespace Umbraco.Web.Templates // Remove the data attribute (so we do not re-process this) img.Attributes.Remove(TemporaryImageDataAttribute); + + // Delete folder & image now its saved in media + // The folder should contain one image - as a unique guid folder created + // for each image uploaded from TinyMceController + var folderName = Path.GetDirectoryName(absoluteTempImagePath); + try + { + File.Delete(absoluteTempImagePath); + Directory.Delete(folderName); + } + catch (Exception ex) + { + logger.Error(typeof(TemplateUtilities), ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath); + } + } return htmlDoc.DocumentNode.OuterHtml;