Skip to content

Commit

Permalink
Merge pull request #232 from advanced-cms/bugfix/221
Browse files Browse the repository at this point in the history
  • Loading branch information
barteksekula committed May 4, 2023
2 parents 61f0377 + 8b5626b commit 7bf241e
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 54 deletions.
@@ -1,10 +1,9 @@
using Advanced.CMS.ExternalReviews.DraftContentAreaPreview;

using Advanced.CMS.ExternalReviews.ReviewLinksRepository;
using EPiServer;
using EPiServer.Core;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Globalization;
using EPiServer.ServiceLocation;

namespace Advanced.CMS.ExternalReviews
Expand All @@ -29,8 +28,7 @@ private void Events_LoadingContent(object sender, ContentEventArgs e)

if (externalReviewState.CustomLoaded.Contains(e.ContentLink.ToString()))
{
var preferredCulture = ServiceLocator.Current.GetInstance<LanguageResolver>().GetPreferredCulture();
var cachedContent = externalReviewState.GetCachedContent(preferredCulture, e.ContentLink);
var cachedContent = externalReviewState.GetCachedContent(e.ContentLink);
if (cachedContent != null)
{
e.ContentLink = cachedContent.ContentLink;
Expand All @@ -51,15 +49,21 @@ private void Events_LoadingContent(object sender, ContentEventArgs e)
return;
}

var unpublishedCulture = ServiceLocator.Current.GetInstance<LanguageResolver>().GetPreferredCulture();
var externalReviewLinksRepository = ServiceLocator.Current.GetInstance<IExternalReviewLinksRepository>();
var externalReviewLink = externalReviewLinksRepository.GetContentByToken(externalReviewState.Token);
if (!externalReviewLink.IsPreviewableLink())
{
return;
}

var content = ServiceLocator.Current.GetInstance<IContentLoader>().Get<IContent>(unpublished);

if (!(content is IVersionable versionable) || reviewsContentLoader.HasExpired(versionable))
if (content is not IVersionable versionable || reviewsContentLoader.HasExpired(versionable))
{
return;
}

externalReviewState.SetCachedLink(unpublishedCulture, content);
externalReviewState.SetCachedLink(content);

e.ContentLink = unpublished;
e.Content = content.AllowAccessToEveryone();
Expand Down
@@ -1,10 +1,8 @@
using Advanced.CMS.ExternalReviews.ReviewLinksRepository;
using EPiServer;
using EPiServer;
using EPiServer.Core;
using EPiServer.Core.Internal;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.Globalization;
using EPiServer.Security;
using EPiServer.ServiceLocation;
using EPiServer.Web;
Expand All @@ -16,7 +14,7 @@ namespace Advanced.CMS.ExternalReviews.DraftContentAreaPreview
/// <summary>
/// Register ContentArea draft preview
/// </summary>
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
[ModuleDependency(typeof(InitializationModule))]
public class DraftContentAreaPreviewInitializerInitializer : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
Expand Down Expand Up @@ -47,8 +45,7 @@ public void ConfigureContainer(ServiceConfigurationContext context)
// Intercepted in order to return unpublished content items
context.Services.Intercept<IPublishedStateAssessor>(
(locator, defaultPublishedStateAssessor) =>
new PublishedStateAssessorDecorator(defaultPublishedStateAssessor,
locator.GetInstance<LanguageResolver>(), locator.GetInstance<ExternalReviewState>()));
new PublishedStateAssessorDecorator(defaultPublishedStateAssessor, locator.GetInstance<ExternalReviewState>()));
// Intercepted in order to not filter out content without Everyone access
context.Services.Intercept<IContentAccessEvaluator>(
Expand Down
@@ -1,19 +1,15 @@
using EPiServer.Core;
using EPiServer.Globalization;

namespace Advanced.CMS.ExternalReviews.DraftContentAreaPreview
{
public class PublishedStateAssessorDecorator : IPublishedStateAssessor
{
private readonly IPublishedStateAssessor _defaultService;
private readonly LanguageResolver _languageResolver;
private readonly ExternalReviewState _externalReviewState;

public PublishedStateAssessorDecorator(IPublishedStateAssessor defaultService,
LanguageResolver languageResolver, ExternalReviewState externalReviewState)
public PublishedStateAssessorDecorator(IPublishedStateAssessor defaultService, ExternalReviewState externalReviewState)
{
_defaultService = defaultService;
_languageResolver = languageResolver;
_externalReviewState = externalReviewState;
}

Expand All @@ -28,8 +24,7 @@ public bool IsPublished(IContent content, PublishedStateCondition condition)

if (_externalReviewState.CustomLoaded.Contains(content.ContentLink.ToString()))
{
var cachedContent =
_externalReviewState.GetCachedContent(_languageResolver.GetPreferredCulture(), content.ContentLink);
var cachedContent = _externalReviewState.GetCachedContent(content.ContentLink);
if (cachedContent != null)
{
return true;
Expand Down
Expand Up @@ -8,7 +8,6 @@
using EPiServer.Core.Internal;
using EPiServer.DataAbstraction;
using EPiServer.Filters;
using EPiServer.Globalization;
using EPiServer.Logging;
using EPiServer.ServiceLocation;

Expand All @@ -18,35 +17,31 @@ namespace Advanced.CMS.ExternalReviews.DraftContentAreaPreview
public class ReviewsContentLoader
{
private readonly IContentLoader _contentLoader;
private readonly IContentLanguageAccessor _languageAccessor;
private readonly ProjectContentResolver _projectContentResolver;
private readonly IContentVersionRepository _contentVersionRepository;
private readonly LanguageResolver _languageResolver;
private readonly IContentProviderManager _contentProviderManager;
private readonly IContentChildrenSorter _childrenSorter;
private readonly ExternalReviewState _externalReviewState;
private static readonly ILogger _log = LogManager.GetLogger(typeof(ReviewsContentLoader));

public ReviewsContentLoader(IContentLoader contentLoader, IContentLanguageAccessor languageAccessor,
public ReviewsContentLoader(IContentLoader contentLoader,
ProjectContentResolver projectContentResolver,
IContentVersionRepository contentVersionRepository,
LanguageResolver languageResolver,
IContentProviderManager contentProviderManager,
IContentChildrenSorter childrenSorter, ExternalReviewState externalReviewState)
{
_contentLoader = contentLoader;
_languageAccessor = languageAccessor;
_projectContentResolver = projectContentResolver;
_contentVersionRepository = contentVersionRepository;
_languageResolver = languageResolver;
_contentProviderManager = contentProviderManager;
_childrenSorter = childrenSorter;
_externalReviewState = externalReviewState;
}

public IEnumerable<T> GetChildrenWithReviews<T>(ContentReference contentLink) where T : IContentData
{
return GetChildrenWithReviews<T>(contentLink, CreateDefaultListOption());
var loaderOptions = new LoaderOptions { LanguageLoaderOption.Fallback(new CultureInfo(_externalReviewState.PreferredLanguage)) };
return GetChildrenWithReviews<T>(contentLink, loaderOptions);
}

public IEnumerable<T> GetChildrenWithReviews<T>(ContentReference contentLink, CultureInfo language)
Expand Down Expand Up @@ -82,7 +77,7 @@ public IEnumerable<T> GetChildrenWithReviews<T>(ContentReference contentLink, Lo
return _contentLoader.GetChildren<T>(contentLink);
}

ContentReference referenceWithoutVersion = contentLink.ToReferenceWithoutVersion();
var referenceWithoutVersion = contentLink.ToReferenceWithoutVersion();
if (referenceWithoutVersion == ContentReference.WasteBasket)
{
return _contentLoader.GetChildren<T>(contentLink);
Expand All @@ -91,8 +86,7 @@ public IEnumerable<T> GetChildrenWithReviews<T>(ContentReference contentLink, Lo
var provider = _contentProviderManager.ProviderMap.GetProvider(referenceWithoutVersion);

var parentContent = _contentLoader.Get<IContent>(referenceWithoutVersion, loaderOptions);
var localizable = parentContent as ILocalizable;
var languageID = localizable != null ? localizable.Language.Name : (string)null;
var languageID = parentContent is ILocalizable localizable ? localizable.Language.Name : null;
var childrenReferences =
provider.GetChildrenReferences<T>(referenceWithoutVersion, languageID, startIndex, maxRows);

Expand Down Expand Up @@ -129,7 +123,7 @@ public IEnumerable<T> GetChildrenWithReviews<T>(ContentReference contentLink, Lo
continue;
}

result.Add((content as IContent).ContentLink);
result.Add((content as IContent)?.ContentLink);
}
}

Expand All @@ -156,17 +150,14 @@ public ContentReference LoadUnpublishedVersion(ContentReference baseReference)
if (_externalReviewState.ProjectId.HasValue)
{
// load version from project
return _projectContentResolver.GetProjectReference(baseReference,
_externalReviewState.ProjectId.Value, _languageResolver.GetPreferredCulture().Name);
return _projectContentResolver.GetProjectReference(baseReference, _externalReviewState.ProjectId.Value, _externalReviewState.PreferredLanguage);
}

// load common draft instead of published version
ContentVersion loadCommonDraft;
try
{
loadCommonDraft =
_contentVersionRepository.LoadCommonDraft(baseReference,
_languageResolver.GetPreferredCulture().Name);
loadCommonDraft = _contentVersionRepository.LoadCommonDraft(baseReference, _externalReviewState.PreferredLanguage);
}
catch (ContentNotFoundException)
{
Expand All @@ -190,9 +181,7 @@ public bool HasExpired(IVersionable content)

private LoaderOptions CreateDefaultListOption()
{
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.Add<LanguageLoaderOption>(LanguageLoaderOption.Fallback(_languageAccessor.Language));
return loaderOptions;
return new LoaderOptions { LanguageLoaderOption.Fallback(new CultureInfo(_externalReviewState.PreferredLanguage)) };
}
}
}
Expand Up @@ -18,17 +18,19 @@ public class PageEditPartialRouter : IPartialRouter<IContent, IContent>
private readonly ProjectContentResolver _projectContentResolver;
private readonly IContentLanguageAccessor _contentLanguageAccessor;
private readonly ExternalReviewState _externalReviewState;
private readonly IContentVersionRepository _contentVersionRepository;

public PageEditPartialRouter(IExternalReviewLinksRepository externalReviewLinksRepository,
ExternalReviewOptions externalReviewOptions,
ProjectContentResolver projectContentResolver, IContentLanguageAccessor contentLanguageAccessor,
ExternalReviewState externalReviewState)
ExternalReviewState externalReviewState, IContentVersionRepository contentVersionRepository)
{
_externalReviewLinksRepository = externalReviewLinksRepository;
_externalReviewOptions = externalReviewOptions;
_projectContentResolver = projectContentResolver;
_contentLanguageAccessor = contentLanguageAccessor;
_externalReviewState = externalReviewState;
_contentVersionRepository = contentVersionRepository;
}

public PartialRouteData GetPartialVirtualPath(IContent content, UrlGeneratorContext urlGeneratorContext)
Expand Down Expand Up @@ -58,11 +60,13 @@ public object RoutePartial(IContent content, UrlResolverContext segmentContext)
return null;
}

var version = _contentVersionRepository.Load(externalReviewLink.ContentLink);
_contentLanguageAccessor.Language = new CultureInfo(version.LanguageBranch);

_externalReviewState.ProjectId = externalReviewLink.ProjectId;
_externalReviewState.IsEditLink = true;
_externalReviewState.Token = token;

_contentLanguageAccessor.Language = new CultureInfo(content.LanguageBranch());
_externalReviewState.PreferredLanguage = version.LanguageBranch;

try
{
Expand Down
15 changes: 10 additions & 5 deletions src/Advanced.CMS.ExternalReviews/ExternalReviewState.cs
@@ -1,6 +1,5 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using EPiServer.Core;
using EPiServer.ServiceLocation;
using Microsoft.AspNetCore.Http;
Expand All @@ -25,6 +24,12 @@ public string Token
set => _httpContextAccessor.HttpContext.Items["Token"] = value;
}

public string PreferredLanguage
{
get => _httpContextAccessor.HttpContext?.Items["PreferredLanguage"] as string;
set => _httpContextAccessor.HttpContext.Items["PreferredLanguage"] = value;
}

public bool IsEditLink
{
get => (string) _httpContextAccessor.HttpContext?.Items["IsEditLink"] == bool.TrueString;
Expand Down Expand Up @@ -88,18 +93,18 @@ public IList<string> CustomLoaded
return _httpContextAccessor.HttpContext?.Items[key] as ConcurrentDictionary<string, IContent>;
}

public IContent GetCachedContent(CultureInfo preferredCulture, ContentReference contentLink)
public IContent GetCachedContent(ContentReference contentLink)
{
if (GetCachedLinksDictionary().TryGetValue(preferredCulture.Name + "_" + contentLink.ToReferenceWithoutVersion(), out var result))
if (GetCachedLinksDictionary().TryGetValue(PreferredLanguage + "_" + contentLink.ToReferenceWithoutVersion(), out var result))
{
return result;
}
return null;
}

public void SetCachedLink(CultureInfo preferredCulture, IContent contentLink)
public void SetCachedLink(IContent contentLink)
{
GetCachedLinksDictionary()[preferredCulture.Name + "_" + contentLink.ContentLink.ToReferenceWithoutVersion()] = contentLink;
GetCachedLinksDictionary()[PreferredLanguage + "_" + contentLink.ContentLink.ToReferenceWithoutVersion()] = contentLink;
}
}
}
10 changes: 7 additions & 3 deletions src/Advanced.CMS.ExternalReviews/PagePreviewPartialRouter.cs
Expand Up @@ -23,19 +23,22 @@ public class PagePreviewPartialRouter : IPartialRouter<IContent, IContent>
private readonly ExternalReviewOptions _externalReviewOptions;
private readonly IContentLanguageAccessor _contentLanguageAccessor;
private readonly ExternalReviewState _externalReviewState;
private readonly IContentVersionRepository _contentVersionRepository;

public PagePreviewPartialRouter(IExternalReviewLinksRepository externalReviewLinksRepository,
ExternalReviewOptions externalReviewOptions,
ProjectContentResolver projectContentResolver,
IExternalLinkPinCodeSecurityHandler externalLinkPinCodeSecurityHandler,
IContentLanguageAccessor contentLanguageAccessor, ExternalReviewState externalReviewState)
IContentLanguageAccessor contentLanguageAccessor, ExternalReviewState externalReviewState,
IContentVersionRepository contentVersionRepository)
{
_externalReviewLinksRepository = externalReviewLinksRepository;
_externalReviewOptions = externalReviewOptions;
_projectContentResolver = projectContentResolver;
_externalLinkPinCodeSecurityHandler = externalLinkPinCodeSecurityHandler;
_contentLanguageAccessor = contentLanguageAccessor;
_externalReviewState = externalReviewState;
_contentVersionRepository = contentVersionRepository;
}

public PartialRouteData GetPartialVirtualPath(IContent content, UrlGeneratorContext segmentContext)
Expand All @@ -62,8 +65,6 @@ public object RoutePartial(IContent content, UrlResolverContext segmentContext)
return null;
}

_contentLanguageAccessor.Language = new CultureInfo(content.LanguageBranch());

nextSegment = segmentContext.GetNextSegment(nextSegment.Remaining);
var token = nextSegment.Next.ToString();

Expand All @@ -73,8 +74,11 @@ public object RoutePartial(IContent content, UrlResolverContext segmentContext)
return null;
}

var version = _contentVersionRepository.Load(externalReviewLink.ContentLink);
_contentLanguageAccessor.Language = new CultureInfo(version.LanguageBranch);
_externalReviewState.Token = token;
_externalReviewState.ProjectId = externalReviewLink.ProjectId;
_externalReviewState.PreferredLanguage = version.LanguageBranch;

// PIN code security check, if user is not authenticated, then redirect to login page
if (!_externalLinkPinCodeSecurityHandler.UserHasAccessToLink(externalReviewLink))
Expand Down
20 changes: 18 additions & 2 deletions src/Advanced.CMS.ExternalReviews/PreviewUrlResolver.cs
@@ -1,4 +1,5 @@
using System.Collections.Specialized;
using System;
using System.Collections.Specialized;
using System.Linq;
using System.Text.RegularExpressions;
using Advanced.CMS.ExternalReviews.ReviewLinksRepository;
Expand Down Expand Up @@ -166,7 +167,22 @@ public bool TryToPermanent(string url, out string permanentUrl)

public ContentRouteData Route(UrlBuilder urlBuilder, RouteArguments routeArguments)
{
return _defaultUrlResolver.Route(urlBuilder, routeArguments);
var contentRouteData = _defaultUrlResolver.Route(urlBuilder, routeArguments);

if (contentRouteData.RemainingPath.StartsWith($"{_externalReviewOptions.Service.ContentPreviewUrl}/", StringComparison.CurrentCultureIgnoreCase))
{
// If we failed to route then it means that a start page in the same language does not exist and our partial routers will not be able to step in
// We need to fallback to master language also if the translated start page is not published
if (contentRouteData.Content == null || !contentRouteData.Content.IsPublished())
{
var masterLanguage = LanguageSelector.AutoDetect().LanguageBranch;
urlBuilder.Path = urlBuilder.Path.Replace($"/{contentRouteData.RouteLanguage}", $"/{masterLanguage}");
var masterRoutedData = _defaultUrlResolver.Route(urlBuilder, routeArguments);
return masterRoutedData;
}
}

return contentRouteData;
}

private string AppendGeneratedPostfix(string url)
Expand Down
Expand Up @@ -45,7 +45,7 @@ private static string GetCssClassForTag(string tagName)

private static string GetTypeSpecificCssClasses(ContentAreaItem contentAreaItem, IContentRepository contentRepository)
{
var content = contentAreaItem.GetContent();
var content = contentAreaItem.LoadContent();
var cssClass = content == null ? String.Empty : content.GetOriginalType().Name.ToLowerInvariant();

var customClassContent = content as ICustomCssInContentArea;
Expand Down

0 comments on commit 7bf241e

Please sign in to comment.