V16 - Introducing signs to variants (#20053)
* Adding signs to variants and adjusting HasPendingChangesSignProvider.cs * HasPendingChangesSignProvider.cs now populates variants & refactoring to move logic to DocumentPresentationFactory.cs * Working HasScheduleSignProvider.cs to provide variant signs * Refactoring ISignProvider.cs to take an IEnumerable again * Moving code from controllers to factories * Refactoring HasPendingChangesSignProvider.cs to use the right Interface method * Refactoring HasScheduleSignProvider.cs to be less bloated, and more readable (hopefully) * Refactoring tests to look at variants and include a list * Changing instantiation to be better * Fixed minor logic issue in HasScheduleSignProvider.cs * Refactoring to include just 1 database call. * Adjusting tests to use the new methods. * Reverted breaking changes
This commit is contained in:
@@ -121,15 +121,4 @@ public abstract class ContentCollectionControllerBase<TContent, TCollectionRespo
|
||||
StatusCode = StatusCodes.Status500InternalServerError,
|
||||
},
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Populates the signs for the collection response models.
|
||||
/// </summary>
|
||||
protected async Task PopulateSigns(IEnumerable<TCollectionResponseModel> itemViewModels)
|
||||
{
|
||||
foreach (ISignProvider signProvider in _signProviders.Where(x => x.CanProvideSigns<TCollectionResponseModel>()))
|
||||
{
|
||||
await signProvider.PopulateSignsAsync(itemViewModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ public class ByKeyDocumentCollectionController : DocumentCollectionControllerBas
|
||||
}
|
||||
|
||||
List<DocumentCollectionResponseModel> collectionResponseModels = await _documentCollectionPresentationFactory.CreateCollectionModelAsync(collectionAttempt.Result!);
|
||||
await PopulateSigns(collectionResponseModels);
|
||||
return CollectionResult(collectionResponseModels, collectionAttempt.Result!.Items.Total);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,25 +17,14 @@ public class ItemDocumentItemController : DocumentItemControllerBase
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IDocumentPresentationFactory _documentPresentationFactory;
|
||||
private readonly SignProviderCollection _signProviders;
|
||||
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public ItemDocumentItemController(
|
||||
IEntityService entityService,
|
||||
IDocumentPresentationFactory documentPresentationFactory,
|
||||
SignProviderCollection signProvider)
|
||||
IDocumentPresentationFactory documentPresentationFactory)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_documentPresentationFactory = documentPresentationFactory;
|
||||
_signProviders = signProvider;
|
||||
}
|
||||
|
||||
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 18")]
|
||||
public ItemDocumentItemController(
|
||||
IEntityService entityService,
|
||||
IDocumentPresentationFactory documentPresentationFactory)
|
||||
: this(entityService, documentPresentationFactory, StaticServiceProvider.Instance.GetRequiredService<SignProviderCollection>())
|
||||
{
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -55,15 +44,6 @@ public class ItemDocumentItemController : DocumentItemControllerBase
|
||||
.OfType<IDocumentEntitySlim>();
|
||||
|
||||
IEnumerable<DocumentItemResponseModel> responseModels = documents.Select(_documentPresentationFactory.CreateItemResponseModel);
|
||||
await PopulateSigns(responseModels);
|
||||
return Ok(responseModels);
|
||||
}
|
||||
|
||||
private async Task PopulateSigns(IEnumerable<DocumentItemResponseModel> itemViewModels)
|
||||
{
|
||||
foreach (ISignProvider signProvider in _signProviders.Where(x => x.CanProvideSigns<DocumentItemResponseModel>()))
|
||||
{
|
||||
await signProvider.PopulateSignsAsync(itemViewModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,6 @@ public class ByKeyMediaCollectionController : MediaCollectionControllerBase
|
||||
}
|
||||
|
||||
List<MediaCollectionResponseModel> collectionResponseModels = await _mediaCollectionPresentationFactory.CreateCollectionModelAsync(collectionAttempt.Result!);
|
||||
await PopulateSigns(collectionResponseModels);
|
||||
return CollectionResult(collectionResponseModels, collectionAttempt.Result!.Items.Total);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.Services.Signs;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
@@ -13,9 +16,24 @@ public abstract class ContentCollectionPresentationFactory<TContent, TCollection
|
||||
where TValueResponseModelBase : ValueResponseModelBase
|
||||
where TVariantResponseModel : VariantResponseModelBase
|
||||
{
|
||||
private readonly SignProviderCollection _signProviderCollection;
|
||||
private readonly IUmbracoMapper _mapper;
|
||||
|
||||
protected ContentCollectionPresentationFactory(IUmbracoMapper mapper) => _mapper = mapper;
|
||||
[Obsolete("Please use the controller with all parameters, will be removed in Umbraco 18")]
|
||||
protected ContentCollectionPresentationFactory(IUmbracoMapper mapper)
|
||||
: this(
|
||||
mapper,
|
||||
StaticServiceProvider.Instance.GetRequiredService<SignProviderCollection>())
|
||||
{
|
||||
}
|
||||
|
||||
protected ContentCollectionPresentationFactory(
|
||||
IUmbracoMapper mapper,
|
||||
SignProviderCollection signProviderCollection)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_signProviderCollection = signProviderCollection;
|
||||
}
|
||||
|
||||
public async Task<List<TCollectionResponseModel>> CreateCollectionModelAsync(ListViewPagedModel<TContent> contentCollection)
|
||||
{
|
||||
@@ -36,8 +54,19 @@ public abstract class ContentCollectionPresentationFactory<TContent, TCollection
|
||||
|
||||
await SetUnmappedProperties(contentCollection, collectionResponseModels);
|
||||
|
||||
|
||||
await PopulateSigns(collectionResponseModels);
|
||||
|
||||
return collectionResponseModels;
|
||||
}
|
||||
|
||||
protected virtual Task SetUnmappedProperties(ListViewPagedModel<TContent> contentCollection, List<TCollectionResponseModel> collectionResponseModels) => Task.CompletedTask;
|
||||
|
||||
private async Task PopulateSigns(IEnumerable<TCollectionResponseModel> models)
|
||||
{
|
||||
foreach (ISignProvider signProvider in _signProviderCollection.Where(x => x.CanProvideSigns<TCollectionResponseModel>()))
|
||||
{
|
||||
await signProvider.PopulateSignsAsync(models);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.Mapping.Content;
|
||||
using Umbraco.Cms.Api.Management.Services.Signs;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentBlueprint.Item;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
@@ -23,7 +26,9 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
private readonly IPublicAccessService _publicAccessService;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IIdKeyMap _idKeyMap;
|
||||
private readonly SignProviderCollection _signProviderCollection;
|
||||
|
||||
[Obsolete("Please use the controller with all parameters. Scheduled for removal in Umbraco 18")]
|
||||
public DocumentPresentationFactory(
|
||||
IUmbracoMapper umbracoMapper,
|
||||
IDocumentUrlFactory documentUrlFactory,
|
||||
@@ -31,6 +36,25 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
IPublicAccessService publicAccessService,
|
||||
TimeProvider timeProvider,
|
||||
IIdKeyMap idKeyMap)
|
||||
: this(
|
||||
umbracoMapper,
|
||||
documentUrlFactory,
|
||||
templateService,
|
||||
publicAccessService,
|
||||
timeProvider,
|
||||
idKeyMap,
|
||||
StaticServiceProvider.Instance.GetRequiredService<SignProviderCollection>())
|
||||
{
|
||||
}
|
||||
|
||||
public DocumentPresentationFactory(
|
||||
IUmbracoMapper umbracoMapper,
|
||||
IDocumentUrlFactory documentUrlFactory,
|
||||
ITemplateService templateService,
|
||||
IPublicAccessService publicAccessService,
|
||||
TimeProvider timeProvider,
|
||||
IIdKeyMap idKeyMap,
|
||||
SignProviderCollection signProviderCollection)
|
||||
{
|
||||
_umbracoMapper = umbracoMapper;
|
||||
_documentUrlFactory = documentUrlFactory;
|
||||
@@ -38,6 +62,7 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
_publicAccessService = publicAccessService;
|
||||
_timeProvider = timeProvider;
|
||||
_idKeyMap = idKeyMap;
|
||||
_signProviderCollection = signProviderCollection;
|
||||
}
|
||||
|
||||
[Obsolete("Schedule for removal in v17")]
|
||||
@@ -105,6 +130,8 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
|
||||
responseModel.Variants = CreateVariantsItemResponseModels(entity);
|
||||
|
||||
PopulateSignsOnDocuments(responseModel);
|
||||
|
||||
return responseModel;
|
||||
}
|
||||
|
||||
@@ -125,23 +152,29 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
{
|
||||
if (entity.Variations.VariesByCulture() is false)
|
||||
{
|
||||
yield return new()
|
||||
var model = new DocumentVariantItemResponseModel()
|
||||
{
|
||||
Name = entity.Name ?? string.Empty,
|
||||
State = DocumentVariantStateHelper.GetState(entity, null),
|
||||
Culture = null,
|
||||
};
|
||||
|
||||
PopulateSignsOnVariants(model);
|
||||
yield return model;
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> cultureNamePair in entity.CultureNames)
|
||||
{
|
||||
yield return new()
|
||||
var model = new DocumentVariantItemResponseModel()
|
||||
{
|
||||
Name = cultureNamePair.Value,
|
||||
Culture = cultureNamePair.Key,
|
||||
State = DocumentVariantStateHelper.GetState(entity, cultureNamePair.Key)
|
||||
};
|
||||
|
||||
PopulateSignsOnVariants(model);
|
||||
yield return model;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,4 +289,20 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
|
||||
|
||||
return Attempt.SucceedWithStatus(ContentPublishingOperationStatus.Success, model);
|
||||
}
|
||||
|
||||
private void PopulateSignsOnDocuments(DocumentItemResponseModel model)
|
||||
{
|
||||
foreach (ISignProvider signProvider in _signProviderCollection.Where(x => x.CanProvideSigns<DocumentItemResponseModel>()))
|
||||
{
|
||||
signProvider.PopulateSignsAsync([model]).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateSignsOnVariants(DocumentVariantItemResponseModel model)
|
||||
{
|
||||
foreach (ISignProvider signProvider in _signProviderCollection.Where(x => x.CanProvideSigns<DocumentVariantItemResponseModel>()))
|
||||
{
|
||||
signProvider.PopulateSignsAsync([model]).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Services.Signs;
|
||||
@@ -17,15 +14,15 @@ public class HasPendingChangesSignProvider : ISignProvider
|
||||
/// <inheritdoc/>
|
||||
public bool CanProvideSigns<TItem>()
|
||||
where TItem : IHasSigns =>
|
||||
typeof(TItem) == typeof(DocumentTreeItemResponseModel) ||
|
||||
typeof(TItem) == typeof(DocumentCollectionResponseModel) ||
|
||||
typeof(TItem) == typeof(DocumentItemResponseModel);
|
||||
typeof(TItem) == typeof(DocumentVariantItemResponseModel) ||
|
||||
typeof(TItem) == typeof(DocumentVariantResponseModel);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task PopulateSignsAsync<TItem>(IEnumerable<TItem> itemViewModels)
|
||||
public Task PopulateSignsAsync<TItem>(IEnumerable<TItem> items)
|
||||
where TItem : IHasSigns
|
||||
{
|
||||
foreach (TItem item in itemViewModels)
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
if (HasPendingChanges(item))
|
||||
{
|
||||
@@ -39,11 +36,10 @@ public class HasPendingChangesSignProvider : ISignProvider
|
||||
/// <summary>
|
||||
/// Determines if the given item has any variant that has pending changes.
|
||||
/// </summary>
|
||||
private bool HasPendingChanges(object item) => item switch
|
||||
private static bool HasPendingChanges(object item) => item switch
|
||||
{
|
||||
DocumentTreeItemResponseModel { Variants: var v } when v.Any(x => x.State == DocumentVariantState.PublishedPendingChanges) => true,
|
||||
DocumentCollectionResponseModel { Variants: var v } when v.Any(x => x.State == DocumentVariantState.PublishedPendingChanges) => true,
|
||||
DocumentItemResponseModel { Variants: var v } when v.Any(x => x.State == DocumentVariantState.PublishedPendingChanges) => true,
|
||||
DocumentVariantItemResponseModel variant => variant.State == DocumentVariantState.PublishedPendingChanges,
|
||||
DocumentVariantResponseModel variant => variant.State == DocumentVariantState.PublishedPendingChanges,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
@@ -15,11 +18,16 @@ internal class HasScheduleSignProvider : ISignProvider
|
||||
private const string Alias = Constants.Conventions.Signs.Prefix + "ScheduledForPublish";
|
||||
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IIdKeyMap _keyMap;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HasScheduleSignProvider"/> class.
|
||||
/// </summary>
|
||||
public HasScheduleSignProvider(IContentService contentService) => _contentService = contentService;
|
||||
public HasScheduleSignProvider(IContentService contentService, IIdKeyMap keyMap)
|
||||
{
|
||||
_contentService = contentService;
|
||||
_keyMap = keyMap;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CanProvideSigns<TItem>()
|
||||
@@ -29,15 +37,89 @@ internal class HasScheduleSignProvider : ISignProvider
|
||||
typeof(TItem) == typeof(DocumentItemResponseModel);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task PopulateSignsAsync<TItem>(IEnumerable<TItem> itemViewModels)
|
||||
public Task PopulateSignsAsync<TItem>(IEnumerable<TItem> items)
|
||||
where TItem : IHasSigns
|
||||
{
|
||||
IEnumerable<Guid> contentKeysScheduledForPublishing = _contentService.GetScheduledContentKeys(itemViewModels.Select(x => x.Id));
|
||||
foreach (Guid key in contentKeysScheduledForPublishing)
|
||||
IDictionary<int, IEnumerable<ContentSchedule>> schedules = _contentService.GetContentSchedulesByIds(items.Select(x => x.Id).ToArray());
|
||||
foreach (TItem item in items)
|
||||
{
|
||||
itemViewModels.First(x => x.Id == key).AddSign(Alias);
|
||||
Attempt<int> itemId = _keyMap.GetIdForKey(item.Id, UmbracoObjectTypes.Document);
|
||||
if (itemId.Success is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!schedules.TryGetValue(itemId.Result, out IEnumerable<ContentSchedule>? contentSchedules))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case DocumentTreeItemResponseModel documentTreeItemResponseModel:
|
||||
documentTreeItemResponseModel.Variants = PopulateVariants(documentTreeItemResponseModel.Variants, contentSchedules);
|
||||
break;
|
||||
|
||||
case DocumentCollectionResponseModel documentCollectionResponseModel:
|
||||
documentCollectionResponseModel.Variants = PopulateVariants(documentCollectionResponseModel.Variants, contentSchedules);
|
||||
break;
|
||||
|
||||
case DocumentItemResponseModel documentItemResponseModel:
|
||||
documentItemResponseModel.Variants = PopulateVariants(documentItemResponseModel.Variants, contentSchedules);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private IEnumerable<DocumentVariantItemResponseModel> PopulateVariants(
|
||||
IEnumerable<DocumentVariantItemResponseModel> variants, IEnumerable<ContentSchedule> schedules)
|
||||
{
|
||||
DocumentVariantItemResponseModel[] variantsArray = variants.ToArray();
|
||||
if (variantsArray.Length == 1)
|
||||
{
|
||||
DocumentVariantItemResponseModel variant = variantsArray[0];
|
||||
variant.AddSign(Alias);
|
||||
return variantsArray;
|
||||
}
|
||||
|
||||
foreach (DocumentVariantItemResponseModel variant in variantsArray)
|
||||
{
|
||||
ContentSchedule? schedule = schedules.FirstOrDefault(x => x.Culture == variant.Culture);
|
||||
bool isScheduled = schedule != null && schedule.Date > DateTime.Now && string.Equals(schedule.Culture, variant.Culture);
|
||||
|
||||
if (isScheduled)
|
||||
{
|
||||
variant.AddSign(Alias);
|
||||
}
|
||||
}
|
||||
|
||||
return variantsArray;
|
||||
}
|
||||
|
||||
private IEnumerable<DocumentVariantResponseModel> PopulateVariants(
|
||||
IEnumerable<DocumentVariantResponseModel> variants, IEnumerable<ContentSchedule> schedules)
|
||||
{
|
||||
DocumentVariantResponseModel[] variantsArray = variants.ToArray();
|
||||
if (variantsArray.Length == 1)
|
||||
{
|
||||
DocumentVariantResponseModel variant = variantsArray[0];
|
||||
variant.AddSign(Alias);
|
||||
return variantsArray;
|
||||
}
|
||||
|
||||
foreach (DocumentVariantResponseModel variant in variantsArray)
|
||||
{
|
||||
ContentSchedule? schedule = schedules.FirstOrDefault(x => x.Culture == variant.Culture);
|
||||
bool isScheduled = schedule != null && schedule.Date > DateTime.Now && string.Equals(schedule.Culture, variant.Culture);
|
||||
|
||||
if (isScheduled)
|
||||
{
|
||||
variant.AddSign(Alias);
|
||||
}
|
||||
}
|
||||
|
||||
return variantsArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public interface ISignProvider
|
||||
/// Populates the provided item view models with signs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">Type of item view model supporting signs.</typeparam>
|
||||
/// <param name="itemViewModels">The collection of item view models to be populated with signs.</param>
|
||||
Task PopulateSignsAsync<TItem>(IEnumerable<TItem> itemViewModels)
|
||||
Task PopulateSignsAsync<TItem>(IEnumerable<TItem> items)
|
||||
where TItem : IHasSigns;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,25 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class DocumentVariantItemResponseModel : VariantItemResponseModelBase
|
||||
public class DocumentVariantItemResponseModel : VariantItemResponseModelBase, IHasSigns
|
||||
{
|
||||
private readonly List<SignModel> _signs = [];
|
||||
|
||||
public Guid Id { get; }
|
||||
|
||||
public IEnumerable<SignModel> Signs
|
||||
{
|
||||
get => _signs.AsEnumerable();
|
||||
set
|
||||
{
|
||||
_signs.Clear();
|
||||
_signs.AddRange(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSign(string alias) => _signs.Add(new SignModel { Alias = alias });
|
||||
|
||||
public void RemoveSign(string alias) => _signs.RemoveAll(x => x.Alias == alias);
|
||||
|
||||
public required DocumentVariantState State { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class DocumentVariantResponseModel : VariantResponseModelBase
|
||||
public class DocumentVariantResponseModel : VariantResponseModelBase, IHasSigns
|
||||
{
|
||||
public DocumentVariantState State { get; set; }
|
||||
|
||||
@@ -11,4 +11,22 @@ public class DocumentVariantResponseModel : VariantResponseModelBase
|
||||
public DateTimeOffset? ScheduledPublishDate { get; set; }
|
||||
|
||||
public DateTimeOffset? ScheduledUnpublishDate { get; set; }
|
||||
|
||||
private readonly List<SignModel> _signs = [];
|
||||
|
||||
public Guid Id { get; }
|
||||
|
||||
public IEnumerable<SignModel> Signs
|
||||
{
|
||||
get => _signs.AsEnumerable();
|
||||
set
|
||||
{
|
||||
_signs.Clear();
|
||||
_signs.AddRange(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSign(string alias) => _signs.Add(new SignModel { Alias = alias });
|
||||
|
||||
public void RemoveSign(string alias) => _signs.RemoveAll(x => x.Alias == alias);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Immutable;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
|
||||
@@ -53,11 +54,11 @@ public interface IDocumentRepository : IContentRepository<int, IContent>, IReadR
|
||||
/// <summary>
|
||||
/// Gets the content keys from the provided collection of keys that are scheduled for publishing.
|
||||
/// </summary>
|
||||
/// <param name="keys">The content keys.</param>
|
||||
/// <param name="documentIds">The IDs of the documents.</param>
|
||||
/// <returns>
|
||||
/// The provided collection of content keys filtered for those that are scheduled for publishing.
|
||||
/// </returns>
|
||||
IEnumerable<Guid> GetScheduledContentKeys(Guid[] keys) => [];
|
||||
IDictionary<int, IEnumerable<ContentSchedule>> GetContentSchedulesByIds(int[] documentIds) => ImmutableDictionary<int, IEnumerable<ContentSchedule>>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Get the count of published items
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -1009,18 +1010,29 @@ public class ContentService : RepositoryService, IContentService
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<Guid> GetScheduledContentKeys(IEnumerable<Guid> keys)
|
||||
public IDictionary<int, IEnumerable<ContentSchedule>> GetContentSchedulesByIds(Guid[] keys)
|
||||
{
|
||||
Guid[] idsA = keys.ToArray();
|
||||
if (idsA.Length == 0)
|
||||
if (keys.Length == 0)
|
||||
{
|
||||
return Enumerable.Empty<Guid>();
|
||||
return ImmutableDictionary<int, IEnumerable<ContentSchedule>>.Empty;
|
||||
}
|
||||
|
||||
List<int> contentIds = [];
|
||||
foreach (var key in keys)
|
||||
{
|
||||
Attempt<int> contentId = _idKeyMap.GetIdForKey(key, UmbracoObjectTypes.Document);
|
||||
if (contentId.Success is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
contentIds.Add(contentId.Result);
|
||||
}
|
||||
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
scope.ReadLock(Constants.Locks.ContentTree);
|
||||
return _documentRepository.GetScheduledContentKeys(idsA);
|
||||
return _documentRepository.GetContentSchedulesByIds(contentIds.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -276,13 +277,14 @@ public interface IContentService : IContentServiceBase<IContent>
|
||||
bool HasChildren(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content keys from the provided collection of keys that are scheduled for publishing.
|
||||
/// Gets a dictionary of content Ids and their matching content schedules.
|
||||
/// </summary>
|
||||
/// <param name="keys">The content keys.</param>
|
||||
/// <returns>
|
||||
/// The provided collection of content keys filtered for those that are scheduled for publishing.
|
||||
/// A dictionary with a nodeId and an IEnumerable of matching ContentSchedules.
|
||||
/// </returns>
|
||||
IEnumerable<Guid> GetScheduledContentKeys(IEnumerable<Guid> keys) => [];
|
||||
IDictionary<int, IEnumerable<ContentSchedule>> GetContentSchedulesByIds(Guid[] keys) => ImmutableDictionary<int, IEnumerable<ContentSchedule>>.Empty;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1672,24 +1672,30 @@ public class DocumentRepository : ContentRepositoryBase<int, IContent, DocumentR
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Guid> GetScheduledContentKeys(Guid[] keys)
|
||||
public IDictionary<int, IEnumerable<ContentSchedule>> GetContentSchedulesByIds(int[] documentIds)
|
||||
{
|
||||
var action = ContentScheduleAction.Release.ToString();
|
||||
DateTime now = DateTime.UtcNow;
|
||||
Sql<ISqlContext> sql = Sql()
|
||||
.Select<ContentScheduleDto>()
|
||||
.From<ContentScheduleDto>()
|
||||
.WhereIn<ContentScheduleDto>(contentScheduleDto => contentScheduleDto.NodeId, documentIds);
|
||||
|
||||
Sql<ISqlContext> sql = SqlContext.Sql();
|
||||
sql
|
||||
.Select<NodeDto>(x => x.UniqueId)
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentDto>().On<DocumentDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>().On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.WhereIn<NodeDto>(x => x.UniqueId, keys)
|
||||
.WhereIn<NodeDto>(x => x.NodeId, Sql()
|
||||
.Select<ContentScheduleDto>(x => x.NodeId)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x => x.Action == action && x.Date >= now));
|
||||
List<ContentScheduleDto>? contentScheduleDtos = Database.Fetch<ContentScheduleDto>(sql);
|
||||
|
||||
return Database.Fetch<Guid>(sql);
|
||||
IDictionary<int, IEnumerable<ContentSchedule>> dictionary = contentScheduleDtos
|
||||
.GroupBy(contentSchedule => contentSchedule.NodeId)
|
||||
.ToDictionary(
|
||||
group => group.Key,
|
||||
group => group.Select(scheduleDto => new ContentSchedule(
|
||||
scheduleDto.Id,
|
||||
LanguageRepository.GetIsoCodeById(scheduleDto.LanguageId) ?? Constants.System.InvariantCulture,
|
||||
scheduleDto.Date,
|
||||
scheduleDto.Action == ContentScheduleAction.Release.ToString()
|
||||
? ContentScheduleAction.Release
|
||||
: ContentScheduleAction.Expire))
|
||||
.ToList().AsEnumerable()); // We have to materialize it here,
|
||||
// to avoid this being used after the scope is disposed.
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -688,7 +688,7 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Scheduled_Content_Keys()
|
||||
public void Can_Get_Content_Schedules_By_Keys()
|
||||
{
|
||||
// Arrange
|
||||
var root = ContentService.GetById(Textpage.Id);
|
||||
@@ -699,11 +699,12 @@ internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
ContentService.Publish(content, content.AvailableCultures.ToArray());
|
||||
|
||||
// Act
|
||||
var keys = ContentService.GetScheduledContentKeys([Textpage.Key, Subpage.Key, Subpage2.Key]).ToList();
|
||||
var keys = ContentService.GetContentSchedulesByIds([Textpage.Key, Subpage.Key, Subpage2.Key]).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, keys.Count);
|
||||
Assert.AreEqual(Subpage.Key, keys.First());
|
||||
Assert.AreEqual(keys[0].Key, Subpage.Id);
|
||||
Assert.AreEqual(keys[0].Value.First().Id, contentSchedule.FullSchedule.First().Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -11,116 +11,76 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Signs;
|
||||
internal class HasPendingChangesSignProviderTests
|
||||
{
|
||||
[Test]
|
||||
public void HasPendingChangesSignProvider_Can_Provide_Document_Tree_Signs()
|
||||
public void HasPendingChangesSignProvider_Can_Provide_Variant_Item_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentTreeItemResponseModel>());
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentVariantItemResponseModel>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasPendingChangesSignProvider_Can_Provide_Document_Collection_Signs()
|
||||
public void HasPendingChangesSignProvider_Can_Provide_Variant_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentCollectionResponseModel>());
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentVariantResponseModel>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasPendingChangesSignProvider_Can_Provide_Document_Item_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentItemResponseModel>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task HasPendingChangesSignProvider_Should_Populate_Document_Tree_Signs()
|
||||
public async Task HasPendingChangesSignProvider_Should_Populate_Variant_Item_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
|
||||
var viewModels = new List<DocumentTreeItemResponseModel>
|
||||
var variants = new List<DocumentVariantItemResponseModel>
|
||||
{
|
||||
new() { Id = Guid.NewGuid() },
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(), Variants =
|
||||
[
|
||||
new()
|
||||
{
|
||||
State = DocumentVariantState.PublishedPendingChanges,
|
||||
Culture = null,
|
||||
Name = "Test",
|
||||
},
|
||||
],
|
||||
State = DocumentVariantState.PublishedPendingChanges,
|
||||
Culture = null,
|
||||
Name = "Test",
|
||||
},
|
||||
new()
|
||||
{
|
||||
State = DocumentVariantState.Published,
|
||||
Culture = null,
|
||||
Name = "Test2",
|
||||
},
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
await sut.PopulateSignsAsync(variants);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
Assert.AreEqual(variants[0].Signs.Count(), 1);
|
||||
Assert.AreEqual(variants[1].Signs.Count(), 0);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
var signModel = variants[0].Signs.First();
|
||||
Assert.AreEqual("Umb.PendingChanges", signModel.Alias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task HasPendingChangesSignProvider_Should_Populate_Document_Collection_Signs()
|
||||
public async Task HasPendingChangesSignProvider_Should_Populate_Variant_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
|
||||
var viewModels = new List<DocumentCollectionResponseModel>
|
||||
var variants = new List<DocumentVariantResponseModel>
|
||||
{
|
||||
new() { Id = Guid.NewGuid() },
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(), Variants =
|
||||
[
|
||||
new()
|
||||
{
|
||||
State = DocumentVariantState.PublishedPendingChanges,
|
||||
Culture = null,
|
||||
Name = "Test",
|
||||
},
|
||||
],
|
||||
State = DocumentVariantState.PublishedPendingChanges,
|
||||
Culture = null,
|
||||
Name = "Test",
|
||||
},
|
||||
new()
|
||||
{
|
||||
State = DocumentVariantState.Published,
|
||||
Culture = null,
|
||||
Name = "Test2",
|
||||
},
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
await sut.PopulateSignsAsync(variants);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
Assert.AreEqual(variants[0].Signs.Count(), 1);
|
||||
Assert.AreEqual(variants[1].Signs.Count(), 0);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
Assert.AreEqual("Umb.PendingChanges", signModel.Alias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task HasPendingChangesSignProvider_Should_Populate_Document_Item_Signs()
|
||||
{
|
||||
var sut = new HasPendingChangesSignProvider();
|
||||
|
||||
var viewModels = new List<DocumentItemResponseModel>
|
||||
{
|
||||
new() { Id = Guid.NewGuid() },
|
||||
new()
|
||||
{
|
||||
Id = Guid.NewGuid(), Variants =
|
||||
[
|
||||
new()
|
||||
{
|
||||
State = DocumentVariantState.PublishedPendingChanges,
|
||||
Culture = null,
|
||||
Name = "Test",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
var signModel = variants[0].Signs.First();
|
||||
Assert.AreEqual("Umb.PendingChanges", signModel.Alias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Services.Signs;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -16,8 +20,9 @@ internal class HasScheduleSignProviderTests
|
||||
public void HasScheduleSignProvider_Can_Provide_Document_Tree_Signs()
|
||||
{
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentTreeItemResponseModel>());
|
||||
}
|
||||
|
||||
@@ -25,8 +30,9 @@ internal class HasScheduleSignProviderTests
|
||||
public void HasScheduleSignProvider_Can_Provide_Document_Collection_Signs()
|
||||
{
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentCollectionResponseModel>());
|
||||
}
|
||||
|
||||
@@ -34,8 +40,9 @@ internal class HasScheduleSignProviderTests
|
||||
public void HasScheduleSignProvider_Can_Provide_Document_Item_Signs()
|
||||
{
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
Assert.IsTrue(sut.CanProvideSigns<DocumentItemResponseModel>());
|
||||
}
|
||||
|
||||
@@ -47,23 +54,37 @@ internal class HasScheduleSignProviderTests
|
||||
new() { Key = Guid.NewGuid(), Name = "Item 1" }, new() { Key = Guid.NewGuid(), Name = "Item 2" },
|
||||
};
|
||||
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[0].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(1));
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[1].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(2));
|
||||
|
||||
Guid[] keys = entities.Select(x => x.Key).ToArray();
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
contentServiceMock
|
||||
.Setup(x => x.GetScheduledContentKeys(It.IsAny<IEnumerable<Guid>>()))
|
||||
.Returns([entities[1].Key]);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
.Setup(x => x.GetContentSchedulesByIds(keys))
|
||||
.Returns(CreateContentSchedules());
|
||||
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
|
||||
var variant1 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
|
||||
var variant2 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
|
||||
var variant3 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.PublishedPendingChanges, Name = "Test" };
|
||||
|
||||
var viewModels = new List<DocumentTreeItemResponseModel>
|
||||
{
|
||||
new() { Id = entities[0].Key }, new() { Id = entities[1].Key },
|
||||
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
var signModel = viewModels[0].Variants.First().Signs.First();
|
||||
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
|
||||
}
|
||||
|
||||
@@ -75,23 +96,36 @@ internal class HasScheduleSignProviderTests
|
||||
new() { Key = Guid.NewGuid(), Name = "Item 1" }, new() { Key = Guid.NewGuid(), Name = "Item 2" },
|
||||
};
|
||||
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[0].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(1));
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[1].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(2));
|
||||
|
||||
Guid[] keys = entities.Select(x => x.Key).ToArray();
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
contentServiceMock
|
||||
.Setup(x => x.GetScheduledContentKeys(It.IsAny<IEnumerable<Guid>>()))
|
||||
.Returns([entities[1].Key]);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
.Setup(x => x.GetContentSchedulesByIds(keys))
|
||||
.Returns(CreateContentSchedules());
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
|
||||
var variant1 = new DocumentVariantResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
|
||||
var variant2 = new DocumentVariantResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
|
||||
var variant3 = new DocumentVariantResponseModel() { State = DocumentVariantState.PublishedPendingChanges, Name = "Test" };
|
||||
|
||||
var viewModels = new List<DocumentCollectionResponseModel>
|
||||
{
|
||||
new() { Id = entities[0].Key }, new() { Id = entities[1].Key },
|
||||
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
var signModel = viewModels[0].Variants.First().Signs.First();
|
||||
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
|
||||
}
|
||||
|
||||
@@ -103,23 +137,51 @@ internal class HasScheduleSignProviderTests
|
||||
new() { Key = Guid.NewGuid(), Name = "Item 1" }, new() { Key = Guid.NewGuid(), Name = "Item 2" },
|
||||
};
|
||||
|
||||
var idKeyMapMock = new Mock<IIdKeyMap>();
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[0].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(1));
|
||||
idKeyMapMock.Setup(x => x.GetIdForKey(entities[1].Key, UmbracoObjectTypes.Document))
|
||||
.Returns(Attempt.Succeed(2));
|
||||
|
||||
Guid[] keys = entities.Select(x => x.Key).ToArray();
|
||||
var contentServiceMock = new Mock<IContentService>();
|
||||
contentServiceMock
|
||||
.Setup(x => x.GetScheduledContentKeys(It.IsAny<IEnumerable<Guid>>()))
|
||||
.Returns([entities[1].Key]);
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object);
|
||||
.Setup(x => x.GetContentSchedulesByIds(keys))
|
||||
.Returns(CreateContentSchedules());
|
||||
|
||||
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
|
||||
|
||||
var variant1 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
|
||||
var variant2 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
|
||||
var variant3 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.PublishedPendingChanges, Name = "Test" };
|
||||
|
||||
var viewModels = new List<DocumentItemResponseModel>
|
||||
{
|
||||
new() { Id = entities[0].Key }, new() { Id = entities[1].Key },
|
||||
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
|
||||
};
|
||||
|
||||
await sut.PopulateSignsAsync(viewModels);
|
||||
|
||||
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
|
||||
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
|
||||
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
|
||||
|
||||
var signModel = viewModels[1].Signs.First();
|
||||
var signModel = viewModels[0].Variants.First().Signs.First();
|
||||
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
|
||||
}
|
||||
|
||||
private Dictionary<int, IEnumerable<ContentSchedule>> CreateContentSchedules()
|
||||
{
|
||||
Dictionary<int, IEnumerable<ContentSchedule>> contentSchedules = new Dictionary<int, IEnumerable<ContentSchedule>>();
|
||||
|
||||
contentSchedules.Add(1, [
|
||||
new ContentSchedule("en-EN", DateTime.Now.AddDays(1), ContentScheduleAction.Release), // Scheduled for release
|
||||
new ContentSchedule("da-DA", DateTime.Now.AddDays(-1), ContentScheduleAction.Release) // Not Scheduled for release
|
||||
]);
|
||||
contentSchedules.Add(2, [
|
||||
new ContentSchedule("*", DateTime.Now.AddDays(1), ContentScheduleAction.Release) // Scheduled for release
|
||||
]);
|
||||
|
||||
return contentSchedules;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user