Skip to content

Commit 615978a

Browse files
cornehoskamgitbook-bot
authored andcommitted
GITBOOK-11: Update Cookie Consent
1 parent 98ae9ad commit 615978a

File tree

2 files changed

+90
-16
lines changed

2 files changed

+90
-16
lines changed

16/umbraco-engage/developers/ab-testing/csharp-api.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,68 @@ public class ExampleService
7070
}
7171
}
7272
```
73+
74+
## Retrieving Active A/B test variants
75+
76+
You can retrieve the active A/B test variants for a visitor in different ways depending on your specific scenario:
77+
78+
* `IAbTestingVisitorService.GetVisitorAbTestVariants(visitorExternalId, pageId, culture, contentTypeId)`
79+
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces`
80+
* Retrieves active A/B test variants on a specific page, without requiring a request context.
81+
* The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()`
82+
* `IAbTestVisitorToVariantManager.GetActiveVisitorVariants(visitorExternalId)`
83+
* Namespace: `Umbraco.Engage.Infrastructure.AbTesting`
84+
* Retrieves _all_ active A/B test variants for the given visitor throughout the website.
85+
* The visitor external id can be retrieved using `IAnalyticsVisitorExternalIdHandler.GetExternalId()`
86+
87+
### Example - Getting the A/B test variants for the current visitor
88+
89+
This example demonstrates how to create a service that retrieves the active A/B test variants for a specific visitor, content, and culture variation. The service wraps the `IAbTestingVisitorService.GetVisitorAbTestVariants()` method, using the current HttpContext and UmbracoContext to obtain the visitor ID and requested content.
90+
91+
```cs
92+
using Umbraco.Cms.Core.Models.PublishedContent;
93+
using Umbraco.Cms.Core.Web;
94+
using Umbraco.Engage.Infrastructure.AbTesting.Models;
95+
using Umbraco.Engage.Infrastructure.AbTesting.Services.Interfaces;
96+
using Umbraco.Engage.Infrastructure.Analytics.Collection.Visitor;
97+
98+
namespace Umbraco.Example;
99+
100+
public class ExampleService
101+
{
102+
private readonly IHttpContextAccessor _httpContextAccessor;
103+
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
104+
private readonly IAnalyticsVisitorExternalIdHandler _externalIdHandler;
105+
private readonly IAbTestingVisitorService _abTestingVisitorService;
106+
107+
public ExampleService(
108+
IHttpContextAccessor httpContextAccessor,
109+
IUmbracoContextAccessor umbracoContextAccessor,
110+
IAnalyticsVisitorExternalIdHandler externalIdHandler,
111+
IAbTestingVisitorService abTestingVisitorService)
112+
{
113+
_httpContextAccessor = httpContextAccessor;
114+
_umbracoContextAccessor = umbracoContextAccessor;
115+
_externalIdHandler = externalIdHandler ;
116+
_abTestingVisitorService = abTestingVisitorService;
117+
}
118+
119+
/// <summary>
120+
/// Gets the active A/B test variants for the current visitor.
121+
/// </summary>
122+
/// <returns>Active <see cref="AbTestVariant"/>s for the visitor, or an empty list if unavailable.</returns>
123+
public IEnumerable<AbTestVariant> GetCurrentVisitorActiveAbTestVariants()
124+
{
125+
if (_httpContextAccessor?.HttpContext is not HttpContext httpCtx ||
126+
_externalIdHandler.GetExternalId(httpCtx) is not Guid externalId)
127+
return [];
128+
129+
if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbCtx) ||
130+
umbCtx.PublishedRequest?.Culture is not string culture ||
131+
umbCtx.PublishedRequest?.PublishedContent is not IPublishedContent content)
132+
return [];
133+
134+
return _abTestingVisitorService.GetVisitorAbTestVariants(externalId, content.Id, culture, content.ContentType.Id);
135+
}
136+
}
137+
```

16/umbraco-engage/security-and-privacy/gdpr/how-to-become-gdpr-compliant-using-cookiebot.md

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ The rest of the code is deserializing the JSON string stored inside the cookie f
2828
```cs
2929
using System.Text.Json;
3030
using System.Text.Json.Serialization;
31+
using System.Text.RegularExpressions;
3132
using System.Web;
3233
using Umbraco.Engage.Infrastructure.Permissions.ModulePermissions;
3334

@@ -56,7 +57,7 @@ namespace Umbraco.Engage.StarterKit.CookieBot
5657
return IsAllowed(context, "preferences");
5758
}
5859

59-
private bool IsAllowed(HttpContext context, string cookiePermission)
60+
public bool IsAllowed(HttpContext context, string cookiePermission)
6061
{
6162
// C# Code from CookieBot to check for their cookie
6263
// https://www.cookiebot.com/en/developer/#h-server-side-usage
@@ -81,34 +82,41 @@ namespace Umbraco.Engage.StarterKit.CookieBot
8182
return false;
8283
}
8384

84-
private bool CheckCookieBotValue(string rawCookieBotConsentValues, string cookiePermissionToCheck)
85+
public bool CheckCookieBotValue(string rawCookieBotConsentValues, string cookiePermissionToCheck)
8586
{
8687
// Read current user consent in encoded JSON
8788
// Sample JSON cookie payload
8889
/*
89-
{
90-
"stamp": "Ov4gD1JVnDnBaJv8K2wYQlyWlnNlT/AKO768tibZYdQGNj/EolraLw==",
91-
"necessary": true,
92-
"preferences": true,
93-
"statistics": true,
94-
"marketing": true,
95-
"method": "explicit",
96-
"ver": 1,
97-
"utc": 1698057791350,
98-
"region": "gb"
99-
}
90+
* {
91+
* stamp:'Ov4gD1JVnDnBaJv8K2wYQlyWlnNlT/AKO768tibZYdQGNj/EolraLw==',
92+
* necessary:true,
93+
* preferences:false,
94+
* statistics:true,
95+
* marketing:false,
96+
* method:'explicit',
97+
* ver:1,
98+
* utc:1698057791350,
99+
* region:'gb'
100+
* }
100101
*/
101102

102103
// Decode the consent string
103-
var decodedConsent = HttpUtility.UrlDecode(rawCookieBotConsentValues);
104+
var rawDecodedConsent = HttpUtility.UrlDecode(rawCookieBotConsentValues);
104105

105-
if(decodedConsent == null)
106+
if(rawDecodedConsent == null)
106107
{
107108
return false;
108109
}
110+
111+
// Because the CookieBot consent cookie is not actually valid JSON, we need to do some preprocessing.
112+
// Step 1: Quote property names (e.g., stamp → "stamp")
113+
var consentStep1 = Regex.Replace(rawDecodedConsent, @"(?<={|,)\s*(\w+)\s*:", m => $"\"{m.Groups[1].Value}\":");
114+
115+
// Step 2: Replace single-quoted string values with double quotes
116+
var consentStep2 = Regex.Replace(consentStep1, @"'([^']*)'", "\"$1\"");
109117

110118
// Deserialize the consent to a dynamic object
111-
var cookieBotConsentValues = JsonSerializer.Deserialize<CookieBotConsent>(decodedConsent);
119+
var cookieBotConsentValues = JsonSerializer.Deserialize<CookieBotConsent>(consentStep2);
112120
if (cookieBotConsentValues == null)
113121
{
114122
// Something went wrong with the cookieConsent deserialization
@@ -142,6 +150,7 @@ namespace Umbraco.Engage.StarterKit.CookieBot
142150
public bool Necessary { get; set; }
143151

144152
[JsonPropertyName("preferences")]
153+
145154
public bool Preferences { get; set; }
146155

147156
[JsonPropertyName("statistics")]

0 commit comments

Comments
 (0)