Merge pull request #449 from nul800sebastiaan/uaas-events

Adding events for use by Courier/UaaS
This commit is contained in:
Morten Christensen
2014-08-20 14:12:38 +02:00
10 changed files with 496 additions and 393 deletions

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.IO;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a Partial View file
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class PartialView : File
{
private readonly Regex _headerMatch = new Regex("^@inherits\\s+?.*$", RegexOptions.Multiline | RegexOptions.Compiled);
public PartialView(string path)
: base(path)
{
base.Path = path;
}
/// <summary>
/// Boolean indicating whether the file could be validated
/// </summary>
/// <returns>True if file is valid, otherwise false</returns>
public override bool IsValid()
{
//TODO: Validate using the macro engine
//var engine = MacroEngineFactory.GetEngine(PartialViewMacroEngine.EngineName);
//engine.Validate(...)
var validatePath = IOHelper.ValidateEditPath(IOHelper.MapPath(Path), BasePath);
var verifyFileExtension = IOHelper.VerifyFileExtension(Path, new List<string> { "cshtml" });
return validatePath && verifyFileExtension;
}
public string OldFileName { get; set; }
public string FileName { get; set; }
public string SnippetName { get; set; }
public bool CreateMacro { get; set; }
public string CodeHeader { get; set; }
public string ParentFolderName { get; set; }
public string EditViewFile { get; set; }
public string BasePath { get; set; }
public string ReturnUrl { get; set; }
internal Regex HeaderMatch
{
get { return _headerMatch; }
}
internal Attempt<string> TryGetSnippetPath(string fileName)
{
var partialViewsFileSystem = new PhysicalFileSystem(BasePath);
var snippetPath = IOHelper.MapPath(string.Format("{0}/PartialViewMacros/Templates/{1}", SystemDirectories.Umbraco, fileName));
return partialViewsFileSystem.FileExists(snippetPath)
? Attempt<string>.Succeed(snippetPath)
: Attempt<string>.Fail();
}
}
}

View File

@@ -1,7 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Repositories;
@@ -17,19 +23,21 @@ namespace Umbraco.Core.Services
private readonly RepositoryFactory _repositoryFactory;
private readonly IUnitOfWorkProvider _fileUowProvider;
private readonly IDatabaseUnitOfWorkProvider _dataUowProvider;
private readonly IMacroService _macroService;
public FileService()
: this(new RepositoryFactory())
{ }
public FileService(RepositoryFactory repositoryFactory)
: this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory)
: this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory, new MacroService())
{
}
public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory)
public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory, IMacroService macroService)
{
_repositoryFactory = repositoryFactory;
_macroService = macroService;
_fileUowProvider = fileProvider;
_dataUowProvider = dataProvider;
}
@@ -362,6 +370,138 @@ namespace Umbraco.Core.Services
return template.IsValid();
}
// TODO: Before making this public: How to get feedback in the UI when cancelled
internal Attempt<PartialView> CreatePartialView(PartialView partialView)
{
var partialViewsFileSystem = new PhysicalFileSystem(partialView.BasePath);
var relativeFilePath = partialView.ParentFolderName.EnsureEndsWith('/') + partialViewsFileSystem.GetRelativePath(partialView.FileName);
partialView.ReturnUrl = string.Format(partialView.EditViewFile + "?file={0}", HttpUtility.UrlEncode(relativeFilePath));
//return the link to edit the file if it already exists
if (partialViewsFileSystem.FileExists(partialView.Path))
return Attempt<PartialView>.Succeed(partialView);
if (CreatingPartialView.IsRaisedEventCancelled(new NewEventArgs<PartialView>(partialView, true, partialView.Alias, -1), this))
{
// We have nowhere to return to, clear ReturnUrl
partialView.ReturnUrl = string.Empty;
var failureMessage = string.Format("Creating Partial View {0} was cancelled by an event handler.", partialViewsFileSystem.GetFullPath(partialView.FileName));
LogHelper.Info<FileService>(failureMessage);
return Attempt<PartialView>.Fail(partialView, new ArgumentException(failureMessage));
}
//create the file
var snippetPathAttempt = partialView.TryGetSnippetPath(partialView.SnippetName);
if (snippetPathAttempt.Success == false)
{
throw new InvalidOperationException("Could not load template with name " + partialView.SnippetName);
}
using (var snippetFile = new StreamReader(partialViewsFileSystem.OpenFile(snippetPathAttempt.Result)))
{
var snippetContent = snippetFile.ReadToEnd().Trim();
//strip the @inherits if it's there
snippetContent = partialView.HeaderMatch.Replace(snippetContent, string.Empty);
var content = string.Format("{0}{1}{2}", partialView.CodeHeader, Environment.NewLine, snippetContent);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
partialViewsFileSystem.AddFile(partialView.Path, stream);
}
}
if (partialView.CreateMacro)
CreatePartialViewMacro(partialView);
CreatedPartialView.RaiseEvent(new NewEventArgs<PartialView>(partialView, false, partialView.Alias, -1), this);
return Attempt<PartialView>.Succeed(partialView);
}
internal void CreatePartialViewMacro(PartialView partialView)
{
var name = partialView.FileName.Substring(0, (partialView.FileName.LastIndexOf('.') + 1))
.Trim('.')
.SplitPascalCasing()
.ToFirstUpperInvariant();
var macro = new Macro(name, name) { ScriptPath = partialView.BasePath + partialView.FileName };
_macroService.Save(macro);
}
// TODO: Before making this public: How to get feedback in the UI when cancelled
internal bool DeletePartialView(PartialView partialView, int userId = 0)
{
var partialViewsFileSystem = new PhysicalFileSystem(partialView.BasePath);
if (DeletingPartialView.IsRaisedEventCancelled(new DeleteEventArgs<PartialView>(partialView), this))
{
LogHelper.Info<FileService>(string.Format("Deleting Partial View {0} was cancelled by an event handler.", partialViewsFileSystem.GetFullPath(partialView.FileName)));
return false;
}
if (partialViewsFileSystem.FileExists(partialView.FileName))
{
partialViewsFileSystem.DeleteFile(partialView.FileName);
LogHelper.Info<FileService>(string.Format("Partial View file {0} deleted by user {1}", partialViewsFileSystem.GetFullPath(partialView.FileName), userId));
}
// TODO: does this ever even happen? I don't think folders show up in the tree currently.
// Leaving this here as it was in the original PartialViewTasks code - SJ
else if (partialViewsFileSystem.DirectoryExists(partialView.FileName))
{
partialViewsFileSystem.DeleteDirectory(partialView.FileName, true);
LogHelper.Info<FileService>(string.Format("Partial View directory {0} deleted by user {1}", partialViewsFileSystem.GetFullPath(partialView.FileName), userId));
}
DeletedPartialView.RaiseEvent(new DeleteEventArgs<PartialView>(partialView, false), this);
return true;
}
internal Attempt<PartialView> SavePartialView(PartialView partialView, int userId = 0)
{
if (SavingPartialView.IsRaisedEventCancelled(new SaveEventArgs<PartialView>(partialView, true), this))
{
return Attempt<PartialView>.Fail(new ArgumentException("Save was cancelled by an event handler " + partialView.FileName));
}
//Directory check.. only allow files in script dir and below to be edited
if (partialView.IsValid() == false)
{
return Attempt<PartialView>.Fail(
new ArgumentException(string.Format("Illegal path: {0} or illegal file extension {1}",
partialView.Path,
partialView.FileName.Substring(partialView.FileName.LastIndexOf(".", StringComparison.Ordinal)))));
}
//NOTE: I've left the below here just for informational purposes. If we save a file this way, then the UTF8
// BOM mucks everything up, strangely, if we use WriteAllText everything is ok!
// http://issues.umbraco.org/issue/U4-2118
//using (var sw = System.IO.File.CreateText(savePath))
//{
// sw.Write(val);
//}
System.IO.File.WriteAllText(partialView.Path, partialView.Content, Encoding.UTF8);
//deletes the old file
if (partialView.FileName != partialView.OldFileName)
{
// Create a new PartialView class so that we can set the FileName of the file that needs deleting
var deletePartial = partialView;
deletePartial.FileName = partialView.OldFileName;
DeletePartialView(deletePartial, userId);
}
SavedPartialView.RaiseEvent(new SaveEventArgs<PartialView>(partialView), this);
return Attempt.Succeed(partialView);
}
//TODO Method to change name and/or alias of view/masterpage template
#region Event Handlers
@@ -425,6 +565,37 @@ namespace Umbraco.Core.Services
/// </summary>
public static event TypedEventHandler<IFileService, SaveEventArgs<Stylesheet>> SavedStylesheet;
/// <summary>
/// Occurs before Save
/// </summary>
internal static event TypedEventHandler<IFileService, SaveEventArgs<PartialView>> SavingPartialView;
/// <summary>
/// Occurs after Save
/// </summary>
internal static event TypedEventHandler<IFileService, SaveEventArgs<PartialView>> SavedPartialView;
/// <summary>
/// Occurs before Create
/// </summary>
internal static event TypedEventHandler<IFileService, NewEventArgs<PartialView>> CreatingPartialView;
/// <summary>
/// Occurs after Create
/// </summary>
internal static event TypedEventHandler<IFileService, NewEventArgs<PartialView>> CreatedPartialView;
/// <summary>
/// Occurs before Delete
/// </summary>
internal static event TypedEventHandler<IFileService, DeleteEventArgs<PartialView>> DeletingPartialView;
/// <summary>
/// Occurs after Delete
/// </summary>
internal static event TypedEventHandler<IFileService, DeleteEventArgs<PartialView>> DeletedPartialView;
#endregion
}
}

View File

@@ -144,7 +144,7 @@ namespace Umbraco.Core.Services
_dataTypeService = new Lazy<IDataTypeService>(() => new DataTypeService(provider, repositoryFactory.Value));
if (_fileService == null)
_fileService = new Lazy<IFileService>(() => new FileService(fileProvider, provider, repositoryFactory.Value));
_fileService = new Lazy<IFileService>(() => new FileService(fileProvider, provider, repositoryFactory.Value, _macroService.Value));
if (_localizationService == null)
_localizationService = new Lazy<ILocalizationService>(() => new LocalizationService(provider, repositoryFactory.Value));

View File

@@ -364,6 +364,7 @@
<Compile Include="Models\PublishedContent\IPublishedContentModelFactory.cs" />
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
<Compile Include="Models\PartialView.cs" />
<Compile Include="Models\TagCacheStorageType.cs" />
<Compile Include="Models\TaggableObjectTypes.cs" />
<Compile Include="Models\TaggedEntity.cs" />

View File

@@ -9,17 +9,17 @@ using umbraco.presentation.create;
namespace Umbraco.Web.UI.Umbraco.Create
{
public partial class PartialViewMacro : UserControl
{
public partial class PartialViewMacro : UserControl
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
DataBind();
LoadTemplates(PartialViewTemplate);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
DataBind();
LoadTemplates(PartialViewTemplate);
}
private static void LoadTemplates(ListControl list)
{
@@ -45,44 +45,47 @@ namespace Umbraco.Web.UI.Umbraco.Create
}
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
//Seriously, need to overhaul create dialogs, this is rediculous:
// http://issues.umbraco.org/issue/U4-1373
protected void SubmitButton_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
//Seriously, need to overhaul create dialogs, this is rediculous:
// http://issues.umbraco.org/issue/U4-1373
var createMacroVal = 0;
if (CreateMacroCheckBox.Checked)
createMacroVal = 1;
var createMacroVal = 0;
if (CreateMacroCheckBox.Checked)
createMacroVal = 1;
string returnUrl = dialogHandler_temp.Create(Request.GetItemAsString("nodeType"),
createMacroVal, //apparently we need to pass this value to 'ParentID'... of course! :P then we'll extract it in PartialViewTasks to create it.
PartialViewTemplate.SelectedValue + "|||" + FileName.Text);
BasePage.Current.ClientTools
.ChangeContentFrameUrl(returnUrl)
.ChildNodeCreated()
.CloseModalWindow();
}
}
protected void MacroExistsValidator_OnServerValidate(object source, ServerValidateEventArgs args)
{
if (CreateMacroCheckBox.Checked)
{
BasePage.Current.ClientTools
.ChangeContentFrameUrl(returnUrl)
.ChildNodeCreated()
.CloseModalWindow();
}
}
protected void MacroExistsValidator_OnServerValidate(object source, ServerValidateEventArgs args)
{
if (CreateMacroCheckBox.Checked)
{
//TODO: Shouldn't this use our string functions to create the alias ?
var fileName = FileName.Text + ".cshtml";
var name = fileName
.Substring(0, (fileName.LastIndexOf('.') + 1)).Trim('.')
.SplitPascalCasing().ToFirstUpperInvariant();
var fileName = FileName.Text;
var name = fileName.Contains(".")
? fileName.Substring(0, (fileName.LastIndexOf('.') + 1)).Trim('.')
: fileName;
name = name.SplitPascalCasing().ToFirstUpperInvariant();
var macro = ApplicationContext.Current.Services.MacroService.GetByAlias(name);
if (macro != null)
{
args.IsValid = false;
}
}
}
}
}
}
}
}
}

View File

@@ -488,6 +488,7 @@
<Compile Include="umbraco.presentation\umbraco\create\DLRScripting.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\create\PartialViewTasksBase.cs" />
<Compile Include="umbraco.presentation\umbraco\create\xslt.ascx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>

View File

@@ -2,8 +2,11 @@
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Macros;
using Umbraco.Web.Mvc;
using umbraco;
@@ -16,91 +19,72 @@ using Template = umbraco.cms.businesslogic.template.Template;
namespace Umbraco.Web.WebServices
{
/// <summary>
/// A REST controller used to save files such as templates, partial views, macro files, etc...
/// </summary>
/// <remarks>
/// This isn't fully implemented yet but we should migrate all of the logic in the umbraco.presentation.webservices.codeEditorSave
/// over to this controller.
/// </remarks>
public class SaveFileController : UmbracoAuthorizedController
{
/// A REST controller used to save files such as templates, partial views, macro files, etc...
/// </summary>
/// <remarks>
/// This isn't fully implemented yet but we should migrate all of the logic in the umbraco.presentation.webservices.codeEditorSave
/// over to this controller.
/// </remarks>
public class SaveFileController : UmbracoAuthorizedController
{
/// <summary>
/// Saves a partial view for a partial view macr
/// </summary>
/// <param name="filename"></param>
/// <param name="oldName"></param>
/// <param name="contents"></param>
/// <returns></returns>
[HttpPost]
public JsonResult SavePartialView(string filename, string oldName, string contents)
{
var folderPath = SystemDirectories.MvcViews.EnsureEndsWith('/');// +"/Partials/";
/// <summary>
/// Saves a partial view for a partial view macro
/// </summary>
/// <param name="filename"></param>
/// <param name="oldName"></param>
/// <param name="contents"></param>
/// <returns></returns>
[HttpPost]
public JsonResult SavePartialView(string filename, string oldName, string contents)
{
var folderPath = SystemDirectories.MvcViews.EnsureEndsWith('/');// +"/Partials/";
var savePath = filename.StartsWith("~/") ? IOHelper.MapPath(filename) : IOHelper.MapPath(folderPath + filename);
// validate file
IOHelper.ValidateEditPath(IOHelper.MapPath(folderPath + filename), folderPath);
// validate extension
IOHelper.ValidateFileExtension(IOHelper.MapPath(folderPath + filename), new[] { "cshtml" }.ToList());
//TODO: Validate using the macro engine
var engine = MacroEngineFactory.GetEngine(PartialViewMacroEngine.EngineName);
//engine.Validate(...)
var partialView = new PartialView(savePath)
{
BasePath = folderPath,
OldFileName = oldName,
FileName = filename,
Content = contents,
};
var val = contents;
var saveOldPath = oldName.StartsWith("~/") ? IOHelper.MapPath(oldName) : IOHelper.MapPath(folderPath + oldName);
var savePath = filename.StartsWith("~/") ? IOHelper.MapPath(filename) : IOHelper.MapPath(folderPath + filename);
var fileService = (FileService)ApplicationContext.Current.Services.FileService;
var attempt = fileService.SavePartialView(partialView);
//Directory check.. only allow files in script dir and below to be edited
if (!savePath.StartsWith(IOHelper.MapPath(folderPath)))
{
return Failed(
ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
//pass in a new exception ... this will also append the the message
new ArgumentException("Illegal path: " + savePath));
}
if (attempt.Success == false)
{
return Failed(
ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
//pass in a new exception ... this will also append the the message
attempt.Exception);
}
//deletes the old file
if (savePath != saveOldPath)
{
if (System.IO.File.Exists(saveOldPath))
System.IO.File.Delete(saveOldPath);
}
return Success(ui.Text("speechBubbles", "partialViewSavedText"), ui.Text("speechBubbles", "partialViewSavedHeader"));
}
//NOTE: I've left the below here just for informational purposes. If we save a file this way, then the UTF8
// BOM mucks everything up, strangely, if we use WriteAllText everything is ok!
// http://issues.umbraco.org/issue/U4-2118
//using (var sw = System.IO.File.CreateText(savePath))
//{
// sw.Write(val);
//}
System.IO.File.WriteAllText(savePath, val, Encoding.UTF8);
return Success(ui.Text("speechBubbles", "partialViewSavedText"), ui.Text("speechBubbles", "partialViewSavedHeader"));
}
/// <summary>
/// Saves a template
/// </summary>
/// <param name="templateName"></param>
/// <param name="templateAlias"></param>
/// <param name="templateContents"></param>
/// <param name="templateId"></param>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
[HttpPost]
public JsonResult SaveTemplate(string templateName, string templateAlias, string templateContents, int templateId, int masterTemplateId)
{
Template t;
bool pathChanged = false;
try
{
t = new Template(templateId)
{
Text = templateName,
Alias = templateAlias,
Design = templateContents
};
/// <summary>
/// Saves a template
/// </summary>
/// <param name="templateName"></param>
/// <param name="templateAlias"></param>
/// <param name="templateContents"></param>
/// <param name="templateId"></param>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
[HttpPost]
public JsonResult SaveTemplate(string templateName, string templateAlias, string templateContents, int templateId, int masterTemplateId)
{
Template t;
bool pathChanged = false;
try
{
t = new Template(templateId)
{
Text = templateName,
Alias = templateAlias,
Design = templateContents
};
//check if the master page has changed
if (t.MasterTemplate != masterTemplateId)
@@ -108,16 +92,16 @@ namespace Umbraco.Web.WebServices
pathChanged = true;
t.MasterTemplate = masterTemplateId;
}
}
catch (ArgumentException ex)
{
//the template does not exist
return Failed("Template does not exist", ui.Text("speechBubbles", "templateErrorHeader"), ex);
}
}
catch (ArgumentException ex)
{
//the template does not exist
return Failed("Template does not exist", ui.Text("speechBubbles", "templateErrorHeader"), ex);
}
try
{
t.Save();
try
{
t.Save();
//ensure the correct path is synced as the parent might have been changed
// http://issues.umbraco.org/issue/U4-2300
@@ -128,14 +112,14 @@ namespace Umbraco.Web.WebServices
}
var syncPath = "-1,init," + t.Path.Replace("-1,", "");
return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader"),
new {path = syncPath});
}
catch (Exception ex)
{
return Failed(ui.Text("speechBubbles", "templateErrorText"), ui.Text("speechBubbles", "templateErrorHeader"), ex);
}
}
return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader"),
new { path = syncPath });
}
catch (Exception ex)
{
return Failed(ui.Text("speechBubbles", "templateErrorText"), ui.Text("speechBubbles", "templateErrorHeader"), ex);
}
}
/// <summary>
/// Returns a successful message
@@ -151,27 +135,26 @@ namespace Umbraco.Web.WebServices
d["message"] = message;
d["header"] = header;
return Json(d);
}
return Json(d);
}
/// <summary>
/// Returns a failed message
/// </summary>
/// <param name="message">The message to display in the speach bubble</param>
/// <param name="header">The header to display in the speach bubble</param>
/// <param name="exception">The exception if there was one</param>
/// <returns></returns>
private JsonResult Failed(string message, string header, Exception exception = null)
{
if (exception != null)
LogHelper.Error<SaveFileController>("An error occurred saving a file. " + message, exception);
return Json(new
{
success = false,
header = header,
message = message + (exception == null ? "" : (exception.Message + ". Check log for details."))
});
}
}
/// <summary>
/// Returns a failed message
/// </summary>
/// <param name="message">The message to display in the speach bubble</param>
/// <param name="header">The header to display in the speach bubble</param>
/// <param name="exception">The exception if there was one</param>
/// <returns></returns>
private JsonResult Failed(string message, string header, Exception exception = null)
{
if (exception != null)
LogHelper.Error<SaveFileController>("An error occurred saving a file. " + message, exception);
return Json(new
{
success = false,
header = header,
message = message + (exception == null ? "" : (exception.Message + ". Check log for details."))
});
}
}
}

View File

@@ -1,14 +1,4 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Web.Mvc;
using Umbraco.Web.UI;
using umbraco.BasePages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using umbraco.BusinessLogic;
namespace umbraco
@@ -17,100 +7,21 @@ namespace umbraco
/// The UI 'tasks' for the create dialog and delete processes
/// </summary>
[UmbracoWillObsolete("http://issues.umbraco.org/issue/U4-1373", "This will one day be removed when we overhaul the create process")]
public class PartialViewMacroTasks : LegacyDialogTask
public class PartialViewMacroTasks : PartialViewTasksBase
{
private const string CodeHeader = "@inherits Umbraco.Web.Macros.PartialViewMacroPage";
private string _returnUrl = "";
private readonly Regex _headerMatch = new Regex("^@inherits\\s+?.*$", RegexOptions.Multiline | RegexOptions.Compiled);
protected virtual string EditViewFile
protected override string CodeHeader
{
get { return "Settings/Views/EditView.aspx"; }
get { return "@inherits Umbraco.Web.Macros.PartialViewMacroPage"; }
}
protected string BasePath
{
get { return SystemDirectories.MvcViews + "/" + ParentFolderName.EnsureEndsWith('/'); }
}
protected virtual string ParentFolderName
protected override string ParentFolderName
{
get { return "MacroPartials"; }
}
public override bool PerformSave()
{
var pipesIndex = Alias.IndexOf("|||", System.StringComparison.Ordinal);
var template = Alias.Substring(0, pipesIndex).Trim();
var fileName = Alias.Substring(pipesIndex + 3, Alias.Length - pipesIndex - 3) + ".cshtml";
var fullFilePath = IOHelper.MapPath(BasePath + fileName);
//return the link to edit the file if it already exists
if (File.Exists(fullFilePath))
{
_returnUrl = string.Format(EditViewFile + "?file={0}", HttpUtility.UrlEncode(ParentFolderName.EnsureEndsWith('/') + fileName));
return true;
}
//create the file
using (var sw = File.CreateText(fullFilePath))
{
using (var templateFile = File.OpenText(IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViewMacros/Templates/" + template)))
{
var templateContent = templateFile.ReadToEnd().Trim();
//strip the @inherits if it's there
templateContent = _headerMatch.Replace(templateContent, string.Empty);
sw.Write(
"{0}{1}{2}",
CodeHeader,
Environment.NewLine,
templateContent);
}
}
// Create macro?
if (ParentID == 1)
{
//TODO: Shouldn't this use our string functions to create the alias ?
var name = fileName
.Substring(0, (fileName.LastIndexOf('.') + 1)).Trim('.')
.SplitPascalCasing().ToFirstUpperInvariant();
var m = cms.businesslogic.macro.Macro.MakeNew(name);
m.ScriptingFile = BasePath + fileName;
m.Save();
}
_returnUrl = string.Format(EditViewFile + "?treeType={0}&file={1}", "partialViewMacros", HttpUtility.UrlEncode(ParentFolderName.EnsureEndsWith('/') + fileName));
return true;
}
public override string ReturnUrl
{
get { return _returnUrl; }
}
public override string AssignedApp
{
get { return DefaultApps.developer.ToString(); }
}
public override bool PerformDelete()
{
var path = IOHelper.MapPath(BasePath + Alias.TrimStart('/'));
if (File.Exists(path))
File.Delete(path);
else if (Directory.Exists(path))
Directory.Delete(path, true);
LogHelper.Info<PartialViewTasks>(string.Format("{0} Deleted by user {1}", Alias, User.Id));
return true;
}
}
}

View File

@@ -1,155 +1,27 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Web.Mvc;
using Umbraco.Web.UI;
using umbraco.BasePages;
using Umbraco.Core;
using Umbraco.Core.CodeAnnotations;
using umbraco.BusinessLogic;
namespace umbraco
{
/// <summary>
/// The UI 'tasks' for the create dialog and delete processes
/// </summary>
[UmbracoWillObsolete("http://issues.umbraco.org/issue/U4-1373", "This will one day be removed when we overhaul the create process")]
public class PartialViewTasks : LegacyDialogTask
/// <summary>
/// The UI 'tasks' for the create dialog and delete processes
/// </summary>
[UmbracoWillObsolete("http://issues.umbraco.org/issue/U4-1373", "This will one day be removed when we overhaul the create process")]
public class PartialViewTasks : PartialViewTasksBase
{
private const string CodeHeader = "@inherits Umbraco.Web.Mvc.UmbracoTemplatePage";
private readonly Regex _headerMatch = new Regex("^@inherits\\s+?.*$", RegexOptions.Multiline | RegexOptions.Compiled);
protected virtual string EditViewFile
protected override string CodeHeader
{
get { return "Settings/Views/EditView.aspx"; }
get { return "@inherits Umbraco.Web.Mvc.UmbracoTemplatePage"; }
}
protected string BasePath
{
get { return SystemDirectories.MvcViews + "/" + ParentFolderName.EnsureEndsWith('/'); }
}
protected virtual string ParentFolderName
protected override string ParentFolderName
{
get { return "Partials"; }
}
public override bool PerformSave()
{
var pipesIndex = Alias.IndexOf("|||", System.StringComparison.Ordinal);
var template = Alias.Substring(0, pipesIndex).Trim();
var fileName = Alias.Substring(pipesIndex + 3, Alias.Length - pipesIndex - 3);
if (!fileName.ToLowerInvariant().EndsWith(".cshtml"))
{
fileName += ".cshtml";
}
var fullFilePath = IOHelper.MapPath(BasePath + fileName);
//return the link to edit the file if it already exists
if (File.Exists(fullFilePath))
{
_returnUrl = string.Format(EditViewFile + "?file={0}", HttpUtility.UrlEncode(ParentFolderName.EnsureEndsWith('/') + fileName));
return true;
}
//create the file
using (var sw = File.CreateText(fullFilePath))
{
var templatePathAttempt = TryGetTemplatePath(template);
if (templatePathAttempt.Success == false)
{
throw new InvalidOperationException("Could not load template with name " + template);
}
using (var templateFile = File.OpenText(templatePathAttempt.Result))
{
var templateContent = templateFile.ReadToEnd().Trim();
//strip the @inherits if it's there
templateContent = _headerMatch.Replace(templateContent, string.Empty);
sw.Write(
"{0}{1}{2}",
CodeHeader,
Environment.NewLine,
templateContent);
}
}
// Create macro?
if (ParentID == 1)
{
var name = fileName
.Substring(0, (fileName.LastIndexOf('.') + 1)).Trim('.')
.SplitPascalCasing().ToFirstUpperInvariant();
var m = cms.businesslogic.macro.Macro.MakeNew(name);
m.ScriptingFile = BasePath + fileName;
m.Save();
}
_returnUrl = string.Format(EditViewFile + "?file={0}", HttpUtility.UrlEncode(ParentFolderName.EnsureEndsWith('/') + fileName));
return true;
}
protected virtual void WriteTemplateHeader(StreamWriter sw)
public override string AssignedApp
{
//write out the template header
sw.Write("@inherits ");
sw.Write(typeof(UmbracoTemplatePage).FullName.TrimEnd("`1"));
}
public override bool PerformDelete()
{
var path = IOHelper.MapPath(BasePath + Alias.TrimStart('/'));
if (File.Exists(path))
File.Delete(path);
else if (Directory.Exists(path))
Directory.Delete(path, true);
LogHelper.Info<PartialViewTasks>(string.Format("{0} Deleted by user {1}", Alias, UmbracoEnsuredPage.CurrentUser.Id));
return true;
}
private string _returnUrl = "";
public override string ReturnUrl
{
get { return _returnUrl; }
}
public override string AssignedApp
{
get { return DefaultApps.settings.ToString(); }
}
/// <summary>
/// Looks first in the Partial View template folder and then in the macro partials template folder if not found
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private Attempt<string> TryGetTemplatePath(string fileName)
{
var templatePath = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViews/Templates/" + fileName);
if (File.Exists(templatePath))
{
return Attempt<string>.Succeed(templatePath);
}
templatePath = IOHelper.MapPath(SystemDirectories.Umbraco + "/PartialViewMacros/Templates/" + fileName);
return File.Exists(templatePath)
? Attempt<string>.Succeed(templatePath)
: Attempt<string>.Fail();
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.UI;
using umbraco.BasePages;
using Umbraco.Core;
namespace umbraco
{
/// <summary>
/// The base UI 'tasks' for the create dialog and delete processes
/// </summary>
[UmbracoWillObsolete("http://issues.umbraco.org/issue/U4-1373", "This will one day be removed when we overhaul the create process")]
public abstract class PartialViewTasksBase : LegacyDialogTask
{
private string _returnUrl = string.Empty;
public override string ReturnUrl
{
get { return _returnUrl; }
}
protected abstract string CodeHeader { get; }
protected abstract string ParentFolderName { get; }
public override string AssignedApp
{
get { return string.Empty; }
}
protected virtual string EditViewFile
{
get { return "Settings/Views/EditView.aspx"; }
}
protected string BasePath
{
get { return SystemDirectories.MvcViews + "/" + ParentFolderName.EnsureEndsWith('/'); }
}
public override bool PerformSave()
{
var pipesIndex = Alias.IndexOf("|||", StringComparison.Ordinal);
var snippetName = Alias.Substring(0, pipesIndex).Trim();
var fileName = Alias.Substring(pipesIndex + 3, Alias.Length - pipesIndex - 3);
if (fileName.ToLowerInvariant().EndsWith(".cshtml") == false)
{
fileName += ".cshtml";
}
var partialViewsFileSystem = new PhysicalFileSystem(BasePath);
var fullFilePath = partialViewsFileSystem.GetFullPath(fileName);
var model = new PartialView(fullFilePath)
{
FileName = fileName,
SnippetName = snippetName,
CreateMacro = ParentID == 1,
CodeHeader = CodeHeader,
ParentFolderName = ParentFolderName,
EditViewFile = EditViewFile,
BasePath = BasePath
};
var fileService = (FileService)ApplicationContext.Current.Services.FileService;
var attempt = fileService.CreatePartialView(model);
_returnUrl = attempt.Result.ReturnUrl;
return attempt.Success;
}
public override bool PerformDelete()
{
var partialViewsFileSystem = new PhysicalFileSystem(BasePath);
var path = Alias.TrimStart('/');
var fullFilePath = partialViewsFileSystem.GetFullPath(path);
var model = new PartialView(fullFilePath) { BasePath = BasePath, FileName = path };
var fileService = (FileService)ApplicationContext.Current.Services.FileService;
return fileService.DeletePartialView(model, UmbracoEnsuredPage.CurrentUser.Id);
}
}
}