Created
June 12, 2023 12:14
-
-
Save j3rbr0wn/29a197364b60c57d619b8070016566d2 to your computer and use it in GitHub Desktop.
Content Cleaner Tool for Optimizely CMS 12. Admin plugin to allow finding content of a specific type and deleting instances.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@using EPiServer.Framework.Localization | |
@using EPiServer.Web.Mvc.Html | |
@using EPiServer.Shell.Web.Mvc.Html | |
@using EPiServer.Core | |
@using EPiServer.Web | |
@using EPiServer.Web.Mvc | |
@using EPiServer.Web.Routing | |
@using MyCms12Website.Models.ViewModels | |
@using MyCms12Website.Models.Blocks | |
@using MyCms12Website.Models.Pages | |
@using Microsoft.AspNetCore.Mvc.Razor | |
@using Microsoft.AspNetCore.Html | |
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@using EPiServer.Framework.Web.Resources | |
@using EPiServer.Shell.Navigation | |
@using EPiServer.Editor | |
@using Microsoft.AspNetCore.Mvc.TagHelpers | |
@model MyCms12Website.Business.Plugins.ContentCleanerTool.ContentCleanerToolViewModel | |
@{ | |
Layout = null; | |
} | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Content Type Cleaner Tool</title> | |
<!-- Shell --> | |
@ClientResources.RenderResources("ShellCore") | |
<!-- LightTheme --> | |
@ClientResources.RenderResources("ShellCoreLightTheme") | |
</head> | |
<body class="epi-workspace"> | |
@Html.AntiForgeryToken() | |
@Html.Raw(Html.CreatePlatformNavigationMenu()) | |
<div @Html.Raw(Html.ApplyPlatformNavigation())> | |
<div class="epi-contentContainer epi-padding"> | |
<div class="epi-contentArea"> | |
<h1 class="EP-prefix">Content Type Cleaner Tool</h1> | |
<div> | |
<p id="message"></p> | |
</div> | |
<div> | |
<form action="/contentcleanertool/index/" method="post" id="contentTypeSelectionForm"> | |
<h2>Content Type Selection</h2> | |
<div> | |
<label asp-for="ContentTypeId">Select content type:</label> | |
<select asp-for="ContentTypeId" asp-items="@Model.ContentItems"> | |
</select> | |
<button type="submit" class="epi-cmsButton">List content</button> | |
</div> | |
</form> | |
</div> | |
@if (Model.ContentUsages?.Any() ?? false) | |
{ | |
<div> | |
<h2>Content</h2> | |
<table> | |
<tr> | |
<th>Id</th> | |
<th>Location</th> | |
<th></th> | |
<th></th> | |
</tr> | |
@foreach (var item in Model.ContentUsages) | |
{ | |
<tr> | |
<td> | |
@item.Content.ContentLink.ID | |
</td> | |
<td> | |
<a href="@item.ContentUrl" target="_blank"> | |
@item.Breadcrumb | |
</a> | |
</td> | |
<td> | |
<a href="@PageEditing.GetEditUrl(item.Content.ContentLink)" target="_blank"> | |
Edit | |
</a> | |
</td> | |
<td> | |
<button class="js-delete-button" data-contentref="@item.Content.ContentLink"> | |
Delete | |
</button> | |
</td> | |
</tr> | |
} | |
</table> | |
</div> | |
} | |
</div> | |
</div> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js" crossorigin="anonymous"></script> | |
<script> | |
$(document).ready(function () { | |
$('.js-delete-button').click(function () { | |
let contentRef = $(this).data('contentref'); | |
$.get('/contentcleanertool/delete/', { contentRef: contentRef }) | |
.done(function (data) { | |
$( "#contentTypeSelectionForm" ).trigger( "submit" ); | |
}) | |
.fail(function(jqXHR, textStatus, errorThrown) { | |
$( "#message" ).text( `Delete failed - ${jqXHR.responseText}` ); | |
}); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using EPiServer.Security; | |
using EPiServer.Web.Routing; | |
using Microsoft.AspNetCore.Authorization; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.Rendering; | |
using System.Net; | |
using System.Text; | |
namespace MyCms12Website.Business.Plugins.ContentCleanerTool.Controllers; | |
[Authorize(Roles = "Administrators")] | |
[Route("[controller]")] | |
public class ContentCleanerToolController : Controller | |
{ | |
private readonly IContentRepository _contentRepository; | |
private readonly IContentModelUsage _contentModelUsage; | |
private readonly IContentTypeRepository _contentTypeRepository; | |
private readonly IUrlResolver _urlResolver; | |
public ContentCleanerToolController(IUrlResolver urlResolver, IContentTypeRepository contentTypeRepository, IContentModelUsage contentModelUsage, IContentRepository contentRepository) | |
{ | |
_urlResolver = urlResolver; | |
_contentTypeRepository = contentTypeRepository; | |
_contentModelUsage = contentModelUsage; | |
_contentRepository = contentRepository; | |
} | |
[Route("[action]")] | |
[HttpGet] | |
public IActionResult Index() | |
{ | |
var model = new ContentCleanerToolViewModel() | |
{ | |
ContentItems = GetContentTypes() | |
}; | |
return View("/Business/Plugins/ContentCleanerTool/Views/ContentCleanerTool/Index.cshtml", model); | |
} | |
[Route("[action]")] | |
[HttpPost] | |
public IActionResult Index(ContentCleanerToolViewModel model) | |
{ | |
model.ContentItems = GetContentTypes(); | |
if (ModelState.IsValid) | |
{ | |
model.ContentUsages = GetContentTypeUsages(model.ContentTypeId); | |
} | |
return View("/Business/Plugins/ContentCleanerTool/Views/ContentCleanerTool/Index.cshtml", model); | |
} | |
[Route("[action]")] | |
[HttpGet] | |
public IActionResult Delete(string contentRef) | |
{ | |
try | |
{ | |
if (ModelState.IsValid) | |
{ | |
DeleteItem(contentRef); | |
} | |
return new OkResult(); | |
} | |
catch (Exception ex) | |
{ | |
return new ContentResult | |
{ | |
StatusCode = (int)HttpStatusCode.InternalServerError, | |
ContentType = "application/json", | |
Content = $"Error - {ex.Message}" | |
}; | |
} | |
} | |
private void DeleteItem(string contentRef) | |
{ | |
_contentRepository.Delete(ContentReference.Parse(contentRef), forceDelete: false, access: AccessLevel.NoAccess); | |
} | |
private List<ContentUsageBreadcrumb<ContentUsage>> GetContentTypeUsages(int selectedTypeID) | |
{ | |
var contentType = _contentTypeRepository.Load(selectedTypeID); | |
return _contentModelUsage.ListContentOfContentType(contentType) | |
.Select(x => new ContentUsageBreadcrumb<ContentUsage>(x) | |
{ | |
Breadcrumb = BreadCrumb(x.ContentLink), | |
ContentUrl = _urlResolver.GetUrl(x.ContentLink) | |
}) | |
.OrderBy(x => x.Name) | |
.ToList(); | |
} | |
private IEnumerable<SelectListItem> GetContentTypes() | |
{ | |
var uploads = _contentTypeRepository.List().OrderBy(p => p.Name); | |
return uploads.Select(x => new SelectListItem | |
{ | |
Value = x.ID.ToString(), | |
Text = x.Name | |
}).ToList(); | |
} | |
public string BreadCrumb(ContentReference cReference) | |
{ | |
if (cReference == null) | |
return string.Empty; | |
var ancestor = _contentRepository.GetAncestors(cReference).ToList(); | |
var content = _contentRepository.Get<IContent>(cReference); | |
var path = new StringBuilder(); | |
for (var x = ancestor.Count - 1; x >= 0; x--) | |
{ | |
path.Append($"\\{ancestor[x].Name}"); | |
} | |
return $"{path}\\{content.Name}".Trim("\\".ToCharArray()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Mvc.Rendering; | |
namespace MyCms12Website.Business.Plugins.ContentCleanerTool; | |
public class ContentCleanerToolViewModel | |
{ | |
public IEnumerable<SelectListItem> ContentItems { get; set; } | |
public IEnumerable<ContentUsageBreadcrumb<ContentUsage>> ContentUsages { get; set; } = new List<ContentUsageBreadcrumb<ContentUsage>>(); | |
public int ContentTypeId { get; set; } | |
} | |
public class ContentUsageBreadcrumb<TContent> : ContentUsage | |
{ | |
public ContentUsageBreadcrumb(TContent content) | |
{ | |
Content = content; | |
} | |
public TContent Content { get; } | |
public string ContentUrl { get; set; } | |
public string Breadcrumb { get; set; } | |
} |
Nice Tool. Can you explain the need for the ModelState.IsValid check in the POST Method of the controller? For me it only returns content items if I comment out that check and I'm curious about it's intented purpose.
@Brian-Jaxon if ModelState.IsValid
always returns false this could be the reason https://stackoverflow.com/a/72689810
@j3rbr0wn You should stick all this in a Razor Class Library and put it onto the Optimizely Nuget Feed :)
@j3rbr0wn You should stick all this in a Razor Class Library and put it onto the Optimizely Nuget Feed :)
@paulmcgann is on it!
https://github.com/paulmcgann/content-cleaner
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice one getting this to CMS 12.