diff --git a/src/Umbraco.Web/Editors/CodeFileController.cs b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs similarity index 69% rename from src/Umbraco.Web/Editors/CodeFileController.cs rename to src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs index 2de3283b95..cfb4d94ad4 100644 --- a/src/Umbraco.Web/Editors/CodeFileController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs @@ -1,59 +1,66 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; -using System.Web.Http; +using Microsoft.AspNetCore.Mvc; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; + using Umbraco.Core.Configuration; + using Umbraco.Core.Configuration.Legacy; using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Persistence; + using Umbraco.Core.Mapping; + using Umbraco.Core.Models; using Umbraco.Core.Services; -using Umbraco.Core.Strings; -using Umbraco.Core.Strings.Css; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; -using Umbraco.Web.Trees; + using Umbraco.Core.Strings; + using Umbraco.Core.Strings.Css; + using Umbraco.Extensions; + using Umbraco.Web.Models.ContentEditing; using Stylesheet = Umbraco.Core.Models.Stylesheet; using StylesheetRule = Umbraco.Web.Models.ContentEditing.StylesheetRule; -using Umbraco.Core.Mapping; -using Umbraco.Web.Routing; +using Umbraco.Web.BackOffice.Filters; + using Umbraco.Web.Common.ActionsResults; + using Umbraco.Web.Common.Attributes; +using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Editors; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.BackOffice.Controllers { // TODO: Put some exception filters in our webapi to return 404 instead of 500 when we throw ArgumentNullException // ref: https://www.exceptionnotfound.net/the-asp-net-web-api-exception-handling-pipeline-a-guided-tour/ [PluginController("UmbracoApi")] - [PrefixlessBodyModelValidator] + //[PrefixlessBodyModelValidator] [UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)] public class CodeFileController : BackOfficeNotificationsController { private readonly IIOHelper _ioHelper; private readonly IFileSystems _fileSystems; + private readonly IFileService _fileService; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILocalizedTextService _localizedTextService; + private readonly UmbracoMapper _umbracoMapper; + private readonly IShortStringHelper _shortStringHelper; + private readonly IGlobalSettings _globalSettings; public CodeFileController( - IGlobalSettings globalSettings, - IUmbracoContextAccessor umbracoContextAccessor, - ISqlContext sqlContext, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger logger, - IRuntimeState runtimeState, - IShortStringHelper shortStringHelper, - UmbracoMapper umbracoMapper, IIOHelper ioHelper, IFileSystems fileSystems, - IPublishedUrlProvider publishedUrlProvider) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider) + IFileService fileService, + IUmbracoContextAccessor umbracoContextAccessor, + ILocalizedTextService localizedTextService, + UmbracoMapper umbracoMapper, + IShortStringHelper shortStringHelper, + IGlobalSettings globalSettings) { + _ioHelper = ioHelper; _fileSystems = fileSystems; + _fileService = fileService; + _umbracoContextAccessor = umbracoContextAccessor; + _localizedTextService = localizedTextService; + _umbracoMapper = umbracoMapper; + _shortStringHelper = shortStringHelper; + _globalSettings = globalSettings; } /// @@ -63,32 +70,33 @@ namespace Umbraco.Web.Editors /// /// Will return a simple 200 if file creation succeeds [ValidationFilter] - public HttpResponseMessage PostCreate(string type, CodeFileDisplay display) + public IActionResult PostCreate(string type, CodeFileDisplay display) { if (display == null) throw new ArgumentNullException("display"); if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); + var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; switch (type) { case Core.Constants.Trees.PartialViews: var view = new PartialView(PartialViewType.PartialView, display.VirtualPath); view.Content = display.Content; - var result = Services.FileService.CreatePartialView(view, display.Snippet, Security.CurrentUser.Id); - return result.Success == true ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateNotificationValidationErrorResponse(result.Exception.Message); + var result = _fileService.CreatePartialView(view, display.Snippet, currentUser.Id); + return result.Success == true ? Ok() : throw HttpResponseException.CreateNotificationValidationErrorResponse(result.Exception.Message); case Core.Constants.Trees.PartialViewMacros: var viewMacro = new PartialView(PartialViewType.PartialViewMacro, display.VirtualPath); viewMacro.Content = display.Content; - var resultMacro = Services.FileService.CreatePartialViewMacro(viewMacro, display.Snippet, Security.CurrentUser.Id); - return resultMacro.Success == true ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateNotificationValidationErrorResponse(resultMacro.Exception.Message); + var resultMacro = _fileService.CreatePartialViewMacro(viewMacro, display.Snippet, currentUser.Id); + return resultMacro.Success == true ? Ok() : throw HttpResponseException.CreateNotificationValidationErrorResponse(resultMacro.Exception.Message); case Core.Constants.Trees.Scripts: var script = new Script(display.VirtualPath); - Services.FileService.SaveScript(script, Security.CurrentUser.Id); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.SaveScript(script, currentUser.Id); + return Ok(); default: - return Request.CreateResponse(HttpStatusCode.NotFound); + return NotFound(); } } @@ -100,13 +108,13 @@ namespace Umbraco.Web.Editors /// The name of the container/folder /// [HttpPost] - public HttpResponseMessage PostCreateContainer(string type, string parentId, string name) + public IActionResult PostCreateContainer(string type, string parentId, string name) { if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); if (string.IsNullOrWhiteSpace(parentId)) throw new ArgumentException("Value cannot be null or whitespace.", "parentId"); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name"); if (name.ContainsAny(Path.GetInvalidPathChars())) { - return Request.CreateNotificationValidationErrorResponse(Services.TextService.Localize("codefile/createFolderIllegalChars")); + throw HttpResponseException.CreateNotificationValidationErrorResponse(_localizedTextService.Localize("codefile/createFolderIllegalChars")); } // if the parentId is root (-1) then we just need an empty string as we are @@ -129,24 +137,24 @@ namespace Umbraco.Web.Editors { case Core.Constants.Trees.PartialViews: virtualPath = NormalizeVirtualPath(name, Core.Constants.SystemDirectories.PartialViews); - Services.FileService.CreatePartialViewFolder(virtualPath); + _fileService.CreatePartialViewFolder(virtualPath); break; case Core.Constants.Trees.PartialViewMacros: virtualPath = NormalizeVirtualPath(name, Core.Constants.SystemDirectories.MacroPartials); - Services.FileService.CreatePartialViewMacroFolder(virtualPath); + _fileService.CreatePartialViewMacroFolder(virtualPath); break; case Core.Constants.Trees.Scripts: - virtualPath = NormalizeVirtualPath(name, GlobalSettings.UmbracoScriptsPath); - Services.FileService.CreateScriptFolder(virtualPath); + virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoScriptsPath); + _fileService.CreateScriptFolder(virtualPath); break; case Core.Constants.Trees.Stylesheets: - virtualPath = NormalizeVirtualPath(name, GlobalSettings.UmbracoCssPath); - Services.FileService.CreateStyleSheetFolder(virtualPath); + virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoCssPath); + _fileService.CreateStyleSheetFolder(virtualPath); break; } - return Request.CreateResponse(HttpStatusCode.OK, new CodeFileDisplay + return Ok(new CodeFileDisplay { VirtualPath = virtualPath, Path = Url.GetTreePathFromFilePath(virtualPath) @@ -159,7 +167,7 @@ namespace Umbraco.Web.Editors /// This is a string but will be 'scripts' 'partialViews', 'partialViewMacros' or 'stylesheets' /// The filename or urlencoded path of the file to open /// The file and its contents from the virtualPath - public CodeFileDisplay GetByPath(string type, string virtualPath) + public IActionResult GetByPath(string type, string virtualPath) { if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); if (string.IsNullOrWhiteSpace(virtualPath)) throw new ArgumentException("Value cannot be null or whitespace.", "virtualPath"); @@ -169,55 +177,53 @@ namespace Umbraco.Web.Editors switch (type) { case Core.Constants.Trees.PartialViews: - var view = Services.FileService.GetPartialView(virtualPath); + var view = _fileService.GetPartialView(virtualPath); if (view != null) { - var display = Mapper.Map(view); + var display = _umbracoMapper.Map(view); display.FileType = Core.Constants.Trees.PartialViews; display.Path = Url.GetTreePathFromFilePath(view.Path); display.Id = System.Web.HttpUtility.UrlEncode(view.Path); - return display; + return Ok(display); } - throw new HttpResponseException(HttpStatusCode.NotFound); + break; case Core.Constants.Trees.PartialViewMacros: - var viewMacro = Services.FileService.GetPartialViewMacro(virtualPath); + var viewMacro = _fileService.GetPartialViewMacro(virtualPath); if (viewMacro != null) { - var display = Mapper.Map(viewMacro); + var display = _umbracoMapper.Map(viewMacro); display.FileType = Core.Constants.Trees.PartialViewMacros; display.Path = Url.GetTreePathFromFilePath(viewMacro.Path); display.Id = System.Web.HttpUtility.UrlEncode(viewMacro.Path); - return display; + return Ok(display); } - throw new HttpResponseException(HttpStatusCode.NotFound); - + break; case Core.Constants.Trees.Scripts: - var script = Services.FileService.GetScriptByName(virtualPath); + var script = _fileService.GetScriptByName(virtualPath); if (script != null) { - var display = Mapper.Map(script); + var display = _umbracoMapper.Map(script); display.FileType = Core.Constants.Trees.Scripts; display.Path = Url.GetTreePathFromFilePath(script.Path); display.Id = System.Web.HttpUtility.UrlEncode(script.Path); - return display; + return Ok(display); } - throw new HttpResponseException(HttpStatusCode.NotFound); - + break; case Core.Constants.Trees.Stylesheets: - var stylesheet = Services.FileService.GetStylesheetByName(virtualPath); + var stylesheet = _fileService.GetStylesheetByName(virtualPath); if (stylesheet != null) { - var display = Mapper.Map(stylesheet); + var display = _umbracoMapper.Map(stylesheet); display.FileType = Core.Constants.Trees.Stylesheets; display.Path = Url.GetTreePathFromFilePath(stylesheet.Path); display.Id = System.Web.HttpUtility.UrlEncode(stylesheet.Path); - return display; + return Ok(display); } - throw new HttpResponseException(HttpStatusCode.NotFound); + break; } - throw new HttpResponseException(HttpStatusCode.NotFound); + return NotFound(); } /// @@ -233,7 +239,7 @@ namespace Umbraco.Web.Editors switch (type) { case Core.Constants.Trees.PartialViews: - snippets = Services.FileService.GetPartialViewSnippetNames( + snippets = _fileService.GetPartialViewSnippetNames( //ignore these - (this is taken from the logic in "PartialView.ascx.cs") "Gallery", "ListChildPagesFromChangeableSource", @@ -241,13 +247,13 @@ namespace Umbraco.Web.Editors "ListImagesFromMediaFolder"); break; case Core.Constants.Trees.PartialViewMacros: - snippets = Services.FileService.GetPartialViewSnippetNames(); + snippets = _fileService.GetPartialViewSnippetNames(); break; default: throw new HttpResponseException(HttpStatusCode.NotFound); } - return snippets.Select(snippet => new SnippetDisplay() {Name = snippet.SplitPascalCasing(ShortStringHelper).ToFirstUpperInvariant(), FileName = snippet}); + return snippets.Select(snippet => new SnippetDisplay() {Name = snippet.SplitPascalCasing(_shortStringHelper).ToFirstUpperInvariant(), FileName = snippet}); } /// @@ -257,7 +263,7 @@ namespace Umbraco.Web.Editors /// /// /// - public CodeFileDisplay GetScaffold(string type, string id, string snippetName = null) + public IActionResult GetScaffold(string type, string id, string snippetName = null) { if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("Value cannot be null or whitespace.", "id"); @@ -267,27 +273,27 @@ namespace Umbraco.Web.Editors switch (type) { case Core.Constants.Trees.PartialViews: - codeFileDisplay = Mapper.Map(new PartialView(PartialViewType.PartialView, string.Empty)); + codeFileDisplay = _umbracoMapper.Map(new PartialView(PartialViewType.PartialView, string.Empty)); codeFileDisplay.VirtualPath = Core.Constants.SystemDirectories.PartialViews; if (snippetName.IsNullOrWhiteSpace() == false) - codeFileDisplay.Content = Services.FileService.GetPartialViewSnippetContent(snippetName); + codeFileDisplay.Content = _fileService.GetPartialViewSnippetContent(snippetName); break; case Core.Constants.Trees.PartialViewMacros: - codeFileDisplay = Mapper.Map(new PartialView(PartialViewType.PartialViewMacro, string.Empty)); + codeFileDisplay = _umbracoMapper.Map(new PartialView(PartialViewType.PartialViewMacro, string.Empty)); codeFileDisplay.VirtualPath = Core.Constants.SystemDirectories.MacroPartials; if (snippetName.IsNullOrWhiteSpace() == false) - codeFileDisplay.Content = Services.FileService.GetPartialViewMacroSnippetContent(snippetName); + codeFileDisplay.Content = _fileService.GetPartialViewMacroSnippetContent(snippetName); break; case Core.Constants.Trees.Scripts: - codeFileDisplay = Mapper.Map(new Script(string.Empty)); - codeFileDisplay.VirtualPath = GlobalSettings.UmbracoScriptsPath; + codeFileDisplay = _umbracoMapper.Map(new Script(string.Empty)); + codeFileDisplay.VirtualPath = _globalSettings.UmbracoScriptsPath; break; case Core.Constants.Trees.Stylesheets: - codeFileDisplay = Mapper.Map(new Stylesheet(string.Empty)); - codeFileDisplay.VirtualPath = GlobalSettings.UmbracoCssPath; + codeFileDisplay = _umbracoMapper.Map(new Stylesheet(string.Empty)); + codeFileDisplay.VirtualPath = _globalSettings.UmbracoCssPath; break; default: - throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Unsupported editortype")); + return new UmbracoProblemResult("Unsupported editortype", HttpStatusCode.BadRequest); } // Make sure that the root virtual path ends with '/' @@ -302,7 +308,7 @@ namespace Umbraco.Web.Editors codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.TrimStart("~"); codeFileDisplay.FileType = type; - return codeFileDisplay; + return new OkObjectResult(codeFileDisplay); } /// @@ -313,67 +319,65 @@ namespace Umbraco.Web.Editors /// Will return a simple 200 if file deletion succeeds [HttpDelete] [HttpPost] - public HttpResponseMessage Delete(string type, string virtualPath) + public IActionResult Delete(string type, string virtualPath) { if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); if (string.IsNullOrWhiteSpace(virtualPath)) throw new ArgumentException("Value cannot be null or whitespace.", "virtualPath"); virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath); - + var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; switch (type) { case Core.Constants.Trees.PartialViews: if (IsDirectory(virtualPath, Core.Constants.SystemDirectories.PartialViews)) { - Services.FileService.DeletePartialViewFolder(virtualPath); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeletePartialViewFolder(virtualPath); + return Ok(); } - if (Services.FileService.DeletePartialView(virtualPath, Security.CurrentUser.Id)) + if (_fileService.DeletePartialView(virtualPath, currentUser.Id)) { - return Request.CreateResponse(HttpStatusCode.OK); + return Ok(); } - return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View or folder found with the specified path"); + return new UmbracoProblemResult("No Partial View or folder found with the specified path", HttpStatusCode.NotFound); case Core.Constants.Trees.PartialViewMacros: if (IsDirectory(virtualPath, Core.Constants.SystemDirectories.MacroPartials)) { - Services.FileService.DeletePartialViewMacroFolder(virtualPath); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeletePartialViewMacroFolder(virtualPath); + return Ok(); } - if (Services.FileService.DeletePartialViewMacro(virtualPath, Security.CurrentUser.Id)) + if (_fileService.DeletePartialViewMacro(virtualPath, currentUser.Id)) { - return Request.CreateResponse(HttpStatusCode.OK); + return Ok(); } - return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View Macro or folder found with the specified path"); + return new UmbracoProblemResult("No Partial View Macro or folder found with the specified path", HttpStatusCode.NotFound); case Core.Constants.Trees.Scripts: - if (IsDirectory(virtualPath, GlobalSettings.UmbracoScriptsPath)) + if (IsDirectory(virtualPath, _globalSettings.UmbracoScriptsPath)) { - Services.FileService.DeleteScriptFolder(virtualPath); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeleteScriptFolder(virtualPath); + return Ok(); } - if (Services.FileService.GetScriptByName(virtualPath) != null) + if (_fileService.GetScriptByName(virtualPath) != null) { - Services.FileService.DeleteScript(virtualPath, Security.CurrentUser.Id); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeleteScript(virtualPath, currentUser.Id); + return Ok(); } - return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Script or folder found with the specified path"); - + return new UmbracoProblemResult("No Script or folder found with the specified path", HttpStatusCode.NotFound); case Core.Constants.Trees.Stylesheets: - if (IsDirectory(virtualPath, GlobalSettings.UmbracoCssPath)) + if (IsDirectory(virtualPath, _globalSettings.UmbracoCssPath)) { - Services.FileService.DeleteStyleSheetFolder(virtualPath); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeleteStyleSheetFolder(virtualPath); + return Ok(); } - if (Services.FileService.GetStylesheetByName(virtualPath) != null) + if (_fileService.GetStylesheetByName(virtualPath) != null) { - Services.FileService.DeleteStylesheet(virtualPath, Security.CurrentUser.Id); - return Request.CreateResponse(HttpStatusCode.OK); + _fileService.DeleteStylesheet(virtualPath, currentUser.Id); + return Ok(); } - return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Stylesheet found with the specified path"); - + return new UmbracoProblemResult("No Stylesheet found with the specified path", HttpStatusCode.NotFound); default: - return Request.CreateResponse(HttpStatusCode.NotFound); + return NotFound(); } throw new HttpResponseException(HttpStatusCode.NotFound); @@ -384,13 +388,13 @@ namespace Umbraco.Web.Editors /// /// /// The updated CodeFileDisplay model - public CodeFileDisplay PostSave(CodeFileDisplay display) + public IActionResult PostSave(CodeFileDisplay display) { if (display == null) throw new ArgumentNullException("display"); if (ModelState.IsValid == false) { - throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + return ValidationProblem(ModelState); } switch (display.FileType) @@ -399,57 +403,57 @@ namespace Umbraco.Web.Editors var partialViewResult = CreateOrUpdatePartialView(display); if (partialViewResult.Success) { - display = Mapper.Map(partialViewResult.Result, display); + display = _umbracoMapper.Map(partialViewResult.Result, display); display.Path = Url.GetTreePathFromFilePath(partialViewResult.Result.Path); display.Id = System.Web.HttpUtility.UrlEncode(partialViewResult.Result.Path); - return display; + return Ok(display); } display.AddErrorNotification( - Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), - Services.TextService.Localize("speechBubbles/partialViewErrorText")); + _localizedTextService.Localize("speechBubbles/partialViewErrorHeader"), + _localizedTextService.Localize("speechBubbles/partialViewErrorText")); break; case Core.Constants.Trees.PartialViewMacros: var partialViewMacroResult = CreateOrUpdatePartialViewMacro(display); if (partialViewMacroResult.Success) { - display = Mapper.Map(partialViewMacroResult.Result, display); + display = _umbracoMapper.Map(partialViewMacroResult.Result, display); display.Path = Url.GetTreePathFromFilePath(partialViewMacroResult.Result.Path); display.Id = System.Web.HttpUtility.UrlEncode(partialViewMacroResult.Result.Path); - return display; + return Ok(display); } display.AddErrorNotification( - Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), - Services.TextService.Localize("speechBubbles/partialViewErrorText")); + _localizedTextService.Localize("speechBubbles/partialViewErrorHeader"), + _localizedTextService.Localize("speechBubbles/partialViewErrorText")); break; case Core.Constants.Trees.Scripts: var scriptResult = CreateOrUpdateScript(display); - display = Mapper.Map(scriptResult, display); + display = _umbracoMapper.Map(scriptResult, display); display.Path = Url.GetTreePathFromFilePath(scriptResult.Path); display.Id = System.Web.HttpUtility.UrlEncode(scriptResult.Path); - return display; + return Ok(display); //display.AddErrorNotification( - // Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), - // Services.TextService.Localize("speechBubbles/partialViewErrorText")); + // _localizedTextService.Localize("speechBubbles/partialViewErrorHeader"), + // _localizedTextService.Localize("speechBubbles/partialViewErrorText")); case Core.Constants.Trees.Stylesheets: var stylesheetResult = CreateOrUpdateStylesheet(display); - display = Mapper.Map(stylesheetResult, display); + display = _umbracoMapper.Map(stylesheetResult, display); display.Path = Url.GetTreePathFromFilePath(stylesheetResult.Path); display.Id = System.Web.HttpUtility.UrlEncode(stylesheetResult.Path); - return display; + return Ok(display); default: throw new HttpResponseException(HttpStatusCode.NotFound); } - return display; + return Ok(display); } /// @@ -524,16 +528,16 @@ namespace Umbraco.Web.Editors private IScript CreateOrUpdateScript(CodeFileDisplay display) { return CreateOrUpdateFile(display, ".js", _fileSystems.ScriptsFileSystem, - name => Services.FileService.GetScriptByName(name), - (script, userId) => Services.FileService.SaveScript(script, userId), + name => _fileService.GetScriptByName(name), + (script, userId) => _fileService.SaveScript(script, userId), name => new Script(name)); } private IStylesheet CreateOrUpdateStylesheet(CodeFileDisplay display) { return CreateOrUpdateFile(display, ".css", _fileSystems.StylesheetsFileSystem, - name => Services.FileService.GetStylesheetByName(name), - (stylesheet, userId) => Services.FileService.SaveStylesheet(stylesheet, userId), + name => _fileService.GetStylesheetByName(name), + (stylesheet, userId) => _fileService.SaveStylesheet(stylesheet, userId), name => new Stylesheet(name) ); } @@ -555,7 +559,7 @@ namespace Umbraco.Web.Editors ? relPath + display.Name : relPath.EnsureEndsWith('/') + display.Name; } - + var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; var file = getFileByName(relPath); if (file != null) { @@ -565,13 +569,13 @@ namespace Umbraco.Web.Editors file.Content = display.Content; //try/catch? since this doesn't return an Attempt? - saveFile(file, Security.CurrentUser.Id); + saveFile(file, currentUser.Id); } else { file = createFile(relPath); file.Content = display.Content; - saveFile(file, Security.CurrentUser.Id); + saveFile(file, currentUser.Id); } return file; @@ -580,13 +584,13 @@ namespace Umbraco.Web.Editors private Attempt CreateOrUpdatePartialView(CodeFileDisplay display) { return CreateOrUpdatePartialView(display, Core.Constants.SystemDirectories.PartialViews, - Services.FileService.GetPartialView, Services.FileService.SavePartialView, Services.FileService.CreatePartialView); + _fileService.GetPartialView, _fileService.SavePartialView, _fileService.CreatePartialView); } private Attempt CreateOrUpdatePartialViewMacro(CodeFileDisplay display) { return CreateOrUpdatePartialView(display, Core.Constants.SystemDirectories.MacroPartials, - Services.FileService.GetPartialViewMacro, Services.FileService.SavePartialViewMacro, Services.FileService.CreatePartialViewMacro); + _fileService.GetPartialViewMacro, _fileService.SavePartialViewMacro, _fileService.CreatePartialViewMacro); } /// @@ -608,6 +612,8 @@ namespace Umbraco.Web.Editors display.Name = EnsureCorrectFileExtension(display.Name, ".cshtml"); Attempt partialViewResult; + var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var virtualPath = NormalizeVirtualPath(display.VirtualPath, systemDirectory); var view = getView(virtualPath); if (view != null) @@ -617,13 +623,13 @@ namespace Umbraco.Web.Editors view.Path = orgPath + display.Name; view.Content = display.Content; - partialViewResult = saveView(view, Security.CurrentUser.Id); + partialViewResult = saveView(view, currentUser.Id); } else { view = new PartialView(PartialViewType.PartialView, virtualPath + display.Name); view.Content = display.Content; - partialViewResult = createView(view, display.Snippet, Security.CurrentUser.Id); + partialViewResult = createView(view, display.Snippet, currentUser.Id); } return partialViewResult; diff --git a/src/Umbraco.Web.BackOffice/Trees/UrlHelperExtensions.cs b/src/Umbraco.Web.BackOffice/Trees/UrlHelperExtensions.cs new file mode 100644 index 0000000000..3c94e3f9a0 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Trees/UrlHelperExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Text; +using System.Web; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core; + +namespace Umbraco.Extensions +{ + public static class UrlHelperExtensions + { + internal static string GetTreePathFromFilePath(this IUrlHelper urlHelper, string virtualPath, string basePath = "") + { + //This reuses the Logic from umbraco.cms.helpers.DeepLink class + //to convert a filepath to a tree syncing path string. + + //removes the basepath from the path + //and normalizes paths - / is used consistently between trees and editors + basePath = basePath.TrimStart("~"); + virtualPath = virtualPath.TrimStart("~"); + virtualPath = virtualPath.Substring(basePath.Length); + virtualPath = virtualPath.Replace('\\', '/'); + + //-1 is the default root id for trees + var sb = new StringBuilder("-1"); + + //split the virtual path and iterate through it + var pathPaths = virtualPath.Split('/'); + + for (var p = 0; p < pathPaths.Length; p++) + { + var path = HttpUtility.UrlEncode(string.Join("/", pathPaths.Take(p + 1))); + if (string.IsNullOrEmpty(path) == false) + { + sb.Append(","); + sb.Append(path); + } + } + return sb.ToString().TrimEnd(","); + } + } +} diff --git a/src/Umbraco.Web.Common/ActionsResults/UmbracoProblemResult.cs b/src/Umbraco.Web.Common/ActionsResults/UmbracoProblemResult.cs new file mode 100644 index 0000000000..235ef0c037 --- /dev/null +++ b/src/Umbraco.Web.Common/ActionsResults/UmbracoProblemResult.cs @@ -0,0 +1,13 @@ +using System.Net; +using Microsoft.AspNetCore.Mvc; + +namespace Umbraco.Web.Common.ActionsResults +{ + public class UmbracoProblemResult : ObjectResult + { + public UmbracoProblemResult(string message, HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError) : base(new {Message = message}) + { + StatusCode = (int) httpStatusCode; + } + } +} diff --git a/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs b/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs index d5268a884f..e332c89536 100644 --- a/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs +++ b/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs @@ -35,7 +35,7 @@ namespace Umbraco.Web.Common.ApplicationModels ActionModelConventions = new List() { - new ClientErrorResultFilterConvention(), // TODO: Need to determine exactly how this affects errors + new ClientErrorResultFilterConvention(), // Ensures the responses without any body is converted into a simple json object with info instead of a string like "Status Code: 404; Not Found" new InvalidModelStateFilterConvention(), // automatically 400 responses if ModelState is invalid before hitting the controller new ConsumesConstraintForFormFileParameterConvention(), // If an controller accepts files, it must accept multipart/form-data. new InferParameterBindingInfoConvention(modelMetadataProvider), // no need for [FromBody] everywhere, A complex type parameter is assigned to FromBody @@ -74,9 +74,9 @@ namespace Umbraco.Web.Common.ApplicationModels foreach (var convention in ActionModelConventions) { convention.Apply(action); - } + } } - + } } diff --git a/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs b/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs index 750417fab6..cb14a5a546 100644 --- a/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs +++ b/src/Umbraco.Web.Common/Exceptions/HttpResponseException.cs @@ -4,6 +4,7 @@ using System.Net; using System.Runtime.Serialization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Common.Exceptions { @@ -68,5 +69,16 @@ namespace Umbraco.Web.Common.Exceptions } }; } + + public static HttpResponseException CreateNotificationValidationErrorResponse(string errorMessage) + { + var notificationModel = new SimpleNotificationModel + { + Message = errorMessage + }; + notificationModel.AddErrorNotification(errorMessage, string.Empty); + return CreateValidationErrorResponse(notificationModel); + } + } } diff --git a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs index 3221023ca2..f4b516a764 100644 --- a/src/Umbraco.Web/Trees/UrlHelperExtensions.cs +++ b/src/Umbraco.Web/Trees/UrlHelperExtensions.cs @@ -33,34 +33,5 @@ namespace Umbraco.Web.Trees return actionUrl; } - internal static string GetTreePathFromFilePath(this UrlHelper urlHelper, string virtualPath, string basePath = "") - { - //This reuses the Logic from umbraco.cms.helpers.DeepLink class - //to convert a filepath to a tree syncing path string. - - //removes the basepath from the path - //and normalizes paths - / is used consistently between trees and editors - basePath = basePath.TrimStart("~"); - virtualPath = virtualPath.TrimStart("~"); - virtualPath = virtualPath.Substring(basePath.Length); - virtualPath = virtualPath.Replace('\\', '/'); - - //-1 is the default root id for trees - var sb = new StringBuilder("-1"); - - //split the virtual path and iterate through it - var pathPaths = virtualPath.Split('/'); - - for (var p = 0; p < pathPaths.Length; p++) - { - var path = HttpUtility.UrlEncode(string.Join("/", pathPaths.Take(p + 1))); - if (string.IsNullOrEmpty(path) == false) - { - sb.Append(","); - sb.Append(path); - } - } - return sb.ToString().TrimEnd(","); - } } }