2012-12-30 03:11:21 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Linq;
|
2013-04-19 10:18:46 -02:00
|
|
|
|
using System.Text;
|
2012-12-30 03:11:21 +03:00
|
|
|
|
using System.Web.Mvc;
|
2014-08-14 17:20:25 +02:00
|
|
|
|
using Umbraco.Core.Events;
|
2012-12-30 03:11:21 +03:00
|
|
|
|
using Umbraco.Core.IO;
|
|
|
|
|
|
using Umbraco.Core.Logging;
|
2014-08-19 12:51:07 +02:00
|
|
|
|
using Umbraco.Core.Models;
|
2014-08-19 10:39:52 +02:00
|
|
|
|
using Umbraco.Core.Services;
|
2013-01-01 00:42:20 +03:00
|
|
|
|
using Umbraco.Web.Macros;
|
2012-12-30 03:11:21 +03:00
|
|
|
|
using Umbraco.Web.Mvc;
|
|
|
|
|
|
using umbraco;
|
2013-01-01 00:42:20 +03:00
|
|
|
|
using umbraco.cms.businesslogic.macro;
|
2013-08-30 14:15:51 +10:00
|
|
|
|
using System.Collections.Generic;
|
2012-12-31 02:51:30 +03:00
|
|
|
|
using Umbraco.Core;
|
2013-08-30 14:15:51 +10:00
|
|
|
|
|
2013-02-11 03:55:58 +06:00
|
|
|
|
using Template = umbraco.cms.businesslogic.template.Template;
|
2012-12-30 03:11:21 +03:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.WebServices
|
|
|
|
|
|
{
|
2013-02-09 04:05:01 +06:00
|
|
|
|
/// <summary>
|
2014-08-14 17:20:25 +02:00
|
|
|
|
/// 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
|
|
|
|
|
|
{
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Saves a partial view macro
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filename"></param>
|
|
|
|
|
|
/// <param name="oldName"></param>
|
|
|
|
|
|
/// <param name="contents"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
public JsonResult SavePartialViewMacro(string filename, string oldName, string contents)
|
|
|
|
|
|
{
|
|
|
|
|
|
//NOTE: This is a bit of a hack because we're sharing the View editor with templates/partial views/partial view macros, so the path starts with
|
|
|
|
|
|
// 'Partials' which we need to remove because the path that we construct the partial view with is a relative path to the root path of
|
|
|
|
|
|
// Views/Partials
|
|
|
|
|
|
if (filename.InvariantStartsWith("MacroPartials/"))
|
|
|
|
|
|
{
|
|
|
|
|
|
filename = filename.TrimStart("MacroPartials/");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (oldName.IsNullOrWhiteSpace() == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (oldName.InvariantStartsWith("MacroPartials/"))
|
|
|
|
|
|
{
|
|
|
|
|
|
oldName = oldName.TrimStart("MacroPartials/");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var fileService = (FileService)Services.FileService;
|
|
|
|
|
|
|
|
|
|
|
|
//try to get the file by the old name first if they are different and delete that file
|
|
|
|
|
|
if (filename.Trim().InvariantEquals(oldName.Trim()) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
var existing = fileService.GetPartialViewMacro(oldName);
|
|
|
|
|
|
if (existing != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var success = fileService.DeletePartialViewMacro(existing.Path, Security.GetUserId());
|
|
|
|
|
|
if (success == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Failed(
|
|
|
|
|
|
ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
|
|
|
|
|
|
//pass in a new exception ... this will also append the the message
|
|
|
|
|
|
new Exception("Could not delete old file: " + oldName));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var partialView = new PartialView(filename)
|
|
|
|
|
|
{
|
|
|
|
|
|
Content = contents
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var attempt = fileService.SavePartialViewMacro(partialView);
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Success(ui.Text("speechBubbles", "partialViewSavedText"), ui.Text("speechBubbles", "partialViewSavedHeader"));
|
|
|
|
|
|
}
|
2014-08-14 17:20:25 +02:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
/// Saves a partial view
|
2014-08-14 17:20:25 +02:00
|
|
|
|
/// </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)
|
|
|
|
|
|
{
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
//NOTE: This is a bit of a hack because we're sharing the View editor with templates/partial views/partial view macros, so the path starts with
|
|
|
|
|
|
// 'Partials' which we need to remove because the path that we construct the partial view with is a relative path to the root path of
|
|
|
|
|
|
// Views/Partials
|
|
|
|
|
|
if (filename.InvariantStartsWith("Partials/"))
|
|
|
|
|
|
{
|
|
|
|
|
|
filename = filename.TrimStart("Partials/");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (oldName.IsNullOrWhiteSpace() == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (oldName.InvariantStartsWith("Partials/"))
|
|
|
|
|
|
{
|
|
|
|
|
|
oldName = oldName.TrimStart("Partials/");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-08-14 17:20:25 +02:00
|
|
|
|
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
var fileService = (FileService)Services.FileService;
|
|
|
|
|
|
|
|
|
|
|
|
//try to get the file by the old name first if they are different and delete that file
|
|
|
|
|
|
if (filename.Trim().InvariantEquals(oldName.Trim()) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
var existing = fileService.GetPartialView(oldName);
|
|
|
|
|
|
if (existing != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var success = fileService.DeletePartialView(existing.Path, Security.GetUserId());
|
|
|
|
|
|
if (success == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Failed(
|
|
|
|
|
|
ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
|
|
|
|
|
|
//pass in a new exception ... this will also append the the message
|
|
|
|
|
|
new Exception("Could not delete old file: " + oldName));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var partialView = new PartialView(filename)
|
2014-08-14 17:20:25 +02:00
|
|
|
|
{
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
Content = contents
|
2014-08-19 12:51:07 +02:00
|
|
|
|
};
|
Updates PartialView & PartialViewMacros models/services/repositories, streamlines their operations, fixes up other underlying problems with the FileRepository, fixes tree syncing for partial views, partial view macros and scripts, fixes scripts being created in folders, allows partial views and partial view macros to be managed and created in folders, fixes FileUnitOfWork to use a queue, publicizes some internal test classes, fixes tree syncing when dealing with invariant case, adds correct validation to the create dialogs of scripts and partial views (and partial view macros)
2014-10-22 16:44:45 +10:00
|
|
|
|
|
2014-08-19 12:51:07 +02:00
|
|
|
|
var attempt = fileService.SavePartialView(partialView);
|
2014-08-14 17:20:25 +02:00
|
|
|
|
|
2014-08-19 12:51:07 +02:00
|
|
|
|
if (attempt.Success == false)
|
2014-08-14 17:20:25 +02:00
|
|
|
|
{
|
|
|
|
|
|
return Failed(
|
|
|
|
|
|
ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
|
|
|
|
|
|
//pass in a new exception ... this will also append the the message
|
2014-08-19 12:51:07 +02:00
|
|
|
|
attempt.Exception);
|
2014-08-14 17:20:25 +02:00
|
|
|
|
}
|
2013-04-18 23:00:57 +06:00
|
|
|
|
|
2014-08-14 17:20:25 +02:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2014-12-05 17:29:47 +11:00
|
|
|
|
//TODO: Change this over to use the new API - Also this will be migrated to a TemplateEditor or ViewEditor when it's all moved to angular
|
|
|
|
|
|
|
2014-08-14 17:20:25 +02:00
|
|
|
|
Template t;
|
|
|
|
|
|
bool pathChanged = false;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
t = new Template(templateId)
|
|
|
|
|
|
{
|
|
|
|
|
|
Text = templateName,
|
|
|
|
|
|
Alias = templateAlias,
|
|
|
|
|
|
Design = templateContents
|
|
|
|
|
|
};
|
2013-08-30 14:15:51 +10:00
|
|
|
|
|
2014-12-05 17:29:47 +11:00
|
|
|
|
//check if the master page has changed - we need to normalize both - if it's 0 or -1, then make it 0... this is easy
|
|
|
|
|
|
// to do with Math.Max
|
|
|
|
|
|
if (Math.Max(t.MasterTemplate, 0) != Math.Max(masterTemplateId, 0))
|
2013-08-30 14:15:51 +10:00
|
|
|
|
{
|
2014-12-05 17:29:47 +11:00
|
|
|
|
t.MasterTemplate = Math.Max(masterTemplateId, 0);
|
|
|
|
|
|
pathChanged = true;
|
2013-08-30 14:15:51 +10:00
|
|
|
|
}
|
2014-08-14 17:20:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
catch (ArgumentException ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
//the template does not exist
|
|
|
|
|
|
return Failed("Template does not exist", ui.Text("speechBubbles", "templateErrorHeader"), ex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
t.Save();
|
2012-12-30 03:11:21 +03:00
|
|
|
|
|
2013-08-30 14:15:51 +10:00
|
|
|
|
//ensure the correct path is synced as the parent might have been changed
|
|
|
|
|
|
// http://issues.umbraco.org/issue/U4-2300
|
|
|
|
|
|
if (pathChanged)
|
|
|
|
|
|
{
|
|
|
|
|
|
//need to re-look it up
|
|
|
|
|
|
t = new Template(templateId);
|
|
|
|
|
|
}
|
|
|
|
|
|
var syncPath = "-1,init," + t.Path.Replace("-1,", "");
|
|
|
|
|
|
|
2014-08-14 17:20:25 +02:00
|
|
|
|
return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader"),
|
2015-01-09 17:01:38 +11:00
|
|
|
|
new
|
|
|
|
|
|
{
|
|
|
|
|
|
path = syncPath,
|
|
|
|
|
|
contents = t.Design
|
|
|
|
|
|
});
|
2014-08-14 17:20:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Failed(ui.Text("speechBubbles", "templateErrorText"), ui.Text("speechBubbles", "templateErrorHeader"), ex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-12-30 03:11:21 +03:00
|
|
|
|
|
2013-08-30 14:15:51 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns a successful 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="additionalVals"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private JsonResult Success(string message, string header, object additionalVals = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var d = additionalVals == null ? new Dictionary<string, object>() : additionalVals.ToDictionary<object>();
|
|
|
|
|
|
d["success"] = true;
|
|
|
|
|
|
d["message"] = message;
|
|
|
|
|
|
d["header"] = header;
|
|
|
|
|
|
|
2014-08-14 17:20:25 +02:00
|
|
|
|
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."))
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-12-30 03:11:21 +03:00
|
|
|
|
}
|