From e90001605d4445d704bcb734d0a9a1dd11c6edb6 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Sun, 26 Jan 2014 12:17:22 -0500 Subject: [PATCH] #20453: Adding Clone Button to Media Library #20453: Fixing Formatting Issues #20453: Adding Clone Button to Media Library Work Item: 20453 Conflicts: src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js --- .../Media/Services/MediaServiceTests.cs | 3 ++ .../Services/FileSystems/AzureFileSystem.cs | 12 +++++ .../Controllers/AdminController.cs | 31 +++++++++++++ .../Scripts/media-library.js | 44 ++++++++++++++++--- .../Services/IMediaLibraryService.cs | 9 ++++ .../Services/MediaLibraryService.cs | 14 ++++++ .../Views/Admin/Index.cshtml | 3 ++ .../Media/FileSystemStorageProvider.cs | 14 ++++++ .../FileSystems/Media/IStorageProvider.cs | 7 +++ 9 files changed, 132 insertions(+), 5 deletions(-) diff --git a/src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs b/src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs index 9cb0cf14a..cf3e309a0 100644 --- a/src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs +++ b/src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs @@ -257,6 +257,9 @@ namespace Orchard.Tests.Modules.Media.Services { public void RenameFile(string path, string newPath) { } + public void CopyFile(string originalPath, string duplicatePath) { + } + public IStorageFile CreateFile(string path) { throw new NotImplementedException(); } diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs index b6632df1c..545b39856 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs @@ -261,6 +261,18 @@ namespace Orchard.Azure.Services.FileSystems { blob.Delete(); } + public void CopyFile(string path, string newPath) { + path = ConvertToRelativeUriPath(path); + newPath = ConvertToRelativeUriPath(newPath); + + Container.EnsureBlobExists(String.Concat(_root, path)); + Container.EnsureBlobDoesNotExist(String.Concat(_root, newPath)); + + var blob = Container.GetBlockBlobReference(String.Concat(_root, path)); + var newBlob = Container.GetBlockBlobReference(String.Concat(_root, newPath)); + newBlob.StartCopyFromBlob(blob); + } + public IStorageFile CreateFile(string path) { path = ConvertToRelativeUriPath(path); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs index 7ef6642a0..bd9ab44fa 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs @@ -1,7 +1,9 @@ using System; +using System.IO; using System.Linq; using System.Web.Mvc; using Orchard.ContentManagement; +using Orchard.Core.Title.Models; using Orchard.Localization; using Orchard.Logging; using Orchard.MediaLibrary.Models; @@ -180,6 +182,35 @@ namespace Orchard.MediaLibrary.Controllers { } } + [HttpPost] + public ActionResult Clone(int mediaItemId) { + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't clone media items"))) + return new HttpUnauthorizedResult(); + + try { + var media = Services.ContentManager.Get(mediaItemId).As(); + + var newFileName = Path.GetFileNameWithoutExtension(media.FileName) + " Copy" + Path.GetExtension(media.FileName); + + _mediaLibraryService.CopyFile(media.FolderPath, media.FileName, media.FolderPath, newFileName); + + var clonedContentItem = Services.ContentManager.Clone(media.ContentItem); + var clonedMediaPart = clonedContentItem.As(); + var clonedTitlePart = clonedContentItem.As(); + + clonedMediaPart.FileName = newFileName; + clonedTitlePart.Title = clonedTitlePart.Title + " Copy"; + + Services.ContentManager.Publish(clonedContentItem); + + return Json(true); + } + catch (Exception e) { + Logger.Error(e, "Could not clone media item."); + return Json(false); + } + } + private FolderHierarchy GetFolderHierarchy(IMediaFolder root) { Argument.ThrowIfNull(root, "root"); return new FolderHierarchy(root) {Children = _mediaLibraryService.GetMediaFolders(root.MediaPath).Select(GetFolderHierarchy)}; diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js index de41d19ca..be7e8209b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js @@ -485,16 +485,16 @@ $(function () { var pickAndClose = function () { if (parent.$.colorbox) { - var selectedData = []; + var selectedData = []; for (var i = 0; i < viewModel.selection().length; i++) { - var selection = viewModel.selection()[i]; + var selection = viewModel.selection()[i]; selectedData.push(selection.data); - } - parent.$.colorbox.selectedData = selectedData; + } + parent.$.colorbox.selectedData = selectedData; parent.$.colorbox.close(); }; } - + $("#media-library-main-selection-select > .button-select").on('click', function () { pickAndClose(); }); @@ -571,5 +571,39 @@ $(function () { }); return false; }); + + $('#clone-selection-button').click(function () { + if (!confirm(settings.cloneConfirmationMessage)) { + return false; + } + + var ids = []; + viewModel.selection().forEach(function (item) { ids.push(item.data.id); }); + + if (ids.length != 1) { + return false; + } + + var url = settings.cloneActionUrl; + + $.ajax({ + type: "POST", + url: url, + dataType: "json", + traditional: true, + data: { + mediaItemId: ids[0], + __RequestVerificationToken: settings.antiForgeryToken + } + }).done(function (result) { + if (result) { + viewModel.getMediaItems(viewModel.pageCount); + } else { + console.log('failed to clone media items'); + } + return false; + }); + return false; + }); })(window.mediaLibrarySettings); }) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs index cb56c861e..7424c9fa5 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs @@ -96,6 +96,15 @@ namespace Orchard.MediaLibrary.Services { /// The new file name. void MoveFile(string currentPath, string filename, string newPath, string newFilename); + /// + /// Moves a media file. + /// + /// The path to the file's parent folder. + /// The file name. + /// The path where the file will be copied to. + /// The new file name. + void CopyFile(string currentPath, string filename, string duplicatePath, string duplicateFilename); + /// /// Uploads a media file based on a posted file. /// diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs index 379c940a4..f713b4a6c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs @@ -355,6 +355,20 @@ namespace Orchard.MediaLibrary.Services { _storageProvider.RenameFile(_storageProvider.Combine(currentPath, filename), _storageProvider.Combine(newPath, newFilename)); } + /// + /// Copies a file in the storage provider. + /// + /// The relative path to the file to be copied. + /// The relative path to the new file. + public void CopyFile(string currentPath, string filename, string duplicatePath, string duplicateFilename) { + Argument.ThrowIfNullOrEmpty(currentPath, "currentPath"); + Argument.ThrowIfNullOrEmpty(duplicatePath, "duplicatePath"); + Argument.ThrowIfNullOrEmpty(filename, "filename"); + Argument.ThrowIfNullOrEmpty(duplicateFilename, "duplicateFilename"); + + _storageProvider.CopyFile(_storageProvider.Combine(currentPath, filename), _storageProvider.Combine(duplicatePath, duplicateFilename)); + } + /// /// Uploads a media file based on a posted file. /// diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml index 4c710d285..5a9dce068 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml @@ -68,6 +68,7 @@
+
@@ -94,9 +95,11 @@ var mediaLibrarySettings = { importActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("Import", "Admin"))', moveActionUrl: '@Url.Action("Move", "Folder", new {area = "Orchard.MediaLibrary"})', deleteActionUrl: '@Url.Action("Delete", "Admin", new {area = "Orchard.MediaLibrary"})', + cloneActionUrl: '@Url.Action("Clone", "Admin", new {area = "Orchard.MediaLibrary"})', hasFolderPath: @(viewModel.FolderPath != null ? "true" : "false"), folderPath: '@HttpUtility.JavaScriptStringEncode(viewModel.FolderPath)', deleteConfirmationMessage: '@HttpUtility.JavaScriptStringEncode(T("Are you sure you want to delete these media items ?").Text)', + cloneConfirmationMessage: '@HttpUtility.JavaScriptStringEncode(T("Are you sure you want to clone this media item ?").Text)', errorMessage: '@HttpUtility.JavaScriptStringEncode(T("An unexpected error occured, please refresh the page and try again.").Text)', antiForgeryToken: '@Html.AntiForgeryTokenValueOrchard()', childFolders: (@Display.Partial(TemplateName: "ChildFolders", Model: viewModel.ChildFoldersViewModel))['childFolders'] diff --git a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs index 61da10c0b..5b6200657 100644 --- a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs @@ -268,6 +268,20 @@ namespace Orchard.FileSystems.Media { File.Move(sourceFileInfo.FullName, targetFileInfo.FullName); } + public void CopyFile(string originalPath, string duplicatePath) { + FileInfo sourceFileInfo = new FileInfo(MapStorage(originalPath)); + if (!sourceFileInfo.Exists) { + throw new ArgumentException(T("File {0} does not exist", originalPath).ToString()); + } + + FileInfo targetFileInfo = new FileInfo(MapStorage(duplicatePath)); + if (targetFileInfo.Exists) { + throw new ArgumentException(T("File {0} already exists", duplicatePath).ToString()); + } + + File.Copy(sourceFileInfo.FullName, targetFileInfo.FullName); + } + /// /// Creates a file in the storage provider. /// diff --git a/src/Orchard/FileSystems/Media/IStorageProvider.cs b/src/Orchard/FileSystems/Media/IStorageProvider.cs index 63702fc34..fedffcc3a 100644 --- a/src/Orchard/FileSystems/Media/IStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/IStorageProvider.cs @@ -96,6 +96,13 @@ namespace Orchard.FileSystems.Media { /// The relative path to the new file. void RenameFile(string oldPath, string newPath); + /// + /// Copies a file in the storage provider. + /// + /// The relative path to the file to be copied. + /// The relative path to the new file. + void CopyFile(string originalPath, string duplicatePath); + /// /// Creates a file in the storage provider. ///