Merge remote-tracking branch 'origin/v13/dev' into v14/dev
# Conflicts: # Directory.Build.props # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
This commit is contained in:
@@ -34,7 +34,7 @@ public class ArtifactDependency
|
||||
/// <value>
|
||||
/// <c>true</c> if the dependency is included when building a dependency tree and gets deployed in the correct order; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool Ordering { get; }
|
||||
public bool Ordering { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dependency mode.
|
||||
@@ -42,7 +42,7 @@ public class ArtifactDependency
|
||||
/// <value>
|
||||
/// The dependency mode.
|
||||
/// </value>
|
||||
public ArtifactDependencyMode Mode { get; }
|
||||
public ArtifactDependencyMode Mode { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the checksum.
|
||||
|
||||
@@ -21,25 +21,39 @@ public class ArtifactDependencyCollection : ICollection<ArtifactDependency>
|
||||
/// <inheritdoc />
|
||||
public void Add(ArtifactDependency item)
|
||||
{
|
||||
if (item.Mode == ArtifactDependencyMode.Exist &&
|
||||
_dependencies.TryGetValue(item.Udi, out ArtifactDependency? existingItem) &&
|
||||
existingItem.Mode == ArtifactDependencyMode.Match)
|
||||
if (_dependencies.TryGetValue(item.Udi, out ArtifactDependency? existingItem))
|
||||
{
|
||||
// Don't downgrade dependency mode from Match to Exist
|
||||
return;
|
||||
}
|
||||
// Update existing item
|
||||
if (existingItem.Mode is ArtifactDependencyMode.Exist)
|
||||
{
|
||||
// Allow updating dependency mode from Exist to Match
|
||||
existingItem.Mode = item.Mode;
|
||||
}
|
||||
|
||||
_dependencies[item.Udi] = item;
|
||||
if (existingItem.Ordering is false)
|
||||
{
|
||||
// Allow updating non-ordering to ordering
|
||||
existingItem.Ordering = item.Ordering;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(item.Checksum) is false)
|
||||
{
|
||||
// Allow updating checksum if set
|
||||
existingItem.Checksum = item.Checksum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new item
|
||||
_dependencies[item.Udi] = item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear() => _dependencies.Clear();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(ArtifactDependency item)
|
||||
=> _dependencies.TryGetValue(item.Udi, out ArtifactDependency? existingItem) &&
|
||||
// Check whether it has the same or higher dependency mode
|
||||
(existingItem.Mode == item.Mode || existingItem.Mode == ArtifactDependencyMode.Match);
|
||||
public bool Contains(ArtifactDependency item) => _dependencies.ContainsKey(item.Udi);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(ArtifactDependency[] array, int arrayIndex) => _dependencies.Values.CopyTo(array, arrayIndex);
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Manifest;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Sync;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.PreMigration;
|
||||
|
||||
// we use a composer here so its easier to clean this up when we no longer need it.
|
||||
// same for additional classes in the same file, nice and self contained
|
||||
// should only be used to migrate from v13 to v14
|
||||
// ⚠️ FIXME: PLEASE DELETE THIS IN V14! ⚠️
|
||||
public class DataTypeSplitDataCollectorComposer : IComposer
|
||||
{
|
||||
public void Compose(IUmbracoBuilder builder)
|
||||
{
|
||||
builder.AddNotificationHandler<UmbracoApplicationStartedNotification, DataTypeSplitDataCollector>();
|
||||
}
|
||||
}
|
||||
|
||||
public class DataTypeSplitDataCollector : INotificationHandler<UmbracoApplicationStartedNotification>
|
||||
{
|
||||
private readonly DataEditorCollection _dataEditors;
|
||||
private readonly IManifestParser _manifestParser;
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
private readonly IKeyValueService _keyValueService;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly ILogger<DataTypeSplitDataCollector> _logger;
|
||||
private readonly ICoreScopeProvider _coreScopeProvider;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerRoleAccessor _serverRoleAccessor;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
|
||||
public DataTypeSplitDataCollector(
|
||||
DataEditorCollection dataEditors,
|
||||
IManifestParser manifestParser,
|
||||
IDataTypeService dataTypeService,
|
||||
IKeyValueService keyValueService,
|
||||
IJsonSerializer jsonSerializer,
|
||||
ILogger<DataTypeSplitDataCollector> logger,
|
||||
ICoreScopeProvider coreScopeProvider,
|
||||
IRuntimeState runtimeState,
|
||||
IServerRoleAccessor serverRoleAccessor,
|
||||
IUmbracoVersion umbracoVersion)
|
||||
{
|
||||
_dataEditors = dataEditors;
|
||||
_manifestParser = manifestParser;
|
||||
_dataTypeService = dataTypeService;
|
||||
_keyValueService = keyValueService;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_logger = logger;
|
||||
_coreScopeProvider = coreScopeProvider;
|
||||
_runtimeState = runtimeState;
|
||||
_serverRoleAccessor = serverRoleAccessor;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
}
|
||||
|
||||
public void Handle(UmbracoApplicationStartedNotification notification)
|
||||
{
|
||||
// should only be used to collect data in v13
|
||||
if (_umbracoVersion.Version.Major is not 13)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// only run this if the application is actually running and not in an install/upgrade state
|
||||
if (_runtimeState.Level != RuntimeLevel.Run)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// do not run on load balanced subscribers
|
||||
if (_serverRoleAccessor.CurrentServerRole == ServerRole.Subscriber)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var manifestEditorsData = _manifestParser.CombinedManifest.PropertyEditors
|
||||
.Select(pe => new EditorAliasSplitData(pe.Alias){EditorUiAlias = pe.Alias, EditorAlias = EditorAliasFromValueEditorValueType(pe.GetValueEditor().ValueType)})
|
||||
.ToDictionary(data => data.OriginalEditorAlias);
|
||||
|
||||
_logger.LogDebug("Found {count} custom PropertyEditor(s) configured trough manifest files",manifestEditorsData.Count);
|
||||
|
||||
var fromCodeEditorsData = _dataEditors
|
||||
.Where(de =>
|
||||
de.GetType().Assembly.GetName().FullName
|
||||
.StartsWith("umbraco.core", StringComparison.InvariantCultureIgnoreCase) is false
|
||||
&& de.GetType().Assembly.GetName().FullName
|
||||
.StartsWith("umbraco.infrastructure", StringComparison.InvariantCultureIgnoreCase) is false)
|
||||
.Select(de => new EditorAliasSplitData(de.Alias) { EditorAlias = de.Alias })
|
||||
.ToDictionary(data => data.OriginalEditorAlias);
|
||||
|
||||
_logger.LogDebug("Found {count} custom PropertyEditor(s) configured trough code",fromCodeEditorsData.Count);
|
||||
|
||||
var combinedEditorsData = new Dictionary<string, EditorAliasSplitData>(manifestEditorsData);
|
||||
foreach (KeyValuePair<string,EditorAliasSplitData> pair in fromCodeEditorsData)
|
||||
{
|
||||
combinedEditorsData.Add(pair.Key,pair.Value);
|
||||
}
|
||||
|
||||
if (combinedEditorsData.Any() == false)
|
||||
{
|
||||
_logger.LogDebug("No custom PropertyEditors found, skipping collection datatype migration data.");
|
||||
return;
|
||||
}
|
||||
|
||||
using ICoreScope coreScope = _coreScopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
IEnumerable<IDataType> dataTypes = _dataTypeService.GetAll();
|
||||
|
||||
DataTypeEditorAliasMigrationData[] migrationData = dataTypes
|
||||
.Where(dt => combinedEditorsData.ContainsKey(dt.EditorAlias))
|
||||
.Select(dt => new DataTypeEditorAliasMigrationData
|
||||
{
|
||||
DataTypeId = dt.Id,
|
||||
EditorAlias = combinedEditorsData[dt.EditorAlias].EditorAlias,
|
||||
EditorUiAlias = combinedEditorsData[dt.EditorAlias].EditorUiAlias
|
||||
}).ToArray();
|
||||
|
||||
_logger.LogDebug("Collected migration data for {count} DataType(s) that use custom PropertyEditors",migrationData.Length);
|
||||
|
||||
_keyValueService.SetValue("migrateDataEditorSplitCollectionData",_jsonSerializer.Serialize(migrationData));
|
||||
}
|
||||
|
||||
private class EditorAliasSplitData
|
||||
{
|
||||
public EditorAliasSplitData(string originalEditorAlias)
|
||||
{
|
||||
OriginalEditorAlias = originalEditorAlias;
|
||||
}
|
||||
|
||||
public string OriginalEditorAlias { get; init; }
|
||||
public string? EditorUiAlias { get; init; }
|
||||
public string? EditorAlias { get; init; }
|
||||
}
|
||||
|
||||
private class DataTypeEditorAliasMigrationData
|
||||
{
|
||||
public int DataTypeId { get; set; }
|
||||
public string? EditorUiAlias { get; init; }
|
||||
public string? EditorAlias { get; init; }
|
||||
}
|
||||
|
||||
private string EditorAliasFromValueEditorValueType(string valueType)
|
||||
{
|
||||
switch (valueType)
|
||||
{
|
||||
case ValueTypes.Date: return "Umbraco.Plain.DateTime";
|
||||
case ValueTypes.DateTime: return "Umbraco.Plain.DateTime";
|
||||
case ValueTypes.Decimal: return "Umbraco.Plain.Decimal";
|
||||
case ValueTypes.Integer: return "Umbraco.Plain.Integer";
|
||||
case ValueTypes.Bigint: return "Umbraco.Plain.Integer";
|
||||
case ValueTypes.Json: return "Umbraco.Plain.Json";
|
||||
case ValueTypes.Time: return "Umbraco.Plain.Time";
|
||||
case ValueTypes.String: return "Umbraco.Plain.String";
|
||||
case ValueTypes.Xml: return "Umbraco.Plain.String";
|
||||
default:return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1229,8 +1229,11 @@ AND umbracoNode.id <> @id",
|
||||
/// If this is not done, then in some cases the "edited" value for a particular culture for a document will remain true
|
||||
/// when it should be false
|
||||
/// if the property was changed to invariant. In order to do this we need to recalculate this value based on the values
|
||||
/// stored for each
|
||||
/// property, culture and current/published version.
|
||||
/// stored for each property, culture and current/published version.
|
||||
///
|
||||
/// Some of the sql statements in this function have a tendency to take a lot of parameters (nodeIds)
|
||||
/// as the WhereIn Npoco method translates all the nodeIds being passed in as parameters when using the SqlClient provider.
|
||||
/// this results in to many parameters (>2100) error => We need to batch the calls
|
||||
/// </remarks>
|
||||
private void RenormalizeDocumentEditedFlags(
|
||||
IReadOnlyCollection<int> propertyTypeIds,
|
||||
@@ -1386,16 +1389,19 @@ AND umbracoNode.id <> @id",
|
||||
// Now bulk update the table DocumentCultureVariationDto, once for edited = true, another for edited = false
|
||||
foreach (IGrouping<bool, DocumentCultureVariationDto> editValue in toUpdate.GroupBy(x => x.Edited))
|
||||
{
|
||||
Database.Execute(Sql().Update<DocumentCultureVariationDto>(u => u.Set(x => x.Edited, editValue.Key))
|
||||
.WhereIn<DocumentCultureVariationDto>(x => x.Id, editValue.Select(x => x.Id)));
|
||||
// update in batches to account for maximum parameter count
|
||||
foreach (IEnumerable<DocumentCultureVariationDto> batchedValues in editValue.InGroupsOf(Constants.Sql.MaxParameterCount))
|
||||
{
|
||||
Database.Execute(Sql().Update<DocumentCultureVariationDto>(u => u.Set(x => x.Edited, editValue.Key))
|
||||
.WhereIn<DocumentCultureVariationDto>(x => x.Id, batchedValues.Select(x => x.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
// Now bulk update the umbracoDocument table
|
||||
// we need to do this in batches as the WhereIn Npoco method translates to all the nodeIds being passed in as parameters when using the SqlClient provider
|
||||
// this results in to many parameters (>2100) being passed to the client when there are a lot of documents being normalized
|
||||
foreach (IGrouping<bool, KeyValuePair<int, bool>> groupByValue in editedDocument.GroupBy(x => x.Value))
|
||||
{
|
||||
foreach (IEnumerable<KeyValuePair<int, bool>> batch in groupByValue.InGroupsOf(2000))
|
||||
// update in batches to account for maximum parameter count
|
||||
foreach (IEnumerable<KeyValuePair<int, bool>> batch in groupByValue.InGroupsOf(Constants.Sql.MaxParameterCount))
|
||||
{
|
||||
Database.Execute(Sql().Update<DocumentDto>(u => u.Set(x => x.Edited, groupByValue.Key))
|
||||
.WhereIn<DocumentDto>(x => x.NodeId, batch.Select(x => x.Key)));
|
||||
|
||||
@@ -778,6 +778,7 @@ public class ContentController : ContentControllerBase
|
||||
/// <param name="contentId">The content id to copy</param>
|
||||
/// <param name="name">The name of the blueprint</param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionCreateBlueprintFromId)]
|
||||
[HttpPost]
|
||||
public ActionResult<SimpleNotificationModel> CreateBlueprintFromContent(
|
||||
[FromQuery] int contentId,
|
||||
@@ -833,7 +834,9 @@ public class ContentController : ContentControllerBase
|
||||
/// <summary>
|
||||
/// Saves content
|
||||
/// </summary>
|
||||
[ContentSaveValidation]
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
|
||||
[FileUploadCleanupFilter]
|
||||
[ContentSaveValidation(skipUserAccessValidation:true)] // skip user access validation because we "only" require Settings access to create new blueprints from scratch
|
||||
public async Task<ActionResult<ContentItemDisplay<ContentVariantDisplay>?>?> PostSaveBlueprint(
|
||||
[ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem)
|
||||
{
|
||||
@@ -1993,6 +1996,7 @@ public class ContentController : ContentControllerBase
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public IActionResult DeleteBlueprint(int id)
|
||||
|
||||
@@ -180,6 +180,13 @@ public static partial class UmbracoBuilderExtensions
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionDelete.ActionLetter));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionCreateBlueprintFromId, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(backOfficeAuthenticationScheme);
|
||||
policy.Requirements.Add(
|
||||
new ContentPermissionsQueryStringRequirement(ActionCreateBlueprintFromContent.ActionLetter, "contentId"));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.BackOfficeAccess, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(backOfficeAuthenticationScheme);
|
||||
|
||||
@@ -20,9 +20,12 @@ namespace Umbraco.Cms.Web.BackOffice.Filters;
|
||||
/// </summary>
|
||||
internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
|
||||
{
|
||||
public ContentSaveValidationAttribute() : base(typeof(ContentSaveValidationFilter)) =>
|
||||
public ContentSaveValidationAttribute(bool skipUserAccessValidation = false)
|
||||
: base(typeof(ContentSaveValidationFilter))
|
||||
{
|
||||
Order = -3000; // More important than ModelStateInvalidFilter.FilterOrder
|
||||
|
||||
Arguments = new object[] { skipUserAccessValidation };
|
||||
}
|
||||
|
||||
private sealed class ContentSaveValidationFilter : IAsyncActionFilter
|
||||
{
|
||||
@@ -32,6 +35,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
private readonly IPropertyValidationService _propertyValidationService;
|
||||
private readonly bool _skipUserAccessValidation;
|
||||
|
||||
|
||||
public ContentSaveValidationFilter(
|
||||
@@ -40,7 +44,8 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
|
||||
IPropertyValidationService propertyValidationService,
|
||||
IAuthorizationService authorizationService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
ILocalizationService localizationService)
|
||||
ILocalizationService localizationService,
|
||||
bool skipUserAccessValidation)
|
||||
{
|
||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
|
||||
@@ -49,6 +54,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
|
||||
_authorizationService = authorizationService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_localizationService = localizationService;
|
||||
_skipUserAccessValidation = skipUserAccessValidation;
|
||||
}
|
||||
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
@@ -88,7 +94,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await ValidateUserAccessAsync(model, context))
|
||||
if (_skipUserAccessValidation is false && await ValidateUserAccessAsync(model, context) is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public static class AuthorizationPolicies
|
||||
public const string ContentPermissionProtectById = nameof(ContentPermissionProtectById);
|
||||
public const string ContentPermissionBrowseById = nameof(ContentPermissionBrowseById);
|
||||
public const string ContentPermissionDeleteById = nameof(ContentPermissionDeleteById);
|
||||
public const string ContentPermissionCreateBlueprintFromId = nameof(ContentPermissionCreateBlueprintFromId);
|
||||
|
||||
public const string MediaPermissionByResource = nameof(MediaPermissionByResource);
|
||||
public const string MediaPermissionPathById = nameof(MediaPermissionPathById);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<!-- Update template.json files with the default UmbracoVersion value set to the current build version -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Umbraco.JsonSchema.Extensions" PrivateAssets="all" />
|
||||
|
||||
@@ -58,21 +58,64 @@ public class IndexInitializer
|
||||
_contentTypeService = contentTypeService;
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor that is not obsolete. This will be removed in Umbraco 15.")]
|
||||
public IndexInitializer(
|
||||
IShortStringHelper shortStringHelper,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
MediaUrlGeneratorCollection mediaUrlGenerators,
|
||||
IScopeProvider scopeProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<ContentSettings> contentSettings, IContentTypeService contentTypeService)
|
||||
IOptions<ContentSettings> contentSettings,
|
||||
ILocalizationService localizationService)
|
||||
: this(
|
||||
shortStringHelper,
|
||||
propertyEditors,
|
||||
mediaUrlGenerators,
|
||||
scopeProvider,
|
||||
loggerFactory,
|
||||
contentSettings,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>(), contentTypeService)
|
||||
shortStringHelper,
|
||||
propertyEditors,
|
||||
mediaUrlGenerators,
|
||||
scopeProvider,
|
||||
loggerFactory,
|
||||
contentSettings,
|
||||
localizationService, StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor that is not obsolete. This will be removed in Umbraco 15.")]
|
||||
public IndexInitializer(
|
||||
IShortStringHelper shortStringHelper,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
MediaUrlGeneratorCollection mediaUrlGenerators,
|
||||
IScopeProvider scopeProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<ContentSettings> contentSettings,
|
||||
IContentTypeService contentTypeService)
|
||||
: this(
|
||||
shortStringHelper,
|
||||
propertyEditors,
|
||||
mediaUrlGenerators,
|
||||
scopeProvider,
|
||||
loggerFactory,
|
||||
contentSettings,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>(), contentTypeService)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor that is not obsolete. This will be removed in Umbraco 15.")]
|
||||
public IndexInitializer(
|
||||
IShortStringHelper shortStringHelper,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
MediaUrlGeneratorCollection mediaUrlGenerators,
|
||||
IScopeProvider scopeProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<ContentSettings> contentSettings)
|
||||
: this(
|
||||
shortStringHelper,
|
||||
propertyEditors,
|
||||
mediaUrlGenerators,
|
||||
scopeProvider,
|
||||
loggerFactory,
|
||||
contentSettings,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
@@ -49,6 +47,71 @@ public class ArtifactBaseTests
|
||||
string.Join(",", artifact.Dependencies.Select(x => x.Udi.ToString())));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Dependencies_Correctly_Updates_Mode()
|
||||
{
|
||||
var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, Guid.NewGuid());
|
||||
|
||||
var dependencies = new ArtifactDependencyCollection
|
||||
{
|
||||
// Keep Match
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Match),
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist),
|
||||
};
|
||||
|
||||
Assert.AreEqual(1, dependencies.Count);
|
||||
var dependency = dependencies.First();
|
||||
Assert.AreEqual(udi, dependency.Udi);
|
||||
Assert.AreEqual(false, dependency.Ordering);
|
||||
Assert.AreEqual(ArtifactDependencyMode.Match, dependency.Mode);
|
||||
Assert.AreEqual(null, dependency.Checksum);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Dependencies_Correctly_Updates_Ordering()
|
||||
{
|
||||
var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, Guid.NewGuid());
|
||||
|
||||
var dependencies = new ArtifactDependencyCollection
|
||||
{
|
||||
// Keep ordering (regardless of mode)
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Match),
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist),
|
||||
new ArtifactDependency(udi, true, ArtifactDependencyMode.Match),
|
||||
new ArtifactDependency(udi, true, ArtifactDependencyMode.Exist),
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Match),
|
||||
new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist),
|
||||
};
|
||||
|
||||
Assert.AreEqual(1, dependencies.Count);
|
||||
var dependency = dependencies.First();
|
||||
Assert.AreEqual(udi, dependency.Udi);
|
||||
Assert.AreEqual(true, dependency.Ordering);
|
||||
Assert.AreEqual(ArtifactDependencyMode.Match, dependency.Mode);
|
||||
Assert.AreEqual(null, dependency.Checksum);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Dependencies_Correctly_Updates_Checksum()
|
||||
{
|
||||
var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, Guid.NewGuid());
|
||||
|
||||
var dependencies = new ArtifactDependencyCollection
|
||||
{
|
||||
// Keep checksum
|
||||
new ArtifactDependency(udi, true, ArtifactDependencyMode.Match, "123"),
|
||||
new ArtifactDependency(udi, true, ArtifactDependencyMode.Match, string.Empty),
|
||||
new ArtifactDependency(udi, true, ArtifactDependencyMode.Match),
|
||||
};
|
||||
|
||||
Assert.AreEqual(1, dependencies.Count);
|
||||
var dependency = dependencies.First();
|
||||
Assert.AreEqual(udi, dependency.Udi);
|
||||
Assert.AreEqual(true, dependency.Ordering);
|
||||
Assert.AreEqual(ArtifactDependencyMode.Match, dependency.Mode);
|
||||
Assert.AreEqual("123", dependency.Checksum);
|
||||
}
|
||||
|
||||
private class TestArtifact : ArtifactBase<GuidUdi>
|
||||
{
|
||||
public TestArtifact(GuidUdi udi, IEnumerable<ArtifactDependency> dependencies = null)
|
||||
|
||||
Reference in New Issue
Block a user