Files
Umbraco-CMS/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs

683 lines
32 KiB
C#
Raw Normal View History

using System;
2017-05-12 14:49:44 +02:00
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Strings.Css;
using Umbraco.Cms.Web.BackOffice.Filters;
using Umbraco.Cms.Web.BackOffice.Trees;
using Umbraco.Cms.Web.Common.ActionsResults;
using Umbraco.Cms.Web.Common.Attributes;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
using Stylesheet = Umbraco.Cms.Core.Models.Stylesheet;
using StylesheetRule = Umbraco.Cms.Core.Models.ContentEditing.StylesheetRule;
namespace Umbraco.Cms.Web.BackOffice.Controllers
2017-05-12 14:49:44 +02:00
{
// TODO: Put some exception filters in our webapi to return 404 instead of 500 when we throw ArgumentNullException
2017-05-12 14:49:44 +02:00
// ref: https://www.exceptionnotfound.net/the-asp-net-web-api-exception-handling-pipeline-a-guided-tour/
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
//[PrefixlessBodyModelValidator]
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
2017-05-12 14:49:44 +02:00
public class CodeFileController : BackOfficeNotificationsController
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IFileSystems _fileSystems;
private readonly IFileService _fileService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly ILocalizedTextService _localizedTextService;
private readonly UmbracoMapper _umbracoMapper;
private readonly IShortStringHelper _shortStringHelper;
private readonly GlobalSettings _globalSettings;
public CodeFileController(
IHostingEnvironment hostingEnvironment,
IFileSystems fileSystems,
IFileService fileService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
ILocalizedTextService localizedTextService,
UmbracoMapper umbracoMapper,
IShortStringHelper shortStringHelper,
IOptions<GlobalSettings> globalSettings)
{
_hostingEnvironment = hostingEnvironment;
_fileSystems = fileSystems;
_fileService = fileService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_localizedTextService = localizedTextService;
_umbracoMapper = umbracoMapper;
_shortStringHelper = shortStringHelper;
_globalSettings = globalSettings.Value;
}
2017-05-12 14:49:44 +02:00
/// <summary>
/// Used to create a brand new file
/// </summary>
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros'</param>
/// <param name="display"></param>
/// <returns>Will return a simple 200 if file creation succeeds</returns>
[ValidationFilter]
public ActionResult<CodeFileDisplay> PostCreate(string type, CodeFileDisplay display)
2017-05-12 14:49:44 +02:00
{
if (display == null) throw new ArgumentNullException("display");
if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type");
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
2017-05-12 14:49:44 +02:00
switch (type)
{
case Constants.Trees.PartialViews:
2017-05-30 10:50:09 +02:00
var view = new PartialView(PartialViewType.PartialView, display.VirtualPath);
2017-05-12 14:49:44 +02:00
view.Content = display.Content;
var result = _fileService.CreatePartialView(view, display.Snippet, currentUser.Id);
if (result.Success)
return Ok();
else
return ValidationErrorResult.CreateNotificationValidationErrorResult(result.Exception.Message);
2017-05-12 14:49:44 +02:00
case Constants.Trees.PartialViewMacros:
2017-05-30 10:50:09 +02:00
var viewMacro = new PartialView(PartialViewType.PartialViewMacro, display.VirtualPath);
2017-05-12 14:49:44 +02:00
viewMacro.Content = display.Content;
var resultMacro = _fileService.CreatePartialViewMacro(viewMacro, display.Snippet, currentUser.Id);
if (resultMacro.Success)
return Ok();
else
return ValidationErrorResult.CreateNotificationValidationErrorResult(resultMacro.Exception.Message);
2017-05-12 14:49:44 +02:00
case Constants.Trees.Scripts:
2017-05-12 14:49:44 +02:00
var script = new Script(display.VirtualPath);
_fileService.SaveScript(script, currentUser.Id);
return Ok();
2017-05-12 14:49:44 +02:00
default:
return NotFound();
2017-05-12 14:49:44 +02:00
}
}
/// <summary>
/// Used to create a container/folder in 'partialViews', 'partialViewMacros', 'scripts' or 'stylesheets'
2017-05-12 14:49:44 +02:00
/// </summary>
/// <param name="type">'partialViews', 'partialViewMacros' or 'scripts'</param>
/// <param name="parentId">The virtual path of the parent.</param>
/// <param name="name">The name of the container/folder</param>
/// <returns></returns>
[HttpPost]
public ActionResult<CodeFileDisplay> PostCreateContainer(string type, string parentId, string name)
2017-05-12 14:49:44 +02:00
{
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 ValidationErrorResult.CreateNotificationValidationErrorResult(_localizedTextService.Localize("codefile/createFolderIllegalChars"));
}
2017-05-12 14:49:44 +02:00
// if the parentId is root (-1) then we just need an empty string as we are
// creating the path below and we don't want -1 in the path
if (parentId == Constants.System.RootString)
2017-05-12 14:49:44 +02:00
{
parentId = string.Empty;
}
name = System.Web.HttpUtility.UrlDecode(name);
if (parentId.IsNullOrWhiteSpace() == false)
{
parentId = System.Web.HttpUtility.UrlDecode(parentId);
name = parentId.EnsureEndsWith("/") + name;
}
var virtualPath = string.Empty;
switch (type)
{
case Constants.Trees.PartialViews:
virtualPath = NormalizeVirtualPath(name, Constants.SystemDirectories.PartialViews);
_fileService.CreatePartialViewFolder(virtualPath);
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.PartialViewMacros:
virtualPath = NormalizeVirtualPath(name, Constants.SystemDirectories.MacroPartials);
_fileService.CreatePartialViewMacroFolder(virtualPath);
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.Scripts:
virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoScriptsPath);
_fileService.CreateScriptFolder(virtualPath);
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.Stylesheets:
virtualPath = NormalizeVirtualPath(name, _globalSettings.UmbracoCssPath);
_fileService.CreateStyleSheetFolder(virtualPath);
break;
2017-05-12 14:49:44 +02:00
}
return new CodeFileDisplay
2017-05-12 14:49:44 +02:00
{
VirtualPath = virtualPath,
Path = Url.GetTreePathFromFilePath(virtualPath)
};
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Used to get a specific file from disk via the FileService
/// </summary>
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros' or 'stylesheets'</param>
2020-10-05 20:48:38 +02:00
/// <param name="virtualPath">The filename or URL encoded path of the file to open</param>
2017-05-12 14:49:44 +02:00
/// <returns>The file and its contents from the virtualPath</returns>
public ActionResult<CodeFileDisplay> GetByPath(string type, string virtualPath)
2017-05-12 14:49:44 +02:00
{
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);
switch (type)
{
case Constants.Trees.PartialViews:
var view = _fileService.GetPartialView(virtualPath);
2017-05-12 14:49:44 +02:00
if (view != null)
{
var display = _umbracoMapper.Map<IPartialView, CodeFileDisplay>(view);
display.FileType = Constants.Trees.PartialViews;
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(view.Path);
display.Id = System.Web.HttpUtility.UrlEncode(view.Path);
return display;
2017-05-12 14:49:44 +02:00
}
break;
case Constants.Trees.PartialViewMacros:
var viewMacro = _fileService.GetPartialViewMacro(virtualPath);
2017-05-12 14:49:44 +02:00
if (viewMacro != null)
{
var display = _umbracoMapper.Map<IPartialView, CodeFileDisplay>(viewMacro);
display.FileType = Constants.Trees.PartialViewMacros;
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(viewMacro.Path);
display.Id = System.Web.HttpUtility.UrlEncode(viewMacro.Path);
return display;
2017-05-12 14:49:44 +02:00
}
break;
case Constants.Trees.Scripts:
var script = _fileService.GetScriptByName(virtualPath);
2017-05-12 14:49:44 +02:00
if (script != null)
{
var display = _umbracoMapper.Map<IScript, CodeFileDisplay>(script);
display.FileType = Constants.Trees.Scripts;
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(script.Path);
display.Id = System.Web.HttpUtility.UrlEncode(script.Path);
return display;
2017-05-12 14:49:44 +02:00
}
break;
case Constants.Trees.Stylesheets:
var stylesheet = _fileService.GetStylesheetByName(virtualPath);
2018-10-27 21:18:03 +02:00
if (stylesheet != null)
{
var display = _umbracoMapper.Map<IStylesheet, CodeFileDisplay>(stylesheet);
display.FileType = Constants.Trees.Stylesheets;
2018-10-27 21:18:03 +02:00
display.Path = Url.GetTreePathFromFilePath(stylesheet.Path);
display.Id = System.Web.HttpUtility.UrlEncode(stylesheet.Path);
return display;
2018-10-27 21:18:03 +02:00
}
break;
2017-05-12 14:49:44 +02:00
}
return NotFound();
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Used to get a list of available templates/snippets to base a new Partial View or Partial View Macro from
2017-05-12 14:49:44 +02:00
/// </summary>
/// <param name="type">This is a string but will be 'partialViews', 'partialViewMacros'</param>
/// <returns>Returns a list of <see cref="SnippetDisplay"/> if a correct type is sent</returns>
public ActionResult<IEnumerable<SnippetDisplay>> GetSnippets(string type)
2017-05-12 14:49:44 +02:00
{
if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type");
IEnumerable<string> snippets;
switch (type)
{
case Constants.Trees.PartialViews:
snippets = _fileService.GetPartialViewSnippetNames(
2017-05-12 14:49:44 +02:00
//ignore these - (this is taken from the logic in "PartialView.ascx.cs")
"Gallery",
"ListChildPagesFromChangeableSource",
"ListChildPagesOrderedByProperty",
"ListImagesFromMediaFolder");
break;
case Constants.Trees.PartialViewMacros:
snippets = _fileService.GetPartialViewSnippetNames();
2017-05-12 14:49:44 +02:00
break;
default:
return NotFound();
2017-05-12 14:49:44 +02:00
}
return snippets.Select(snippet => new SnippetDisplay() { Name = snippet.SplitPascalCasing(_shortStringHelper).ToFirstUpperInvariant(), FileName = snippet }).ToList();
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Used to scaffold the json object for the editors for 'scripts', 'partialViews', 'partialViewMacros' and 'stylesheets'
2017-05-12 14:49:44 +02:00
/// </summary>
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros' or 'stylesheets'</param>
2017-05-12 14:49:44 +02:00
/// <param name="id"></param>
/// <param name="snippetName"></param>
/// <returns></returns>
public ActionResult<CodeFileDisplay> GetScaffold(string type, string id, string snippetName = null)
2017-05-12 14:49:44 +02:00
{
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");
CodeFileDisplay codeFileDisplay;
2017-05-12 14:49:44 +02:00
switch (type)
{
case Constants.Trees.PartialViews:
codeFileDisplay = _umbracoMapper.Map<IPartialView, CodeFileDisplay>(new PartialView(PartialViewType.PartialView, string.Empty));
codeFileDisplay.VirtualPath = Constants.SystemDirectories.PartialViews;
2017-05-12 14:49:44 +02:00
if (snippetName.IsNullOrWhiteSpace() == false)
codeFileDisplay.Content = _fileService.GetPartialViewSnippetContent(snippetName);
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.PartialViewMacros:
codeFileDisplay = _umbracoMapper.Map<IPartialView, CodeFileDisplay>(new PartialView(PartialViewType.PartialViewMacro, string.Empty));
codeFileDisplay.VirtualPath = Constants.SystemDirectories.MacroPartials;
2017-05-12 14:49:44 +02:00
if (snippetName.IsNullOrWhiteSpace() == false)
codeFileDisplay.Content = _fileService.GetPartialViewMacroSnippetContent(snippetName);
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.Scripts:
codeFileDisplay = _umbracoMapper.Map<Script, CodeFileDisplay>(new Script(string.Empty));
codeFileDisplay.VirtualPath = _globalSettings.UmbracoScriptsPath;
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.Stylesheets:
codeFileDisplay = _umbracoMapper.Map<Stylesheet, CodeFileDisplay>(new Stylesheet(string.Empty));
codeFileDisplay.VirtualPath = _globalSettings.UmbracoCssPath;
2018-10-27 21:18:03 +02:00
break;
2017-05-12 14:49:44 +02:00
default:
return new UmbracoProblemResult("Unsupported editortype", HttpStatusCode.BadRequest);
2017-05-12 14:49:44 +02:00
}
// Make sure that the root virtual path ends with '/'
codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.EnsureEndsWith("/");
if (id != Constants.System.RootString)
2017-05-12 14:49:44 +02:00
{
Merge remote-tracking branch 'origin/v8/dev' into netcore/dev # Conflicts: # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/CacheKeys.cs # src/Umbraco.Core/Composing/TypeFinder.cs # src/Umbraco.Core/Configuration/GlobalSettings.cs # src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs # src/Umbraco.Core/Configuration/IGlobalSettings.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs # src/Umbraco.Core/Constants-AppSettings.cs # src/Umbraco.Core/Editors/UserEditorAuthorizationHelper.cs # src/Umbraco.Core/Extensions/StringExtensions.cs # src/Umbraco.Core/Extensions/UriExtensions.cs # src/Umbraco.Core/IO/IOHelper.cs # src/Umbraco.Core/IO/PhysicalFileSystem.cs # src/Umbraco.Core/Media/Exif/MathEx.cs # src/Umbraco.Core/Media/UploadAutoFillProperties.cs # src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs # src/Umbraco.Core/Models/Membership/User.cs # src/Umbraco.Core/Models/UserExtensions.cs # src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs # src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs # src/Umbraco.Core/Routing/AliasUrlProvider.cs # src/Umbraco.Core/Routing/DefaultUrlProvider.cs # src/Umbraco.Core/Routing/UriUtility.cs # src/Umbraco.Core/Routing/UrlProviderExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Security/BackOfficeUserStore.cs # src/Umbraco.Core/Security/ContentPermissions.cs # src/Umbraco.Core/Sync/ApplicationUrlHelper.cs # src/Umbraco.Core/Trees/TreeNode.cs # src/Umbraco.Core/Udi.cs # src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs # src/Umbraco.Infrastructure/Scoping/Scope.cs # src/Umbraco.Infrastructure/Search/ExamineComponent.cs # src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.Infrastructure/Services/Implement/MediaService.cs # src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs # src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config # src/Umbraco.Tests/TestHelpers/SettingsForTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs # src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs # src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs # src/Umbraco.Web.BackOffice/Controllers/MediaController.cs # src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs # src/Umbraco.Web.BackOffice/Controllers/TourController.cs # src/Umbraco.Web.BackOffice/Controllers/UserGroupEditorAuthorizationHelper.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs # src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.BackOffice/Trees/FileSystemTreeController.cs # src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs # src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs # src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js # src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Cache/MemberCacheRefresher.cs # src/Umbraco.Web/Composing/ModuleInjector.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/Editors/UserGroupsController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/ImageCropperTemplateExtensions.cs # src/Umbraco.Web/Logging/WebProfiler.cs # src/Umbraco.Web/Logging/WebProfilerProvider.cs # src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs # src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs # src/Umbraco.Web/Mvc/JsonNetResult.cs # src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs # src/Umbraco.Web/Mvc/RenderRouteHandler.cs # src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/RoutableDocumentFilter.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Routing/PublishedRouter.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/BackOfficeClaimsIdentityFactory.cs # src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs # src/Umbraco.Web/Trees/DictionaryTreeController.cs # src/Umbraco.Web/Trees/LanguageTreeController.cs # src/Umbraco.Web/Trees/LogViewerTreeController.cs # src/Umbraco.Web/Trees/PackagesTreeController.cs # src/Umbraco.Web/UmbracoApplication.cs # src/Umbraco.Web/UmbracoApplicationBase.cs # src/Umbraco.Web/UmbracoInjectedModule.cs # src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs # src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs # src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs
2021-03-05 15:36:27 +01:00
codeFileDisplay.VirtualPath += id.TrimStart(Constants.CharArrays.ForwardSlash).EnsureEndsWith("/");
2017-05-12 14:49:44 +02:00
//if it's not new then it will have a path, otherwise it won't
codeFileDisplay.Path = Url.GetTreePathFromFilePath(id);
}
2017-07-20 11:21:28 +02:00
codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.TrimStart("~");
2017-05-12 14:49:44 +02:00
codeFileDisplay.FileType = type;
return codeFileDisplay;
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Used to delete a specific file from disk via the FileService
/// </summary>
2018-11-01 16:01:34 +01:00
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros' or 'stylesheets'</param>
2020-10-05 20:48:38 +02:00
/// <param name="virtualPath">The filename or URL encoded path of the file to delete</param>
2017-05-12 14:49:44 +02:00
/// <returns>Will return a simple 200 if file deletion succeeds</returns>
[HttpDelete]
[HttpPost]
public IActionResult Delete(string type, string virtualPath)
2017-05-12 14:49:44 +02:00
{
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");
2017-07-20 11:21:28 +02:00
2017-05-12 14:49:44 +02:00
virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath);
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
2017-05-12 14:49:44 +02:00
switch (type)
{
case Constants.Trees.PartialViews:
if (IsDirectory(_hostingEnvironment.MapPathContentRoot(Path.Combine(Constants.SystemDirectories.PartialViews, virtualPath))))
2017-05-12 14:49:44 +02:00
{
_fileService.DeletePartialViewFolder(virtualPath);
return Ok();
2017-05-12 14:49:44 +02:00
}
if (_fileService.DeletePartialView(virtualPath, currentUser.Id))
2017-05-12 14:49:44 +02:00
{
return Ok();
2017-05-12 14:49:44 +02:00
}
return new UmbracoProblemResult("No Partial View or folder found with the specified path", HttpStatusCode.NotFound);
2017-05-12 14:49:44 +02:00
case Constants.Trees.PartialViewMacros:
if (IsDirectory(_hostingEnvironment.MapPathContentRoot(Path.Combine(Constants.SystemDirectories.MacroPartials, virtualPath))))
2017-05-12 14:49:44 +02:00
{
_fileService.DeletePartialViewMacroFolder(virtualPath);
return Ok();
2017-05-12 14:49:44 +02:00
}
if (_fileService.DeletePartialViewMacro(virtualPath, currentUser.Id))
2017-05-12 14:49:44 +02:00
{
return Ok();
2017-05-12 14:49:44 +02:00
}
return new UmbracoProblemResult("No Partial View Macro or folder found with the specified path", HttpStatusCode.NotFound);
2017-05-12 14:49:44 +02:00
case Constants.Trees.Scripts:
if (IsDirectory(_hostingEnvironment.MapPathWebRoot(Path.Combine(_globalSettings.UmbracoScriptsPath, virtualPath))))
2017-05-12 14:49:44 +02:00
{
_fileService.DeleteScriptFolder(virtualPath);
return Ok();
2017-05-12 14:49:44 +02:00
}
if (_fileService.GetScriptByName(virtualPath) != null)
2017-05-12 14:49:44 +02:00
{
_fileService.DeleteScript(virtualPath, currentUser.Id);
return Ok();
2017-05-12 14:49:44 +02:00
}
return new UmbracoProblemResult("No Script or folder found with the specified path", HttpStatusCode.NotFound);
case Constants.Trees.Stylesheets:
if (IsDirectory(_hostingEnvironment.MapPathWebRoot(Path.Combine(_globalSettings.UmbracoCssPath, virtualPath))))
{
_fileService.DeleteStyleSheetFolder(virtualPath);
return Ok();
}
if (_fileService.GetStylesheetByName(virtualPath) != null)
2018-11-01 16:01:34 +01:00
{
_fileService.DeleteStylesheet(virtualPath, currentUser.Id);
return Ok();
2018-11-01 16:01:34 +01:00
}
return new UmbracoProblemResult("No Stylesheet found with the specified path", HttpStatusCode.NotFound);
2017-05-12 14:49:44 +02:00
default:
return NotFound();
2017-05-12 14:49:44 +02:00
}
}
/// <summary>
/// Used to create or update a 'partialview', 'partialviewmacro', 'script' or 'stylesheets' file
2017-05-12 14:49:44 +02:00
/// </summary>
/// <param name="display"></param>
/// <returns>The updated CodeFileDisplay model</returns>
public ActionResult<CodeFileDisplay> PostSave(CodeFileDisplay display)
2017-05-12 14:49:44 +02:00
{
if (display == null) throw new ArgumentNullException("display");
TryValidateModel(display);
2017-05-12 14:49:44 +02:00
if (ModelState.IsValid == false)
{
return ValidationProblem(ModelState);
2017-05-12 14:49:44 +02:00
}
switch (display.FileType)
{
case Constants.Trees.PartialViews:
2017-05-12 14:49:44 +02:00
var partialViewResult = CreateOrUpdatePartialView(display);
if (partialViewResult.Success)
{
display = _umbracoMapper.Map(partialViewResult.Result, display);
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(partialViewResult.Result.Path);
display.Id = System.Web.HttpUtility.UrlEncode(partialViewResult.Result.Path);
return display;
2017-05-12 14:49:44 +02:00
}
display.AddErrorNotification(
_localizedTextService.Localize("speechBubbles/partialViewErrorHeader"),
_localizedTextService.Localize("speechBubbles/partialViewErrorText"));
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.PartialViewMacros:
2017-05-12 14:49:44 +02:00
var partialViewMacroResult = CreateOrUpdatePartialViewMacro(display);
if (partialViewMacroResult.Success)
{
display = _umbracoMapper.Map(partialViewMacroResult.Result, display);
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(partialViewMacroResult.Result.Path);
display.Id = System.Web.HttpUtility.UrlEncode(partialViewMacroResult.Result.Path);
return display;
2017-05-12 14:49:44 +02:00
}
display.AddErrorNotification(
_localizedTextService.Localize("speechBubbles/partialViewErrorHeader"),
_localizedTextService.Localize("speechBubbles/partialViewErrorText"));
2017-05-12 14:49:44 +02:00
break;
case Constants.Trees.Scripts:
2017-05-12 14:49:44 +02:00
var scriptResult = CreateOrUpdateScript(display);
display = _umbracoMapper.Map(scriptResult, display);
2017-05-12 14:49:44 +02:00
display.Path = Url.GetTreePathFromFilePath(scriptResult.Path);
display.Id = System.Web.HttpUtility.UrlEncode(scriptResult.Path);
return display;
2017-05-12 14:49:44 +02:00
2018-10-27 21:18:03 +02:00
//display.AddErrorNotification(
// _localizedTextService.Localize("speechBubbles/partialViewErrorHeader"),
// _localizedTextService.Localize("speechBubbles/partialViewErrorText"));
2017-05-12 14:49:44 +02:00
case Constants.Trees.Stylesheets:
2017-07-20 11:21:28 +02:00
2018-10-27 21:18:03 +02:00
var stylesheetResult = CreateOrUpdateStylesheet(display);
display = _umbracoMapper.Map(stylesheetResult, display);
2018-10-27 21:18:03 +02:00
display.Path = Url.GetTreePathFromFilePath(stylesheetResult.Path);
display.Id = System.Web.HttpUtility.UrlEncode(stylesheetResult.Path);
return display;
2017-05-12 14:49:44 +02:00
default:
return NotFound();
2017-05-12 14:49:44 +02:00
}
return display;
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Extracts "umbraco style rules" from a style sheet
/// </summary>
/// <param name="data">The style sheet data</param>
/// <returns>The style rules</returns>
public StylesheetRule[] PostExtractStylesheetRules(StylesheetData data)
{
if (data.Content.IsNullOrWhiteSpace())
{
return new StylesheetRule[0];
}
return StylesheetHelper.ParseRules(data.Content)?.Select(rule => new StylesheetRule
{
Name = rule.Name,
Selector = rule.Selector,
Styles = rule.Styles
}).ToArray();
}
/// <summary>
/// Creates a style sheet from CSS and style rules
/// </summary>
/// <param name="data">The style sheet data</param>
/// <returns>The style sheet combined from the CSS and the rules</returns>
/// <remarks>
/// Any "umbraco style rules" in the CSS will be removed and replaced with the rules passed in <see cref="data"/>
/// </remarks>
public string PostInterpolateStylesheetRules(StylesheetData data)
{
// first remove all existing rules
var existingRules = data.Content.IsNullOrWhiteSpace()
? new Cms.Core.Strings.Css.StylesheetRule[0]
: StylesheetHelper.ParseRules(data.Content).ToArray();
foreach (var rule in existingRules)
{
data.Content = StylesheetHelper.ReplaceRule(data.Content, rule.Name, null);
}
Merge remote-tracking branch 'origin/v8/dev' into netcore/dev # Conflicts: # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/CacheKeys.cs # src/Umbraco.Core/Composing/TypeFinder.cs # src/Umbraco.Core/Configuration/GlobalSettings.cs # src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs # src/Umbraco.Core/Configuration/IGlobalSettings.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs # src/Umbraco.Core/Constants-AppSettings.cs # src/Umbraco.Core/Editors/UserEditorAuthorizationHelper.cs # src/Umbraco.Core/Extensions/StringExtensions.cs # src/Umbraco.Core/Extensions/UriExtensions.cs # src/Umbraco.Core/IO/IOHelper.cs # src/Umbraco.Core/IO/PhysicalFileSystem.cs # src/Umbraco.Core/Media/Exif/MathEx.cs # src/Umbraco.Core/Media/UploadAutoFillProperties.cs # src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs # src/Umbraco.Core/Models/Membership/User.cs # src/Umbraco.Core/Models/UserExtensions.cs # src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs # src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs # src/Umbraco.Core/Routing/AliasUrlProvider.cs # src/Umbraco.Core/Routing/DefaultUrlProvider.cs # src/Umbraco.Core/Routing/UriUtility.cs # src/Umbraco.Core/Routing/UrlProviderExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Security/BackOfficeUserStore.cs # src/Umbraco.Core/Security/ContentPermissions.cs # src/Umbraco.Core/Sync/ApplicationUrlHelper.cs # src/Umbraco.Core/Trees/TreeNode.cs # src/Umbraco.Core/Udi.cs # src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs # src/Umbraco.Infrastructure/Scoping/Scope.cs # src/Umbraco.Infrastructure/Search/ExamineComponent.cs # src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.Infrastructure/Services/Implement/MediaService.cs # src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs # src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config # src/Umbraco.Tests/TestHelpers/SettingsForTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs # src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs # src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs # src/Umbraco.Web.BackOffice/Controllers/MediaController.cs # src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs # src/Umbraco.Web.BackOffice/Controllers/TourController.cs # src/Umbraco.Web.BackOffice/Controllers/UserGroupEditorAuthorizationHelper.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs # src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.BackOffice/Trees/FileSystemTreeController.cs # src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs # src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs # src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js # src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Cache/MemberCacheRefresher.cs # src/Umbraco.Web/Composing/ModuleInjector.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/Editors/UserGroupsController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/ImageCropperTemplateExtensions.cs # src/Umbraco.Web/Logging/WebProfiler.cs # src/Umbraco.Web/Logging/WebProfilerProvider.cs # src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs # src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs # src/Umbraco.Web/Mvc/JsonNetResult.cs # src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs # src/Umbraco.Web/Mvc/RenderRouteHandler.cs # src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/RoutableDocumentFilter.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Routing/PublishedRouter.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/BackOfficeClaimsIdentityFactory.cs # src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs # src/Umbraco.Web/Trees/DictionaryTreeController.cs # src/Umbraco.Web/Trees/LanguageTreeController.cs # src/Umbraco.Web/Trees/LogViewerTreeController.cs # src/Umbraco.Web/Trees/PackagesTreeController.cs # src/Umbraco.Web/UmbracoApplication.cs # src/Umbraco.Web/UmbracoApplicationBase.cs # src/Umbraco.Web/UmbracoInjectedModule.cs # src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs # src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs # src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs
2021-03-05 15:36:27 +01:00
data.Content = data.Content.TrimEnd(Constants.CharArrays.LineFeedCarriageReturn);
// now add all the posted rules
if (data.Rules != null && data.Rules.Any())
{
foreach (var rule in data.Rules)
{
data.Content = StylesheetHelper.AppendRule(data.Content, new Cms.Core.Strings.Css.StylesheetRule
{
Name = rule.Name,
Selector = rule.Selector,
Styles = rule.Styles
});
}
data.Content += Environment.NewLine;
}
return data.Content;
}
2017-05-12 14:49:44 +02:00
/// <summary>
/// Create or Update a Script
/// </summary>
/// <param name="display"></param>
/// <returns></returns>
/// <remarks>
/// It's important to note that Scripts are DIFFERENT from cshtml files since scripts use IFileSystem and cshtml files
/// use a normal file system because they must exist on a real file system for ASP.NET to work.
/// </remarks>
private IScript CreateOrUpdateScript(CodeFileDisplay display)
2017-05-12 14:49:44 +02:00
{
return CreateOrUpdateFile(display, ".js", _fileSystems.ScriptsFileSystem,
name => _fileService.GetScriptByName(name),
(script, userId) => _fileService.SaveScript(script, userId),
name => new Script(name));
2017-05-12 14:49:44 +02:00
}
private IStylesheet CreateOrUpdateStylesheet(CodeFileDisplay display)
2018-10-27 21:18:03 +02:00
{
return CreateOrUpdateFile(display, ".css", _fileSystems.StylesheetsFileSystem,
name => _fileService.GetStylesheetByName(name),
(stylesheet, userId) => _fileService.SaveStylesheet(stylesheet, userId),
2018-10-27 21:18:03 +02:00
name => new Stylesheet(name)
);
}
private T CreateOrUpdateFile<T>(CodeFileDisplay display, string extension, IFileSystem fileSystem,
Func<string, T> getFileByName, Action<T, int> saveFile, Func<string, T> createFile) where T : IFile
2018-10-27 21:18:03 +02:00
{
//must always end with the correct extension
display.Name = EnsureCorrectFileExtension(display.Name, extension);
var virtualPath = display.VirtualPath ?? string.Empty;
// this is all weird, should be using relative paths everywhere!
var relPath = fileSystem.GetRelativePath(virtualPath);
if (relPath.EndsWith(extension) == false)
{
//this would typically mean it's new
relPath = relPath.IsNullOrWhiteSpace()
? relPath + display.Name
: relPath.EnsureEndsWith('/') + display.Name;
}
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
2018-10-27 21:18:03 +02:00
var file = getFileByName(relPath);
if (file != null)
{
// might need to find the path
var orgPath = file.OriginalPath.Substring(0, file.OriginalPath.IndexOf(file.Name));
file.Path = orgPath + display.Name;
file.Content = display.Content;
//try/catch? since this doesn't return an Attempt?
saveFile(file, currentUser.Id);
2018-10-27 21:18:03 +02:00
}
else
{
file = createFile(relPath);
file.Content = display.Content;
saveFile(file, currentUser.Id);
2018-10-27 21:18:03 +02:00
}
return file;
}
2017-05-12 14:49:44 +02:00
private Attempt<IPartialView> CreateOrUpdatePartialView(CodeFileDisplay display)
{
return CreateOrUpdatePartialView(display, Constants.SystemDirectories.PartialViews,
_fileService.GetPartialView, _fileService.SavePartialView, _fileService.CreatePartialView);
2017-05-12 14:49:44 +02:00
}
2017-07-20 11:21:28 +02:00
2017-05-12 14:49:44 +02:00
private Attempt<IPartialView> CreateOrUpdatePartialViewMacro(CodeFileDisplay display)
{
return CreateOrUpdatePartialView(display, Constants.SystemDirectories.MacroPartials,
_fileService.GetPartialViewMacro, _fileService.SavePartialViewMacro, _fileService.CreatePartialViewMacro);
2017-05-12 14:49:44 +02:00
}
/// <summary>
/// Helper method to take care of persisting partial views or partial view macros - so we're not duplicating the same logic
/// </summary>
/// <param name="display"></param>
/// <param name="systemDirectory"></param>
/// <param name="getView"></param>
/// <param name="saveView"></param>
/// <param name="createView"></param>
/// <returns></returns>
private Attempt<IPartialView> CreateOrUpdatePartialView(
CodeFileDisplay display, string systemDirectory,
Func<string, IPartialView> getView,
Func<IPartialView, int, Attempt<IPartialView>> saveView,
Func<IPartialView, string, int, Attempt<IPartialView>> createView)
{
//must always end with the correct extension
display.Name = EnsureCorrectFileExtension(display.Name, ".cshtml");
Attempt<IPartialView> partialViewResult;
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
2017-05-12 14:49:44 +02:00
var virtualPath = NormalizeVirtualPath(display.VirtualPath, systemDirectory);
var view = getView(virtualPath);
if (view != null)
{
// might need to find the path
var orgPath = view.OriginalPath.Substring(0, view.OriginalPath.IndexOf(view.Name));
view.Path = orgPath + display.Name;
view.Content = display.Content;
partialViewResult = saveView(view, currentUser.Id);
2017-05-12 14:49:44 +02:00
}
else
{
2017-05-30 10:50:09 +02:00
view = new PartialView(PartialViewType.PartialView, virtualPath + display.Name);
2017-05-12 14:49:44 +02:00
view.Content = display.Content;
partialViewResult = createView(view, display.Snippet, currentUser.Id);
2017-05-12 14:49:44 +02:00
}
return partialViewResult;
}
private string NormalizeVirtualPath(string virtualPath, string systemDirectory)
{
if (virtualPath.IsNullOrWhiteSpace())
return string.Empty;
systemDirectory = systemDirectory.TrimStart("~");
systemDirectory = systemDirectory.Replace('\\', '/');
virtualPath = virtualPath.TrimStart("~");
virtualPath = virtualPath.Replace('\\', '/');
virtualPath = virtualPath.ReplaceFirst(systemDirectory, string.Empty);
return virtualPath;
}
private string EnsureCorrectFileExtension(string value, string extension)
{
if (value.EndsWith(extension) == false)
value += extension;
return value;
}
private bool IsDirectory(string path)
2017-05-12 14:49:44 +02:00
{
var dirInfo = new DirectoryInfo(path);
return dirInfo.Attributes == FileAttributes.Directory;
}
// this is an internal class for passing stylesheet data from the client to the controller while editing
public class StylesheetData
{
public string Content { get; set; }
public StylesheetRule[] Rules { get; set; }
}
2017-05-12 14:49:44 +02:00
}
}