Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application Insights front-end telemetry #1085

Merged
merged 16 commits into from
Jun 17, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
There is a separate <a href="@Model.TransfersCookiesUrl">cookies page for the transfers part of this service.</a>
</p>

<h2 class="govuk-heading-m">Analytics cookies (optional)</h2>

<h3 class="govuk-heading-s">Google Analytics</h3>

<p class="govuk-body">
With your permission, we use Google Analytics to collect data about how you use the service. This information helps us improve our service.
These cookies do not collect your name or address, they do collect a unique user identifier
Expand All @@ -50,19 +54,32 @@
<li>what you click on while you’re visiting the site</li>
</ul>
<p class="govuk-body">Google is not allowed to share our analytics data with anyone.</p>

<h3 class="govuk-heading-s">Azure Application Insights</h3>

<p class="govuk-body">We use Azure Application Insights software to collect information about how you use this website. We do this to help make sure the site is meeting the needs of its users and to help us make improvements.</p>
<p class="govuk-body">Azure Application Insights stores information about:</p>
<ul class="govuk-list govuk-list--bullet">
<li>the pages you visit on this website</li>
<li>how long you spend on each page</li>
<li>how you got to the site</li>
<li>what you click on while you're visiting the site</li>
</ul>
<p class="govuk-body">We don't allow Microsoft to use or share our analytics data.</p>

<form method="post">
<div class="govuk-form-group">
<fieldset class="govuk-fieldset">
<legend class="govuk-fieldset__legend govuk-fieldset__legend--m">
<h3 class="govuk-fieldset__heading">
Do you accept Google Analytics cookies?
Do you accept analytical cookies?
</h3>
</legend>
<div class="govuk-radios">
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="cookie-consent-accept" name="consent" type="radio" value="true" checked="@Model.Consent">
<label class="govuk-label govuk-radios__label" for="cookie-consent-accept">
Yes, opt in to Google Analytics cookies
Yes, opt in to analytical cookies
</label>
</div>
<div class="govuk-radios__item">
Expand All @@ -76,6 +93,7 @@
</div>
<input type="submit" name="commit" value="Save changes" class="govuk-button" data-qa="submit" data-module="govuk-button" data-disable-with="Save changes">
</form>

<h2 class="govuk-heading-l">How we use cookies</h2>
<h3 class="govuk-heading-m">Essential cookies</h3>
<p class="govuk-body">
Expand Down Expand Up @@ -119,7 +137,10 @@
</tr>
</tbody>
</table>
<h3 class="govuk-heading-m">Measuring website usage (Google Analytics)</h3>

<h2 class="govuk-heading-m">Analytical cookies</h2>

<h3 class="govuk-heading-s">Google Analytics</h3>
<p class="govuk-body">Google Analytics sets the following cookies:</p>
<table class="govuk-table" aria-label="Google analytics cookies">
<thead class="govuk-table__header">
Expand Down Expand Up @@ -152,5 +173,34 @@
</tr>
</tbody>
</table>

<h3 class="govuk-heading-s">Application Insights</h3>
<p class="govuk-body">Azure Application Insights sets the following cookies:</p>
<table class="govuk-table" aria-label="App Insights cookies">
<thead class="govuk-table__head">
<tr class="govuk-table__row">
<th scope="col" class="govuk-table__header">Name</th>
<th scope="col" class="govuk-table__header">Purpose</th>
<th scope="col" class="govuk-table__header">Expires</th>
</tr>
</thead>
<tbody class="govuk-table__body">
<tr class="govuk-table__row">
<td class="govuk-table__cell">ai_session</td>
<td class="govuk-table__cell">This helps us track activity happening over a single browser session</td>
<td class="govuk-table__cell">1 hour</td>
</tr>
<tr class="govuk-table__row">
<td class="govuk-table__cell">ai_user</td>
<td class="govuk-table__cell">This helps us to identify the number of distinct users accessing the site over time by tracking if you've visited before</td>
<td class="govuk-table__cell">1 year</td>
</tr>
<tr class="govuk-table__row">
<td class="govuk-table__cell">ai_authuser</td>
<td class="govuk-table__cell">This helps us to identify authenticated users and how they interact with the site</td>
<td class="govuk-table__cell">When you close your browser</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,105 +1,112 @@
using Dfe.PrepareConversions.Configuration;
using Dfe.PrepareConversions.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;

namespace Dfe.PrepareConversions.Pages.Public;

public class CookiePreferences : PageModel
{
private const string CONSENT_COOKIE_NAME = ".ManageAnAcademyConversion.Consent";
private readonly ILogger<CookiePreferences> _logger;
private readonly IOptions<ServiceLinkOptions> _options;

public CookiePreferences(ILogger<CookiePreferences> logger, IOptions<ServiceLinkOptions> options)
{
_logger = logger;
_options = options;
}

public bool? Consent { get; set; }
public bool PreferencesSet { get; set; }
public string ReturnPath { get; set; }

public string TransfersCookiesUrl { get; set; }

public ActionResult OnGet(bool? consent, string returnUrl)
{
ReturnPath = returnUrl;
TransfersCookiesUrl = $"{_options.Value.TransfersUrl}/cookie-preferences?returnUrl=%2Fhome";

if (Request.Cookies.ContainsKey(CONSENT_COOKIE_NAME))
{
Consent = bool.Parse(Request.Cookies[CONSENT_COOKIE_NAME] ?? string.Empty);
}

if (consent.HasValue)
{
PreferencesSet = true;

ApplyCookieConsent(consent);

if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}

return RedirectToPage(Links.Public.CookiePreferences);
}

return Page();
}

public IActionResult OnPost(bool? consent, string returnUrl)
{
ReturnPath = returnUrl;

if (Request.Cookies.ContainsKey(CONSENT_COOKIE_NAME))
{
Consent = bool.Parse(Request.Cookies[CONSENT_COOKIE_NAME] ?? string.Empty);
}

if (consent.HasValue)
{
Consent = consent;
PreferencesSet = true;

CookieOptions cookieOptions = new() { Expires = DateTime.Today.AddMonths(6), Secure = true, HttpOnly = true };
Response.Cookies.Append(CONSENT_COOKIE_NAME, consent.Value.ToString(), cookieOptions);

if (consent.Value is false)
{
ApplyCookieConsent(false);
}

return Page();
}

return Page();
}

private void ApplyCookieConsent(bool? consent)
{
if (consent.HasValue)
{
CookieOptions cookieOptions = new() { Expires = DateTime.Today.AddMonths(6), Secure = true, HttpOnly = true };
Response.Cookies.Append(CONSENT_COOKIE_NAME, consent.Value.ToString(), cookieOptions);
}

if (consent is false)
{
foreach (string cookie in Request.Cookies.Keys)
{
if (cookie.StartsWith("_ga") || cookie.Equals("_gid"))
{
_logger.LogInformation("Expiring Google analytics cookie: {cookie}", cookie);
Response.Cookies.Append(cookie, string.Empty, new CookieOptions { Expires = DateTime.Now.AddDays(-1), Secure = true, SameSite = SameSiteMode.Lax, HttpOnly = true });
}
}
}
}
}
using Dfe.PrepareConversions.Configuration;
using Dfe.PrepareConversions.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;

namespace Dfe.PrepareConversions.Pages.Public;

public class CookiePreferences : PageModel
{
private const string CONSENT_COOKIE_NAME = ".ManageAnAcademyConversion.Consent";
private readonly ILogger<CookiePreferences> _logger;
private readonly IOptions<ServiceLinkOptions> _options;

public CookiePreferences(ILogger<CookiePreferences> logger, IOptions<ServiceLinkOptions> options)
{
_logger = logger;
_options = options;
}

public bool? Consent { get; set; }
public bool PreferencesSet { get; set; }
public string ReturnPath { get; set; }

public string TransfersCookiesUrl { get; set; }

public ActionResult OnGet(bool? consent, string returnUrl)
{
ReturnPath = returnUrl;
TransfersCookiesUrl = $"{_options.Value.TransfersUrl}/cookie-preferences?returnUrl=%2Fhome";

if (Request.Cookies.ContainsKey(CONSENT_COOKIE_NAME))
{
Consent = bool.Parse(Request.Cookies[CONSENT_COOKIE_NAME] ?? string.Empty);
}

if (consent.HasValue)
{
PreferencesSet = true;

ApplyCookieConsent(consent);

if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}

return RedirectToPage(Links.Public.CookiePreferences);
}

return Page();
}

public IActionResult OnPost(bool? consent, string returnUrl)
{
ReturnPath = returnUrl;

if (Request.Cookies.ContainsKey(CONSENT_COOKIE_NAME))
{
Consent = bool.Parse(Request.Cookies[CONSENT_COOKIE_NAME] ?? string.Empty);
}

if (consent.HasValue)
{
Consent = consent;
PreferencesSet = true;

CookieOptions cookieOptions = new() { Expires = DateTime.Today.AddMonths(6), Secure = true, HttpOnly = true };
Response.Cookies.Append(CONSENT_COOKIE_NAME, consent.Value.ToString(), cookieOptions);

if (consent.Value is false)
{
ApplyCookieConsent(false);
}

return Page();
}

return Page();
}

private void ApplyCookieConsent(bool? consent)
{
if (consent.HasValue)
{
CookieOptions cookieOptions = new() { Expires = DateTime.Today.AddMonths(6), Secure = true, HttpOnly = true };
Response.Cookies.Append(CONSENT_COOKIE_NAME, consent.Value.ToString(), cookieOptions);
}

if (consent is false)
{
foreach (string cookie in Request.Cookies.Keys)
{
// Google Analytics
if (cookie.StartsWith("_ga") || cookie.Equals("_gid"))
{
_logger.LogInformation("Expiring Google analytics cookie: {cookie}", cookie);
Response.Cookies.Append(cookie, string.Empty, new CookieOptions { Expires = DateTime.Now.AddDays(-1), Secure = true, SameSite = SameSiteMode.Lax, HttpOnly = true });
}
// App Insights
if (cookie.StartsWith("ai_"))
{
_logger.LogInformation("Expiring App insights cookie: {cookie}", cookie);
Response.Cookies.Append(cookie, string.Empty, new CookieOptions { Expires = DateTime.Now.AddYears(-1), Secure = true, SameSite = SameSiteMode.Lax, HttpOnly = true });
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
var analyticsConsent = Context.Request.Cookies.ContainsKey(".ManageAnAcademyConversion.Consent")
&& bool.Parse(Context.Request.Cookies[".ManageAnAcademyConversion.Consent"] ?? string.Empty);

var showAnalytics = Configuration["GoogleAnalytics:Enable"] == "Yes" && analyticsConsent;
var enableGoogleAnalytics = Configuration["GoogleAnalytics:Enable"] == "Yes" && analyticsConsent;
var enableAppInsightsAnalytics = Configuration["ApplicationInsights:EnableBrowserAnalytics"] == "Yes" && analyticsConsent;

var titleDescription = Context.Request.Path == "/project-type"
? string.Empty
Expand All @@ -15,6 +16,8 @@
var isFormAMatPage = Context.Request.Path.Value.Contains("/form-a-mat/project-list") || Context.Request.Path.Value.Contains("/schools-in-this-mat/");

var notificationBannerMessage = Configuration["notificationBannerMessage"] ?? string.Empty;

var authenticatedUserId = User.Identity is not null && User.Identity.IsAuthenticated ? User.Identity.Name ?? "Unknown" : "Anonymous";
}

<!DOCTYPE html>
Expand All @@ -38,7 +41,7 @@
<link rel="stylesheet" href="~/dist/site.css" />
<link rel="stylesheet" href="~/dist/accessible-autocomplete.min.css" asp-add-nonce />
<link rel="stylesheet" href="~/dist/dfefrontend-1.0.1.min.css" asp-add-nonce />
@if (showAnalytics)
@if (enableGoogleAnalytics)
{
<!-- Google Tag Manager -->
<script asp-add-nonce>
Expand All @@ -49,24 +52,39 @@
}); var f = d.getElementsByTagName(s)[0],
j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-5H6G773');</script>
<!-- End Google Tag Manager -->
})(window, document, 'script', 'dataLayer', 'GTM-5H6G773');
</script>
<!-- End Google Tag Manager -->
}

@if (analyticsConsent)
@if (enableAppInsightsAnalytics)
{
<!-- Google Tag Manager (noscript) -->
<noscript asp-add-nonce>
<iframe title="GATagManager" src=https://www.googletagmanager.com/ns.html?id =GTM-5H6G773 height="0" width="0" style="display: none; visibility: hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<!-- Application insights -->
<script type="text/javascript" integrity="sha384-g/ZkzetdQypWdY0NBZT5r2L3BR9/hURD8OBcd1rEaBpgX6QC7EaTL+o+mzWrBcXW" crossorigin="anonymous" src="https://js.monitor.azure.com/scripts/b/ext/ai.clck.2.8.18.min.js"></script>
<script type="text/javascript" asp-add-nonce>
window.appInsights = {
connectionString: '@Configuration["ApplicationInsights:ConnectionString"]',
authenticatedUserId: '@authenticatedUserId'
}
</script>
<script type="text/javascript" src="~/dist/application-insights.min.js" asp-add-nonce></script>
<!-- End Application insights -->
}

<script type="text/javascript" src="~/dist/accessible-autocomplete.min.js" asp-add-nonce></script>

</head>
<body class="govuk-template__body">

@if (enableGoogleAnalytics)
{
<!-- Google Tag Manager (noscript) -->
<noscript asp-add-nonce>
<iframe title="GATagManager" src="https://www.googletagmanager.com/ns.html?id=GTM-5H6G773" height="0" width="0" style="display: none; visibility: hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
}

<script asp-add-nonce>
document.body.className = ((document.body.className) ? document.body.className + ' js-enabled' : 'js-enabled');
</script>
Expand Down
Loading
Loading