예제 #1
0
        private async Task <IEnumerable <Site> > GetSitesFromCacheAsync()
        {
            IEnumerable <Site> sites;
            var cachedSites = await _cache.GetStringFromCache(CacheKey.Sites);

            if (cachedSites == null)
            {
                sites = await _siteRepository.GetAllAsync();

                if (!sites.Any())
                {
                    _logger.LogInformation("No sites in database, inserting initial site");
                    sites = await InsertInitialSiteAsync();
                }
                await _cache.SaveToCacheAsync(CacheKey.Sites,
                                              JsonConvert.SerializeObject(sites),
                                              8);

                _logger.LogTrace("Cache miss on sites: {Count} loaded", sites.Count());
            }
            else
            {
                sites = JsonConvert.DeserializeObject <IEnumerable <Site> >(cachedSites);
            }

            foreach (var site in sites)
            {
                string key = $"s{site.Id}.{CacheKey.SiteSettings}";
                var    cachedSiteSettings = await _cache.GetStringFromCache(key);

                if (cachedSiteSettings == null)
                {
                    site.Settings = await _siteSettingRepository.GetBySiteIdAsync(site.Id);

                    await _cache.SaveToCacheAsync(key,
                                                  JsonConvert.SerializeObject(site.Settings),
                                                  8);

                    _logger.LogTrace("Cache miss on site settings for site id {Id}, {Count} loaded",
                                     site.Id,
                                     site.Settings.Count);
                }
                else
                {
                    site.Settings = JsonConvert.DeserializeObject <ICollection <SiteSetting> >(cachedSiteSettings);
                }
            }

            return(sites);
        }
예제 #2
0
        public async Task <StatusSummary> GetCurrentStatsAsync(ReportCriterion request)
        {
            if (request.SiteId == null ||
                request.SiteId != GetCurrentSiteId())
            {
                request.SiteId = GetCurrentSiteId();
            }
            string cacheKey    = $"s{request.SiteId}.p{request.ProgramId}.sys{request.SystemId}.b{request.BranchId}.{CacheKey.CurrentStats}";
            var    summaryJson = await _cache.GetStringFromCache(cacheKey);

            if (string.IsNullOrEmpty(summaryJson))
            {
                var summary = new StatusSummary
                {
                    RegisteredUsers     = await _userRepository.GetCountAsync(request),
                    Achievers           = await _userRepository.GetAchieverCountAsync(request),
                    PointsEarned        = await _userLogRepository.PointsEarnedTotalAsync(request),
                    CompletedChallenges = await _userLogRepository
                                          .CompletedChallengeCountAsync(request),
                    BadgesEarned = await _userLogRepository.EarnedBadgeCountAsync(request),
                    DaysUntilEnd = await GetDaysUntilEnd(),
                    AsOf         = _dateTimeProvider.Now
                };
                await _cache.SaveToCacheAsync(cacheKey,
                                              JsonConvert.SerializeObject(summary),
                                              ExpireInTimeSpan());

                return(summary);
            }
            else
            {
                return(JsonConvert.DeserializeObject <StatusSummary>(summaryJson));
            }
        }
예제 #3
0
        GetGeocodedAddressAsync(string address)
        {
            var serviceResult = new ServiceResult <string>();

            var(geocodingEnabled, APIKey) = await _siteLookupService.GetSiteSettingStringAsync(
                GetCurrentSiteId(),
                SiteSettingKey.Events.GoogleMapsAPIKey);

            if (!geocodingEnabled)
            {
                _logger.LogCritical("Geocoding called without geocoding enabled");

                serviceResult.Message = "Geocoding is not enabled.";
                serviceResult.Status  = ServiceResultStatus.Error;

                return(serviceResult);
            }

            var formattedAddress = address.Trim();

            var cacheKey    = $"a{formattedAddress}.{CacheKey.AddressGeocoding}";
            var geolocation = await _cache.GetStringFromCache(cacheKey);

            if (!string.IsNullOrWhiteSpace(geolocation))
            {
                serviceResult.Status = ServiceResultStatus.Success;
                serviceResult.Data   = geolocation;
            }
            else
            {
                dynamic jsonResult;

                using (var client = new HttpClient())
                {
                    try
                    {
                        var encodedAddress = WebUtility.UrlEncode(formattedAddress);
                        var response       = await client.GetAsync($"https://maps.googleapis.com/maps/api/geocode/json?address={encodedAddress}&key={APIKey}");

                        response.EnsureSuccessStatusCode();

                        var stringResult = await response.Content.ReadAsStringAsync();

                        jsonResult = JsonConvert.DeserializeObject(stringResult);

                        if (jsonResult.status == "ZERO_RESULTS")
                        {
                            serviceResult.Status  = ServiceResultStatus.Warning;
                            serviceResult.Message = "No results found for address.";
                        }
                        else if (jsonResult.status != "OK")
                        {
                            _logger.LogError($"Error getting geocoding results for address {address}: {jsonResult.status}");
                            serviceResult.Status  = ServiceResultStatus.Error;
                            serviceResult.Message = "An error occured, please try again later.";
                        }
                        else
                        {
                            var    result    = jsonResult.results[0];
                            double latitude  = result.geometry.location.lat;
                            double longitude = result.geometry.location.lng;

                            geolocation = $"{latitude},{longitude}";

                            await _cache.SaveToCacheAsync(cacheKey,
                                                          geolocation,
                                                          ExpireInTimeSpan(60));

                            serviceResult.Status = ServiceResultStatus.Success;
                            serviceResult.Data   = geolocation;
                        }
                    }
                    catch (HttpRequestException ex)
                    {
                        _logger.LogCritical(ex, $"Google API error: {ex.Message}");
                        serviceResult.Status  = ServiceResultStatus.Error;
                        serviceResult.Message = "An error occured, please try again later.";
                    }
                    catch (Exception ex)
                    {
                        _logger.LogCritical(ex, ex.Message);
                        serviceResult.Status  = ServiceResultStatus.Error;
                        serviceResult.Message = "An error occured, please try again later.";
                    }
                }
            }
            return(serviceResult);
        }
예제 #4
0
        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.GetStringFromCache(siteCssCacheKey);

            var jsLastModified = await _cache.GetStringFromCache(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();
                                    }
        }
예제 #5
0
        public async Task <Social> GetAsync(string culture)
        {
            var expiration = DateTime.Now.AddHours(CacheInHours).Ticks;

            int?headerId = await _cache.GetIntFromCacheAsync(CacheKey.SocialHeader);

            if (!headerId.HasValue)
            {
                var headerIdRecord = await _socialHeaderRepository
                                     .GetByDateAsync(_dateTimeProvider.Now);

                if (headerIdRecord == null)
                {
                    return(null);
                }

                if (headerIdRecord.NextStartDate.HasValue &&
                    headerIdRecord.NextStartDate.Value != default)
                {
                    expiration = Math.Min(expiration,
                                          headerIdRecord.NextStartDate.Value.Ticks);
                }

                await _cache.SaveToCacheAsync(CacheKey.SocialHeader,
                                              headerIdRecord.Id,
                                              TimeSpan.FromTicks(expiration));

                headerId = headerIdRecord.Id;
            }

            if (!headerId.HasValue)
            {
                return(null);
            }

            var languageId = await _languageService.GetLanguageIdAsync(culture);

            Social social = null;

            var cacheKey = GetCacheKey(CacheKey.Social, headerId.Value, languageId);

            var socialCache = await _cache.GetStringFromCache(cacheKey);

            if (!string.IsNullOrEmpty(socialCache))
            {
                try
                {
                    social = JsonSerializer.Deserialize <Social>(socialCache);
                }
                catch (JsonException jex)
                {
                    _logger.LogError("Unable to deserialize social object: {ErrorMessage}",
                                     jex.Message);
                }
            }

            if (social == null)
            {
                social = await _socialRepository.GetByHeaderLanguageAsync(headerId.Value, languageId);

                await _cache.SaveToCacheAsync(cacheKey,
                                              JsonSerializer.Serialize(social),
                                              TimeSpan.FromTicks(expiration));
            }

            return(social);
        }