Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(dotnet build *)",
"Bash(dotnet restore *)",
"Bash(dotnet test *)"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateRazorSdkCompilation>true</GenerateRazorSdkCompilation>
Expand All @@ -13,10 +13,10 @@
<ProjectReference Include="..\Geta.Optimizely.Extensions\Geta.Optimizely.Extensions.csproj" />
</ItemGroup>

<Import Project="..\..\sub\geta-foundation-core\src\Foundation\modules\ModulesInclude.proj"/>
<Import Project="..\..\sub\geta-foundation-core\src\Foundation\modules\ModulesInclude.proj" />

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.36" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.7" />
</ItemGroup>

</Project>
16 changes: 9 additions & 7 deletions src/Geta.Optimizely.Extensions.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
}
},
"AllowedHosts": "*",
"EPiServer": {
"Find": {
"DefaultIndex": "changeme",
"ServiceUrl": "http://changeme",
"TrackingSanitizerEnabled": true,
"TrackingTimeout": 30000
},
"Optimizely": {
"ContentGraph": {
"GatewayAddress": "https://cg.optimizely.com",
"AppKey": "changeme",
"Secret": "changeme",
"SingleKey": "changeme"
}
},
"EPiServer": {
"OdpVisitorGroupOptions": {
"OdpCookieName": "vuid",
"CacheTimeoutSeconds": 1,
Expand Down
43 changes: 38 additions & 5 deletions src/Geta.Optimizely.Extensions/ContentAreaExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Linq;
using System.Linq;
using EPiServer;
using EPiServer.Core;
using EPiServer.Security;
using EPiServer.ServiceLocation;

namespace Geta.Optimizely.Extensions
{
Expand All @@ -9,13 +12,43 @@ namespace Geta.Optimizely.Extensions
public static class ContentAreaExtensions
{
/// <summary>
/// Checks if content area has content.
/// Checks if content area has any content that is visible to the current user
/// (published, not expired and not access restricted).
/// </summary>
/// <param name="contentArea">The content area.</param>
/// <returns>Returns true if content area has content and false when not.</returns>
/// <returns>Returns true if the content area has at least one visible item and false when not.</returns>
public static bool HasContent(this ContentArea contentArea)
{
return contentArea?.FilteredItems != null && contentArea.FilteredItems.Any();
if (contentArea?.Items == null)
{
return false;
}

var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
var publishedStateAssessor = ServiceLocator.Current.GetInstance<IPublishedStateAssessor>();
var accessEvaluator = ServiceLocator.Current.GetInstance<IContentAccessEvaluator>();
var principal = ServiceLocator.Current.GetInstance<IPrincipalAccessor>().Principal;

return contentArea.Items.Any(item => IsVisible(item, contentLoader, publishedStateAssessor, accessEvaluator, principal));
}

// CMS 13 removed ContentArea.FilteredItems. This replicates its visibility filtering
// (publish state, expiration and read access) so HasContent does not report items
// that would not actually be rendered for the current user.
private static bool IsVisible(
ContentAreaItem item,
IContentLoader contentLoader,
IPublishedStateAssessor publishedStateAssessor,
IContentAccessEvaluator accessEvaluator,
System.Security.Principal.IPrincipal principal)
{
if (item?.ContentLink == null || !contentLoader.TryGet<IContent>(item.ContentLink, out var content))
{
return false;
}

return publishedStateAssessor.IsPublished(content)
&& accessEvaluator.HasAccess(content, principal, AccessLevel.Read);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<PackageId>Geta.Optimizely.Extensions</PackageId>
<Title>Extensions and helpers library for Optimizely CMS</Title>
<Authors>Geta Digital</Authors>
Expand All @@ -18,9 +18,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="EPiServer.CMS.AspNetCore.HtmlHelpers" Version="12.6.0" />
<PackageReference Include="EPiServer.CMS.UI.Core" Version="12.7.0" />
<PackageReference Include="Geta.Net.Extensions" Version="3.0.0" />
<PackageReference Include="EPiServer.CMS.AspNetCore.HtmlHelpers" Version="13.0.2" />
<PackageReference Include="EPiServer.CMS.UI.Core" Version="13.0.2" />
<PackageReference Include="Geta.Net.Extensions" Version="3.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
40 changes: 18 additions & 22 deletions src/Geta.Optimizely.Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Geta.Optimizely.Extensions
{
/// <summary>
/// Extension methods for working with JSON data
/// </summary>
public static class JsonExtensions
{
/// <summary>
/// Convert object to JSON
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj">Object to convert</param>
/// <param name="includeNull">Include null property values</param>
/// <returns></returns>
public static string ToJson<T>(this T obj, bool includeNull = true)
private static readonly JsonSerializerOptions OptionsWithNulls = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
Converters = { new JsonStringEnumConverter() }
};

private static readonly JsonSerializerOptions OptionsWithoutNulls = new()
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new JsonConverter[] { new StringEnumConverter() },
NullValueHandling = includeNull ? NullValueHandling.Include : NullValueHandling.Ignore
};
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = { new JsonStringEnumConverter() }
};

return JsonConvert.SerializeObject(obj, settings);
public static string ToJson<T>(this T obj, bool includeNull = true)
{
return JsonSerializer.Serialize(obj, includeNull ? OptionsWithNulls : OptionsWithoutNulls);
}
}
}
}
19 changes: 13 additions & 6 deletions src/Geta.Optimizely.Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using EPiServer.Core.Html;
using Geta.Net.Extensions;
using System;
using System.Net;
using System.Text.RegularExpressions;
using Geta.Net.Extensions;
using Microsoft.AspNetCore.Http;

namespace Geta.Optimizely.Extensions
Expand All @@ -18,9 +19,15 @@ public static class StringExtensions
/// <returns>A string with text.</returns>
public static string StripHtml(this string htmlText, int maxLength = 0)
{
return string.IsNullOrWhiteSpace(htmlText)
? htmlText
: TextIndexer.StripHtml(htmlText, maxLength);
if (string.IsNullOrWhiteSpace(htmlText))
return htmlText;


var stripped = Regex.Replace(htmlText, "<[^>]*>", string.Empty, RegexOptions.None, TimeSpan.FromSeconds(1));
stripped = WebUtility.HtmlDecode(stripped);
return maxLength > 0 && stripped.Length > maxLength
? stripped[..maxLength]
: stripped;
}

/// <summary>
Expand Down Expand Up @@ -100,4 +107,4 @@ public static string AddHost(this string url, Func<Uri> getBaseUri)
return uriBuilder.ToString();
}
}
}
}
2 changes: 1 addition & 1 deletion src/Geta.Optimizely.Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class TypeExtensions
/// <returns>PageType instance if found.</returns>
public static PageType GetPageType(this Type pageType)
{
return ServiceLocator.Current.GetInstance<IContentTypeRepository<PageType>>().Load(pageType);
return ServiceLocator.Current.GetInstance<IContentTypeRepository>().Load(pageType) as PageType;
}
}
}
5 changes: 2 additions & 3 deletions src/Geta.Optimizely.Extensions/UrlHelperExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Castle.Core.Internal;
using EPiServer;
using EPiServer;
using EPiServer.Core;
using EPiServer.ServiceLocation;
using EPiServer.Web.Mvc.Html;
Expand Down Expand Up @@ -30,7 +29,7 @@ public static class UrlHelperExtensions
public static IHtmlContent PageLinkUrl(this IUrlHelper urlHelper, PageReference pageLink, string defaultValue)
{
var url = urlHelper.PageLinkUrl(pageLink) as HtmlString;
return url == null || url.Value.IsNullOrEmpty() ? new HtmlString(defaultValue) : url;
return url == null || string.IsNullOrEmpty(url.Value) ? new HtmlString(defaultValue) : url;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion sub/geta-foundation-core
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.4.1" />
<PackageReference Include="coverlet.msbuild" Version="3.1.2">
<PackageReference Include="Castle.Core" Version="5.2.1" />
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Loading