Merge remote-tracking branch 'origin/release/15.0' into v15/dev

# Conflicts:
#	src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs
#	src/Umbraco.Web.UI.Client
#	tests/Umbraco.Tests.Common/Builders/MediaTypeEditingBuilder.cs
This commit is contained in:
Bjarke Berg
2024-10-10 11:11:08 +02:00
35 changed files with 833 additions and 126 deletions

View File

@@ -12,28 +12,28 @@
</ItemGroup>
<!-- Microsoft packages -->
<ItemGroup>
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0-preview.7.24406.2" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0-preview.9.24507.7" />
</ItemGroup>
<!-- Umbraco packages -->
<ItemGroup>
@@ -58,9 +58,9 @@
<PackageVersion Include="ncrontab" Version="3.3.3" />
<PackageVersion Include="NPoco" Version="5.7.1" />
<PackageVersion Include="NPoco.SqlServer" Version="5.7.1" />
<PackageVersion Include="OpenIddict.Abstractions" Version="5.8.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="5.8.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="5.8.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="6.0.0-preview1.24504.78" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="6.0.0-preview1.24504.78" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="6.0.0-preview1.24504.78" />
<PackageVersion Include="Serilog" Version="4.0.2" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.2" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="3.0.0" />
@@ -69,7 +69,7 @@
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact.Reader" Version="4.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.2" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="8.0.4" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.Map" Version="2.0.0" />
@@ -81,6 +81,8 @@
<ItemGroup>
<!-- Both Microsoft.EntityFrameworkCore.SqlServer and NPoco.SqlServer bring in a vulnerable version of Azure.Identity -->
<PackageVersion Include="Azure.Identity" Version="1.12.1" />
<!-- Both Microsoft.EntityFrameworkCore.SqlServer and NPoco.SqlServer bring in a vulnerable version of Azure.Identity -->
<PackageVersion Include="System.Runtime.Caching" Version="9.0.0-rc.2.24473.5" />
<!-- Dazinator.Extensions.FileProviders brings in a vulnerable version of System.Net.Http -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<!-- Examine brings in a vulnerable version of System.Security.Cryptography.Xml -->
@@ -88,9 +90,9 @@
<!-- Both Dazinator.Extensions.FileProviders and MiniProfiler.AspNetCore.Mvc bring in a vulnerable version of System.Text.RegularExpressions -->
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<!-- Both OpenIddict.AspNetCore, Npoco.SqlServer and Microsoft.EntityFrameworkCore.SqlServer bring in a vulnerable version of Microsoft.IdentityModel.JsonWebTokens -->
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
<!-- Both Azure.Identity, Microsoft.EntityFrameworkCore.SqlServer, Dazinator.Extensions.FileProviders bring in legacy versions of System.Text.Encodings.Web -->
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0-rc.2.24473.5" />
<!-- NPoco.SqlServer bring in vulnerable version of Microsoft.Data.SqlClient -->
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.2.2" />
</ItemGroup>

View File

@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100-rc.1.24452.12",
"version": "9.0.100-rc.2.24474.11",
"rollForward": "latestFeature",
"allowPrerelease": true
}

View File

@@ -41,7 +41,7 @@ public static class UmbracoBuilderAuthExtensions
.SetTokenEndpointUris(
Paths.MemberApi.TokenEndpoint.TrimStart(Constants.CharArrays.ForwardSlash),
Paths.BackOfficeApi.TokenEndpoint.TrimStart(Constants.CharArrays.ForwardSlash))
.SetLogoutEndpointUris(
.SetEndSessionEndpointUris(
Paths.MemberApi.LogoutEndpoint.TrimStart(Constants.CharArrays.ForwardSlash),
Paths.BackOfficeApi.LogoutEndpoint.TrimStart(Constants.CharArrays.ForwardSlash))
.SetRevocationEndpointUris(
@@ -62,7 +62,7 @@ public static class UmbracoBuilderAuthExtensions
.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableLogoutEndpointPassthrough();
.EnableEndSessionEndpointPassthrough();
// Enable reference tokens
// - see https://documentation.openiddict.com/configuration/token-storage.html

View File

@@ -41,7 +41,7 @@ public class MemberApplicationManager : OpenIdDictApplicationManagerBase, IMembe
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.EndSession,
OpenIddictConstants.Permissions.Endpoints.Revocation,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,

View File

@@ -132,7 +132,7 @@ public class BackOfficeApplicationManager : OpenIdDictApplicationManagerBase, IB
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.EndSession,
OpenIddictConstants.Permissions.Endpoints.Revocation,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,

View File

@@ -6,8 +6,12 @@
<ItemGroup>
<!-- Take top-level depedendency on Azure.Identity, because Microsoft.EntityFrameworkCore.SqlServer depends on a vulnerable version -->
<PackageReference Include="Azure.Identity" />
<!-- Take top-level depedendency on System.Runtime.Caching, because Microsoft.EntityFrameworkCore.SqlServer depends on a vulnerable version -->
<PackageReference Include="System.Runtime.Caching" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<!-- Both OpenIddict.AspNetCore, Npoco.SqlServer and Microsoft.EntityFrameworkCore.SqlServer bring in a vulnerable version of Microsoft.IdentityModel.JsonWebTokens -->
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens"/>
</ItemGroup>

View File

@@ -16,6 +16,8 @@
<!-- Take top-level depedendency on Azure.Identity, because Microsoft.EntityFrameworkCore.SqlServer depends on a vulnerable version -->
<PackageReference Include="Azure.Identity" />
<!-- Take top-level depedendency on System.Runtime.Caching, because Microsoft.EntityFrameworkCore.SqlServer depends on a vulnerable version -->
<PackageReference Include="System.Runtime.Caching" />
<!-- Both Azure.Identity, Microsoft.EntityFrameworkCore.SqlServer, Dazinator.Extensions.FileProviders bring in legacy versions of System.Text.Encodings.Web -->
<PackageReference Include="System.Text.Encodings.Web"/>

View File

@@ -18,7 +18,8 @@
<!-- Take top-level depedendency on Azure.Identity, because NPoco.SqlServer depends on a vulnerable version -->
<PackageReference Include="Azure.Identity" />
<PackageReference Include="NPoco.SqlServer" />
<!-- Take top-level depedendency on System.Runtime.Caching, because Microsoft.EntityFrameworkCore.SqlServer depends on a vulnerable version -->
<PackageReference Include="System.Runtime.Caching" />
<!-- Both OpenIddict.AspNetCore, Npoco.SqlServer and Microsoft.EntityFrameworkCore.SqlServer bring in a vulnerable version of Microsoft.IdentityModel.JsonWebTokens -->
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens"/>

View File

@@ -31,6 +31,7 @@
var allowPasswordReset = SecuritySettings.Value.AllowPasswordReset && EmailSender.CanSendRequiredEmail();
var disableLocalLogin = ExternalLogins.HasDenyLocalLogin();
}
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="@GlobalSettings.Value.DefaultUILanguage">
@@ -44,7 +45,7 @@
<meta name="pinterest" content="nopin"/>
<title>Umbraco</title>
<link rel="stylesheet" href="~/umbraco/backoffice/css/uui-css.css" />
<link rel="stylesheet" href="~/umbraco/backoffice/css/uui-css.css" asp-append-version="true" />
<style>
body {
margin: 0;
@@ -54,7 +55,7 @@
</style>
@await Html.BackOfficeImportMapScriptAsync(JsonSerializer, BackOfficePathGenerator, PackageManifestService)
<script type="module" src="~/umbraco/login/login.js"></script>
<script type="module" src="~/umbraco/login/login.js" asp-append-version="true"></script>
</head>
<body class="uui-font uui-text" style="margin: 0; padding: 0; overflow: hidden">

View File

@@ -14,6 +14,7 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
{
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
private readonly IIdKeyMap _idKeyMap;
public ContentTypeCacheRefresher(
@@ -23,12 +24,14 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
IContentTypeCommonRepository contentTypeCommonRepository,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IPublishedModelFactory publishedModelFactory)
IPublishedModelFactory publishedModelFactory,
IPublishedContentTypeFactory publishedContentTypeFactory)
: base(appCaches, serializer, eventAggregator, factory)
{
_idKeyMap = idKeyMap;
_contentTypeCommonRepository = contentTypeCommonRepository;
_publishedModelFactory = publishedModelFactory;
_publishedContentTypeFactory = publishedContentTypeFactory;
}
#region Json
@@ -114,6 +117,8 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
// TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
_publishedModelFactory.WithSafeLiveFactoryReset(() => { });
_publishedContentTypeFactory.NotifyDataTypeChanges();
// now we can trigger the event
base.Refresh(payloads);
}

View File

@@ -13,6 +13,7 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
{
private readonly IIdKeyMap _idKeyMap;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
public DataTypeCacheRefresher(
AppCaches appCaches,
@@ -20,11 +21,13 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
IIdKeyMap idKeyMap,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IPublishedModelFactory publishedModelFactory)
IPublishedModelFactory publishedModelFactory,
IPublishedContentTypeFactory publishedContentTypeFactory)
: base(appCaches, serializer, eventAggregator, factory)
{
_idKeyMap = idKeyMap;
_publishedModelFactory = publishedModelFactory;
_publishedContentTypeFactory = publishedContentTypeFactory;
}
#region Json
@@ -86,6 +89,9 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
// TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
_publishedModelFactory.WithSafeLiveFactoryReset(() => { });
var changedIds = payloads.Select(x => x.Id).ToArray();
_publishedContentTypeFactory.NotifyDataTypeChanges(changedIds);
base.Refresh(payloads);
}

View File

@@ -2,7 +2,9 @@
// See LICENSE for more details.
using System.Data;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Models.PublishedContent;
@@ -1909,5 +1911,491 @@ public static class PublishedContentExtensions
private static Dictionary<string, string> GetAliasesAndNames(IContentTypeBase? contentType) =>
contentType?.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name) ?? new Dictionary<string, string>();
#endregion
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? Ancestor(this IPublishedContent content, int maxLevel)
{
return content.Ancestor(GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? Ancestor(this IPublishedContent content, string contentTypeAlias)
{
return content.Ancestor(GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? Ancestor<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return Ancestor<T>(content, GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Ancestors(this IPublishedContent content, int maxLevel)
{
return content.Ancestors(GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Ancestors(this IPublishedContent content, string contentTypeAlias)
{
return content.Ancestors(GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Ancestors<T>(this IPublishedContent content)
where T : class, IPublishedContent
{
return Ancestors<T>(content, GetPublishedCache(content), GetNavigationQueryService(content));
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Ancestors<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return Ancestors<T>(content, GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel)
{
return AncestorOrSelf(content, GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias)
{
return AncestorOrSelf(content, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? AncestorOrSelf<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return AncestorOrSelf<T>(content, GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> AncestorsOrSelf(this IPublishedContent content, int maxLevel)
{
return content.AncestorsOrSelf(GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias)
{
return content.Ancestors(GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> AncestorsOrSelf<T>(this IPublishedContent content, int maxLevel)
where T : class, IPublishedContent
{
return AncestorsOrSelf<T>(content, GetPublishedCache(content), GetNavigationQueryService(content), maxLevel);
}
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> AncestorsOrSelf(this IPublishedContent content, bool orSelf,
Func<IPublishedContent, bool>? func)
{
return AncestorsOrSelf(content, GetPublishedCache(content), GetNavigationQueryService(content), orSelf, func);
}
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Breadcrumbs(
this IPublishedContent content,
bool andSelf = true) =>
content.Breadcrumbs(GetPublishedCache(content), GetNavigationQueryService(content), andSelf);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Breadcrumbs(
this IPublishedContent content,
int minLevel,
bool andSelf = true) =>
content.Breadcrumbs(GetPublishedCache(content), GetNavigationQueryService(content), minLevel, andSelf);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Breadcrumbs<T>(
this IPublishedContent content,
bool andSelf = true)
where T : class, IPublishedContent=>
content.Breadcrumbs<T>(GetPublishedCache(content), GetNavigationQueryService(content), andSelf);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Children(
this IPublishedContent content,
IVariationContextAccessor? variationContextAccessor,
string? culture = null)
=> Children(content, variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Children(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
Func<IPublishedContent, bool> predicate,
string? culture = null) =>
content.Children(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture).Where(predicate);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> ChildrenOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? contentTypeAlias,
string? culture = null) =>
content.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), x => x.ContentType.Alias.InvariantEquals(contentTypeAlias),
culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Children<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture).OfType<T>();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static DataTable ChildrenAsTable(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
IContentTypeService contentTypeService,
IMediaTypeService mediaTypeService,
IMemberTypeService memberTypeService,
IPublishedUrlProvider publishedUrlProvider,
string contentTypeAliasFilter = "",
string? culture = null)
=> GenerateDataTable(content, variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), contentTypeService, mediaTypeService, memberTypeService, publishedUrlProvider, contentTypeAliasFilter, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(
this IEnumerable<IPublishedContent> parentNodes,
IVariationContextAccessor variationContextAccessor,
string docTypeAlias,
string? culture = null) => parentNodes.SelectMany(x =>
x.DescendantsOrSelfOfType(variationContextAccessor, GetPublishedCache(parentNodes.First()),
GetNavigationQueryService(parentNodes.First()), docTypeAlias, culture));
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> DescendantsOrSelf<T>(
this IEnumerable<IPublishedContent> parentNodes,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
parentNodes.SelectMany(x => x.DescendantsOrSelf<T>(variationContextAccessor, GetPublishedCache(parentNodes.First()),
GetNavigationQueryService(parentNodes.First()), culture));
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Descendants(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, null, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Descendants(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, p => p.Level >= level, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> DescendantsOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias, string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Descendants<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.Descendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture).OfType<T>();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Descendants<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null)
where T : class, IPublishedContent =>
content.Descendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), level, culture).OfType<T>();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> DescendantsOrSelf(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, null, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> DescendantsOrSelf(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, p => p.Level >= level, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> DescendantsOrSelf<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture).OfType<T>();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> DescendantsOrSelf<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null)
where T : class, IPublishedContent =>
content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), level, culture).OfType<T>();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? Descendant(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
content.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? Descendant(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null) => content
.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, culture).FirstOrDefault(x => x.Level == level);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? DescendantOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) => content
.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, culture)
.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? Descendant<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), false, culture).FirstOrDefault(x => x is T) as T;
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? Descendant<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null)
where T : class, IPublishedContent =>
content.Descendant(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), level, culture) as T;
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? DescendantOrSelf(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null) => content
.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, culture).FirstOrDefault(x => x.Level == level);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? DescendantOrSelfOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) => content
.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, culture)
.FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias));
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? DescendantOrSelf<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), true, culture).FirstOrDefault(x => x is T) as T;
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? DescendantOrSelf<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
int level,
string? culture = null)
where T : class, IPublishedContent =>
content.DescendantOrSelf(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), level, culture) as T;
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? FirstChild(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
content.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? FirstChildOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) =>
content.ChildrenOfType(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), contentTypeAlias, culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? FirstChild(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
Func<IPublishedContent, bool> predicate,
string? culture = null)
=> content.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), predicate, culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IPublishedContent? FirstChild(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
Guid uniqueId,
string? culture = null) => content
.Children(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), x => x.Key == uniqueId, culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? FirstChild<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
content.Children<T>(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture)?.FirstOrDefault();
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static T? FirstChild<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
Func<T, bool> predicate,
string? culture = null)
where T : class, IPublishedContent =>
content.Children<T>(variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture)?.FirstOrDefault(predicate);
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> Siblings(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) =>
Siblings(content, GetPublishedCache(content), GetNavigationQueryService(content), variationContextAccessor, culture);
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> SiblingsOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) =>
SiblingsOfType(content, variationContextAccessor,
GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> Siblings<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent =>
Siblings<T>(content, variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent>? SiblingsAndSelf(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null) => SiblingsAndSelf(content, GetPublishedCache(content), GetNavigationQueryService(content), variationContextAccessor, culture);
[Obsolete(
"Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<IPublishedContent> SiblingsAndSelfOfType(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string contentTypeAlias,
string? culture = null) => SiblingsAndSelfOfType(content, variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), contentTypeAlias, culture);
[Obsolete("Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")]
public static IEnumerable<T> SiblingsAndSelf<T>(
this IPublishedContent content,
IVariationContextAccessor variationContextAccessor,
string? culture = null)
where T : class, IPublishedContent => SiblingsAndSelf<T>(content, variationContextAccessor, GetPublishedCache(content),
GetNavigationQueryService(content), culture);
private static INavigationQueryService GetNavigationQueryService(IPublishedContent content)
{
switch (content.ContentType.ItemType)
{
case PublishedItemType.Content:
return StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
case PublishedItemType.Media:
return StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
default:
throw new NotSupportedException("Unsupported content type.");
}
}
private static IPublishedCache GetPublishedCache(IPublishedContent content)
{
switch (content.ContentType.ItemType)
{
case PublishedItemType.Content:
return StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>();
case PublishedItemType.Media:
return StaticServiceProvider.Instance.GetRequiredService<IPublishedMediaCache>();
default:
throw new NotSupportedException("Unsupported content type.");
}
}
}

View File

@@ -11,7 +11,7 @@ public interface IPublishedContentCache : IPublishedCache
/// <param name="preview">A value indicating whether to consider unpublished content.</param>
/// <returns>The content, or null.</returns>
/// <remarks>Considers published or unpublished content depending on defaults.</remarks>
Task<IPublishedContent?> GetByIdAsync(int id, bool preview = false);
Task<IPublishedContent?> GetByIdAsync(int id, bool? preview = null);
/// <summary>
/// Gets a content identified by its unique identifier.
@@ -20,7 +20,7 @@ public interface IPublishedContentCache : IPublishedCache
/// <param name="preview">A value indicating whether to consider unpublished content.</param>
/// <returns>The content, or null.</returns>
/// <remarks>Considers published or unpublished content depending on defaults.</remarks>
Task<IPublishedContent?> GetByIdAsync(Guid key, bool preview = false);
Task<IPublishedContent?> GetByIdAsync(Guid key, bool? preview = null);
// FIXME: All these routing methods needs to be removed, as they are no longer part of the content cache
/// <summary>

View File

@@ -50,6 +50,22 @@ internal abstract class EntityTypeContainerService<TTreeEntity, TEntityContainer
return await Task.FromResult(_entityContainerRepository.Get(id));
}
/// <inheritdoc />
public async Task<IEnumerable<EntityContainer>> GetAsync(string name, int level)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
ReadLock(scope);
return await Task.FromResult(_entityContainerRepository.Get(name, level));
}
/// <inheritdoc />
public async Task<IEnumerable<EntityContainer>> GetAllAsync()
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
ReadLock(scope);
return await Task.FromResult(_entityContainerRepository.GetMany());
}
/// <inheritdoc />
public async Task<EntityContainer?> GetParentAsync(EntityContainer container)
=> await Task.FromResult(GetParent(container));

View File

@@ -14,6 +14,20 @@ public interface IEntityTypeContainerService<TTreeEntity>
/// <returns></returns>
Task<EntityContainer?> GetAsync(Guid id);
/// <summary>
/// Gets containers by name and level
/// </summary>
/// <param name="name">The name of the containers to get.</param>
/// <param name="level">The level in the tree of the containers to get.</param>
/// <returns></returns>
Task<IEnumerable<EntityContainer>> GetAsync(string name, int level);
/// <summary>
/// Gets all containers
/// </summary>
/// <returns></returns>
Task<IEnumerable<EntityContainer>> GetAllAsync();
/// <summary>
/// Gets the parent container of a container
/// </summary>

View File

@@ -15,5 +15,7 @@ public interface IPreviewService
/// </summary>
Task EndPreviewAsync();
bool IsInPreview();
Task<Attempt<ClaimsIdentity>> TryGetPreviewClaimsIdentityAsync();
}

View File

@@ -1,5 +1,6 @@
using System.Security.Claims;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Preview;
using Umbraco.Cms.Core.Security;
@@ -13,15 +14,18 @@ public class PreviewService : IPreviewService
private readonly ICookieManager _cookieManager;
private readonly IPreviewTokenGenerator _previewTokenGenerator;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IRequestCache _requestCache;
public PreviewService(
ICookieManager cookieManager,
IPreviewTokenGenerator previewTokenGenerator,
IServiceScopeFactory serviceScopeFactory)
IServiceScopeFactory serviceScopeFactory,
IRequestCache requestCache)
{
_cookieManager = cookieManager;
_previewTokenGenerator = previewTokenGenerator;
_serviceScopeFactory = serviceScopeFactory;
_requestCache = requestCache;
}
public async Task<bool> TryEnterPreviewAsync(IUser user)
@@ -42,6 +46,11 @@ public class PreviewService : IPreviewService
return Task.CompletedTask;
}
public bool IsInPreview() =>
_requestCache.Get(
"IsInPreview",
() => TryGetPreviewClaimsIdentityAsync().GetAwaiter().GetResult().Success) as bool? ?? false;
public async Task<Attempt<ClaimsIdentity>> TryGetPreviewClaimsIdentityAsync()
{
var cookieValue = _cookieManager.GetCookieValue(Constants.Web.PreviewCookieName);

View File

@@ -1,4 +1,5 @@
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Core;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0;
@@ -11,5 +12,10 @@ public class AddDocumentUrl : MigrationBase
}
protected override void Migrate()
=> Create.Table<DocumentUrlDto>().Do();
{
if (TableExists(Constants.DatabaseSchema.Tables.DocumentUrl) is false)
{
Create.Table<DocumentUrlDto>().Do();
}
}
}

View File

@@ -29,7 +29,9 @@ public static class UmbracoBuilderExtensions
/// </summary>
public static IUmbracoBuilder AddUmbracoHybridCache(this IUmbracoBuilder builder)
{
#pragma warning disable EXTEXP0018
builder.Services.AddHybridCache();
#pragma warning restore EXTEXP0018
builder.Services.AddSingleton<IDatabaseCacheRepository, DatabaseCacheRepository>();
builder.Services.AddSingleton<IPublishedContentCache, DocumentCache>();
builder.Services.AddSingleton<IPublishedMediaCache, MediaCache>();

View File

@@ -21,19 +21,19 @@ public sealed class DocumentCache : IPublishedContentCache
_publishedContentTypeCache = publishedContentTypeCache;
}
public async Task<IPublishedContent?> GetByIdAsync(int id, bool preview = false) => await _documentCacheService.GetByIdAsync(id, preview);
public async Task<IPublishedContent?> GetByIdAsync(int id, bool? preview = null) => await _documentCacheService.GetByIdAsync(id, preview);
public async Task<IPublishedContent?> GetByIdAsync(Guid key, bool preview = false) => await _documentCacheService.GetByKeyAsync(key, preview);
public async Task<IPublishedContent?> GetByIdAsync(Guid key, bool? preview = null) => await _documentCacheService.GetByKeyAsync(key, preview);
public IPublishedContent? GetById(bool preview, int contentId) => GetByIdAsync(contentId, preview).GetAwaiter().GetResult();
public IPublishedContent? GetById(bool preview, Guid contentId) => GetByIdAsync(contentId, preview).GetAwaiter().GetResult();
public IPublishedContent? GetById(int contentId) => GetByIdAsync(contentId, false).GetAwaiter().GetResult();
public IPublishedContent? GetById(int contentId) => GetByIdAsync(contentId).GetAwaiter().GetResult();
public IPublishedContent? GetById(Guid contentId) => GetByIdAsync(contentId, false).GetAwaiter().GetResult();
public IPublishedContent? GetById(Guid contentId) => GetByIdAsync(contentId).GetAwaiter().GetResult();
public IPublishedContentType? GetContentType(int id) => _publishedContentTypeCache.Get(PublishedItemType.Content, id);

View File

@@ -22,6 +22,7 @@ internal sealed class DocumentCacheService : IDocumentCacheService
private readonly ICacheNodeFactory _cacheNodeFactory;
private readonly IEnumerable<IDocumentSeedKeyProvider> _seedKeyProviders;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPreviewService _previewService;
private readonly CacheSettings _cacheSettings;
private HashSet<Guid>? _seedKeys;
@@ -54,7 +55,8 @@ internal sealed class DocumentCacheService : IDocumentCacheService
ICacheNodeFactory cacheNodeFactory,
IEnumerable<IDocumentSeedKeyProvider> seedKeyProviders,
IOptions<CacheSettings> cacheSettings,
IPublishedModelFactory publishedModelFactory)
IPublishedModelFactory publishedModelFactory,
IPreviewService previewService)
{
_databaseCacheRepository = databaseCacheRepository;
_idKeyMap = idKeyMap;
@@ -64,22 +66,30 @@ internal sealed class DocumentCacheService : IDocumentCacheService
_cacheNodeFactory = cacheNodeFactory;
_seedKeyProviders = seedKeyProviders;
_publishedModelFactory = publishedModelFactory;
_previewService = previewService;
_cacheSettings = cacheSettings.Value;
}
public async Task<IPublishedContent?> GetByKeyAsync(Guid key, bool preview = false)
public async Task<IPublishedContent?> GetByKeyAsync(Guid key, bool? preview = null)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope();
bool calculatedPreview = preview ?? GetPreview();
ContentCacheNode? contentCacheNode = await _hybridCache.GetOrCreateAsync(
GetCacheKey(key, preview), // Unique key to the cache entry
async cancel => await _databaseCacheRepository.GetContentSourceAsync(key, preview));
GetCacheKey(key, calculatedPreview), // Unique key to the cache entry
async cancel => await _databaseCacheRepository.GetContentSourceAsync(key, calculatedPreview));
scope.Complete();
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, preview).CreateModel(_publishedModelFactory);
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, calculatedPreview).CreateModel(_publishedModelFactory);
}
public async Task<IPublishedContent?> GetByIdAsync(int id, bool preview = false)
private bool GetPreview()
{
return _previewService.IsInPreview();
}
public async Task<IPublishedContent?> GetByIdAsync(int id, bool? preview = null)
{
Attempt<Guid> keyAttempt = _idKeyMap.GetKeyForId(id, UmbracoObjectTypes.Document);
if (keyAttempt.Success is false)
@@ -87,12 +97,14 @@ internal sealed class DocumentCacheService : IDocumentCacheService
return null;
}
bool calculatedPreview = preview ?? GetPreview();
using ICoreScope scope = _scopeProvider.CreateCoreScope();
ContentCacheNode? contentCacheNode = await _hybridCache.GetOrCreateAsync(
GetCacheKey(keyAttempt.Result, preview), // Unique key to the cache entry
async cancel => await _databaseCacheRepository.GetContentSourceAsync(id, preview));
GetCacheKey(keyAttempt.Result, calculatedPreview), // Unique key to the cache entry
async cancel => await _databaseCacheRepository.GetContentSourceAsync(id, calculatedPreview));
scope.Complete();
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, preview).CreateModel(_publishedModelFactory);;
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, calculatedPreview).CreateModel(_publishedModelFactory);;
}
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)

View File

@@ -5,9 +5,9 @@ namespace Umbraco.Cms.Infrastructure.HybridCache.Services;
public interface IDocumentCacheService
{
Task<IPublishedContent?> GetByKeyAsync(Guid key, bool preview = false);
Task<IPublishedContent?> GetByKeyAsync(Guid key, bool? preview = null);
Task<IPublishedContent?> GetByIdAsync(int id, bool preview = false);
Task<IPublishedContent?> GetByIdAsync(int id, bool? preview = null);
Task SeedAsync(CancellationToken cancellationToken);

View File

@@ -8,6 +8,7 @@ using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.HybridCache.Factories;
using Umbraco.Cms.Infrastructure.HybridCache.Persistence;
using Umbraco.Cms.Infrastructure.HybridCache.Serialization;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.HybridCache.Services;
@@ -20,6 +21,7 @@ internal class MediaCacheService : IMediaCacheService
private readonly IPublishedContentFactory _publishedContentFactory;
private readonly ICacheNodeFactory _cacheNodeFactory;
private readonly IEnumerable<IMediaSeedKeyProvider> _seedKeyProviders;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly CacheSettings _cacheSettings;
private HashSet<Guid>? _seedKeys;
@@ -51,6 +53,7 @@ internal class MediaCacheService : IMediaCacheService
IPublishedContentFactory publishedContentFactory,
ICacheNodeFactory cacheNodeFactory,
IEnumerable<IMediaSeedKeyProvider> seedKeyProviders,
IPublishedModelFactory publishedModelFactory,
IOptions<CacheSettings> cacheSettings)
{
_databaseCacheRepository = databaseCacheRepository;
@@ -60,6 +63,7 @@ internal class MediaCacheService : IMediaCacheService
_publishedContentFactory = publishedContentFactory;
_cacheNodeFactory = cacheNodeFactory;
_seedKeyProviders = seedKeyProviders;
_publishedModelFactory = publishedModelFactory;
_cacheSettings = cacheSettings.Value;
}
@@ -78,7 +82,7 @@ internal class MediaCacheService : IMediaCacheService
async cancel => await _databaseCacheRepository.GetMediaSourceAsync(idAttempt.Result));
scope.Complete();
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedMedia(contentCacheNode);
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedMedia(contentCacheNode).CreateModel(_publishedModelFactory);
}
public async Task<IPublishedContent?> GetByIdAsync(int id)
@@ -94,7 +98,7 @@ internal class MediaCacheService : IMediaCacheService
$"{keyAttempt.Result}", // Unique key to the cache entry
async cancel => await _databaseCacheRepository.GetMediaSourceAsync(id));
scope.Complete();
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedMedia(contentCacheNode);
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedMedia(contentCacheNode).CreateModel(_publishedModelFactory);
}
public async Task<bool> HasContentByIdAsync(int id)
@@ -144,7 +148,7 @@ internal class MediaCacheService : IMediaCacheService
foreach (Guid key in SeedKeys)
{
if(cancellationToken.IsCancellationRequested)
if (cancellationToken.IsCancellationRequested)
{
break;
}
@@ -187,7 +191,8 @@ internal class MediaCacheService : IMediaCacheService
private HybridCacheEntryOptions GetSeedEntryOptions() => new()
{
Expiration = _cacheSettings.SeedCacheDuration, LocalCacheExpiration = _cacheSettings.SeedCacheDuration,
Expiration = _cacheSettings.SeedCacheDuration,
LocalCacheExpiration = _cacheSettings.SeedCacheDuration,
};
private string GetCacheKey(Guid key, bool preview) => preview ? $"{key}+draft" : $"{key}";

View File

@@ -22,9 +22,15 @@ public static class FriendlyPublishedContentExtensions
private static IPublishedContentCache PublishedContentCache { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>();
private static IPublishedMediaCache PublishedMediaCache { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedMediaCache>();
private static IDocumentNavigationQueryService DocumentNavigationQueryService { get; } =
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
private static IMediaNavigationQueryService MediaNavigationQueryService { get; } =
StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
private static IPublishedModelFactory PublishedModelFactory { get; } =
StaticServiceProvider.Instance.GetRequiredService<IPublishedModelFactory>();
@@ -61,6 +67,33 @@ public static class FriendlyPublishedContentExtensions
private static IMemberTypeService MemberTypeService { get; } =
StaticServiceProvider.Instance.GetRequiredService<IMemberTypeService>();
private static INavigationQueryService GetNavigationQueryService(IPublishedContent content)
{
switch (content.ContentType.ItemType)
{
case PublishedItemType.Content:
return DocumentNavigationQueryService;
case PublishedItemType.Media:
return MediaNavigationQueryService;
default:
throw new NotSupportedException("Unsupported content type.");
}
}
private static IPublishedCache GetPublishedCache(IPublishedContent content)
{
switch (content.ContentType.ItemType)
{
case PublishedItemType.Content:
return PublishedContentCache;
case PublishedItemType.Media:
return PublishedMediaCache;
default:
throw new NotSupportedException("Unsupported content type.");
}
}
/// <summary>
/// Creates a strongly typed published content model for an internal published content.
/// </summary>
@@ -207,7 +240,7 @@ public static class FriendlyPublishedContentExtensions
/// set to 1.
/// </remarks>
public static IPublishedContent Root(this IPublishedContent content)
=> content.Root(PublishedContentCache, DocumentNavigationQueryService);
=> content.Root(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the root content (ancestor or self at level 1) for the specified <paramref name="content" /> if it's of the
@@ -226,7 +259,7 @@ public static class FriendlyPublishedContentExtensions
/// </remarks>
public static T? Root<T>(this IPublishedContent content)
where T : class, IPublishedContent
=> content.Root<T>(PublishedContentCache, DocumentNavigationQueryService);
=> content.Root<T>(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the parent of the content item.
@@ -236,7 +269,7 @@ public static class FriendlyPublishedContentExtensions
/// <returns>The parent of content of the specified content type or <c>null</c>.</returns>
public static T? Parent<T>(this IPublishedContent content)
where T : class, IPublishedContent
=> content.Parent<T>(PublishedContentCache, DocumentNavigationQueryService);
=> content.Parent<T>(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the ancestors of the content.
@@ -245,7 +278,7 @@ public static class FriendlyPublishedContentExtensions
/// <returns>The ancestors of the content, in down-top order.</returns>
/// <remarks>Does not consider the content itself.</remarks>
public static IEnumerable<IPublishedContent> Ancestors(this IPublishedContent content)
=> content.Ancestors(PublishedContentCache, DocumentNavigationQueryService);
=> content.Ancestors(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the content and its ancestors.
@@ -253,7 +286,7 @@ public static class FriendlyPublishedContentExtensions
/// <param name="content">The content.</param>
/// <returns>The content and its ancestors, in down-top order.</returns>
public static IEnumerable<IPublishedContent> AncestorsOrSelf(this IPublishedContent content)
=> content.AncestorsOrSelf(PublishedContentCache, DocumentNavigationQueryService);
=> content.AncestorsOrSelf(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the content and its ancestors, of a specified content type.
@@ -264,7 +297,7 @@ public static class FriendlyPublishedContentExtensions
/// <remarks>May or may not begin with the content itself, depending on its content type.</remarks>
public static IEnumerable<T> AncestorsOrSelf<T>(this IPublishedContent content)
where T : class, IPublishedContent
=> content.AncestorsOrSelf<T>(PublishedContentCache, DocumentNavigationQueryService);
=> content.AncestorsOrSelf<T>(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the ancestor of the content, i.e. its parent.
@@ -272,7 +305,7 @@ public static class FriendlyPublishedContentExtensions
/// <param name="content">The content.</param>
/// <returns>The ancestor of the content.</returns>
public static IPublishedContent? Ancestor(this IPublishedContent content)
=> content.Ancestor(PublishedContentCache, DocumentNavigationQueryService);
=> content.Ancestor(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the nearest ancestor of the content, of a specified content type.
@@ -283,7 +316,7 @@ public static class FriendlyPublishedContentExtensions
/// <remarks>Does not consider the content itself. May return <c>null</c>.</remarks>
public static T? Ancestor<T>(this IPublishedContent content)
where T : class, IPublishedContent
=> content.Ancestor<T>(PublishedContentCache, DocumentNavigationQueryService);
=> content.Ancestor<T>(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Gets the content or its nearest ancestor, of a specified content type.
@@ -294,7 +327,7 @@ public static class FriendlyPublishedContentExtensions
/// <remarks>May or may not return the content itself depending on its content type. May return <c>null</c>.</remarks>
public static T? AncestorOrSelf<T>(this IPublishedContent content)
where T : class, IPublishedContent
=> content.AncestorOrSelf<T>(PublishedContentCache, DocumentNavigationQueryService);
=> content.AncestorOrSelf<T>(GetPublishedCache(content), GetNavigationQueryService(content));
/// <summary>
/// Returns all DescendantsOrSelf of all content referenced
@@ -311,7 +344,7 @@ public static class FriendlyPublishedContentExtensions
/// </remarks>
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(
this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string? culture = null)
=> parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, docTypeAlias, culture);
=> parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), docTypeAlias, culture);
/// <summary>
/// Returns all DescendantsOrSelf of all content referenced
@@ -329,77 +362,77 @@ public static class FriendlyPublishedContentExtensions
this IEnumerable<IPublishedContent> parentNodes,
string? culture = null)
where T : class, IPublishedContent
=> parentNodes.DescendantsOrSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> parentNodes.DescendantsOrSelf<T>(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), culture);
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string? culture = null)
=> content.Descendants(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, int level, string? culture = null)
=> content.Descendants(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IEnumerable<IPublishedContent> DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.DescendantsOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.DescendantsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.Descendants<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Descendants<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, int level, string? culture = null)
where T : class, IPublishedContent
=> content.Descendants<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.Descendants<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IEnumerable<IPublishedContent> DescendantsOrSelf(
this IPublishedContent content,
string? culture = null)
=> content.DescendantsOrSelf(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, int level, string? culture = null)
=> content.DescendantsOrSelf(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.DescendantsOrSelfOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.DescendantsOrSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.DescendantsOrSelf<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, int level, string? culture = null)
where T : class, IPublishedContent
=> content.DescendantsOrSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.DescendantsOrSelf<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IPublishedContent? Descendant(this IPublishedContent content, string? culture = null)
=> content.Descendant(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IPublishedContent? Descendant(this IPublishedContent content, int level, string? culture = null)
=> content.Descendant(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IPublishedContent? DescendantOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.DescendantOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.DescendantOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
public static T? Descendant<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.Descendant<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Descendant<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static T? Descendant<T>(this IPublishedContent content, int level, string? culture = null)
where T : class, IPublishedContent
=> content.Descendant<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.Descendant<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string? culture = null)
=> content.DescendantOrSelf(VariationContextAccessor, culture);
public static IPublishedContent? DescendantOrSelf(this IPublishedContent content, int level, string? culture = null)
=> content.DescendantOrSelf(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
public static IPublishedContent? DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.DescendantOrSelfOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.DescendantOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
public static T? DescendantOrSelf<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.DescendantOrSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.DescendantOrSelf<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static T? DescendantOrSelf<T>(this IPublishedContent content, int level, string? culture = null)
where T : class, IPublishedContent
=> content.DescendantOrSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, level, culture);
=> content.DescendantOrSelf<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture);
/// <summary>
/// Gets the children of the content item.
@@ -427,7 +460,7 @@ public static class FriendlyPublishedContentExtensions
/// </para>
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string? culture = null)
=> content.Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
/// <summary>
/// Gets the children of the content, filtered by a predicate.
@@ -446,7 +479,7 @@ public static class FriendlyPublishedContentExtensions
this IPublishedContent content,
Func<IPublishedContent, bool> predicate,
string? culture = null)
=> content.Children(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, predicate, culture);
=> content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture);
/// <summary>
/// Gets the children of the content, of any of the specified types.
@@ -459,7 +492,7 @@ public static class FriendlyPublishedContentExtensions
/// <param name="contentTypeAlias">The content type alias.</param>
/// <returns>The children of the content, of any of the specified types.</returns>
public static IEnumerable<IPublishedContent>? ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.ChildrenOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.ChildrenOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
/// <summary>
/// Gets the children of the content, of a given content type.
@@ -476,30 +509,30 @@ public static class FriendlyPublishedContentExtensions
/// </remarks>
public static IEnumerable<T>? Children<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.Children<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Children<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static IPublishedContent? FirstChild(this IPublishedContent content, string? culture = null)
=> content.FirstChild(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
/// <summary>
/// Gets the first child of the content, of a given content type.
/// </summary>
public static IPublishedContent? FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.FirstChildOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.FirstChildOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
public static IPublishedContent? FirstChild(this IPublishedContent content, Func<IPublishedContent, bool> predicate, string? culture = null)
=> content.FirstChild(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, predicate, culture);
=> content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture);
public static IPublishedContent? FirstChild(this IPublishedContent content, Guid uniqueId, string? culture = null)
=> content.FirstChild(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, uniqueId, culture);
=> content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), uniqueId, culture);
public static T? FirstChild<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.FirstChild<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.FirstChild<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
public static T? FirstChild<T>(this IPublishedContent content, Func<T, bool> predicate, string? culture = null)
where T : class, IPublishedContent
=> content.FirstChild(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, predicate, culture);
=> content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture);
/// <summary>
/// Gets the siblings of the content.
@@ -514,7 +547,7 @@ public static class FriendlyPublishedContentExtensions
/// <para>Note that in V7 this method also return the content node self.</para>
/// </remarks>
public static IEnumerable<IPublishedContent>? Siblings(this IPublishedContent content, string? culture = null)
=> content.Siblings(PublishedContentCache, DocumentNavigationQueryService, VariationContextAccessor, culture);
=> content.Siblings(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, culture);
/// <summary>
/// Gets the siblings of the content, of a given content type.
@@ -530,7 +563,7 @@ public static class FriendlyPublishedContentExtensions
/// <para>Note that in V7 this method also return the content node self.</para>
/// </remarks>
public static IEnumerable<IPublishedContent>? SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null)
=> content.SiblingsOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.SiblingsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
/// <summary>
/// Gets the siblings of the content, of a given content type.
@@ -547,7 +580,7 @@ public static class FriendlyPublishedContentExtensions
/// </remarks>
public static IEnumerable<T>? Siblings<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.Siblings<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.Siblings<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position.
@@ -561,7 +594,7 @@ public static class FriendlyPublishedContentExtensions
public static IEnumerable<IPublishedContent>? SiblingsAndSelf(
this IPublishedContent content,
string? culture = null)
=> content.SiblingsAndSelf(PublishedContentCache, DocumentNavigationQueryService, VariationContextAccessor, culture);
=> content.SiblingsAndSelf(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, culture);
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
@@ -577,7 +610,7 @@ public static class FriendlyPublishedContentExtensions
this IPublishedContent content,
string contentTypeAlias,
string? culture = null)
=> content.SiblingsAndSelfOfType(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, contentTypeAlias, culture);
=> content.SiblingsAndSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture);
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
@@ -591,7 +624,7 @@ public static class FriendlyPublishedContentExtensions
/// <returns>The siblings of the content including the node itself, of the given content type.</returns>
public static IEnumerable<T>? SiblingsAndSelf<T>(this IPublishedContent content, string? culture = null)
where T : class, IPublishedContent
=> content.SiblingsAndSelf<T>(VariationContextAccessor, PublishedContentCache, DocumentNavigationQueryService, culture);
=> content.SiblingsAndSelf<T>(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture);
/// <summary>
/// Gets the url of the content item.
@@ -626,8 +659,8 @@ public static class FriendlyPublishedContentExtensions
=>
content.ChildrenAsTable(
VariationContextAccessor,
PublishedContentCache,
DocumentNavigationQueryService,
GetPublishedCache(content),
GetNavigationQueryService(content),
ContentTypeService,
MediaTypeService,
MemberTypeService,
@@ -700,4 +733,5 @@ public static class FriendlyPublishedContentExtensions
string term,
string? indexName = null)
=> content.SearchChildren(ExamineManager, UmbracoContextAccessor, term, indexName);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 KiB

After

Width:  |  Height:  |  Size: 286 KiB

View File

@@ -5,12 +5,12 @@
<ItemGroup>
<!-- Microsoft packages -->
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageVersion Include="System.Data.Odbc" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Data.Odbc" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Data.OleDb" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
@@ -22,4 +22,4 @@
<PackageVersion Include="NUnit" Version="3.14.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" PrivateAssets="all" />
</ItemGroup>
</Project>
</Project>

View File

@@ -232,7 +232,8 @@ public static class BuilderExtensions
return builder;
}
public static T WithPropertyValues<T>(this T builder, object propertyValues, string? culture = null, string? segment = null)
public static T WithPropertyValues<T>(this T builder, object propertyValues, string? culture = null,
string? segment = null)
where T : IWithPropertyValues
{
builder.PropertyValues = propertyValues;

View File

@@ -41,7 +41,8 @@ public class MediaTypeEditingBuilder : ContentTypeEditingBaseBuilder<MediaTypeEd
.Build();
}
public static MediaTypeCreateModel CreateBasicFolderMediaType(string alias = "basicFolder", string name = "BasicFolder")
public static MediaTypeCreateModel CreateBasicFolderMediaType(string alias = "basicFolder",
string name = "BasicFolder")
{
var builder = new MediaTypeEditingBuilder();
return (MediaTypeCreateModel)builder

View File

@@ -4,16 +4,16 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers;
public class ContentTypeUpdateHelper
public static class ContentTypeUpdateHelper
{
public ContentTypeUpdateModel CreateContentTypeUpdateModel(IContentType contentType)
public static ContentTypeUpdateModel CreateContentTypeUpdateModel(IContentType contentType)
{
var updateModel = new ContentTypeUpdateModel();
var model = MapBaseProperties<ContentTypeUpdateModel>(contentType, updateModel);
return model;
}
private T MapBaseProperties<T>(IContentType contentType, T model) where T : ContentTypeModelBase
private static T MapBaseProperties<T>(IContentType contentType, T model) where T : ContentTypeModelBase
{
model.Alias = contentType.Alias;
model.Name = contentType.Name;

View File

@@ -67,8 +67,7 @@ public abstract class UmbracoIntegrationTestWithContentEditing : UmbracoIntegrat
Assert.IsTrue(contentTypeAttempt.Success);
var contentTypeResult = contentTypeAttempt.Result;
ContentTypeUpdateHelper contentTypeUpdateHelper = new ContentTypeUpdateHelper();
ContentTypeUpdateModel = contentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult); ContentTypeUpdateModel.AllowedContentTypes = new[]
ContentTypeUpdateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult); ContentTypeUpdateModel.AllowedContentTypes = new[]
{
new ContentTypeSort(contentTypeResult.Key, 0, ContentTypeCreateModel.Alias),
};

View File

@@ -37,8 +37,7 @@ public class PublishedContentTypeCacheTests : UmbracoIntegrationTestWithContentE
Assert.IsNotNull(contentType);
Assert.AreEqual(1, ContentType.PropertyTypes.Count());
// Update the content type
ContentTypeUpdateHelper contentTypeUpdateHelper = new ContentTypeUpdateHelper();
var updateModel = contentTypeUpdateHelper.CreateContentTypeUpdateModel(ContentType);
var updateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(ContentType);
updateModel.Properties = new List<ContentTypePropertyTypeModel>();
await ContentTypeEditingService.UpdateAsync(ContentType, updateModel, Constants.Security.SuperUserKey);

View File

@@ -0,0 +1,98 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.ContentTypeEditing;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.TestHelpers;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.PublishedContent;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class PublishContentTypeFactoryTest : UmbracoIntegrationTest
{
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
builder.AddNotificationHandler<ContentTypeChangedNotification, ContentTypeChangedDistributedCacheNotificationHandler>();
builder.AddNotificationHandler<DataTypeSavedNotification, DataTypeSavedDistributedCacheNotificationHandler>();
builder.Services.AddUnique<IServerMessenger, ContentEventsTests.LocalServerMessenger>();
base.CustomTestSetup(builder);
}
private ITemplateService TemplateService => GetRequiredService<ITemplateService>();
private IContentTypeEditingService ContentTypeEditingService => GetRequiredService<IContentTypeEditingService>();
private IDataTypeService DataTypeService => GetRequiredService<IDataTypeService>();
private IPublishedContentTypeFactory PublishedContentTypeFactory => GetRequiredService<IPublishedContentTypeFactory>();
[Test]
public async Task Can_Update_Content_Type()
{
// Create a content type
var template = TemplateBuilder.CreateTextPageTemplate("defaultTemplate");
await TemplateService.CreateAsync(template, Constants.Security.SuperUserKey);
var contentTypeCreateModel = ContentTypeEditingBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateKey: template.Key);
var contentTypeAttempt = await ContentTypeEditingService.CreateAsync(contentTypeCreateModel, Constants.Security.SuperUserKey);
Assert.IsTrue(contentTypeAttempt.Success);
Assert.IsNotNull(contentTypeAttempt.Result);
// Fetch the content type to cache data types
var contentType = contentTypeAttempt.Result;
PublishedContentTypeFactory.CreateContentType(contentType);
var dataType = new DataTypeBuilder()
.WithId(0)
.Build();
var dataTypeCreateResult = await DataTypeService.CreateAsync(dataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeCreateResult.Success);
contentType.AddPropertyGroup("group", "Group");
var propertyTypeAlias = "test";
var propertyType = new PropertyTypeBuilder()
.WithAlias(propertyTypeAlias)
.WithDataTypeId(dataTypeCreateResult.Result.Id)
.Build();
propertyType.DataTypeKey = dataType.Key;
contentType.AddPropertyType(propertyType, "group", "Group");
// Update the content type
var contentTypeUpdate = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentType);
var updateResult = await ContentTypeEditingService.UpdateAsync(contentType, contentTypeUpdate, Constants.Security.SuperUserKey);
Assert.IsTrue(updateResult.Success);
var publishedContentType = PublishedContentTypeFactory.CreateContentType(updateResult.Result);
Assert.That(publishedContentType.PropertyTypes.Where(x => x.Alias == propertyTypeAlias), Is.Not.Empty);
}
[Test]
public async Task Can_Get_Updated_Datatype()
{
var dataType = new DataTypeBuilder()
.WithId(0)
.Build();
dataType.EditorUiAlias = "NotUpdated";
var dataTypeCreateResult = await DataTypeService.CreateAsync(dataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeCreateResult.Success);
var createdDataType = dataTypeCreateResult.Result;
PublishedDataType createdPublishedDataType = PublishedContentTypeFactory.GetDataType(createdDataType.Id);
Assert.That(createdPublishedDataType.EditorUiAlias, Is.EqualTo("NotUpdated"));
createdDataType.EditorUiAlias = "Updated";
var dataTypeUpdateResult = await DataTypeService.UpdateAsync(createdDataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeUpdateResult.Success);
var updatedPublishedDataType = PublishedContentTypeFactory.GetDataType(createdDataType.Id);
Assert.That(updatedPublishedDataType.EditorUiAlias, Is.EqualTo("Updated"));
}
}

View File

@@ -104,7 +104,8 @@ public class DocumentHybridCacheMockTests : UmbracoIntegrationTestWithContent
GetRequiredService<ICacheNodeFactory>(),
GetSeedProviders(),
Options.Create(new CacheSettings()),
GetRequiredService<IPublishedModelFactory>());
GetRequiredService<IPublishedModelFactory>(),
GetRequiredService<IPreviewService>());
_mockedCache = new DocumentCache(_mockDocumentCacheService, GetRequiredService<IPublishedContentTypeCache>());
}

View File

@@ -1,4 +1,4 @@
using NUnit.Framework;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.PublishedCache;
@@ -36,7 +36,6 @@ public class DocumentHybridCacheTemplateTests : UmbracoIntegrationTestWithConten
// Assert
Assert.AreEqual(updateContentResult.Status, ContentEditingOperationStatus.Success);
var textPageAfter = await PublishedContentHybridCache.GetByIdAsync(TextpageId, true);
// Should this not be null?
Assert.AreEqual(textPageAfter.TemplateId, null);
}
}