/// <summary> /// Determines if the content item should be shown to the current site visitor, based on the personalisation groups associated with it. /// </summary> /// <param name="pickedGroups">List of IPublishedContent items that are the groups you want to check against.</param> /// <param name="showIfNoGroupsDefined">Indicates the response to return if groups cannot be found on the content</param> /// <returns>True if content should be shown to visitor</returns> private static bool ShowToVisitor(IList <IPublishedContent> pickedGroups, bool showIfNoGroupsDefined = true) { if (!pickedGroups.Any()) { // No personalisation groups picked or no property for picker, so we return the provided default return(showIfNoGroupsDefined); } // Check each personalisation group assigned for a match with the current site visitor foreach (var group in pickedGroups) { var definition = group.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); if (IsStickyMatch(definition, group.Id)) { return(true); } var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // If matching any and matched at least one, or matching all and matched all - we've matched one of the definitions // associated with a selected personalisation group if ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())) { MakeStickyMatch(definition, group.Id); return(true); } } // If we've got here, we haven't found a match return(false); }
internal static int ScoreGroups(IList <IPublishedContent> pickedGroups) { // Package is disabled, return default if (PersonalisationGroupsConfig.Value.DisablePackage) { return(0); } // Check each personalisation group assigned for a match with the current site visitor var score = 0; foreach (var group in pickedGroups) { var definition = group.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); if (GroupMatchingHelper.IsStickyMatch(definition, group.Id)) { score += definition.Score; continue; } var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // If matching any and matched at least one, or matching all and matched all - we've matched one of the definitions // associated with a selected personalisation group if ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())) { GroupMatchingHelper.MakeStickyMatch(definition, group.Id); score += definition.Score; } } return(score); }
/// <summary> /// Scores the content item for the current site visitor, based on the personalisation groups associated with it. /// </summary> /// <param name="pickedGroups">List of IPublishedContent items that are the groups you want to check against.</param> /// <returns>True if content should be shown to visitor</returns> private static int ScoreForVisitor(IList <IPublishedContent> pickedGroups) { if (!pickedGroups.Any()) { // No personalisation groups picked or no property for picker, so we score zero return(0); } // Check each personalisation group assigned for a match with the current site visitor var score = 0; foreach (var group in pickedGroups) { var definition = group.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); if (IsStickyMatch(definition, group.Id)) { score += definition.Score; } var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // If matching any and matched at least one, or matching all and matched all - we've matched one of the definitions // associated with a selected personalisation group if ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())) { MakeStickyMatch(definition, group.Id); score += definition.Score; } } return(score); }
/// <summary> /// Adapted IsMatch from https://github.com/AndyButland/UmbracoPersonalisationGroups/blob/master/Zone.UmbracoPersonalisationGroups/ExtensionMethods/PublishedContentExtensions.cs /// </summary> public bool VisitorInSegment(string segmentKey) { var helper = new UmbracoHelper(UmbracoContext.Current); var segment = helper.TypedContent(segmentKey); if (segment == null) { return(false); //something went wrong, we didn't find the segment! } var definition = segment.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); if (IsStickyMatch(definition, segment.Id)) { return(true); } var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // If matching any and matched at least one, or matching all and matched all - we've matched one of the definitions // associated with a selected personalisation group if ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())) { MakeStickyMatch(definition, segment.Id); return(true); } // If we've got here, we haven't found a match return(false); }
internal static bool MatchGroups(IList <IPublishedContent> pickedGroups) { // Package is disabled, return default if (UmbracoConfig.For.PersonalisationGroups().DisablePackage) { return(true); } // Check each personalisation group assigned for a match with the current site visitor foreach (var group in pickedGroups) { var definition = group.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); if (IsStickyMatch(definition, group.Id)) { return(true); } var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // If matching any and matched at least one, or matching all and matched all - we've matched one of the definitions // associated with a selected personalisation group if ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())) { MakeStickyMatch(definition, group.Id); return(true); } } // If we've got here, we haven't found a match return(false); }
/// <summary> /// When overridden in a derived class, returns a read-only stream to the virtual resource. /// </summary> /// <returns> /// A read-only stream to the virtual file. /// </returns> public Stream Open() { string resourceName; // Get this assembly. Assembly assembly = typeof(ResourceController).Assembly; Stream output = EmbeddedResourceHelper.GetResource(assembly, this.virtualPath, out resourceName); if (output == null) { // We need to loop through the loaded criteria and check each one. Assembly localAssembly = assembly; IEnumerable <IPersonalisationGroupCriteria> criteria = PersonalisationGroupMatcher .GetAvailableCriteria().Where(a => a.GetType().Assembly != localAssembly); foreach (IPersonalisationGroupCriteria criterion in criteria) { string resource = EmbeddedResourceHelper.SanitizeCriteriaResourceName(this.virtualPath); assembly = criterion.GetType().Assembly; resourceName = assembly.GetManifestResourceNames().FirstOrDefault(r => r.InvariantEndsWith(resource)); if (!string.IsNullOrWhiteSpace(resourceName)) { return(EmbeddedResourceHelper.GetResource(assembly, resource, out resourceName)); } } } return(output); }
/// <summary> /// Adds an extension method to UmbracoHelper to calculate a hash for the current visitor for all visitor groups /// </summary> /// <param name="helper">Instance of UmbracoHelper</param> /// <param name="personalisationGroupsRootNode">Root node for the personalisation groups</param> /// <param name="cacheUserIdentifier">Identifier for the user to use in the cache key (likely the session Id)</param> /// <param name="cacheForSeconds">Length of time in seconds to cache the generated personalisation group hash for the visitor</param> /// <returns>Has for the visitor for all groups</returns> public static string GetPersonalisationGroupsHashForVisitor(this UmbracoHelper helper, IPublishedContent personalisationGroupsRootNode, string cacheUserIdentifier, int cacheForSeconds) { Mandate.ParameterNotNull(personalisationGroupsRootNode, "personalisationGroupsRootNode"); var cacheKey = $"{cacheUserIdentifier}-{AppConstants.CacheKeys.PersonalisationGroupsVisitorHash}"; return((string)UmbracoContext.Current.Application.ApplicationCache.RuntimeCache .GetCacheItem(cacheKey, () => { var groups = personalisationGroupsRootNode.Descendants(AppConstants.DocumentTypeAliases.PersonalisationGroup); var sb = new StringBuilder(); foreach (var group in groups) { var definition = group.GetPropertyValue <PersonalisationGroupDefinition>(AppConstants.PersonalisationGroupDefinitionPropertyAlias); var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); var matched = ((definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count())); if (sb.Length > 0) { sb.Append(","); } sb.AppendFormat("{0}={1}", group.Name, matched); } return sb.ToString().GetHashCode().ToString(); }, timeout: TimeSpan.FromSeconds(cacheForSeconds))); }
public void PersonalisationGroupMatcher_IsMatch_WithMatchingCriteria_ReturnsTrue() { // Arrange var definitionDetail = TestHelpers.Definitions.MatchingDayOfWeekDefinition(); // Act var result = PersonalisationGroupMatcher.IsMatch(definitionDetail); // Arrange Assert.IsTrue(result); }
public void PersonalisationGroupMatcher_IsMatch_WithMissingCritieria_ThrowsException() { // Arrange var definitionDetail = new PersonalisationGroupDefinitionDetail { Alias = "invalidAlias", Definition = string.Empty, }; // Act PersonalisationGroupMatcher.IsMatch(definitionDetail); }
public static void AppendMatchedGroupDetailToVisitorHashString(StringBuilder sb, PersonalisationGroupDefinition definition, string name) { var matchCount = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); var matched = (definition.Match == PersonalisationGroupDefinitionMatch.Any && matchCount > 0) || (definition.Match == PersonalisationGroupDefinitionMatch.All && matchCount == definition.Details.Count()); if (sb.Length > 0) { sb.Append(","); } sb.AppendFormat("{0}={1}", name, matched); }
/// <summary> /// Returns a value indicating whether the given resource exists. /// </summary> /// <param name="resource">The resource name.</param> /// <returns> /// The <see cref="bool"/>. /// </returns> public static bool ResourceExists(string resource) { // Sanitize the resource request. string resourceRoot = Constants.ResourceRoot; string criteriaRoot = Constants.ResourceForCriteriaRoot; string extension = Constants.ResourceExtension; if (resource.StartsWith(resourceRoot)) { resource = resource.TrimStart(resourceRoot).Replace("/", ".").TrimEnd(extension); } else if (resource.StartsWith(criteriaRoot)) { resource = resource.TrimStart(criteriaRoot).Replace("/", ".").TrimEnd(extension); } else if (resource.EndsWith(extension)) { resource = resource.TrimEnd(extension); } // Check this assembly first. Assembly assembly = typeof(ResourceController).Assembly; // Find the resource name; not case sensitive. string resourceName = assembly.GetManifestResourceNames().FirstOrDefault(r => r.InvariantEndsWith(resource)); if (string.IsNullOrWhiteSpace(resourceName)) { // We need to loop through the loaded criteria and check each one. Assembly localAssembly = assembly; IEnumerable <IPersonalisationGroupCriteria> criteria = PersonalisationGroupMatcher .GetAvailableCriteria().Where(a => a.GetType().Assembly != localAssembly); foreach (IPersonalisationGroupCriteria criterion in criteria) { assembly = criterion.GetType().Assembly; resourceName = assembly.GetManifestResourceNames().FirstOrDefault(r => r.InvariantEndsWith(resource)); if (!string.IsNullOrWhiteSpace(resourceName)) { return(true); } } } return(!string.IsNullOrWhiteSpace(resourceName)); }
public void PersonalisationGroupMatcher_IsMatch_WithMatchingCriteria_ReturnsTrue() { // Arrange var definitionDetail = new PersonalisationGroupDefinitionDetail { Alias = "dayOfWeek", Definition = string.Format("[ {0} ]", (int)(DateTime.Now.DayOfWeek) + 1), }; // Act var result = PersonalisationGroupMatcher.IsMatch(definitionDetail); // Arrange Assert.IsTrue(result); }
public void PersonalisationGroupMatcher_CountMatchingDefinitionDetails_WithDefinitonForMatchAll_AndMatchesAll_ReturnsCount() { // Arrange var definition = new PersonalisationGroupDefinition { Match = PersonalisationGroupDefinitionMatch.All, Details = new List <PersonalisationGroupDefinitionDetail> { TestHelpers.Definitions.MatchingDayOfWeekDefinition(), TestHelpers.Definitions.MatchingTimeOfDayDefinition(), } }; // Act var result = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // Assert Assert.AreEqual(2, result); }
public void PersonalisationGroupMatcher_CountMatchingDefinitionDetails_WithDefinitonForMatchAny_AndMatchingFirst_ReturnsShortCutCount() { // Arrange var definition = new PersonalisationGroupDefinition { Match = PersonalisationGroupDefinitionMatch.All, Details = new List <PersonalisationGroupDefinitionDetail> { Definitions.MatchingDayOfWeekDefinition(), Definitions.NonMatchingDayOfWeekDefinition(), Definitions.MatchingTimeOfDayDefinition(), } }; // Act var result = PersonalisationGroupMatcher.CountMatchingDefinitionDetails(definition); // Assert Assert.AreEqual(1, result); }
/// <summary> /// Gets an embedded resource for a given criteria, that may be from the main assembly or another one /// </summary> /// <param name="criteriaAlias">Alias of criteria</param> /// <param name="fileName">Name of resource</param> /// <returns>File stream of resource</returns> public ActionResult GetResourceForCriteria(string criteriaAlias, string fileName) { Mandate.ParameterNotNullOrEmpty(criteriaAlias, "criteriaAlias"); Mandate.ParameterNotNullOrEmpty(fileName, "fileName"); var criteria = PersonalisationGroupMatcher.GetAvailableCriteria() .SingleOrDefault(x => x.Alias.InvariantEquals(criteriaAlias)); if (criteria != null) { string resourceName; var resourceStream = EmbeddedResourceHelper.GetResource(criteria.GetType().Assembly, criteriaAlias + "." + fileName, out resourceName); if (resourceStream != null) { return(new FileStreamResult(resourceStream, GetMimeType(resourceName))); } } return(HttpNotFound()); }
/// <summary> /// Gets a count of the number of the definition details for a given personalisation group definition that matches /// the current site visitor /// </summary> /// <param name="definition">Personalisation group definition</param> /// <returns>Number of definition details that match</returns> private static int CountMatchingDefinitionDetails(PersonalisationGroupDefinition definition) { var matchCount = 0; foreach (var detail in definition.Details) { var isMatch = PersonalisationGroupMatcher.IsMatch(detail); if (isMatch) { matchCount++; } // We can short-cut here if matching any and found one match, or matching all and found one mismatch if ((isMatch && definition.Match == PersonalisationGroupDefinitionMatch.Any) || (!isMatch && definition.Match == PersonalisationGroupDefinitionMatch.All)) { break; } } return(matchCount); }
/// <summary> /// Gets a JSON list of the available criteria /// </summary> /// <returns>JSON response of available criteria</returns> /// <remarks>Using ContentResult so can serialize with camel case for consistency in client-side code</remarks> public ContentResult Index() { var criteria = PersonalisationGroupMatcher.GetAvailableCriteria(); return(CamelCasedJsonResult(criteria)); }