Merge branch 'hackathon-import-doc-type-to-angular' of https://github.com/kows/Umbraco-CMS into kows-hackathon-import-doc-type-to-angular

# Conflicts:
#	src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs
This commit is contained in:
Warren
2018-08-08 12:01:15 +01:00
13 changed files with 287 additions and 246 deletions

View File

@@ -333,7 +333,18 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
notificationsService.error(value);
});
});
}
},
import: function (file) {
if (!file) {
throw "file cannot be null";
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Import", { file: file })),
"Failed to import document type " + file
);
},
};
}
angular.module('umbraco.resources').factory('contentTypeResource', contentTypeResource);

View File

@@ -0,0 +1,75 @@
angular.module("umbraco")
.controller("Umbraco.Editors.DocumentTypes.ImportController",
function ($scope, contentTypeResource, navigationService, Upload, umbRequestHelper) {
var vm = this;
vm.serverErrorMessage = "";
vm.state = "upload";
vm.model = {};
vm.uploadStatus = "";
$scope.handleFiles = function (files, event) {
if (files && files.length > 0) {
$scope.upload(files[0]);
}
};
$scope.upload = function (file) {
Upload.upload({
url: umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Upload"),
fields: {},
file: file
}).success(function (data, status, headers, config) {
if (data.notifications && data.notifications.length > 0) {
// set error status on file
vm.uploadStatus = "error";
// Throw message back to user with the cause of the error
vm.serverErrorMessage = data.notifications[0].message;
} else {
// set done status on file
vm.uploadStatus = "done";
vm.model = data;
vm.state = "confirm";
}
}).error(function (evt, status, headers, config) {
// set status done
$scope.uploadStatus = "error";
// If file not found, server will return a 404 and display this message
if (status === 404) {
$scope.serverErrorMessage = "File not found";
}
else if (status == 400) {
//it's a validation error
$scope.serverErrorMessage = evt.message;
}
else {
//it's an unhandled error
//if the service returns a detailed error
if (evt.InnerException) {
$scope.serverErrorMessage = evt.InnerException.ExceptionMessage;
//Check if its the common "too large file" exception
if (evt.InnerException.StackTrace && evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
$scope.serverErrorMessage = "File too large to upload";
}
} else if (evt.Message) {
$scope.serverErrorMessage = evt.Message;
}
}
});
};
$scope.cancel = function () {
navigationService.hideDialog();
};
$scope.import = function () {
contentTypeResource.import(vm.model.tempFileName);
vm.state = "done";
}
});

View File

@@ -0,0 +1,72 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DocumentTypes.ImportController as vm">
<table class="propertyPane" id="Table1" cellspacing="0" cellpadding="4" width="360" border="0" runat="server">
<tr>
<td class="propertyContent" colspan="2">
<div ng-if="vm.state === 'upload'">
<p>
<span class="guiDialogNormal">
<localize key="importDocumentTypeHelp">
To import a document type, find the '.udt' file on your computer by clicking the 'Browse' button and click 'Import' (you'll be asked for confirmation on the next screen)
</localize>
</span>
</p>
<!-- Upload -->
<div class="flex items-center justify-center">
<form novalidate name="localPackageForm" class="flex flex-column justify-center items-center tc">
<!-- Drag and drop files area -->
<div ngf-drop
ng-hide="hideDropzone"
ng-model="filesHolder"
ngf-change="handleFiles($files, $event)"
class="umb-upload-local__dropzone"
ngf-drag-over-class="drag-over"
ngf-multiple="false"
ngf-allow-dir="false"
ngf-pattern="*.udt"
ngf-max-size="{{ maxFileSize }}"
ng-class="{'is-small': compact!=='false' || (done.length+queue.length) > 0 }">
<div class="content">
<!-- Drag and drop illustration -->
<i class="icon-box" draggable="false"></i>
<small class="faded" draggable="false"><strong><localize key="packager_dropHere">Drop to upload</localize></strong></small>
<!-- Select files -->
<div class="umb-upload-local__select-file"
ngf-select
ng-model="filesHolder"
ngf-change="handleFiles($files, $event)"
ngf-multiple="true"
ngf-pattern="*.udt"
ngf-max-size="{{ maxFileSize }}">
- <localize key="packager_orClickHereToUpload">or click here to choose files</localize>
</div>
</div>
</div>
</form>
</div>
<a href="#" ng-click="cancel()">>
<localize key="cancel">cancel</localize>
</a>
</div>
<div ng-if="vm.state === 'confirm'">
<strong>
<localize key="name">Name</localize>:
</strong>
{{vm.model.name}}
<br />
<strong>
<localize key="alias">Alias</localize>:
</strong>
{{vm.model.alias}}
<br />
<br />
<button class="btn btn-primary" ng-click="import()">
<localize key="actions_import">Import</localize>
</button>
</div>
<div ng-if="vm.state === 'done'">
{{vm.model.name}} has been imported!
</div>
</td>
</tr>
</table>
</div>

View File

@@ -361,7 +361,6 @@
<Content Include="Umbraco\Developer\Packages\directoryBrowser.aspx" />
<Content Include="Umbraco\Developer\Packages\editPackage.aspx" />
<Content Include="Umbraco\Dialogs\create.aspx" />
<Content Include="Umbraco\Dialogs\importDocumenttype.aspx" />
<Content Include="Umbraco\Dialogs\notifications.aspx" />
<Content Include="Umbraco\Dialogs\protectPage.aspx" />
<Content Include="Umbraco\Dialogs\rollBack.aspx" />

View File

@@ -1,49 +0,0 @@
<%@ Page MasterPageFile="../masterpages/umbracoDialog.Master" Language="c#" Codebehind="importDocumenttype.aspx.cs" AutoEventWireup="false"
Inherits="umbraco.presentation.umbraco.dialogs.importDocumentType" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="body">
<input id="tempFile" type="hidden" name="tempFile" runat="server" />
<asp:Literal ID="FeedBackMessage" runat="server" />
<table class="propertyPane" id="Table1" cellspacing="0" cellpadding="4" width="360" border="0" runat="server">
<tr>
<td class="propertyContent" colspan="2">
<asp:Panel ID="Wizard" runat="server" Visible="True">
<p>
<span class="guiDialogNormal">
<%=Services.TextService.Localize("importDocumentTypeHelp")%>
</span>
</p>
<p>
<input id="documentTypeFile" type="file" runat="server" />
</p>
<asp:Button ID="submit" runat="server"></asp:Button> <em><%= Services.TextService.Localize("or") %></em> <a href="#" onclick="UmbClientMgr.closeModalWindow(); return false;"><%= Services.TextService.Localize("cancel") %></a>
</asp:Panel>
<asp:Panel ID="Confirm" runat="server" Visible="False">
<strong>
<%=Services.TextService.Localize("name")%>
:</strong>
<asp:Literal ID="dtName" runat="server"></asp:Literal>
<br />
<strong>
<%=Services.TextService.Localize("alias")%>
:</strong>
<asp:Literal ID="dtAlias" runat="server"></asp:Literal>
<br />
<br />
<asp:Button ID="import" runat="server"></asp:Button>
</asp:Panel>
<asp:Panel ID="done" runat="server" Visible="False">
<asp:Literal ID="dtNameConfirm" runat="server"></asp:Literal>
has been imported!
</asp:Panel>
</td>
</tr>
</table>
</asp:Content>

View File

@@ -1,21 +1,29 @@
using AutoMapper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.UI;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
namespace Umbraco.Web.Editors
{
@@ -454,5 +462,93 @@ namespace Umbraco.Web.Editors
return response;
}
[HttpPost]
public HttpResponseMessage Import(string file)
{
var filePath = Path.Combine(IOHelper.MapPath(SystemDirectories.Data), file);
if (string.IsNullOrEmpty(file) || !System.IO.File.Exists(filePath))
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
var xd = new XmlDocument();
xd.XmlResolver = null;
xd.Load(filePath);
var userId = Security.GetUserId();
var element = XElement.Parse(xd.InnerXml);
Current.Services.PackagingService.ImportContentTypes(element, userId);
// Try to clean up the temporary file.
try
{
System.IO.File.Delete(filePath);
}
catch (Exception ex)
{
Current.Logger.Error(typeof(ContentTypeController), "Error cleaning up temporary udt file in App_Data: " + ex.Message, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
[HttpPost]
[FileUploadCleanupFilter(false)]
public async Task<ContentTypeImportModel> Upload()
{
if (Request.Content.IsMimeMultipartContent() == false)
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads");
//ensure it exists
Directory.CreateDirectory(root);
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
//must have a file
if (result.FileData.Count == 0)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
var model = new ContentTypeImportModel();
var file = result.FileData[0];
var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
if (ext.InvariantEquals("udt"))
{
//TODO: Currently it has to be here, it's not ideal but that's the way it is right now
var tempDir = IOHelper.MapPath(SystemDirectories.Data);
//ensure it's there
Directory.CreateDirectory(tempDir);
model.TempFileName = "justDelete_" + Guid.NewGuid() + ".udt";
var tempFileLocation = Path.Combine(tempDir, model.TempFileName);
System.IO.File.Copy(file.LocalFileName, tempFileLocation, true);
var xd = new XmlDocument
{
XmlResolver = null
};
xd.Load(tempFileLocation);
model.Alias = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Alias")?.FirstChild.Value;
model.Name = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Name")?.FirstChild.Value;
}
else
{
model.Notifications.Add(new Notification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("media/disallowedFileType"),
SpeechBubbleIcon.Warning));
}
return model;
}
}
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models
{
[DataContract(Name = "contentTypeImportModel")]
public class ContentTypeImportModel : INotificationModel
{
public ContentTypeImportModel()
{
Notifications = new List<Notification>();
}
[DataMember(Name = "alias")]
public string Alias { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notifications")]
public List<Notification> Notifications { get; }
[DataMember(Name = "tempFileName")]
public string TempFileName { get; set; }
}
}

View File

@@ -6,7 +6,6 @@ using System.Net.Http.Formatting;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Services;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web.Models.ContentEditing;
@@ -74,13 +73,7 @@ namespace Umbraco.Web.Trees
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionImport>(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true).ConvertLegacyMenuItem(new EntitySlim
{
Id = int.Parse(id),
Level = 1,
ParentId = Constants.System.Root,
Name = ""
}, "documenttypes", "settings");
menu.Items.Add<ActionImport>(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
return menu;
}

View File

@@ -257,12 +257,6 @@ namespace Umbraco.Web.Trees
"dialogs/sendToTranslation.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
Current.Services.TextService.Localize("actions/sendToTranslate")));
case "UmbClientMgr.appActions().actionImport()":
return Attempt.Succeed(
new LegacyUrlAction(
"dialogs/importDocumentType.aspx",
Current.Services.TextService.Localize("actions/importDocumentType")));
}
return Attempt<LegacyUrlAction>.Fail();
}

View File

@@ -238,6 +238,7 @@
<Compile Include="Models\ContentEditing\UserProfile.cs" />
<Compile Include="Models\ContentEditing\UserSave.cs" />
<Compile Include="Models\ContentEditing\Language.cs" />
<Compile Include="Models\ContentTypeImportModel.cs" />
<Compile Include="Models\Mapping\ActionButtonsResolver.cs" />
<Compile Include="Models\Mapping\AuditMapperProfile.cs" />
<Compile Include="Models\Mapping\ContentItemDisplayNameResolver.cs" />
@@ -1284,10 +1285,6 @@
<Compile Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx.designer.cs">
<DependentUpon>editPackage.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\importDocumenttype.aspx.cs">
<DependentUpon>importDocumenttype.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx.cs">
<DependentUpon>rollBack.aspx</DependentUpon>
</Compile>
@@ -1438,7 +1435,6 @@
<Content Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\dialogs\importDocumenttype.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>

View File

@@ -1,7 +1,4 @@
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when importing a document type
@@ -32,7 +29,7 @@ namespace Umbraco.Web._Legacy.Actions
{
get
{
return string.Format("{0}.actionImport()", ClientTools.Scripts.GetAppActions);
return "";
}
}
@@ -48,7 +45,7 @@ namespace Umbraco.Web._Legacy.Actions
{
get
{
return "importDocumentType";
return "import";
}
}

View File

@@ -1,49 +0,0 @@
<%@ Page MasterPageFile="../masterpages/umbracoDialog.Master" Language="c#" Codebehind="importDocumenttype.aspx.cs" AutoEventWireup="false"
Inherits="umbraco.presentation.umbraco.dialogs.importDocumentType" %>
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="body">
<input id="tempFile" type="hidden" name="tempFile" runat="server" />
<asp:Literal ID="FeedBackMessage" runat="server" />
<table class="propertyPane" id="Table1" cellspacing="0" cellpadding="4" width="360" border="0" runat="server">
<tr>
<td class="propertyContent" colspan="2">
<asp:Panel ID="Wizard" runat="server" Visible="True">
<p>
<span class="guiDialogNormal">
<%=Services.TextService.Localize("importDocumentTypeHelp")%>
</span>
</p>
<p>
<input id="documentTypeFile" type="file" runat="server" />
</p>
<asp:Button ID="submit" runat="server"></asp:Button> <em><%= Services.TextService.Localize("or") %></em> <a href="#" onclick="UmbClientMgr.closeModalWindow(); return false;"><%= Services.TextService.Localize("cancel") %></a>
</asp:Panel>
<asp:Panel ID="Confirm" runat="server" Visible="False">
<strong>
<%=Services.TextService.Localize("name")%>
:</strong>
<asp:Literal ID="dtName" runat="server"></asp:Literal>
<br />
<strong>
<%=Services.TextService.Localize("alias")%>
:</strong>
<asp:Literal ID="dtAlias" runat="server"></asp:Literal>
<br />
<br />
<asp:Button ID="import" runat="server"></asp:Button>
</asp:Panel>
<asp:Panel ID="done" runat="server" Visible="False">
<asp:Literal ID="dtNameConfirm" runat="server"></asp:Literal>
has been imported!
</asp:Panel>
</td>
</tr>
</table>
</asp:Content>

View File

@@ -1,121 +0,0 @@
using Umbraco.Core.Services;
using System;
using System.Linq;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Web;
using Umbraco.Web.Composing;
namespace umbraco.presentation.umbraco.dialogs
{
/// <summary>
/// Summary description for importDocumentType.
/// </summary>
public class importDocumentType : Umbraco.Web.UI.Pages.UmbracoEnsuredPage
{
public importDocumentType()
{
CurrentApp = Constants.Applications.Settings.ToString();
}
protected Literal FeedBackMessage;
protected Literal jsShowWindow;
protected Panel Wizard;
protected HtmlTable Table1;
protected HtmlInputHidden tempFile;
protected HtmlInputFile documentTypeFile;
protected Button submit;
protected Panel Confirm;
protected Literal dtName;
protected Literal dtAlias;
protected Button import;
protected Literal dtNameConfirm;
protected Panel done;
private string tempFileName = "";
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
submit.Text = Services.TextService.Localize("import");
import.Text = Services.TextService.Localize("import");
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.submit.Click += new System.EventHandler(this.submit_Click);
this.import.Click += new System.EventHandler(this.import_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void import_Click(object sender, EventArgs e)
{
var xd = new XmlDocument();
xd.XmlResolver = null;
xd.Load(tempFile.Value);
var userId = Security.GetUserId();
var element = XElement.Parse(xd.InnerXml);
var importContentTypes = Current.Services.PackagingService.ImportContentTypes(element, userId);
var contentType = importContentTypes.FirstOrDefault();
if (contentType != null)
dtNameConfirm.Text = contentType.Name;
// Try to clean up the temporary file.
try
{
System.IO.File.Delete(tempFile.Value);
}
catch(Exception ex)
{
Current.Logger.Error(typeof(importDocumentType), "Error cleaning up temporary udt file in App_Data: " + ex.Message, ex);
}
Wizard.Visible = false;
Confirm.Visible = false;
done.Visible = true;
}
private void submit_Click(object sender, EventArgs e)
{
tempFileName = "justDelete_" + Guid.NewGuid().ToString() + ".udt";
var fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName);
tempFile.Value = fileName;
documentTypeFile.PostedFile.SaveAs(fileName);
var xd = new XmlDocument();
xd.XmlResolver = null;
xd.Load(fileName);
dtName.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Name").FirstChild.Value;
dtAlias.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Alias").FirstChild.Value;
Wizard.Visible = false;
done.Visible = false;
Confirm.Visible = true;
}
}
}