public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { Site site = null; var httpContext = context.HttpContext; // if we've already fetched it on this request it's present in Items int?siteId = null; if (httpContext.User.Identity.IsAuthenticated) { // if the user is authenticated, that is their site siteId = new UserClaimLookup(httpContext.User).GetId(ClaimType.SiteId); } else { string sitePath = context.RouteData.Values["sitePath"]?.ToString(); // first check, did they use a sitePath giving them a specific site if (!string.IsNullOrEmpty(sitePath)) { site = await _siteLookupService.GetSiteByPathAsync(sitePath); if (site != null) { siteId = site.Id; } } // if not check if they already have one in their session if (siteId == null) { siteId = httpContext.Session.GetInt32(SessionKey.SiteId); } // if not then resort to the default if (siteId == null) { siteId = await _siteLookupService.GetDefaultSiteIdAsync(); } } if (site == null) { site = await _siteLookupService.GetByIdAsync((int)siteId); } httpContext.Items[ItemKey.GoogleAnalytics] = site.GoogleAnalyticsTrackingId; httpContext.Items[ItemKey.SiteStage] = _siteLookupService.GetSiteStageAsync(site); httpContext.Session.SetInt32(SessionKey.SiteId, (int)siteId); httpContext.Items[ItemKey.SiteId] = (int)siteId; await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { Site site = null; var httpContext = context.HttpContext; // if we've already fetched it on this request it's present in Items int?siteId = null; if (httpContext.User.Identity.IsAuthenticated) { // if the user is authenticated, that is their site try { siteId = _userContextProvider.GetId(httpContext.User, ClaimType.SiteId); } catch (Exception ex) { _logger.LogError($"Unable to get SiteId claim for user {httpContext.User.Identity.Name}: {ex.Message}"); } } if (siteId == null) { string sitePath = context.RouteData.Values["sitePath"]?.ToString(); // first check, did they use a sitePath giving them a specific site if (!string.IsNullOrEmpty(sitePath)) { site = await _siteLookupService.GetSiteByPathAsync(sitePath); if (site != null) { siteId = site.Id; } } // if not check if they already have one in their session if (siteId == null) { siteId = httpContext.Session.GetInt32(SessionKey.SiteId); } // if not then resort to the default if (siteId == null) { siteId = await _siteLookupService.GetDefaultSiteIdAsync(); } } if (site == null) { site = await _siteLookupService.GetByIdAsync((int)siteId); } var siteStage = _siteLookupService.GetSiteStage(site); bool showChallenges = true; bool showEvents = true; if (siteStage == SiteStage.BeforeRegistration) { // we might need to hide challenges and/or events since we're pre-registration // hide means that if the value is set then we want showChallenges to be false // hence == null rather than != null showChallenges = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey.Challenges.HideUntilRegistrationOpen)? .Value == null; showEvents = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey.Events.HideUntilRegistrationOpen)? .Value == null; } httpContext.Items[ItemKey.GoogleAnalytics] = site.GoogleAnalyticsTrackingId; httpContext.Items[ItemKey.SiteStage] = siteStage; httpContext.Session.SetInt32(SessionKey.SiteId, (int)siteId); httpContext.Items[ItemKey.SiteId] = (int)siteId; httpContext.Items[ItemKey.ShowChallenges] = showChallenges; httpContext.Items[ItemKey.ShowEvents] = showEvents; // only check if the site.css and site.js have changed periodically by default and cache // the last modification time string siteCssCacheKey = $"s{siteId}.{CacheKey.SiteCss}"; string siteJsCacheKey = $"s{siteId}.{CacheKey.SiteJs}"; var cssLastModified = await _cache.GetStringAsync(siteCssCacheKey); var jsLastModified = await _cache.GetStringAsync(siteJsCacheKey); // compute the appropriate cache time in minutes, default to 60 if not provided int cacheMinutes = 60; var cacheSiteCustomizationsMinutes = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey.Web.CacheSiteCustomizationsMinutes)? .Value; if (cacheSiteCustomizationsMinutes != null) { if (!int.TryParse(cacheSiteCustomizationsMinutes, out cacheMinutes)) { _logger.LogError("Could not convert cache site customizations value to a number: {cacheSiteCustomizationsMinutes}", cacheSiteCustomizationsMinutes); } } // kill any cached values if the cache value was set to 0 if (cacheMinutes == 0) { if (!string.IsNullOrEmpty(cssLastModified)) { await _cache.RemoveAsync(siteCssCacheKey); } if (!string.IsNullOrEmpty(jsLastModified)) { await _cache.RemoveAsync(siteJsCacheKey); } } // check for a cache miss and compute the appropriate last modification date if (string.IsNullOrEmpty(cssLastModified) || string.IsNullOrEmpty(jsLastModified)) { // file path to the site.css file string file = _pathResolver.ResolveContentFilePath( Path.Combine($"site{siteId}", "styles", "site.css")); cssLastModified = await UpdateCacheAsync(file, cacheMinutes, cssLastModified, siteCssCacheKey); // file path to the site.js file file = _pathResolver.ResolveContentFilePath( Path.Combine($"site{siteId}", "scripts", "site.js")); jsLastModified = await UpdateCacheAsync(file, cacheMinutes, jsLastModified, siteJsCacheKey); } // if we have values then set appropriate HttpContext.Items if (!string.IsNullOrEmpty(cssLastModified) || !string.IsNullOrEmpty(jsLastModified)) { string contentPath = _config[ConfigurationKey.ContentPath].StartsWith("/") ? _config[ConfigurationKey.ContentPath] : $"/{_config[ConfigurationKey.ContentPath]}"; if (!string.IsNullOrEmpty(cssLastModified)) { httpContext.Items[ItemKey.SiteCss] = $"{contentPath}/site{siteId}/styles/site.css?v={cssLastModified}"; } if (!string.IsNullOrEmpty(jsLastModified)) { httpContext.Items[ItemKey.SiteJs] = $"{contentPath}/site{siteId}/scripts/site.js?v={jsLastModified}"; } } if (string.IsNullOrEmpty(httpContext.Session.GetString(SessionKey.CallItGroup))) { httpContext.Items[ItemKey.HouseholdTitle] = "Family"; } else { httpContext.Items[ItemKey.HouseholdTitle] = "Group"; } if (!string.IsNullOrWhiteSpace(site.ExternalEventListUrl)) { httpContext.Items[ItemKey.ExternalEventListUrl] = site.ExternalEventListUrl; } await next(); }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { Site site = null; await context.HttpContext.Session.LoadAsync(); // if we've already fetched it on this request it's present in Items int?siteId = null; if (context.HttpContext.User.Identity.IsAuthenticated) { // if the user is authenticated, that is their site try { siteId = _userContextProvider.GetId(context.HttpContext.User, ClaimType.SiteId); } catch (Exception ex) { _logger.LogError("Unable to get SiteId claim for user {Name}: {Message}", context.HttpContext.User.Identity.Name, ex.Message); } } if (siteId == null) { string sitePath = context.RouteData.Values["sitePath"]?.ToString(); // first check, did they use a sitePath giving them a specific site if (!string.IsNullOrEmpty(sitePath)) { site = await _siteLookupService.GetSiteByPathAsync(sitePath); if (site != null) { siteId = site.Id; } } // if not check if they already have one in their session if (siteId == null) { siteId = context.HttpContext.Session.GetInt32(SessionKey.SiteId); } // if not then resort to the default if (siteId == null) { siteId = await _siteLookupService.GetDefaultSiteIdAsync(); } } if (site == null) { site = await _siteLookupService.GetByIdAsync((int)siteId); } var siteStage = _siteLookupService.GetSiteStage(site); // we might need to hide challenges and/or events based on system settings // the setting is to hide so the logic is == null rather than != null bool showChallenges = true; bool showEvents = true; if (siteStage == SiteStage.RegistrationOpen || siteStage == SiteStage.BeforeRegistration) { showEvents = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey .Events .HideUntilProgramOpen)? .Value == null; } if (siteStage == SiteStage.BeforeRegistration) { showChallenges = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey .Challenges .HideUntilRegistrationOpen)? .Value == null; if (!showEvents) { // they might be hidden above showEvents = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey .Events .HideUntilRegistrationOpen)? .Value == null; } } context.HttpContext.Items[ItemKey.GoogleAnalytics] = site.GoogleAnalyticsTrackingId; context.HttpContext.Items[ItemKey.RouteId] = context.RouteData.Values["id"]; context.HttpContext.Items[ItemKey.SiteName] = site?.Name ?? _config[ConfigurationKey.DefaultSiteName]; context.HttpContext.Items[ItemKey.SiteStage] = siteStage; context.HttpContext.Session.SetInt32(SessionKey.SiteId, (int)siteId); context.HttpContext.Items[ItemKey.SiteId] = (int)siteId; context.HttpContext.Items[ItemKey.ShowChallenges] = showChallenges; context.HttpContext.Items[ItemKey.ShowEvents] = showEvents; context.HttpContext.Items[ItemKey.WebScheme] = site.IsHttpsForced ? "https" : "http"; // only check if the site.css and site.js have changed periodically by default and // cache the last modification time string siteCssCacheKey = $"s{siteId}.{CacheKey.SiteCss}"; string siteJsCacheKey = $"s{siteId}.{CacheKey.SiteJs}"; var cssLastModified = await _cache.GetStringAsync(siteCssCacheKey); var jsLastModified = await _cache.GetStringAsync(siteJsCacheKey); // compute the appropriate cache time in minutes, default to 60 if not provided int cacheMinutes = 60; var cacheSiteCustomizationsMinutes = site.Settings .FirstOrDefault(_ => _.Key == SiteSettingKey.Web.CacheSiteCustomizationsMinutes)? .Value; if (cacheSiteCustomizationsMinutes != null && !int.TryParse(cacheSiteCustomizationsMinutes, out cacheMinutes)) { _logger.LogError("Could not convert cache site customizations value to a number: {cacheSiteCustomizationsMinutes}", cacheSiteCustomizationsMinutes); } // kill any cached values if the cache value was set to 0 if (cacheMinutes == 0) { if (!string.IsNullOrEmpty(cssLastModified)) { await _cache.RemoveAsync(siteCssCacheKey); } if (!string.IsNullOrEmpty(jsLastModified)) { await _cache.RemoveAsync(siteJsCacheKey); } } // check for a cache miss and compute the appropriate last modification date if (string.IsNullOrEmpty(cssLastModified) || string.IsNullOrEmpty(jsLastModified)) { // file path to the site.css file string file = _pathResolver.ResolveContentFilePath( Path.Combine($"site{siteId}", "styles", "site.css")); cssLastModified = await UpdateCacheAsync(file, cacheMinutes, cssLastModified, siteCssCacheKey); // file path to the site.js file file = _pathResolver.ResolveContentFilePath( Path.Combine($"site{siteId}", "scripts", "site.js")); jsLastModified = await UpdateCacheAsync(file, cacheMinutes, jsLastModified, siteJsCacheKey); } // if we have values then set appropriate HttpContext.Items if (!string.IsNullOrEmpty(cssLastModified) || !string.IsNullOrEmpty(jsLastModified)) { string contentPath = _config[ConfigurationKey.ContentPath].StartsWith("/") ? _config[ConfigurationKey.ContentPath] : $"/{_config[ConfigurationKey.ContentPath]}"; if (!string.IsNullOrEmpty(cssLastModified)) { context.HttpContext.Items[ItemKey.SiteCss] = $"{contentPath}/site{siteId}/styles/site.css?v={cssLastModified}"; } if (!string.IsNullOrEmpty(jsLastModified)) { context.HttpContext.Items[ItemKey.SiteJs] = $"{contentPath}/site{siteId}/scripts/site.js?v={jsLastModified}"; } } context.HttpContext.Items[ItemKey.HouseholdTitle] = string.IsNullOrEmpty(context .HttpContext .Session .GetString(SessionKey.CallItGroup)) ? Annotations.Interface.Family : Annotations.Interface.Group; if (!string.IsNullOrWhiteSpace(site.ExternalEventListUrl)) { context.HttpContext.Items[ItemKey.ExternalEventListUrl] = site.ExternalEventListUrl; } var currentCulture = _userContextProvider.GetCurrentCulture(); context.HttpContext.Items[ItemKey.ISOLanguageName] = currentCulture.TwoLetterISOLanguageName; int?activeUserId = _userContextProvider.GetContext().ActiveUserId; if (_l10nOptions.Value?.SupportedCultures.Count > 1) { var cookieCulture = context .HttpContext .Request .Cookies[CookieRequestCultureProvider.DefaultCookieName]; if (currentCulture.Name == Culture.DefaultName) { if (cookieCulture != null) { context .HttpContext .Response .Cookies .Delete(CookieRequestCultureProvider.DefaultCookieName); if (activeUserId != null) { await _userService.UpdateCulture(null); } } } else { // no cookie or new culture selected, reset cookie context.HttpContext.Response.Cookies.Append( CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider .MakeCookieValue(new RequestCulture(currentCulture.Name)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddDays(14) } ); if (activeUserId != null) { await _userService.UpdateCulture(currentCulture.Name); } } // generate list for drop-down var cultureList = new List <SelectListItem>(); var cultureHrefLang = new Dictionary <string, string> { { "x-default", Culture.DefaultName } }; foreach (var culture in _l10nOptions.Value.SupportedCultures) { var text = culture.Parent != null ? culture.Parent.NativeName : culture.NativeName; cultureList.Add(new SelectListItem(text, culture.Name)); if (!cultureHrefLang.Keys.Contains(culture.Name)) { cultureHrefLang.Add(culture.Name, culture.Name); if (culture.Parent != null && !cultureHrefLang.Keys.Contains(culture.Parent.Name)) { cultureHrefLang.Add(culture.Parent.Name, culture.Parent.Name); } } } context.HttpContext.Items[ItemKey.HrefLang] = cultureHrefLang; context.HttpContext.Items[ItemKey.L10n] = cultureList.OrderBy(_ => _.Text); } using (LogContext.PushProperty(LoggingEnrichment.ActiveUserId, activeUserId)) using (LogContext.PushProperty(LoggingEnrichment.LanguageId, currentCulture?.TwoLetterISOLanguageName)) using (LogContext.PushProperty(LoggingEnrichment.RouteAction, context.RouteData?.Values["action"])) using (LogContext.PushProperty(LoggingEnrichment.RouteArea, context.RouteData?.Values["area"])) using (LogContext.PushProperty(LoggingEnrichment.RouteController, context.RouteData?.Values["controller"])) using (LogContext.PushProperty(LoggingEnrichment.RouteId, context.RouteData?.Values["id"])) using (LogContext.PushProperty(LoggingEnrichment.SiteStage, siteStage)) { await next(); } }
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { Site site = null; var httpContext = context.HttpContext; // if we've already fetched it on this request it's present in Items int?siteId = null; if (httpContext.User.Identity.IsAuthenticated) { // if the user is authenticated, that is their site try { siteId = _userContextProvider.GetId(httpContext.User, ClaimType.SiteId); } catch (Exception ex) { _logger.LogError($"Unable to get SiteId claim for user {httpContext.User.Identity.Name}: {ex.Message}"); } } if (siteId == null) { string sitePath = context.RouteData.Values["sitePath"]?.ToString(); // first check, did they use a sitePath giving them a specific site if (!string.IsNullOrEmpty(sitePath)) { site = await _siteLookupService.GetSiteByPathAsync(sitePath); if (site != null) { siteId = site.Id; } } // if not check if they already have one in their session if (siteId == null) { siteId = httpContext.Session.GetInt32(SessionKey.SiteId); } // if not then resort to the default if (siteId == null) { siteId = await _siteLookupService.GetDefaultSiteIdAsync(); } } if (site == null) { site = await _siteLookupService.GetByIdAsync((int)siteId); } var siteStage = _siteLookupService.GetSiteStage(site); bool showChallenges = true; bool showEvents = true; if (siteStage == SiteStage.BeforeRegistration) { // we might need to hide challenges and/or events since we're pre-registration // hide means that if the value is set then we want showChallenges to be false // hence == null rather than != null showChallenges = site.Settings .Where(_ => _.Key == SiteSettingKey.Challenges.HideUntilRegistrationOpen) .FirstOrDefault()? .Value == null; showEvents = site.Settings .Where(_ => _.Key == SiteSettingKey.Events.HideUntilRegistrationOpen) .FirstOrDefault()? .Value == null; } httpContext.Items[ItemKey.GoogleAnalytics] = site.GoogleAnalyticsTrackingId; httpContext.Items[ItemKey.SiteStage] = siteStage; httpContext.Session.SetInt32(SessionKey.SiteId, (int)siteId); httpContext.Items[ItemKey.SiteId] = (int)siteId; httpContext.Items[ItemKey.ShowChallenges] = showChallenges; httpContext.Items[ItemKey.ShowEvents] = showEvents; if (string.IsNullOrEmpty(httpContext.Session.GetString(SessionKey.CallItGroup))) { httpContext.Items[ItemKey.HouseholdTitle] = "Family"; } else { httpContext.Items[ItemKey.HouseholdTitle] = "Group"; } if (!string.IsNullOrWhiteSpace(site.ExternalEventListUrl)) { httpContext.Items[ItemKey.ExternalEventListUrl] = site.ExternalEventListUrl; } await next(); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IPathResolver pathResolver, RoleService roleService, SiteLookupService siteLookupService) { loggerFactory.AddSerilog(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseStatusCodePagesWithReExecute("/Error/Index/{0}"); } var dbContext = app.ApplicationServices.GetService <Data.Context>(); try { var pending = dbContext.GetPendingMigrations(); if (pending != null && pending.Count() > 0) { Log.Logger.Warning($"Applying {pending.Count()} database migrations, last is: {pending.Last()}"); } } catch (Exception ex) { Log.Logger.Error($"Error looking up migrations to perform: {ex.Message}"); } dbContext.Migrate(); Task.Run(() => siteLookupService.GetDefaultSiteIdAsync()).Wait(); Task.Run(() => roleService.SyncPermissionsAsync()).Wait(); app.UseRequestLocalization(); app.UseResponseCompression(); // configure static files with 7 day cache app.UseStaticFiles(new StaticFileOptions() { OnPrepareResponse = _ => { var headers = _.Context.Response.GetTypedHeaders(); headers.CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue() { MaxAge = TimeSpan.FromDays(7) }; } }); string contentPath = pathResolver.ResolveContentFilePath(); if (!Directory.Exists(contentPath)) { try { Directory.CreateDirectory(contentPath); } catch (Exception ex) { Console.WriteLine($"Unable to create directory '{contentPath}' in {Directory.GetCurrentDirectory()}"); throw (ex); } } string pathString = pathResolver.ResolveContentPath(); if (!pathString.StartsWith("/")) { pathString = "/" + pathString; } // configure /content with 7 day cache app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(contentPath), RequestPath = new PathString(pathString), OnPrepareResponse = _ => { var headers = _.Context.Response.GetTypedHeaders(); headers.CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue() { MaxAge = TimeSpan.FromDays(7) }; } }); app.UseSession(); // set cookie authentication options var cookieAuthOptions = new CookieAuthenticationOptions { AuthenticationScheme = Controllers.Authentication.SchemeGRACookie, LoginPath = new PathString("/SignIn/"), AccessDeniedPath = new PathString("/"), AutomaticAuthenticate = true, AutomaticChallenge = true }; // if there's a data protection path, set it up - for clustered/multi-server configs if (!string.IsNullOrEmpty(Configuration[ConfigurationKey.DataProtectionPath])) { string protectionPath = Configuration[ConfigurationKey.DataProtectionPath]; cookieAuthOptions.DataProtectionProvider = DataProtectionProvider.Create( new DirectoryInfo(Path.Combine(protectionPath, "cookies"))); } app.UseCookieAuthentication(cookieAuthOptions); // sitePath is also referenced in GRA.Controllers.Filter.SiteFilter app.UseMvc(routes => { routes.MapRoute( name: null, template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); routes.MapRoute( name: null, template: "{sitePath}/Info/{stub}", defaults: new { controller = "Info", action = "Index" }, constraints: new { sitePath = new SiteRouteConstraint(app.ApplicationServices.GetRequiredService <Controllers.Base.ISitePathValidator>()) }); routes.MapRoute( name: null, template: "Info/{stub}", defaults: new { controller = "Info", action = "Index" }); routes.MapRoute( name: null, template: "{sitePath}/{controller}/{action}/{id?}", defaults: new { controller = "Home", action = "Index" }, constraints: new { sitePath = new SiteRouteConstraint(app.ApplicationServices.GetRequiredService <Controllers.Base.ISitePathValidator>()) }); routes.MapRoute( name: null, template: "{controller=Home}/{action=Index}/{id?}"); }); app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) }); app.Use(async(context, next) => { if (context.WebSockets.IsWebSocketRequest) { var handler = app.ApplicationServices.GetService <WebSocketHandler>(); await handler.Handle(context); } else { await next(); } }); }