Created
August 25, 2020 13:59
-
-
Save johanbenschop/299ad31f8f63304578fb499549385659 to your computer and use it in GitHub Desktop.
Two scheduled jobs to remove unused content types and properties
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 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; | |
} | |
} | |
} |
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 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