using System; using System.IO; using System.Linq; using System.Web.Mvc; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Web.Cache; using Umbraco.Web.Macros; using Umbraco.Web.Mvc; using umbraco; using umbraco.BasePages; using umbraco.cms.businesslogic.macro; using umbraco.presentation.cache; using Umbraco.Core; using Template = umbraco.cms.businesslogic.template.Template; namespace Umbraco.Web.WebServices { /// /// A REST controller used to save files such as templates, partial views, macro files, etc... /// /// /// This isn't fully implemented yet but we should migrate all of the logic in the umbraco.presentation.webservices.codeEditorSave /// over to this controller. /// public class SaveFileController : UmbracoAuthorizedController { /// /// Saves a partial view for a partial view macr /// /// /// /// /// [HttpPost] public JsonResult SavePartialView(string filename, string oldName, string contents) { var folderPath = SystemDirectories.MvcViews.EnsureEndsWith('/');// +"/Partials/"; // 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 val = contents; var saveOldPath = oldName.StartsWith("~/") ? IOHelper.MapPath(oldName) : IOHelper.MapPath(folderPath + oldName); var savePath = filename.StartsWith("~/") ? IOHelper.MapPath(filename) : IOHelper.MapPath(folderPath + filename); //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)); } //deletes the old file if (savePath != saveOldPath) { if (System.IO.File.Exists(saveOldPath)) System.IO.File.Delete(saveOldPath); } //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")); } /// /// Saves a template /// /// /// /// /// /// /// [HttpPost] public JsonResult SaveTemplate(string templateName, string templateAlias, string templateContents, int templateId, int masterTemplateId) { Template t; try { t = new Template(templateId) { Text = templateName, Alias = templateAlias, MasterTemplate = masterTemplateId, Design = templateContents }; } catch (ArgumentException ex) { //the template does not exist return Failed("Template does not exist", ui.Text("speechBubbles", "templateErrorHeader"), ex); } try { t.Save(); return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader")); } catch (Exception ex) { return Failed(ui.Text("speechBubbles", "templateErrorText"), ui.Text("speechBubbles", "templateErrorHeader"), ex); } } /// /// Returns a successful message /// /// The message to display in the speach bubble /// The header to display in the speach bubble /// private JsonResult Success(string message, string header) { return Json(new { success = true, message = message, header = header }); } /// /// Returns a failed message /// /// The message to display in the speach bubble /// The header to display in the speach bubble /// The exception if there was one /// private JsonResult Failed(string message, string header, Exception exception = null) { if (exception != null) LogHelper.Error("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.")) }); } } }