2021-03-15 13:39:34 +11:00
using System ;
2018-05-02 14:52:00 +10:00
using System.Collections.Generic ;
2016-05-26 17:12:04 +02:00
using System.Linq ;
2021-03-12 21:48:24 +01:00
using Umbraco.Cms.Core.Events ;
2021-02-18 11:06:02 +01:00
using Umbraco.Cms.Core.Models ;
2021-05-11 14:33:49 +02:00
using Umbraco.Cms.Core.Notifications ;
2021-02-18 11:06:02 +01:00
using Umbraco.Cms.Core.Persistence.Repositories ;
using Umbraco.Cms.Core.PublishedCache ;
using Umbraco.Cms.Core.Serialization ;
using Umbraco.Cms.Core.Services ;
using Umbraco.Cms.Core.Services.Changes ;
using Umbraco.Extensions ;
2016-05-26 17:12:04 +02:00
2021-02-18 11:06:02 +01:00
namespace Umbraco.Cms.Core.Cache
2016-05-26 17:12:04 +02:00
{
2021-03-12 21:48:24 +01:00
public sealed class ContentCacheRefresher : PayloadCacheRefresherBase < ContentCacheRefresherNotification , ContentCacheRefresher . JsonPayload >
2016-05-26 17:12:04 +02:00
{
2017-10-31 12:48:24 +01:00
private readonly IPublishedSnapshotService _publishedSnapshotService ;
2020-01-22 14:09:20 +01:00
private readonly IIdKeyMap _idKeyMap ;
2018-05-02 14:52:00 +10:00
private readonly IDomainService _domainService ;
2016-05-26 17:12:04 +02:00
2021-03-12 21:48:24 +01:00
public ContentCacheRefresher (
AppCaches appCaches ,
IJsonSerializer serializer ,
IPublishedSnapshotService publishedSnapshotService ,
IIdKeyMap idKeyMap ,
IDomainService domainService ,
2021-03-15 13:39:34 +11:00
IEventAggregator eventAggregator ,
ICacheRefresherNotificationFactory factory )
: base ( appCaches , serializer , eventAggregator , factory )
2016-05-26 17:12:04 +02:00
{
2017-10-31 12:48:24 +01:00
_publishedSnapshotService = publishedSnapshotService ;
2020-01-22 14:09:20 +01:00
_idKeyMap = idKeyMap ;
2018-05-02 14:52:00 +10:00
_domainService = domainService ;
2016-05-26 17:12:04 +02:00
}
#region Define
public static readonly Guid UniqueId = Guid . Parse ( "900A4FBE-DF3C-41E6-BB77-BE896CD158EA" ) ;
public override Guid RefresherUniqueId = > UniqueId ;
public override string Name = > "ContentCacheRefresher" ;
#endregion
#region Refresher
public override void Refresh ( JsonPayload [ ] payloads )
{
2019-01-17 11:01:23 +01:00
AppCaches . RuntimeCache . ClearOfType < PublicAccessEntry > ( ) ;
2021-03-25 11:49:38 +01:00
AppCaches . RuntimeCache . ClearByKey ( CacheKeys . ContentRecycleBinCacheKey ) ;
2016-11-03 10:31:44 +01:00
2018-05-02 14:52:00 +10:00
var idsRemoved = new HashSet < int > ( ) ;
2019-01-17 11:01:23 +01:00
var isolatedCache = AppCaches . IsolatedCaches . GetOrCreate < IContent > ( ) ;
2018-05-02 14:52:00 +10:00
2019-06-21 15:48:10 +10:00
foreach ( var payload in payloads . Where ( x = > x . Id ! = default ) )
2016-05-26 17:12:04 +02:00
{
2019-09-27 10:49:48 +02:00
//By INT Id
Implements Public Access in netcore (#10137)
* Getting new netcore PublicAccessChecker in place
* Adds full test coverage for PublicAccessChecker
* remove PublicAccessComposer
* adjust namespaces, ensure RoleManager works, separate public access controller, reduce content controller
* Implements the required methods on IMemberManager, removes old migrated code
* Updates routing to be able to re-route, Fixes middleware ordering ensuring endpoints are last, refactors pipeline options, adds public access middleware, ensures public access follows all hops
* adds note
* adds note
* Cleans up ext methods, ensures that members identity is added on both front-end and back ends. updates how UmbracoApplicationBuilder works in that it explicitly starts endpoints at the time of calling.
* Changes name to IUmbracoEndpointBuilder
* adds note
* Fixing tests, fixing error describers so there's 2x one for back office, one for members, fixes TryConvertTo, fixes login redirect
* fixing build
* Fixes keepalive, fixes PublicAccessMiddleware to not throw, updates startup code to be more clear and removes magic that registers middleware.
* adds note
* removes unused filter, fixes build
* fixes WebPath and tests
* Looks up entities in one query
* remove usings
* Fix test, remove stylesheet
* Set status code before we write to response to avoid error
* Ensures that users and members are validated when logging in. Shares more code between users and members.
* Fixes RepositoryCacheKeys to ensure the keys are normalized
* oops didn't mean to commit this
* Fix casing issues with caching, stop boxing value types for all cache operations, stop re-creating string keys in DefaultRepositoryCachePolicy
* bah, far out this keeps getting recommitted. sorry
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-04-20 15:11:45 +10:00
isolatedCache . Clear ( RepositoryCacheKeys . GetKey < IContent , int > ( payload . Id ) ) ;
2019-09-27 10:49:48 +02:00
//By GUID Key
Implements Public Access in netcore (#10137)
* Getting new netcore PublicAccessChecker in place
* Adds full test coverage for PublicAccessChecker
* remove PublicAccessComposer
* adjust namespaces, ensure RoleManager works, separate public access controller, reduce content controller
* Implements the required methods on IMemberManager, removes old migrated code
* Updates routing to be able to re-route, Fixes middleware ordering ensuring endpoints are last, refactors pipeline options, adds public access middleware, ensures public access follows all hops
* adds note
* adds note
* Cleans up ext methods, ensures that members identity is added on both front-end and back ends. updates how UmbracoApplicationBuilder works in that it explicitly starts endpoints at the time of calling.
* Changes name to IUmbracoEndpointBuilder
* adds note
* Fixing tests, fixing error describers so there's 2x one for back office, one for members, fixes TryConvertTo, fixes login redirect
* fixing build
* Fixes keepalive, fixes PublicAccessMiddleware to not throw, updates startup code to be more clear and removes magic that registers middleware.
* adds note
* removes unused filter, fixes build
* fixes WebPath and tests
* Looks up entities in one query
* remove usings
* Fix test, remove stylesheet
* Set status code before we write to response to avoid error
* Ensures that users and members are validated when logging in. Shares more code between users and members.
* Fixes RepositoryCacheKeys to ensure the keys are normalized
* oops didn't mean to commit this
* Fix casing issues with caching, stop boxing value types for all cache operations, stop re-creating string keys in DefaultRepositoryCachePolicy
* bah, far out this keeps getting recommitted. sorry
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-04-20 15:11:45 +10:00
isolatedCache . Clear ( RepositoryCacheKeys . GetKey < IContent , Guid ? > ( payload . Key ) ) ;
2016-05-26 17:12:04 +02:00
2020-01-22 14:09:20 +01:00
_idKeyMap . ClearCache ( payload . Id ) ;
2018-03-29 20:01:14 +11:00
2016-05-26 17:12:04 +02:00
// remove those that are in the branch
if ( payload . ChangeTypes . HasTypesAny ( TreeChangeTypes . RefreshBranch | TreeChangeTypes . Remove ) )
{
var pathid = "," + payload . Id + "," ;
2022-01-21 11:43:58 +01:00
isolatedCache . ClearOfType < IContent > ( ( k , v ) = > v . Path ? . Contains ( pathid ) ? ? false ) ;
2016-05-26 17:12:04 +02:00
}
2018-05-02 14:52:00 +10:00
//if the item is being completely removed, we need to refresh the domains cache if any domain was assigned to the content
if ( payload . ChangeTypes . HasTypesAny ( TreeChangeTypes . Remove ) )
{
idsRemoved . Add ( payload . Id ) ;
}
}
if ( idsRemoved . Count > 0 )
{
2022-02-28 13:14:02 +01:00
var assignedDomains = _domainService . GetAll ( true ) ? . Where ( x = > x . RootContentId . HasValue & & idsRemoved . Contains ( x . RootContentId . Value ) ) . ToList ( ) ;
2018-05-02 14:52:00 +10:00
2022-02-28 13:14:02 +01:00
if ( assignedDomains ? . Count > 0 )
2018-05-02 14:52:00 +10:00
{
2019-01-26 10:52:19 -05:00
// TODO: this is duplicating the logic in DomainCacheRefresher BUT we cannot inject that into this because it it not registered explicitly in the container,
2018-05-02 14:52:00 +10:00
// and we cannot inject the CacheRefresherCollection since that would be a circular reference, so what is the best way to call directly in to the
// DomainCacheRefresher?
ClearAllIsolatedCacheByEntityType < IDomain > ( ) ;
// note: must do what's above FIRST else the repositories still have the old cached
// content and when the PublishedCachesService is notified of changes it does not see
// the new content...
// notify
_publishedSnapshotService . Notify ( assignedDomains . Select ( x = > new DomainCacheRefresher . JsonPayload ( x . Id , DomainChangeTypes . Remove ) ) . ToArray ( ) ) ;
}
2016-05-26 17:12:04 +02:00
}
// note: must do what's above FIRST else the repositories still have the old cached
// content and when the PublishedCachesService is notified of changes it does not see
// the new content...
2019-01-27 01:17:32 -05:00
// TODO: what about this?
2017-09-19 15:51:47 +02:00
// should rename it, and then, this is only for Deploy, and then, ???
//if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
// ...
2019-10-14 15:21:00 +11:00
NotifyPublishedSnapshotService ( _publishedSnapshotService , AppCaches , payloads ) ;
2016-05-26 17:12:04 +02:00
base . Refresh ( payloads ) ;
}
// these events should never trigger
// everything should be PAYLOAD/JSON
2019-10-14 15:21:00 +11:00
public override void RefreshAll ( ) = > throw new NotSupportedException ( ) ;
2016-05-26 17:12:04 +02:00
2019-10-14 15:21:00 +11:00
public override void Refresh ( int id ) = > throw new NotSupportedException ( ) ;
2016-05-26 17:12:04 +02:00
2019-10-14 15:21:00 +11:00
public override void Refresh ( Guid id ) = > throw new NotSupportedException ( ) ;
2016-05-26 17:12:04 +02:00
2019-10-14 15:21:00 +11:00
public override void Remove ( int id ) = > throw new NotSupportedException ( ) ;
2016-05-26 17:12:04 +02:00
#endregion
#region Json
2019-10-14 15:21:00 +11:00
/// <summary>
/// Refreshes the publish snapshot service and if there are published changes ensures that partial view caches are refreshed too
/// </summary>
/// <param name="service"></param>
/// <param name="appCaches"></param>
/// <param name="payloads"></param>
internal static void NotifyPublishedSnapshotService ( IPublishedSnapshotService service , AppCaches appCaches , JsonPayload [ ] payloads )
{
service . Notify ( payloads , out _ , out var publishedChanged ) ;
if ( payloads . Any ( x = > x . ChangeTypes . HasType ( TreeChangeTypes . RefreshAll ) ) | | publishedChanged )
{
// when a public version changes
appCaches . ClearPartialViewCache ( ) ;
}
}
2016-05-26 17:12:04 +02:00
public class JsonPayload
{
2019-09-27 10:49:48 +02:00
public JsonPayload ( int id , Guid ? key , TreeChangeTypes changeTypes )
2016-05-26 17:12:04 +02:00
{
Id = id ;
2019-09-27 10:49:48 +02:00
Key = key ;
2016-05-26 17:12:04 +02:00
ChangeTypes = changeTypes ;
}
public int Id { get ; }
2019-09-27 10:49:48 +02:00
public Guid ? Key { get ; }
2016-05-26 17:12:04 +02:00
public TreeChangeTypes ChangeTypes { get ; }
}
#endregion
#region Indirect
2019-01-17 08:34:29 +01:00
public static void RefreshContentTypes ( AppCaches appCaches )
2016-05-26 17:12:04 +02:00
{
// we could try to have a mechanism to notify the PublishedCachesService
// and figure out whether published items were modified or not... keep it
// simple for now, just clear the whole thing
2019-01-17 08:34:29 +01:00
appCaches . ClearPartialViewCache ( ) ;
2016-05-26 17:12:04 +02:00
2019-01-17 11:01:23 +01:00
appCaches . IsolatedCaches . ClearCache < PublicAccessEntry > ( ) ;
appCaches . IsolatedCaches . ClearCache < IContent > ( ) ;
2016-05-26 17:12:04 +02:00
}
#endregion
}
}