U4-7641 - bugfix + implement for media types

This commit is contained in:
Stephan
2016-02-25 16:02:04 +01:00
parent 610538261e
commit dafde545b0
12 changed files with 237 additions and 6 deletions

View File

@@ -7,6 +7,12 @@ namespace Umbraco.Core.Models
/// </summary
public interface IMediaType : IContentTypeComposition
{
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <param name="newAlias"></param>
/// <returns></returns>
IMediaType DeepCloneWithResetIdentities(string newAlias);
}
}

View File

@@ -38,5 +38,30 @@ namespace Umbraco.Core.Models
: base(parent, alias)
{
}
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <returns></returns>
public IMediaType DeepCloneWithResetIdentities(string alias)
{
var clone = (MediaType)DeepClone();
clone.Alias = alias;
clone.Key = Guid.Empty;
foreach (var propertyGroup in clone.PropertyGroups)
{
propertyGroup.ResetIdentity();
propertyGroup.ResetDirtyProperties(false);
}
foreach (var propertyType in clone.PropertyTypes)
{
propertyType.ResetIdentity();
propertyType.ResetDirtyProperties(false);
}
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -1215,11 +1215,11 @@ AND umbracoNode.id <> @id",
public string GetUniqueAlias(string alias)
{
// alias is unique accross ALL content types!
var aliasColumn = SqlSyntax.GetQuotedColumnName("alias");
var aliases = Database.Fetch<string>(@"SELECT cmsContentType." + aliasColumn + @" FROM cmsContentType
INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id
WHERE cmsContentType." + aliasColumn + @" LIKE @pattern
AND umbracoNode.nodeObjectType = @objectType",
WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
new { pattern = alias + "%", objectType = NodeObjectTypeId });
var i = 1;
string test;

View File

@@ -38,6 +38,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
/// <param name="alias">The original alias.</param>
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
/// /// <remarks>Unique accross all content, media and member types.</remarks>
string GetUniqueAlias(string alias);
}
}

View File

@@ -15,5 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, EntityContainer container);
/// <summary>
/// Derives a unique alias from an existing alias.
/// </summary>
/// <param name="alias">The original alias.</param>
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
/// <remarks>Unique accross all content, media and member types.</remarks>
string GetUniqueAlias(string alias);
}
}

View File

@@ -1067,6 +1067,48 @@ namespace Umbraco.Core.Services
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
}
public Attempt<OperationStatus<MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId)
{
var evtMsgs = EventMessagesFactory.Get();
var uow = UowProvider.GetUnitOfWork();
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
{
try
{
if (containerId > 0)
{
var container = containerRepository.Get(containerId);
if (container == null)
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
}
var alias = repository.GetUniqueAlias(toCopy.Alias);
var copy = toCopy.DeepCloneWithResetIdentities(alias);
copy.Name = copy.Name + " (copy)"; // might not be unique
// if it has a parent, and the parent is a content type, unplug composition
// all other compositions remain in place in the copied content type
if (copy.ParentId > 0)
{
var parent = repository.Get(copy.ParentId);
if (parent != null)
copy.RemoveContentType(parent.Alias);
}
copy.ParentId = containerId;
repository.AddOrUpdate(copy);
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
return Attempt.Fail(new OperationStatus<MoveOperationStatusType>(ex.Operation, evtMsgs));
}
uow.Commit();
}
return Attempt.Succeed(new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
}
public Attempt<OperationStatus<MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId)
{
var evtMsgs = EventMessagesFactory.Get();

View File

@@ -291,6 +291,7 @@ namespace Umbraco.Core.Services
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId);
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int containerId);
Attempt<OperationStatus<MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId);
Attempt<OperationStatus<MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId);
}
}

View File

@@ -53,7 +53,7 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
* .then(function(array) {
* $scope.type = type;
* });
* </pre>
* </pre>
* @param {Int} mediaId id of the media item to retrive allowed child types for
* @returns {Promise} resourcePromise object.
*
@@ -145,9 +145,9 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* alert("node didnt move:" + err.data.Message);
* });
* </pre>
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
@@ -174,6 +174,26 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
'Failed to move content');
},
copy: function (args) {
if (!args) {
throw "args cannot be null";
}
if (!args.parentId) {
throw "args.parentId cannot be null";
}
if (!args.id) {
throw "args.id cannot be null";
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("mediaTypeApiBaseUrl", "PostCopy"),
{
parentId: args.parentId,
id: args.id
}),
'Failed to copy content');
},
createContainer: function(parentId, name) {
return umbRequestHelper.resourcePromise(

View File

@@ -0,0 +1,63 @@
angular.module("umbraco")
.controller("Umbraco.Editors.MediaTypes.CopyController",
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
function nodeSelectHandler(ev, args) {
args.event.preventDefault();
args.event.stopPropagation();
if ($scope.target) {
//un-select if there's a current one selected
$scope.target.selected = false;
}
$scope.target = args.node;
$scope.target.selected = true;
}
$scope.copy = function () {
$scope.busy = true;
$scope.error = false;
mediaTypeResource.copy({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
.then(function (path) {
$scope.error = false;
$scope.success = true;
$scope.busy = false;
//get the currently edited node (if any)
var activeNode = appState.getTreeState("selectedNode");
//we need to do a double sync here: first sync to the copied content - but don't activate the node,
//then sync to the currenlty edited content (note: this might not be the content that was copied!!)
navigationService.syncTree({ tree: "mediaTypes", path: path, forceReload: true, activate: false }).then(function (args) {
if (activeNode) {
var activeNodePath = treeService.getPath(activeNode).join();
//sync to this node now - depending on what was copied this might already be synced but might not be
navigationService.syncTree({ tree: "mediaTypes", path: activeNodePath, forceReload: false, activate: true });
}
});
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
});

View File

@@ -0,0 +1,51 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.MediaTypes.CopyController">
<div class="umb-dialog-body">
<div class="umb-pane">
<p class="abstract" ng-hide="success">
<localize key="contentTypeEditor_folderToCopy">Select the folder to copy</localize> <strong>{{currentNode.name}}</strong>&nbsp;<localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
</p>
<div class="umb-loader-wrapper" ng-show="busy">
<div class="umb-loader"></div>
</div>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<div ng-show="success">
<h5 class="text-success">
<strong>{{currentNode.name}}</strong> <localize key="contentTypeEditor_copiedUnderneath">was copied underneath</localize>&nbsp;<strong>{{target.name}}</strong></h5>
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
</div>
<div ng-hide="success">
<div>
<umb-tree section="settings"
treealias="mediaTypes"
customtreeparams="foldersonly=1"
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
enablecheckboxes="true">
</umb-tree>
</div>
</div>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
<localize key="general_cancel">Cancel</localize>
</a>
<button class="btn btn-primary" ng-click="copy()" ng-disabled="busy">
<localize key="actions_copy">Copy</localize>
</button>
</div>
</div>

View File

@@ -232,5 +232,18 @@ namespace Umbraco.Web.Editors
getContentType: i => Services.ContentTypeService.GetMediaType(i),
doMoveOrCopy: (type, i) => Services.ContentTypeService.MoveMediaType(type, i));
}
/// <summary>
/// Copy the media type
/// </summary>
/// <param name="copy"></param>
/// <returns></returns>
public HttpResponseMessage PostCopy(MoveOrCopy copy)
{
return PerformMoveOrCopy(
copy,
getContentType: i => Services.ContentTypeService.GetMediaType(i),
doMoveOrCopy: (type, i) => Services.ContentTypeService.CopyMediaType(type, i));
}
}
}

View File

@@ -92,6 +92,7 @@ namespace Umbraco.Web.Trees
{
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
menu.Items.Add<ActionCopy>(Services.TextService.Localize(string.Format("actions/{0}", ActionCopy.Instance.Alias)));
}
return menu;