mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
[Fixes 6759] Replace Media Item: Replacing an Image/OEmbed with new one (#7160)
Fixes #6759
This commit is contained in:
committed by
Sébastien Ros
parent
210aebcbe9
commit
794f30af39
@@ -79,10 +79,15 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
public ActionResult Import(string folderPath) {
|
||||
public ActionResult Import(string folderPath, int? replaceId = null) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot import media")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders");
|
||||
var imageSets = _navigationManager.BuildImageSets("mediaproviders");
|
||||
|
||||
@@ -90,9 +95,17 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
Menu = mediaProviderMenu,
|
||||
ImageSets = imageSets,
|
||||
FolderPath = folderPath,
|
||||
MediaTypes = _mediaLibraryService.GetMediaTypes()
|
||||
MediaTypes = _mediaLibraryService.GetMediaTypes(),
|
||||
};
|
||||
|
||||
if (replaceId != null) {
|
||||
var replaceMedia = Services.ContentManager.Get(replaceId.Value).As<MediaPart>();
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
viewModel.Replace = replaceMedia;
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
@@ -101,7 +114,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission.var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
var model = new MediaManagerMediaItemsViewModel {
|
||||
MediaItems = new List<MediaManagerMediaItemViewModel>(),
|
||||
@@ -134,7 +147,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot get child folder listing")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission.
|
||||
// Check permission
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
var model = new MediaManagerChildFoldersViewModel {
|
||||
@@ -213,7 +226,8 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
|
||||
return Json(true);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Could not delete media items.");
|
||||
return Json(false);
|
||||
}
|
||||
@@ -247,7 +261,8 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
Services.ContentManager.Publish(clonedContentItem);
|
||||
|
||||
return Json(true);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Could not clone media item.");
|
||||
return Json(false);
|
||||
}
|
||||
|
||||
@@ -10,18 +10,20 @@ using Orchard.UI.Admin;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
using Orchard.Localization;
|
||||
using System.Linq;
|
||||
using Orchard.FileSystems.Media;
|
||||
|
||||
namespace Orchard.MediaLibrary.Controllers {
|
||||
[Admin, Themed(false)]
|
||||
public class ClientStorageController : Controller {
|
||||
private readonly IMediaLibraryService _mediaLibraryService;
|
||||
private readonly IMimeTypeProvider _mimeTypeProvider;
|
||||
|
||||
public ClientStorageController(
|
||||
IMediaLibraryService mediaManagerService,
|
||||
IContentManager contentManager,
|
||||
IOrchardServices orchardServices) {
|
||||
IMediaLibraryService mediaManagerService,
|
||||
IOrchardServices orchardServices,
|
||||
IMimeTypeProvider mimeTypeProvider) {
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
Services = orchardServices;
|
||||
_mimeTypeProvider = mimeTypeProvider;
|
||||
Services = orchardServices;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
@@ -29,34 +31,39 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
public IOrchardServices Services { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index(string folderPath, string type) {
|
||||
public ActionResult Index(string folderPath, string type, int? replaceId = null) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
// Check permission.
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var viewModel = new ImportMediaViewModel {
|
||||
FolderPath = folderPath,
|
||||
Type = type
|
||||
Type = type,
|
||||
};
|
||||
|
||||
if (replaceId != null) {
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId.Value);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
viewModel.Replace = replaceMedia;
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Upload(string folderPath, string type) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
// Check permission.
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
@@ -64,7 +71,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
var statuses = new List<object>();
|
||||
var settings = Services.WorkContext.CurrentSite.As<MediaLibrarySettingsPart>();
|
||||
var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "")
|
||||
.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(x => x.StartsWith("."));
|
||||
|
||||
// Loop through each file in the request
|
||||
@@ -72,15 +79,15 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
// Pointer to file
|
||||
var file = HttpContext.Request.Files[i];
|
||||
var filename = Path.GetFileName(file.FileName);
|
||||
|
||||
|
||||
// if the file has been pasted, provide a default name
|
||||
if (file.ContentType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) && !filename.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
filename = "clipboard.png";
|
||||
}
|
||||
|
||||
// skip file if the allowed extensions is defined and doesn't match
|
||||
if(allowedExtensions.Any()) {
|
||||
if(!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) {
|
||||
if (allowedExtensions.Any()) {
|
||||
if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) {
|
||||
statuses.Add(new {
|
||||
error = T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text,
|
||||
progress = 1.0,
|
||||
@@ -89,21 +96,107 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
var mediaPart = _mediaLibraryService.ImportMedia(file.InputStream, folderPath, filename, type);
|
||||
Services.ContentManager.Create(mediaPart);
|
||||
try {
|
||||
var mediaPart = _mediaLibraryService.ImportMedia(file.InputStream, folderPath, filename, type);
|
||||
Services.ContentManager.Create(mediaPart);
|
||||
|
||||
statuses.Add(new {
|
||||
id = mediaPart.Id,
|
||||
name = mediaPart.Title,
|
||||
type = mediaPart.MimeType,
|
||||
size = file.ContentLength,
|
||||
progress = 1.0,
|
||||
url= mediaPart.FileName,
|
||||
});
|
||||
statuses.Add(new {
|
||||
id = mediaPart.Id,
|
||||
name = mediaPart.Title,
|
||||
type = mediaPart.MimeType,
|
||||
size = file.ContentLength,
|
||||
progress = 1.0,
|
||||
url = mediaPart.FileName,
|
||||
});
|
||||
}
|
||||
catch (Exception ex) {
|
||||
statuses.Add(new {
|
||||
error = T(ex.Message).Text,
|
||||
progress = 1.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Return JSON
|
||||
return Json(statuses, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Replace(int replaceId, string type) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var statuses = new List<object>();
|
||||
|
||||
var settings = Services.WorkContext.CurrentSite.As<MediaLibrarySettingsPart>();
|
||||
var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "")
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(x => x.StartsWith("."));
|
||||
|
||||
// Loop through each file in the request
|
||||
for (int i = 0; i < HttpContext.Request.Files.Count; i++) {
|
||||
// Pointer to file
|
||||
var file = HttpContext.Request.Files[i];
|
||||
var filename = Path.GetFileName(file.FileName);
|
||||
|
||||
// if the file has been pasted, provide a default name
|
||||
if (file.ContentType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) && !filename.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
filename = "clipboard.png";
|
||||
}
|
||||
|
||||
// skip file if the allowed extensions is defined and doesn't match
|
||||
if (allowedExtensions.Any()) {
|
||||
if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) {
|
||||
statuses.Add(new {
|
||||
error = T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text,
|
||||
progress = 1.0,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var mimeType = _mimeTypeProvider.GetMimeType(filename);
|
||||
|
||||
string replaceContentType = _mediaLibraryService.MimeTypeToContentType(file.InputStream, mimeType, type) ?? type;
|
||||
if (!replaceContentType.Equals(replaceMedia.TypeDefinition.Name, StringComparison.OrdinalIgnoreCase))
|
||||
throw new Exception(T("Cannot replace {0} with {1}", replaceMedia.TypeDefinition.Name, replaceContentType).Text);
|
||||
|
||||
_mediaLibraryService.DeleteFile(replaceMedia.FolderPath, replaceMedia.FileName);
|
||||
_mediaLibraryService.UploadMediaFile(replaceMedia.FolderPath, replaceMedia.FileName, file.InputStream);
|
||||
replaceMedia.MimeType = mimeType;
|
||||
|
||||
// Force a publish event which will update relevant Media properties
|
||||
replaceMedia.ContentItem.VersionRecord.Published = false;
|
||||
Services.ContentManager.Publish(replaceMedia.ContentItem);
|
||||
|
||||
statuses.Add(new {
|
||||
id = replaceMedia.Id,
|
||||
name = replaceMedia.Title,
|
||||
type = replaceMedia.MimeType,
|
||||
size = file.ContentLength,
|
||||
progress = 1.0,
|
||||
url = replaceMedia.FileName,
|
||||
});
|
||||
}
|
||||
catch (Exception ex) {
|
||||
statuses.Add(new {
|
||||
error = T(ex.Message).Text,
|
||||
progress = 1.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Json(statuses, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
private readonly IMediaLibraryService _mediaLibraryService;
|
||||
|
||||
public FolderController(
|
||||
IOrchardServices services,
|
||||
IOrchardServices services,
|
||||
IMediaLibraryService mediaManagerService
|
||||
) {
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
@@ -111,7 +111,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
|
||||
// Shouldn't be able to rename the root folder
|
||||
if(IsRootFolder(viewModel.FolderPath)) {
|
||||
if (IsRootFolder(viewModel.FolderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
|
||||
private bool IsRootFolder(string folderPath) {
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
|
||||
|
||||
return rootMediaFolder == null ?
|
||||
string.IsNullOrEmpty(folderPath) :
|
||||
string.Equals(rootMediaFolder.MediaPath, folderPath, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
@@ -10,6 +10,8 @@ using Orchard.Themes;
|
||||
using Orchard.UI.Admin;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.MediaLibrary.Services;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.MediaLibrary.Controllers {
|
||||
[Admin, Themed(false)]
|
||||
@@ -19,40 +21,64 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
public OEmbedController(
|
||||
IOrchardServices services,
|
||||
IMediaLibraryService mediaManagerService) {
|
||||
Services = services;
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
Services = services;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public IOrchardServices Services { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index(string folderPath, string type, int? replaceId) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
public ActionResult Index(string folderPath, string type) {
|
||||
var viewModel = new OEmbedViewModel {
|
||||
FolderPath = folderPath,
|
||||
Type = type
|
||||
};
|
||||
|
||||
if (replaceId != null) {
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId.Value);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
viewModel.Replace = replaceMedia;
|
||||
|
||||
if (!replaceMedia.TypeDefinition.Name.Equals("OEmbed"))
|
||||
Services.Notifier.Error(T("Cannot replace {0} with OEmbed", replaceMedia.ContentItem.TypeDefinition.Name));
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ActionName("Index")]
|
||||
[ValidateInput(false)]
|
||||
public ActionResult IndexPOST(string folderPath, string url, string type, string title, string html, string thumbnail, string width, string height, string description) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission.
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
public ActionResult IndexPOST(string folderPath, string url, string type, string title, string html, string thumbnail, string width, string height, string description, int? replaceId) {
|
||||
var viewModel = new OEmbedViewModel {
|
||||
Url = url,
|
||||
FolderPath = folderPath
|
||||
FolderPath = folderPath,
|
||||
};
|
||||
|
||||
var webClient = new WebClient {Encoding = Encoding.UTF8};
|
||||
if (replaceId != null) {
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId.Value);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
viewModel.Replace = replaceMedia;
|
||||
|
||||
if (!replaceMedia.ContentItem.TypeDefinition.Name.Equals("OEmbed")) {
|
||||
Services.Notifier.Error(T("Cannot replace {0} with OEmbed", replaceMedia.ContentItem.TypeDefinition.Name));
|
||||
return View(viewModel);
|
||||
}
|
||||
}
|
||||
|
||||
var webClient = new WebClient { Encoding = Encoding.UTF8 };
|
||||
try {
|
||||
// <link rel="alternate" href="http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F23608259" type="text/xml+oembed">
|
||||
|
||||
@@ -120,12 +146,21 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
|
||||
[HttpPost, ValidateInput(false)]
|
||||
public ActionResult MediaPost(string folderPath, string url, string document) {
|
||||
public ActionResult Import(string folderPath, string url, string document) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var content = XDocument.Parse(document);
|
||||
var oembed = content.Root;
|
||||
|
||||
var part = Services.ContentManager.New<MediaPart>("OEmbed");
|
||||
|
||||
|
||||
part.MimeType = "text/html";
|
||||
part.FolderPath = folderPath;
|
||||
part.LogicalType = "OEmbed";
|
||||
@@ -151,13 +186,56 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
|
||||
Services.ContentManager.Create(oembedPart);
|
||||
Services.Notifier.Information(T("Media imported successfully."));
|
||||
}
|
||||
|
||||
var viewModel = new OEmbedViewModel {
|
||||
FolderPath = folderPath
|
||||
};
|
||||
return RedirectToAction("Index", new { folderPath = folderPath });
|
||||
}
|
||||
|
||||
return View("Index", viewModel);
|
||||
[HttpPost, ValidateInput(false)]
|
||||
public ActionResult Replace(int replaceId, string url, string document) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var content = XDocument.Parse(document);
|
||||
var oembed = content.Root;
|
||||
|
||||
if (oembed.Element("title") != null) {
|
||||
replaceMedia.Title = oembed.Element("title").Value;
|
||||
}
|
||||
else {
|
||||
replaceMedia.Title = oembed.Element("url").Value;
|
||||
}
|
||||
if (oembed.Element("description") != null) {
|
||||
replaceMedia.Caption = oembed.Element("description").Value;
|
||||
}
|
||||
|
||||
var oembedPart = replaceMedia.As<OEmbedPart>();
|
||||
|
||||
if (oembedPart != null) {
|
||||
replaceMedia.ContentItem.Record.Infoset.Element.Element("OEmbedPart").Remove();
|
||||
|
||||
oembedPart.Source = url;
|
||||
|
||||
foreach (var element in oembed.Elements()) {
|
||||
oembedPart[element.Name.LocalName] = element.Value;
|
||||
}
|
||||
|
||||
Services.ContentManager.Publish(oembedPart.ContentItem);
|
||||
Services.Notifier.Information(T("Media replaced successfully."));
|
||||
}
|
||||
|
||||
return RedirectToAction("Index", new { folderPath = replaceMedia.FolderPath, replaceId = replaceMedia.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,63 +7,149 @@ using Orchard.MediaLibrary.Services;
|
||||
using Orchard.MediaLibrary.ViewModels;
|
||||
using Orchard.Themes;
|
||||
using Orchard.UI.Admin;
|
||||
using Orchard.FileSystems.Media;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
using System.Linq;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.MediaLibrary.Controllers {
|
||||
[Admin, Themed(false)]
|
||||
public class WebSearchController : Controller {
|
||||
private readonly IMediaLibraryService _mediaLibraryService;
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
private readonly IMimeTypeProvider _mimeTypeProvider;
|
||||
|
||||
public WebSearchController(
|
||||
IMediaLibraryService mediaManagerService,
|
||||
IMediaLibraryService mediaManagerService,
|
||||
IContentManager contentManager,
|
||||
IOrchardServices orchardServices) {
|
||||
IOrchardServices orchardServices,
|
||||
IMimeTypeProvider mimeTypeProvider) {
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
_contentManager = contentManager;
|
||||
|
||||
_mimeTypeProvider = mimeTypeProvider;
|
||||
Services = orchardServices;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public IOrchardServices Services { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index(string folderPath, string type) {
|
||||
var viewModel = new ImportMediaViewModel {
|
||||
FolderPath = folderPath,
|
||||
Type = type
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult ImagePost(string folderPath, string type, string url) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
public ActionResult Index(string folderPath, string type, int? replaceId = null) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
// Check permission.
|
||||
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var viewModel = new ImportMediaViewModel {
|
||||
FolderPath = folderPath,
|
||||
Type = type,
|
||||
};
|
||||
|
||||
if (replaceId != null) {
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId.Value);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
viewModel.Replace = replaceMedia;
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Import(string folderPath, string type, string url) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var settings = Services.WorkContext.CurrentSite.As<MediaLibrarySettingsPart>();
|
||||
var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "")
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(x => x.StartsWith("."));
|
||||
|
||||
try {
|
||||
var filename = Path.GetFileName(url);
|
||||
|
||||
// skip file if the allowed extensions is defined and doesn't match
|
||||
if (allowedExtensions.Any()) {
|
||||
if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) {
|
||||
throw new Exception(T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text);
|
||||
}
|
||||
}
|
||||
|
||||
var buffer = new WebClient().DownloadData(url);
|
||||
var stream = new MemoryStream(buffer);
|
||||
|
||||
var mediaPart = _mediaLibraryService.ImportMedia(stream, folderPath, Path.GetFileName(url), type);
|
||||
|
||||
var mediaPart = _mediaLibraryService.ImportMedia(stream, folderPath, filename, type);
|
||||
_contentManager.Create(mediaPart);
|
||||
|
||||
return new JsonResult {
|
||||
Data = new {folderPath, MediaPath = mediaPart.FileName}
|
||||
};
|
||||
return new JsonResult { Data = new { folderPath, MediaPath = mediaPart.FileName } };
|
||||
|
||||
}
|
||||
catch(Exception e) {
|
||||
return new JsonResult {
|
||||
Data = new { error= e.Message }
|
||||
};
|
||||
catch (Exception e) {
|
||||
return new JsonResult { Data = new { error = e.Message } };
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Replace(int replaceId, string type, string url) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var replaceMedia = Services.ContentManager.Get<MediaPart>(replaceId);
|
||||
if (replaceMedia == null)
|
||||
return HttpNotFound();
|
||||
|
||||
// Check permission
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) {
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
|
||||
var settings = Services.WorkContext.CurrentSite.As<MediaLibrarySettingsPart>();
|
||||
var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "")
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(x => x.StartsWith("."));
|
||||
|
||||
try {
|
||||
var filename = Path.GetFileName(url);
|
||||
|
||||
// skip file if the allowed extensions is defined and doesn't match
|
||||
if (allowedExtensions.Any()) {
|
||||
if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) {
|
||||
throw new Exception(T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text);
|
||||
}
|
||||
}
|
||||
|
||||
var buffer = new WebClient().DownloadData(url);
|
||||
var stream = new MemoryStream(buffer);
|
||||
|
||||
var mimeType = _mimeTypeProvider.GetMimeType(filename);
|
||||
|
||||
string replaceContentType = _mediaLibraryService.MimeTypeToContentType(stream, mimeType, type) ?? type;
|
||||
if (!replaceContentType.Equals(replaceMedia.TypeDefinition.Name, StringComparison.OrdinalIgnoreCase))
|
||||
throw new Exception(T("Cannot replace {0} with {1}", replaceMedia.TypeDefinition.Name, replaceContentType).Text);
|
||||
|
||||
_mediaLibraryService.DeleteFile(replaceMedia.FolderPath, replaceMedia.FileName);
|
||||
_mediaLibraryService.UploadMediaFile(replaceMedia.FolderPath, replaceMedia.FileName, stream);
|
||||
replaceMedia.MimeType = mimeType;
|
||||
|
||||
// Force a publish event which will update relevant Media properties
|
||||
replaceMedia.ContentItem.VersionRecord.Published = false;
|
||||
Services.ContentManager.Publish(replaceMedia.ContentItem);
|
||||
|
||||
return new JsonResult { Data = new { replaceMedia.FolderPath, MediaPath = replaceMedia.FileName } };
|
||||
}
|
||||
catch (Exception e) {
|
||||
return new JsonResult { Data = new { Success = false, error = e.Message } };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,10 @@ namespace Orchard.MediaLibrary.Drivers {
|
||||
context.ImportAttribute(part.PartDefinition.Name, "FileName", fileName =>
|
||||
part.FileName = fileName
|
||||
);
|
||||
|
||||
context.ImportAttribute(part.PartDefinition.Name, "LogicalType", logicalType =>
|
||||
part.LogicalType = logicalType
|
||||
);
|
||||
}
|
||||
|
||||
protected override void Exporting(MediaPart part, ContentManagement.Handlers.ExportContentContext context) {
|
||||
@@ -68,6 +72,7 @@ namespace Orchard.MediaLibrary.Drivers {
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("AlternateText", part.AlternateText);
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("FolderPath", part.FolderPath);
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("FileName", part.FileName);
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("LogicalType", part.LogicalType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,13 +57,10 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
part.Title = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var audioPart = part.As<AudioPart>();
|
||||
|
||||
if (audioPart == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
audioPart.Length = 0;
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new MediaFactorySelectorResult {
|
||||
Priority = -10,
|
||||
MediaFactory = new DocumentFactory(_contentManager)
|
||||
@@ -43,7 +43,6 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
}
|
||||
|
||||
public MediaPart CreateMedia(Stream stream, string path, string mimeType, string contentType) {
|
||||
|
||||
if (String.IsNullOrEmpty(contentType)) {
|
||||
contentType = "Document";
|
||||
}
|
||||
@@ -55,12 +54,9 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
part.Title = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var documentPart = part.As<DocumentPart>();
|
||||
|
||||
if (documentPart == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
documentPart.Length = stream.Length;
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
using Image = System.Drawing.Image;
|
||||
|
||||
namespace Orchard.MediaLibrary.Factories {
|
||||
|
||||
@@ -18,7 +17,6 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
}
|
||||
|
||||
|
||||
public MediaFactorySelectorResult GetMediaFactory(Stream stream, string mimeType, string contentType) {
|
||||
if (!mimeType.StartsWith("image/")) {
|
||||
return null;
|
||||
@@ -38,7 +36,6 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
Priority = -5,
|
||||
MediaFactory = new ImageFactory(_contentManager)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,36 +62,7 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
using (var image = Image.FromStream(stream)) {
|
||||
imagePart.Width = image.Width;
|
||||
imagePart.Height = image.Height;
|
||||
}
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
// Still trying to get .ico dimensions when it's blocked in System.Drawing, see: https://github.com/OrchardCMS/Orchard/issues/4473
|
||||
|
||||
if (mimeType != "image/x-icon" && mimeType != "image/vnd.microsoft.icon") {
|
||||
throw;
|
||||
}
|
||||
|
||||
TryFillDimensionsForIco(stream, imagePart);
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
private void TryFillDimensionsForIco(Stream stream, ImagePart imagePart) {
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream)) {
|
||||
// Reading out the necessary bytes that indicate the image dimensions. For the file format see:
|
||||
// http://en.wikipedia.org/wiki/ICO_%28file_format%29
|
||||
// Reading out leading bytes containing unneded information.
|
||||
binaryReader.ReadBytes(6);
|
||||
// Reading out dimensions. If there are multiple icons bundled in the same file then this is the first image.
|
||||
imagePart.Width = binaryReader.ReadByte();
|
||||
imagePart.Height = binaryReader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
if (!mimeType.StartsWith("image/svg")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (!String.IsNullOrEmpty(contentType)) {
|
||||
var contentDefinition = _contentDefinitionManager.GetTypeDefinition(contentType);
|
||||
if (contentDefinition == null || contentDefinition.Parts.All(x => x.PartDefinition.Name != typeof(VectorImagePart).Name)) {
|
||||
|
||||
@@ -55,13 +55,10 @@ namespace Orchard.MediaLibrary.Factories {
|
||||
part.Title = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var videoPart = part.As<VideoPart>();
|
||||
|
||||
if (videoPart == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
videoPart.Length = 0;
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,20 @@ using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Data;
|
||||
using Orchard.MediaLibrary.Services;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
using System.IO;
|
||||
using Orchard.FileSystems.Media;
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.MediaLibrary.Handlers {
|
||||
public class MediaPartHandler : ContentHandler {
|
||||
private readonly IMediaLibraryService _mediaLibraryService;
|
||||
private readonly IStorageProvider _storageProvider;
|
||||
|
||||
public MediaPartHandler(
|
||||
IStorageProvider storageProvider,
|
||||
IMediaLibraryService mediaLibraryService,
|
||||
IRepository<MediaPartRecord> repository) {
|
||||
_storageProvider = storageProvider;
|
||||
_mediaLibraryService = mediaLibraryService;
|
||||
|
||||
Filters.Add(StorageFilter.For(repository));
|
||||
@@ -21,7 +27,7 @@ namespace Orchard.MediaLibrary.Handlers {
|
||||
}
|
||||
});
|
||||
|
||||
OnIndexing<MediaPart>((context, part) =>
|
||||
OnIndexing<MediaPart>((context, part) =>
|
||||
context.DocumentIndex
|
||||
.Add("media-folderpath", Normalize(part.FolderPath)).Store()
|
||||
.Add("media-filename", Normalize(part.FileName)).Store()
|
||||
@@ -30,22 +36,55 @@ namespace Orchard.MediaLibrary.Handlers {
|
||||
.Add("media-alternatetext", part.AlternateText).Analyze()
|
||||
);
|
||||
|
||||
OnPublished<ImagePart>((context, part) => {
|
||||
var mediaPart = part.As<MediaPart>();
|
||||
var file = _storageProvider.GetFile(_storageProvider.Combine(mediaPart.FolderPath, mediaPart.FileName));
|
||||
|
||||
using (var stream = file.OpenRead()) {
|
||||
try {
|
||||
using (var image = System.Drawing.Image.FromStream(stream)) {
|
||||
part.Width = image.Width;
|
||||
part.Height = image.Height;
|
||||
}
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
// Still trying to get .ico dimensions when it's blocked in System.Drawing, see: https://github.com/OrchardCMS/Orchard/issues/4473
|
||||
if (mediaPart.MimeType != "image/x-icon" && mediaPart.MimeType != "image/vnd.microsoft.icon")
|
||||
throw;
|
||||
TryFillDimensionsForIco(stream, part);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
OnIndexing<ImagePart>((context, part) =>
|
||||
context.DocumentIndex
|
||||
.Add("image-height", part.Height).Analyze().Store()
|
||||
.Add("image-width", part.Width).Analyze().Store()
|
||||
);
|
||||
|
||||
OnPublished<DocumentPart>((context, part) => {
|
||||
var mediaPart = part.As<MediaPart>();
|
||||
var file = _storageProvider.GetFile(_storageProvider.Combine(mediaPart.FolderPath, mediaPart.FileName));
|
||||
|
||||
using (var stream = file.OpenRead()) {
|
||||
part.Length = stream.Length;
|
||||
}
|
||||
});
|
||||
|
||||
OnIndexing<DocumentPart>((context, part) =>
|
||||
context.DocumentIndex
|
||||
.Add("document-length", part.Length).Analyze().Store()
|
||||
);
|
||||
|
||||
OnPublished<VideoPart>((context, part) => part.Length = 0);
|
||||
|
||||
OnIndexing<VideoPart>((context, part) =>
|
||||
context.DocumentIndex
|
||||
.Add("video-length", part.Length).Analyze().Store()
|
||||
);
|
||||
|
||||
OnPublished<AudioPart>((context, part) => part.Length = 0);
|
||||
|
||||
OnIndexing<AudioPart>((context, part) =>
|
||||
context.DocumentIndex
|
||||
.Add("audio-length", part.Length).Analyze().Store()
|
||||
@@ -67,5 +106,18 @@ namespace Orchard.MediaLibrary.Handlers {
|
||||
// when not indexed with Analyze() searches are case sensitive
|
||||
return text.Replace("\\", "/").ToLowerInvariant();
|
||||
}
|
||||
|
||||
private void TryFillDimensionsForIco(Stream stream, ImagePart imagePart) {
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream)) {
|
||||
// Reading out the necessary bytes that indicate the image dimensions. For the file format see:
|
||||
// http://en.wikipedia.org/wiki/ICO_%28file_format%29
|
||||
// Reading out leading bytes containing unneded information.
|
||||
binaryReader.ReadBytes(6);
|
||||
// Reading out dimensions. If there are multiple icons bundled in the same file then this is the first image.
|
||||
imagePart.Width = binaryReader.ReadByte();
|
||||
imagePart.Height = binaryReader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,6 +327,17 @@ $(function () {
|
||||
window.location = url;
|
||||
};
|
||||
|
||||
self.replaceMedia = function (item) {
|
||||
var url = settings.replaceUrl;
|
||||
var ids = [];
|
||||
var folder = "";
|
||||
if (self.displayed()) {
|
||||
folder = self.displayed();
|
||||
}
|
||||
viewModel.selection().forEach(function (item) { ids.push(item.data.id); });
|
||||
var actionurl = url + '?folderPath=' + encodeURIComponent(folder) + "&replaceId=" + encodeURIComponent(ids[0]);
|
||||
window.location = actionurl;
|
||||
}
|
||||
var selectFolderOrRecent = function () {
|
||||
if (self.displayed()) {
|
||||
self.selectFolder(self.displayed());
|
||||
|
||||
@@ -167,5 +167,26 @@ namespace Orchard.MediaLibrary.Services {
|
||||
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
public static string MimeTypeToContentType(this IMediaLibraryService service, Stream stream, string mimeType, string contentType) {
|
||||
var mediaFactory = service.GetMediaFactory(stream, mimeType, contentType);
|
||||
if (mediaFactory == null)
|
||||
return null;
|
||||
|
||||
switch (mediaFactory.GetType().Name) {
|
||||
case "ImageFactory":
|
||||
return "Image";
|
||||
case "AudioFactory":
|
||||
return "Audio";
|
||||
case "DocumentFactory":
|
||||
return "Document";
|
||||
case "VectorImageFactory":
|
||||
return "VectorImage";
|
||||
case "VideoFactory":
|
||||
return "Video";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,8 @@ namespace Orchard.MediaLibrary.Services {
|
||||
|
||||
using (var stream = storageFile.OpenRead()) {
|
||||
var mediaFactory = GetMediaFactory(stream, mimeType, contentType);
|
||||
if (mediaFactory == null)
|
||||
throw new Exception(T("No media factory available to handle this resource.").Text);
|
||||
var mediaPart = mediaFactory.CreateMedia(stream, mediaFile.Name, mimeType, contentType);
|
||||
if (mediaPart != null) {
|
||||
mediaPart.FolderPath = relativePath;
|
||||
|
||||
@@ -46,4 +46,23 @@
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Messages */
|
||||
.message {
|
||||
margin:10px 0 4px 0;
|
||||
padding:4px;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.message-Information {
|
||||
background:#e6f1c9; /* green */
|
||||
border:1px solid #cfe493;
|
||||
color:#062232;
|
||||
}
|
||||
|
||||
.message-Error {
|
||||
background:#e68585; /* red */
|
||||
border:1px solid #990808;
|
||||
color:#fff;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
namespace Orchard.MediaLibrary.ViewModels {
|
||||
using Orchard.MediaLibrary.Models;
|
||||
|
||||
namespace Orchard.MediaLibrary.ViewModels {
|
||||
public class ImportMediaViewModel {
|
||||
public string FolderPath { get; set; }
|
||||
public string Type { get; set; }
|
||||
public MediaPart Replace { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.UI.Navigation;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
|
||||
namespace Orchard.MediaLibrary.ViewModels {
|
||||
public class MediaManagerImportViewModel {
|
||||
@@ -8,5 +9,6 @@ namespace Orchard.MediaLibrary.ViewModels {
|
||||
public IEnumerable<string> ImageSets { get; set; }
|
||||
public string FolderPath { get; set; }
|
||||
public IEnumerable<ContentTypeDefinition> MediaTypes { get; set; }
|
||||
public MediaPart Replace { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,5 +12,4 @@ namespace Orchard.MediaLibrary.ViewModels {
|
||||
public MediaPart MediaPart { get; set; }
|
||||
public dynamic Shape { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Xml.Linq;
|
||||
using Orchard.MediaLibrary.Models;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.MediaLibrary.ViewModels {
|
||||
public class OEmbedViewModel {
|
||||
public string FolderPath { get; set; }
|
||||
public string Url { get; set; }
|
||||
public XDocument Content { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public string Type { get; set; }
|
||||
public MediaPart Replace { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,15 @@
|
||||
<div id="media-library-toolbar">
|
||||
|
||||
<div id="media-library-toolbar-actions">
|
||||
|
||||
<label for="filterMediaType">@T("Create")</label>
|
||||
<label for="filterMediaType">@if (Model.Replace == null) { <text>@T("Create")</text> } else { <text>@T("Replace")</text> }</label>
|
||||
<select id="filterMediaType" name="FilteredMediaType">
|
||||
@Html.SelectOption("", true, T("Any").ToString())
|
||||
@foreach (var mediaType in Model.MediaTypes) {
|
||||
@Html.SelectOption(mediaType.Name, false, mediaType.DisplayName)
|
||||
}
|
||||
</select>
|
||||
|
||||
<a href="@Url.Action("Index", "Admin", new { folderPath = Model.FolderPath})" class="button">@T("Close")</a>
|
||||
|
||||
<a href="@Url.Action("Index", "Admin", new { folderPath = Model.FolderPath})" class="button close">@T("Close")</a>
|
||||
</div>
|
||||
|
||||
@Html.ActionLink(T("Media Library").ToString(), "Index", "Admin", new { area = "Orchard.MediaLibrary" }, null)
|
||||
@@ -37,11 +36,15 @@
|
||||
|
||||
<div id="media-library-main">
|
||||
<div id="media-library-main-navigation">
|
||||
@foreach (var menuItem in Model.Menu) {
|
||||
@foreach (var menuItem in Model.Menu)
|
||||
{
|
||||
string sectionHeaderTextHint = menuItem.Text.TextHint;
|
||||
var itemClassName = "navicon-" + sectionHeaderTextHint.HtmlClassify();
|
||||
|
||||
<div class="import-provider"><a class="navicon @itemClassName" href="@menuItem.Href/Index?folderPath=@HttpUtility.UrlEncode(Model.FolderPath)">@menuItem.Text</a></div>
|
||||
if (Model.Replace == null) {
|
||||
<div class="import-provider"><a class="navicon @itemClassName" href="@menuItem.Href/Index?folderPath=@HttpUtility.UrlEncode(Model.FolderPath)">@menuItem.Text</a></div>
|
||||
} else {
|
||||
<div class="import-provider"><a class="navicon @itemClassName" href="@menuItem.Href/Index?folderPath=@HttpUtility.UrlEncode(Model.FolderPath)&replaceId=@HttpUtility.UrlEncode(Model.Replace.Id.ToString())">@menuItem.Text</a></div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div id="media-library-main-list-wrapper">
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
</ul>
|
||||
<div id="media-library-main-selection-actions">
|
||||
<button id="delete-selection-button">@T("Delete")</button>
|
||||
<button href="#" data-bind="click: replaceMedia, visible: selection().length == 1" class="button" id="replace-selection-button">@T("Replace")</button>
|
||||
<button id="clone-selection-button" data-bind="visible: selection().length == 1">@T("Clone")</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,11 +97,13 @@ var mediaLibrarySettings = {
|
||||
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"})',
|
||||
replaceUrl: '@Url.Action("Import", "Admin", new {area = "Orchard.MediaLibrary" })' ,
|
||||
hasFolderPath: @(!string.IsNullOrEmpty(viewModel.FolderPath) ? "true" : "false"),
|
||||
folderPath: '@HttpUtility.JavaScriptStringEncode(viewModel.FolderPath)',
|
||||
rootFolderPath: '@HttpUtility.JavaScriptStringEncode(viewModel.RootFolderPath ?? "")',
|
||||
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)',
|
||||
replaceConfirmationMessage: '@HttpUtility.JavaScriptStringEncode(T("Are you sure you want to replace 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']
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@model Orchard.MediaLibrary.ViewModels.ImportMediaViewModel
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
@@ -21,11 +20,10 @@
|
||||
@Display.StyleSheetLinks()
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="clientstorage-main">
|
||||
<div id="message">@T("Click here, Drop files or Paste images")</div>
|
||||
<div id="fileupload">
|
||||
<input type="file" name="files[]" multiple="multiple">
|
||||
<input type="file" name="files[]" @if(Model.Replace == null) { <text>multiple="multiple"</text> } >
|
||||
<ul id="fileupload-transfers" data-bind="foreach: transfers">
|
||||
<li data-bind="css: status()" class="transfer">
|
||||
<div class="media-thumbnail" data-bind="html: thumbnail(), visible: status() == 'success'"></div>
|
||||
@@ -36,15 +34,12 @@
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@using(Script.Foot()) {
|
||||
|
||||
@using (Script.Foot()) {
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
//<![CDATA[
|
||||
$(function () {
|
||||
|
||||
function transferViewModel(filename, size) {
|
||||
@@ -63,7 +58,7 @@
|
||||
|
||||
self.transfers = ko.observableArray([]);
|
||||
|
||||
self.upload = function(file) {
|
||||
self.upload = function (file) {
|
||||
var transfer = new transferViewModel(file.name, file.size);
|
||||
self.transfers.push(transfer);
|
||||
return transfer;
|
||||
@@ -73,24 +68,37 @@
|
||||
var viewModel = new clientStorageViewModel();
|
||||
ko.applyBindings(viewModel);
|
||||
|
||||
$('#fileupload').click(function() {
|
||||
console.log('click');
|
||||
$('#fileupload').click(function () {
|
||||
//console.log('click');
|
||||
$('#fileupload > input').trigger('click');
|
||||
});
|
||||
|
||||
$('#fileupload > input').click(function(event) {
|
||||
$('#fileupload > input').click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Add drag-n-drop HTML5 support
|
||||
$('#fileupload').fileupload({
|
||||
url: '@Url.Action("Upload", "ClientStorage")',
|
||||
autoUpload: true,
|
||||
@if(Model.Replace == null) {
|
||||
<text>
|
||||
url: '@Url.Action("Upload")',
|
||||
formData: {
|
||||
folderPath: '@Html.Raw(HttpUtility.JavaScriptStringEncode(Model.FolderPath))',
|
||||
type: '@HttpUtility.JavaScriptStringEncode(Model.Type)',
|
||||
__RequestVerificationToken: '@Html.AntiForgeryTokenValueOrchard()'
|
||||
},
|
||||
</text>
|
||||
} else {
|
||||
<text>
|
||||
url: '@Url.Action("Replace")',
|
||||
formData: {
|
||||
replaceId: '@HttpUtility.JavaScriptStringEncode(Model.Replace.Id.ToString())',
|
||||
type: '@HttpUtility.JavaScriptStringEncode(Model.Type)',
|
||||
__RequestVerificationToken: '@Html.AntiForgeryTokenValueOrchard()'
|
||||
},
|
||||
</text>
|
||||
}
|
||||
done: function (e, data) {
|
||||
console.log(data.result);
|
||||
},
|
||||
@@ -114,7 +122,6 @@
|
||||
data.context = viewModel.upload(file);
|
||||
}
|
||||
|
||||
|
||||
data.submit();
|
||||
},
|
||||
// Callback for upload progress events:
|
||||
@@ -128,11 +135,11 @@
|
||||
pasteZone: window.parent.document,
|
||||
paste: function (e, data) {
|
||||
$.each(data.files, function (index, file) {
|
||||
//console.log('Pasted file type: ' + file.type);
|
||||
console.log('Pasted file type: ' + file.type);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
done: function(e, data) {
|
||||
done: function (e, data) {
|
||||
var result = data.result[0];
|
||||
|
||||
if (result.error) {
|
||||
@@ -142,23 +149,27 @@
|
||||
|
||||
data.context.label('@HttpUtility.JavaScriptStringEncode(T("Loading thumbnail...").Text)');
|
||||
|
||||
|
||||
var url = '@HttpUtility.JavaScriptStringEncode(Url.Action("MediaItem", "Admin"))/' + result.id + '?displayType=Thumbnail';
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
}).done(function(html) {
|
||||
}).done(function (html) {
|
||||
data.context.thumbnail(html);
|
||||
data.context.status('success');
|
||||
@if(Model.Replace != null) {
|
||||
<text>
|
||||
window.parent.$("a.button.close")[0].click();
|
||||
</text>
|
||||
}
|
||||
});
|
||||
},
|
||||
fail: function(e, data) {
|
||||
fail: function (e, data) {
|
||||
data.context.status('error');
|
||||
}
|
||||
});
|
||||
})
|
||||
//]]>
|
||||
//]]>
|
||||
</script>
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,18 @@
|
||||
@Display.StyleSheetLinks()
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="oembed-main">
|
||||
@if (Layout.Messages != null) {
|
||||
<div id="messages">
|
||||
@Display(Layout.Messages)
|
||||
</div>
|
||||
}
|
||||
<div class="query-container">
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
<fieldset>
|
||||
<legend>@T("Please enter the URL of the embeddable media you want to integrate (requires an oEmbed compatible media provider such as YouTube):")</legend>
|
||||
<div id="icon">
|
||||
<button type="submit" class="fa fa-download">@T("Preview")</button>
|
||||
<button type="submit" class="fa fa-download"></button>
|
||||
</div>
|
||||
<div id="query">
|
||||
<input name="url" type="text" autofocus placeholder="@T("media url")" value="@Model.Url" />
|
||||
@@ -126,15 +130,24 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
using (Html.BeginFormAntiForgeryPost(Url.Action("MediaPost"))) {
|
||||
@Html.Hidden("url", Model.Url)
|
||||
@Html.Hidden("folderPath", Model.FolderPath)
|
||||
@Html.Hidden("document", Model.Content.ToString())
|
||||
<br/>
|
||||
<button type="submit">@T("Import")</button>
|
||||
if (Model.Replace == null) {
|
||||
using (Html.BeginFormAntiForgeryPost(Url.Action("Import"))) {
|
||||
@Html.Hidden("folderPath", Model.FolderPath)
|
||||
@Html.Hidden("url", Model.Url)
|
||||
@Html.Hidden("document", Model.Content.ToString())
|
||||
<br/>
|
||||
<button type="submit">@T("Import")</button>
|
||||
}
|
||||
} else {
|
||||
using (Html.BeginFormAntiForgeryPost(Url.Action("Replace"), FormMethod.Post, new { onsubmit = "window.parent.$('a.button.close')[0].click();" })) {
|
||||
@Html.Hidden("replaceId", Model.Replace)
|
||||
@Html.Hidden("url", Model.Url)
|
||||
@Html.Hidden("document", Model.Content.ToString())
|
||||
<br />
|
||||
<button type="submit">@T("Replace")</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
@Display.FootScripts()
|
||||
</body>
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
var self = $(this);
|
||||
var href = self.attr('href');
|
||||
var containsQueryString = href.indexOf("?") >= 0;
|
||||
if (href.indexOf("returnUrl") == -1) {
|
||||
var returnUrl = href + (containsQueryString ? "&" : "?") + "returnUrl=" + encodeURIComponent(window.location);
|
||||
}
|
||||
self.attr('href', returnUrl);
|
||||
});
|
||||
//]]>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@if (HasText(mediaUrl)) {
|
||||
<div class="file-name">
|
||||
<em>@T("Filename:")</em>
|
||||
<span><a href="@mediaUrl">@HttpUtility.UrlDecode(Path.GetFileName(mediaUrl))</a></span>
|
||||
<span><a href="@mediaUrl" target="_blank">@HttpUtility.UrlDecode(Path.GetFileName(mediaUrl))</a></span>
|
||||
</div>
|
||||
}
|
||||
<div class="mime-type">
|
||||
|
||||
@@ -70,12 +70,12 @@
|
||||
|
||||
<div id="websearch-properties-selection" data-bind="visible: selection().length">
|
||||
<h1>@T("SELECTION")</h1>
|
||||
<button id="button-import">IMPORT</button>
|
||||
<button id="button-import">@if (Model.Replace == null) { <text>@T("Import")</text> } else { <text>@T("Replace")</text> } </button>
|
||||
<ul data-bind="foreach: selection">
|
||||
<li>
|
||||
<div class="selection" data-bind="click: $parent.focus, style: { backgroundImage: 'url(' + data.Thumbnail.MediaUrl + ')' }">
|
||||
<div class="selection-overlay">
|
||||
<div class="selection-progress" data-bind="css: status()"></div>
|
||||
<div class="selection-progress" data-bind="css: status(), attr: { 'title': tooltip() == '' ? null : tooltip() }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@@ -83,42 +83,38 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@Html.Hidden("antiforgerytoken", Html.AntiForgeryTokenValueOrchard())
|
||||
@Html.Hidden("action", Url.Action("ImagePost"))
|
||||
@Html.Hidden("folderPath", Model.FolderPath)
|
||||
@Html.Hidden("type", Model.Type)
|
||||
|
||||
@using(Script.Foot()) {
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
//<![CDATA[
|
||||
$(function () {
|
||||
function SearchResult(data) {
|
||||
var self = this;
|
||||
|
||||
|
||||
// values
|
||||
self.data = data;
|
||||
self.hasFocus = ko.observable();
|
||||
self.selected = ko.observable();
|
||||
self.status = ko.observable('');
|
||||
|
||||
self.tooltip = ko.observable('');
|
||||
|
||||
// operations
|
||||
self.setData = function (value) {
|
||||
self.data = value;
|
||||
};
|
||||
|
||||
self.getFilename = function() {
|
||||
self.getFilename = function () {
|
||||
var value = self.data.MediaUrl;
|
||||
return value.substr(value.lastIndexOf('/') + 1);
|
||||
};
|
||||
|
||||
self.kilobytes = function() {
|
||||
self.kilobytes = function () {
|
||||
return Math.round(self.data.FileSize / 1024);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function WebSearchViewModel() {
|
||||
var self = this;
|
||||
|
||||
|
||||
// values
|
||||
self.selection = ko.observableArray([]);
|
||||
self.focus = ko.observable();
|
||||
@@ -127,11 +123,11 @@
|
||||
self.filename = function () {
|
||||
return value.substr(value.lastIndexOf('/') + 1);
|
||||
};
|
||||
|
||||
|
||||
self.doSearch = function () {
|
||||
var query = $('#query > input').val();
|
||||
var url = 'https://api.datamarket.azure.com/Bing/Search/Image?$format=json&Query=%27' + encodeURIComponent(query) + '%27';
|
||||
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
@@ -154,7 +150,7 @@
|
||||
|
||||
self.selection([]);
|
||||
};
|
||||
|
||||
|
||||
self.focus.subscribe(function (oldValue) {
|
||||
if (oldValue) {
|
||||
oldValue.hasFocus(false);
|
||||
@@ -166,7 +162,7 @@
|
||||
newValue.hasFocus(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
self.toggleSelect = function (searchResult) {
|
||||
var index = $.inArray(searchResult, self.selection());
|
||||
if (index == -1) {
|
||||
@@ -176,10 +172,10 @@
|
||||
self.selection.remove(searchResult);
|
||||
searchResult.selected(false);
|
||||
}
|
||||
|
||||
|
||||
self.focus(searchResult);
|
||||
};
|
||||
|
||||
|
||||
self.select = function (searchResult) {
|
||||
var index = $.inArray(searchResult, self.selection());
|
||||
if (index == -1) {
|
||||
@@ -187,7 +183,7 @@
|
||||
self.selection([searchResult]);
|
||||
searchResult.selected(true);
|
||||
}
|
||||
|
||||
|
||||
self.focus(searchResult);
|
||||
};
|
||||
|
||||
@@ -198,52 +194,73 @@
|
||||
|
||||
$("#websearch-results").on("click", "li", function (e) {
|
||||
var searchResult = ko.dataFor(this);
|
||||
if (e.ctrlKey) {
|
||||
viewModel.toggleSelect(searchResult);
|
||||
@if(Model.Replace == null) {
|
||||
<text>
|
||||
if (e.ctrlKey) {
|
||||
viewModel.toggleSelect(searchResult);
|
||||
} else {
|
||||
viewModel.select(searchResult);
|
||||
}
|
||||
</text>
|
||||
} else {
|
||||
<text>
|
||||
viewModel.select(searchResult);
|
||||
</text>
|
||||
}
|
||||
}).on("contextmenu", "li", function(e) {
|
||||
}).on("contextmenu", "li", function (e) {
|
||||
var searchResult = ko.dataFor(this);
|
||||
viewModel.toggleSelect(searchResult);
|
||||
return false;
|
||||
});
|
||||
|
||||
$("#button-import").on("click", function (e) {
|
||||
var antiForgeryToken = $('[name=antiforgerytoken]').val();
|
||||
var folderPath = $('[name=folderPath]').val();
|
||||
var type = $('[name=type]').val();
|
||||
var action = $('[name=action]').val();
|
||||
|
||||
$("#button-import").on("click", function (e) {
|
||||
viewModel.selection().forEach(function (item) {
|
||||
var url = item.data.MediaUrl;
|
||||
item.status('uploading');
|
||||
$.post(action, {
|
||||
folderPath: folderPath,
|
||||
type: type,
|
||||
url: url,
|
||||
__RequestVerificationToken: antiForgeryToken,
|
||||
})
|
||||
item.tooltip('');
|
||||
@if (Model.Replace == null) {
|
||||
<text>
|
||||
$.post('@Url.Action("Import")', {
|
||||
folderPath: '@Html.Raw(HttpUtility.JavaScriptStringEncode(Model.FolderPath))',
|
||||
type: '@HttpUtility.JavaScriptStringEncode(Model.Type)',
|
||||
url: url,
|
||||
__RequestVerificationToken: '@Html.AntiForgeryTokenValueOrchard()'
|
||||
})
|
||||
</text>
|
||||
} else {
|
||||
<text>
|
||||
$.post('@Url.Action("Replace")', {
|
||||
replaceId: '@HttpUtility.JavaScriptStringEncode(Model.Replace.Id.ToString())',
|
||||
type: '@HttpUtility.JavaScriptStringEncode(Model.Type)',
|
||||
url: url,
|
||||
__RequestVerificationToken: '@Html.AntiForgeryTokenValueOrchard()'
|
||||
})
|
||||
</text>
|
||||
}
|
||||
.done(function (data) {
|
||||
if (data.error) {
|
||||
console.log(data);
|
||||
item.status('failure');
|
||||
item.tooltip(data.error);
|
||||
} else {
|
||||
item.status('success');
|
||||
viewModel.selection.remove(item);
|
||||
item.tooltip("Media imported successfully.");
|
||||
@if(Model.Replace != null) {
|
||||
<text>
|
||||
window.parent.$("a.button.close")[0].click();
|
||||
</text>
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function (jqXhr, data) {
|
||||
console.log('failed: ' + JSON.stringify(textStatus));
|
||||
item.status('failure');
|
||||
})
|
||||
.always(function() {
|
||||
.always(function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
//]]>
|
||||
//]]>
|
||||
</script>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user