Upgrading media files asyncronously

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2013-07-15 11:06:28 -07:00
parent bad715f149
commit bade9fe4ce
2 changed files with 112 additions and 66 deletions

View File

@@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Authentication;
using System.Threading;
using System.Web.Mvc;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
using Orchard.ContentManagement.MetaData;
using Orchard.Environment.Features;
using Orchard.FileSystems.Media;
@@ -27,7 +28,7 @@ namespace Upgrade.Controllers {
private readonly IMimeTypeProvider _mimeTypeProvider;
private readonly IContentDefinitionManager _contentDefinitionManager;
private IMediaLibraryService _mediaLibraryService { get { return _mediaLibraryServices.FirstOrDefault(); }}
private int BATCH = 100;
private int BATCH = 10;
public MediaController(
IOrchardServices orchardServices,
@@ -47,6 +48,11 @@ namespace Upgrade.Controllers {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
private Queue<MediaEntry> MediaList {
get { return Session["MediaList"] as Queue<MediaEntry>; }
set { Session["MediaList"] = value; }
}
public ActionResult Index() {
ViewBag.CanMigrate = false;
if (_featureManager.GetEnabledFeatures().All(x => x.Id != "Orchard.MediaLibrary")) {
@@ -66,7 +72,7 @@ namespace Upgrade.Controllers {
extensions.Add(extension);
}
}
}));
}, new CancellationTokenSource()));
foreach (var extension in extensions) {
if (_mimeTypeProvider.GetMimeType("." + extension) == "application/unknown") {
@@ -75,7 +81,8 @@ namespace Upgrade.Controllers {
}
}
// ensuring all media items have been migrated
MediaList = new Queue<MediaEntry>();
var cts = new CancellationTokenSource();
var hasMore = false;
if (ViewBag.CanMigrate) {
@@ -84,88 +91,77 @@ namespace Upgrade.Controllers {
IEnumerable<MediaFolder> mediaFolders = _mediaLibraryService.GetMediaFolders(null);
foreach (var mediaFolder in mediaFolders) {
ImportMediaFolder(mediaFolder, x => {
var media = _orchardServices.ContentManager.Query().ForPart<MediaPart>().Where<MediaPartRecord>(m => m.FolderPath == x.FolderName && m.FileName == x.Name).Slice(0, 1).FirstOrDefault();
if (media == null) {
MediaList.Enqueue(new MediaEntry { FolderName = x.FolderName, FileName = x.Name });
if (!hasMore && _orchardServices.ContentManager.Query().ForPart<MediaPart>().Where<MediaPartRecord>(m => m.FolderPath == x.FolderName && m.FileName == x.Name).Count() == 0) {
hasMore = true;
}
});
if (hasMore) {
break;
}
},
cts);
}
}
if (hasMore) {
_orchardServices.Notifier.Warning(T("Some media files need to be migrated."));
_orchardServices.Notifier.Information(T("{0} media files have been found, {1} media are in the library.", MediaList.Count, _orchardServices.ContentManager.Query<MediaPart>().Count()));
}
else {
_orchardServices.Notifier.Warning(T("All media files have been migrated."));
}
ViewBag.CanMigrateFields = ViewBag.CanMigrate && !hasMore;
return View();
}
[HttpPost, ActionName("Index")]
public ActionResult IndexPOST() {
[HttpPost]
public JsonResult ImportMedia() {
if (!_orchardServices.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to convert media files.")))
return new HttpUnauthorizedResult();
throw new AuthenticationException("");
var count = 0;
var hasMore = false;
// crawl media file, ignore recipes and profiles
IEnumerable<MediaFolder> mediaFolders = _mediaLibraryService.GetMediaFolders(null);
foreach (var mediaFolder in mediaFolders) {
ImportMediaFolder(mediaFolder, x => {
if (count < BATCH) {
if (ImportMediaFile(x) != null) {
count++;
}
}
else {
hasMore = true;
}
});
for (int i = 0; i < BATCH && MediaList.Any(); i++) {
var media = MediaList.Dequeue();
ImportMediaFile(media.FolderName, media.FileName);
}
if (count > 0) {
_orchardServices.Notifier.Information(T("{0} media files were imported.", count));
}
if (hasMore && count <= BATCH) {
_orchardServices.Notifier.Information(T("More than {0} media files were found, please import again.", BATCH));
}
else {
_orchardServices.Notifier.Information(T("All media files were imported."));
}
return RedirectToAction("Index");
return new JsonResult { Data = MediaList.Count };
}
private void ImportMediaFolder(MediaFolder mediaFolder, Action<MediaFile> action) {
private void ImportMediaFolder(MediaFolder mediaFolder, Action<MediaFile> action, CancellationTokenSource cts) {
if (cts.IsCancellationRequested) {
return;
}
foreach (var mediaFile in _mediaLibraryService.GetMediaFiles(mediaFolder.MediaPath)) {
action(mediaFile);
if (cts.IsCancellationRequested) {
return;
}
}
// recursive call on sub-folders
foreach (var subMediaFolder in _mediaLibraryService.GetMediaFolders(mediaFolder.MediaPath)) {
ImportMediaFolder(subMediaFolder, action);
ImportMediaFolder(subMediaFolder, action, cts);
}
}
private MediaPart ImportMediaFile(MediaFile mediaFile) {
private MediaPart ImportMediaFile(string folderName, string fileName) {
// foreach media file, if there is no media with the same url, import it
var contentManager = _orchardServices.ContentManager;
var media = contentManager.Query().ForPart<MediaPart>().Where<MediaPartRecord>(x => x.FolderPath == mediaFile.FolderName && x.FileName == mediaFile.Name).Slice(0, 1).FirstOrDefault();
var mediaExists = contentManager.Query().ForPart<MediaPart>().Where<MediaPartRecord>(x => x.FolderPath == folderName && x.FileName == fileName).Count() > 0;
if (media != null) {
if (mediaExists) {
// _orchardServices.Notifier.Warning(T("Media {0} has already been imported.", mediaFile.MediaPath));
return null;
}
try {
//_orchardServices.Notifier.Information(T("Importing {0}.", mediaFile.MediaPath));
return _mediaLibraryService.ImportMedia(mediaFile.FolderName, mediaFile.Name);
return _mediaLibraryService.ImportMedia(folderName, fileName);
}
catch(Exception e) {
_orchardServices.Notifier.Error(T("Error while importing {0}. Please check the logs", mediaFile.MediaPath));
Logger.Error(e, "Error while importing {0}", mediaFile.MediaPath);
_orchardServices.Notifier.Error(T("Error while importing {0}. Please check the logs", folderName + "/" + fileName));
Logger.Error(e, "Error while importing {0}", folderName + "/" + fileName);
return null;
}
}
@@ -216,5 +212,11 @@ namespace Upgrade.Controllers {
}
return RedirectToAction("Index");
}
[Serializable]
private class MediaEntry {
public string FolderName { get; set; }
public string FileName { get; set; }
}
}
}

View File

@@ -1,23 +1,25 @@
@using Orchard.Utility.Extensions
@{ Layout.Title = T("Migrate Media Files").ToString(); }
@using (Html.BeginFormAntiForgeryPost()) {
Html.ValidationSummary();
<fieldset>
<legend>@T("Migrating Media Files:")</legend>
<span class="hint">@T("This migration step will create and organize new Media Content Items based on the media files in your ~/Media folder.")</span>
@if (ViewBag.CanMigrate) {
<span class="hint">@T("Before importing, please ensure the server has the expected mime types already registered as explained here: <a href=\"http://www.iis.net/configreference/system.webserver/staticcontent/mimemap\">http://www.iis.net/configreference/system.webserver/staticcontent/mimemap</a>")</span>
}
</fieldset>
<fieldset>
@if (ViewBag.CanMigrate) {
<button type="submit">@T("Migrate")</button>
}
</fieldset>
@{
Script.Require("jQuery");
Layout.Title = T("Migrate Media Files").ToString();
}
<fieldset>
<legend>@T("Migrating Media Files:")</legend>
<span class="hint">@T("This migration step will create and organize new Media Content Items based on the media files in your ~/Media folder.")</span>
@if (ViewBag.CanMigrate) {
<span class="hint">@T("Before importing, please ensure the server has the expected mime types already registered as explained here: <a href=\"http://www.iis.net/configreference/system.webserver/staticcontent/mimemap\">http://www.iis.net/configreference/system.webserver/staticcontent/mimemap</a>")</span>
}
</fieldset>
<fieldset>
@if (ViewBag.CanMigrate) {
<button type="button" class="button" id="button-migrate">@T("Migrate")</button>
<div class="message message-Warning" id="message-progress" style="display: none"></div>
}
</fieldset>
@using (Html.BeginFormAntiForgeryPost(Url.Action("MediaPicker", "Media"))) {
<fieldset>
<legend>@T("Migrating Media Picker Fields:")</legend>
@@ -32,4 +34,46 @@
}
</fieldset>
}
@using (Script.Foot()) {
<script type="text/javascript">
$(function() {
var importMediaUrl = '@HttpUtility.JavaScriptStringEncode(Url.Action("ImportMedia", "Media"))';
var antiForgeryToken = '@HttpUtility.JavaScriptStringEncode(Html.AntiForgeryTokenValueOrchard().ToString())';
var endMessage = '@HttpUtility.JavaScriptStringEncode(T("All media files have been processed").Text)';
$('#button-migrate').click(function () {
var remaining = 1;
$('#message-progress').show();
var iID = setInterval(function() {
$.ajax({
type: 'POST',
url: importMediaUrl,
async: false,
data: {
__RequestVerificationToken: antiForgeryToken
},
success: function(data) {
console.log('media remaining: ' + data);
remaining = data;
},
fail: function(result) {
remaining = 0;
console.log("An error occured: " + result);
}
});
$('#message-progress').text('' + remaining + ' files remaining ...');
if (remaining == 0) {
clearInterval(iID);
$('#message-progress').text(endMessage);
}
}, 100);
});
});
</script>
}