Skip to content

Instantly share code, notes, and snippets.

@johanbenschop
Created August 25, 2020 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johanbenschop/299ad31f8f63304578fb499549385659 to your computer and use it in GitHub Desktop.
Save johanbenschop/299ad31f8f63304578fb499549385659 to your computer and use it in GitHub Desktop.
Two scheduled jobs to remove unused content types and properties
using System.Linq;
using EPiServer.DataAbstraction;
using EPiServer.PlugIn;
using EPiServer.Scheduler;
namespace Web.ScheduledJobs
{
[ScheduledPlugIn(
DisplayName = "Remove unused properties on content types",
Description = "",
SortIndex = 220,
GUID = Guid)]
public class RemoveUnusedContentPropertiesJob : ScheduledJobBase
{
private readonly IContentTypeRepository _contentTypeRepository;
private readonly IPropertyDefinitionRepository _propertyDefinitionRepository;
private readonly ContentTypeModelRepository _contentTypeModelRepository;
public const string Guid = "A194D4A3-30AA-46EB-9D9B-302E3C141E8A";
public RemoveUnusedContentPropertiesJob(
IContentTypeRepository contentTypeRepository,
IPropertyDefinitionRepository propertyDefinitionRepository,
ContentTypeModelRepository contentTypeModelRepository)
{
_contentTypeRepository = contentTypeRepository;
_propertyDefinitionRepository = propertyDefinitionRepository;
_contentTypeModelRepository = contentTypeModelRepository;
IsStoppable = false;
}
public override string Execute()
{
OnStatusChanged("Starting job");
var propertiesRemoved = 0;
var contentTypes = _contentTypeRepository.List();
// Filter out Episerver internal properties
contentTypes = contentTypes.Where(ct => !string.IsNullOrEmpty(ct.ModelTypeString));
foreach (var contentType in contentTypes)
{
// Delete all properties that do not exist in code (probably due to renaming or removing them)
var propertiesToRemove = contentType.PropertyDefinitions.Where(IsMissingModelProperty);
foreach (var property in propertiesToRemove)
{
_propertyDefinitionRepository.Delete(property);
++propertiesRemoved;
}
OnStatusChanged($"{propertiesRemoved} properties removed");
}
return $"{propertiesRemoved} properties removed";
}
private bool IsMissingModelProperty(PropertyDefinition propertyDefinition)
{
if (propertyDefinition == null) return false;
if (!propertyDefinition.ExistsOnModel) return true;
return _contentTypeModelRepository.GetPropertyModel(propertyDefinition.ContentTypeID, propertyDefinition) == null;
}
}
}
using System.Linq;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.PlugIn;
using EPiServer.Scheduler;
using EPiServer.Security;
namespace Web.ScheduledJobs
{
[ScheduledPlugIn(
DisplayName = "Delete old content types aggressively",
Description = "Aggressively deletes content types with no backing model and any content based off it",
SortIndex = 210,
GUID = Guid)]
public class RemoveUnusedContentTypesJob : ScheduledJobBase
{
private readonly IContentTypeRepository _contentTypeRepository;
private readonly IContentModelUsage _contentModelUsage;
private readonly IContentRepository _contentRepository;
public const string Guid = "3A048CE8-A263-4E4E-8729-75152372D9E3";
private const int EpiContentModelIdMax = 10;
public RemoveUnusedContentTypesJob(
IContentTypeRepository contentTypeRepository,
IContentModelUsage contentModelUsage,
IContentRepository contentRepository)
{
_contentTypeRepository = contentTypeRepository;
_contentModelUsage = contentModelUsage;
_contentRepository = contentRepository;
IsStoppable = false;
}
public override string Execute()
{
OnStatusChanged("Starting job");
var contentTypes = _contentTypeRepository.List();
var contentTypesWithoutBackingModel = contentTypes
.Where(x => x.ModelType == null && x.ID > EpiContentModelIdMax)
.ToList();
var contentTypesToRemove = contentTypesWithoutBackingModel.Count;
var removedContentTypes = 0;
OnStatusChanged($"Found {contentTypesToRemove} content types without a backing model");
foreach (var contentType in contentTypesWithoutBackingModel)
{
if (_contentModelUsage.IsContentTypeUsed(contentType))
{
var usages = _contentModelUsage.ListContentOfContentType(contentType);
foreach (var contentUsage in usages)
{
try
{
_contentRepository.DeleteChildren(contentUsage.ContentLink, true, AccessLevel.Delete);
_contentRepository.Delete(contentUsage.ContentLink, true);
}
catch
{
// ignored because the DeleteChildren will most likely
// already have deleted an type later in the loop
}
}
}
OnStatusChanged($"Removed unused content type {++removedContentTypes}/{contentTypesToRemove}");
_contentTypeRepository.Delete(contentType);
}
return $"Removed {contentTypesToRemove} unused content types";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment