Skip to content

Instantly share code, notes, and snippets.

@nathanwoulfe
Last active June 2, 2020 15:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathanwoulfe/a5186667fca1a53c48088df13bfa65ea to your computer and use it in GitHub Desktop.
Save nathanwoulfe/a5186667fca1a53c48088df13bfa65ea to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.WebApi;
namespace Api.SiteAdmin
{
public class MediaManagerController : UmbracoAuthorizedApiController
{
private readonly DatabaseContext _dbContext;
private readonly IMediaService _mediaService;
private const string ImgMediaQuery =
@"SELECT nodeId from cmsMedia
WHERE cmsMedia.nodeId not in (select distinct parentId from umbracoRelation where parentId is not null)
AND cmsMedia.nodeId not in (select distinct childId from umbracoRelation where childId is not null)
AND (cmsMedia.mediaPath like '%.png' OR cmsMedia.mediaPath like '%.jpg')";
private const string DocsMediaQuery =
@"SELECT nodeId from cmsMedia
WHERE cmsMedia.nodeId not in (select distinct parentId from umbracoRelation where parentId is not null)
AND cmsMedia.nodeId not in (select distinct childId from umbracoRelation where childId is not null)
AND (
cmsMedia.mediaPath not like '%.png'
AND cmsMedia.mediaPath not like '%.jpg'
AND cmsMedia.mediaPath not like '%.svg'
AND cmsMedia.mediaPath not like '%.css'
AND cmsMedia.mediaPath not like '%.js')";
// bit clunky, but should ignore non-standard stuff like css, js, svg etc
// these are used in canvas pages, so while archiving won't break anything, should leave them alone
private const string MediaQuery =
@"SELECT nodeId from cmsMedia
WHERE cmsMedia.nodeId not in (select distinct parentId from umbracoRelation where parentId is not null)
AND cmsMedia.nodeId not in (select distinct childId from umbracoRelation where childId is not null)
AND (
cmsMedia.mediaPath not like '%.svg'
AND cmsMedia.mediaPath not like '%.css'
AND cmsMedia.mediaPath not like '%.js')";
public MediaManagerController(DatabaseContext dbContext, IMediaService mediaService)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
public IHttpActionResult GetUnusedMedia()
{
return Json(new
{
status = HttpStatusCode.OK,
data = _dbContext.Database.Query<int>(MediaQuery)
});
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
public IHttpActionResult DeleteAll(string type)
{
var items = _dbContext.Database.Query<int>(type == "images" ? ImgMediaQuery : type == "documents" ? DocsMediaQuery : MediaQuery);
return Json(new
{
status = HttpStatusCode.OK,
data = TryDoDelete(items)
});
}
[HttpPost]
public IHttpActionResult DeleteSelected(int[] ids)
{
return Json(new
{
status = HttpStatusCode.OK,
data = TryDoDelete(ids)
});
}
private bool TryDoDelete(IEnumerable<int> ids)
{
var success = false;
var hub = new NotificationsHub();
hub.SendMessage("Fetching media to archive");
try
{
var root = CheckArchiveFolderStructure();
var imageArchive = root.Children().FirstOrDefault(x => x.Name == "Images");
var docsArchive = root.Children().FirstOrDefault(x => x.Name == "Documents");
var imageYears = imageArchive.Children();
var docsYears = docsArchive.Children();
IEnumerable<IMedia> mediaItems = _mediaService.GetByIds(ids).Where(x => !x.Path.Contains(root.Id.ToString()));
hub.SendMessage($"Archiving {mediaItems.Count()} media items");
var i = 1;
foreach (var mediaItem in mediaItems)
{
var targetYear = (mediaItem.CreateDate.Year <= 2013 ? 2013 : mediaItem.CreateDate.Year).ToString();
_mediaService.Move(mediaItem, (mediaItem.ContentType.Alias == KnownDocumentAlias.Media.Image ? imageYears : docsYears).First(x => x.Name == targetYear).Id);
if (i % 5 == 0)
{
hub.SendMessage($"Still going - archived {i} media items");
}
i += 1;
}
success = true;
} catch
{
return false;
}
success = CleanEmptyFolders();
hub.SendMessage("Media archiving complete");
return success;
}
private bool CleanEmptyFolders()
{
try
{
var folders = _mediaService.GetMediaOfMediaType((int)KnownMediaTypeIds.Folder);
foreach (var folder in folders)
{
if (!folder.Children().Any())
{
_mediaService.Delete(folder);
}
}
} catch
{
return false;
}
return true;
}
/// <summary>
/// Ensure the media archive exists, if not create it - root level folders for type (img/file), then by year
/// </summary>
private IMedia CheckArchiveFolderStructure()
{
var root = _mediaService.GetRootMedia().FirstOrDefault(x => x.ContentType.Alias == KnownDocumentAlias.Media.ArchiveFolder);
// create root if needed
if (root == null)
{
root = _mediaService.CreateMedia("Archive", -1, KnownDocumentAlias.Media.ArchiveFolder);
_mediaService.Save(root);
}
// create image/docs folders if needed
if (!root.Children().Any())
{
_mediaService.Save(new[] {
_mediaService.CreateMedia("Images", root, KnownDocumentAlias.Media.ArchiveFolder),
_mediaService.CreateMedia("Documents", root, KnownDocumentAlias.Media.ArchiveFolder)
});
}
// add years for each file type - five prior to current
foreach (var folder in root.Children())
{
// first run will create year folders back to 2013
if (!folder.Children().Any())
{
for (var i = 0; i <= 6; i += 1)
{
var year = DateTime.Now.Year - i;
var yearFolder = _mediaService.CreateMedia(year.ToString(), folder, KnownDocumentAlias.Media.ArchiveFolder);
_mediaService.Save(yearFolder);
}
}
// always check a folder exists for the current year
var currentYear = folder.Children().FirstOrDefault(x => x.Name == DateTime.Now.Year.ToString());
if (currentYear == null)
{
currentYear = _mediaService.CreateMedia(DateTime.Now.Year.ToString(), folder, KnownDocumentAlias.Media.ArchiveFolder);
_mediaService.Save(currentYear);
}
}
return root;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment