From 127953dc141955d1cc6306af01e61ee3942bd4fb Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Thu, 27 Mar 2025 19:56:53 -0700 Subject: [PATCH] CU-868d85dv8 More upgrade work and posthog work. --- .../Resgrid.Providers.MigrationsPg.csproj | 1 + .../Controllers/AccountController.cs | 34 ++++++++++++++++-- .../Middleware/FeatureFlagContextProvider.cs | 36 +++++++++++++++++++ Web/Resgrid.Web/Program.cs | 1 + Web/Resgrid.Web/Resgrid.Web.csproj | 1 + Web/Resgrid.Web/Startup.cs | 22 ++++++++++++ .../Quidjibo.Postgres.csproj | 1 + 7 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 Web/Resgrid.Web/Middleware/FeatureFlagContextProvider.cs diff --git a/Providers/Resgrid.Providers.MigrationsPg/Resgrid.Providers.MigrationsPg.csproj b/Providers/Resgrid.Providers.MigrationsPg/Resgrid.Providers.MigrationsPg.csproj index 191b58a61..7025c4567 100644 --- a/Providers/Resgrid.Providers.MigrationsPg/Resgrid.Providers.MigrationsPg.csproj +++ b/Providers/Resgrid.Providers.MigrationsPg/Resgrid.Providers.MigrationsPg.csproj @@ -26,6 +26,7 @@ + diff --git a/Web/Resgrid.Web/Controllers/AccountController.cs b/Web/Resgrid.Web/Controllers/AccountController.cs index fec0099b2..b545dff4f 100644 --- a/Web/Resgrid.Web/Controllers/AccountController.cs +++ b/Web/Resgrid.Web/Controllers/AccountController.cs @@ -23,6 +23,8 @@ using Microsoft.AspNetCore.Http; using System.Security.Claims; using Microsoft.AspNetCore.Localization; +using static Microsoft.ApplicationInsights.MetricDimensionNames.TelemetryContext; +using PostHog; namespace Resgrid.Web.Controllers { @@ -45,12 +47,14 @@ public class AccountController : Controller private readonly IEmailMarketingProvider _emailMarketingProvider; private readonly ISystemAuditsService _systemAuditsService; private readonly ICacheProvider _cacheProvider; - + private readonly IPostHogClient _posthog; + + public AccountController( UserManager userManager, SignInManager signInManager, IDepartmentsService departmentsService, IUsersService usersService, IEmailService emailService, IInvitesService invitesService, IUserProfileService userProfileService, ISubscriptionsService subscriptionsService, IAffiliateService affiliateService, IEventAggregator eventAggregator, IEmailMarketingProvider emailMarketingProvider, - ISystemAuditsService systemAuditsService, ICacheProvider cacheProvider) + ISystemAuditsService systemAuditsService, ICacheProvider cacheProvider, IPostHogClient posthog) { _userManager = userManager; _signInManager = signInManager; @@ -65,6 +69,7 @@ public AccountController( _emailMarketingProvider = emailMarketingProvider; _systemAuditsService = systemAuditsService; _cacheProvider = cacheProvider; + _posthog = posthog; } #endregion Private Members and Constructors @@ -128,6 +133,29 @@ await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, { var token = await ApiAuthHelper.GetBearerApiTokenAsync(model.Username, model.Password); await _cacheProvider.SetStringAsync(CacheConfig.ApiBearerTokenKeyName + $"_${userId}", token, new TimeSpan(48, 0, 0)); + + if (!String.IsNullOrWhiteSpace(TelemetryConfig.PostHogApiKey)) + { + var email = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value; + var departmentId = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.PrimaryGroupSid)?.Value; + var departmentName = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Actor)?.Value; + var name = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value; + var createdOn = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.OtherPhone)?.Value; + + await _posthog.IdentifyAsync( + userId, + email, + name, + personPropertiesToSet: new() + { + ["departmentId"] = departmentId, + ["departmentName"] = departmentName, + }, + personPropertiesToSetOnce: new() + { + ["createdOn"] = createdOn + }); + } } } catch (Exception ex) @@ -139,7 +167,7 @@ await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, Response.Cookies.Delete(".AspNetCore.Identity.ApplicationC1"); Response.Cookies.Delete(".AspNetCore.Identity.ApplicationC2"); Response.Cookies.Delete(".AspNetCore.Identity.ApplicationC3"); - + if (!String.IsNullOrWhiteSpace(returnUrl)) return RedirectToLocal(returnUrl); else diff --git a/Web/Resgrid.Web/Middleware/FeatureFlagContextProvider.cs b/Web/Resgrid.Web/Middleware/FeatureFlagContextProvider.cs new file mode 100644 index 000000000..e622ddae3 --- /dev/null +++ b/Web/Resgrid.Web/Middleware/FeatureFlagContextProvider.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Http; +using PostHog.FeatureManagement; +using PostHog; +using System.Collections.Generic; +using System.Threading.Tasks; +using Resgrid.Web.Helpers; + +namespace Resgrid.Web.Middleware +{ + /// + /// Provides context and options used to evaluate feature flags for the Resgrid application. + /// + /// The used to get the current user's Id. + public class FeatureFlagContextProvider(IHttpContextAccessor httpContextAccessor) + : PostHogFeatureFlagContextProvider + { + protected override string? GetDistinctId() => + httpContextAccessor.HttpContext?.User.Identity?.Name; + + protected override ValueTask GetFeatureFlagOptionsAsync() + { + return ValueTask.FromResult( + new FeatureFlagOptions + { + PersonProperties = new Dictionary + { + ["email"] = ClaimsAuthorizationHelper.GetEmailAddress(), + }, + Groups = [ + new Group("departmentId", ClaimsAuthorizationHelper.GetDepartmentId().ToString()) + ], + OnlyEvaluateLocally = true + }); + } + } +} diff --git a/Web/Resgrid.Web/Program.cs b/Web/Resgrid.Web/Program.cs index 4f296dea6..c55692c78 100644 --- a/Web/Resgrid.Web/Program.cs +++ b/Web/Resgrid.Web/Program.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Resgrid.Config; using Sentry.Profiling; +using PostHog; namespace Resgrid.Web { diff --git a/Web/Resgrid.Web/Resgrid.Web.csproj b/Web/Resgrid.Web/Resgrid.Web.csproj index bab4c9e39..cfb943c75 100644 --- a/Web/Resgrid.Web/Resgrid.Web.csproj +++ b/Web/Resgrid.Web/Resgrid.Web.csproj @@ -57,6 +57,7 @@ + diff --git a/Web/Resgrid.Web/Startup.cs b/Web/Resgrid.Web/Startup.cs index 243c2593a..a203ca6f0 100644 --- a/Web/Resgrid.Web/Startup.cs +++ b/Web/Resgrid.Web/Startup.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using System.Reflection; +using System.Reflection.PortableExecutable; using System.Threading.Tasks; using Audit.Core; using Autofac; @@ -26,6 +27,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using PostHog.Config; +using PostHog; using Resgrid.Config; using Resgrid.Framework; using Resgrid.Localization; @@ -53,6 +56,8 @@ using StackExchange.Redis; using Stripe; using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; +using Microsoft.Extensions.Http.Logging; +using Resgrid.Web.Middleware; namespace Resgrid.Web { @@ -429,6 +434,23 @@ public void ConfigureServices(IServiceCollection services) services.AddSentryTunneling(); } + if (!string.IsNullOrWhiteSpace(Config.TelemetryConfig.PostHogApiKey)) + { + services.AddPostHog(options => + { + options.PostConfigure(o => + { + o.HostUrl = new Uri(TelemetryConfig.PostHogUrl); + o.ProjectApiKey = TelemetryConfig.PostHogApiKey; + o.SuperProperties.Add("app_name", "ResgridWeb"); + o.SuperProperties.Add("environment", SystemBehaviorConfig.Environment); + }); + + // Enables PostHog as a provider for ASP.NET Core's feature management system. + options.UseFeatureManagement(); + }); + } + this.Services = services; //if (Config.ExternalErrorConfig.ApplicationInsightsEnabled) diff --git a/Workers/Support/Quidjibo.Postgres/Quidjibo.Postgres.csproj b/Workers/Support/Quidjibo.Postgres/Quidjibo.Postgres.csproj index c6f9f035a..559ba9bed 100644 --- a/Workers/Support/Quidjibo.Postgres/Quidjibo.Postgres.csproj +++ b/Workers/Support/Quidjibo.Postgres/Quidjibo.Postgres.csproj @@ -61,6 +61,7 @@ +