protected virtual void AddDescendants(TaxonomyNode taxonomyNode, NavigationFilter filter, ILocalization localization) { using (new Tracer(taxonomyNode, filter, localization)) { // First recurse (depth-first) IList <SitemapItem> children = taxonomyNode.Items; foreach (TaxonomyNode childNode in children.OfType <TaxonomyNode>()) { AddDescendants(childNode, filter, localization); } // Add descendants (on the way back) string taxonomyId; string keywordId; string pageId; ParseSitemapItemId(taxonomyNode.Id, out taxonomyId, out keywordId, out pageId); string taxonomyUri = localization.GetCmUri(taxonomyId, (int)ItemType.Category); string keywordUri = string.IsNullOrEmpty(keywordId) ? taxonomyUri : localization.GetCmUri(keywordId, (int)ItemType.Keyword); IEnumerable <SitemapItem> additionalChildren = ExpandDescendants(keywordUri, taxonomyUri, filter, localization); foreach (SitemapItem additionalChildItem in additionalChildren.Where(childItem => children.All(i => i.Id != childItem.Id))) { children.Add(additionalChildItem); } // Ensure that children are ordered correctly taxonomyNode.Items = SortTaxonomyNodes(children); } }
/// <summary> /// Gets a Navigation subtree for the given Sitemap Item. /// </summary> /// <param name="sitemapItemId">The context <see cref="SitemapItem"/> identifier. Can be <c>null</c>.</param> /// <param name="filter">The <see cref="NavigationFilter"/> used to specify which information to put in the subtree.</param> /// <param name="localization">The context <see cref="ILocalization"/>.</param> /// <returns>A set of Sitemap Items representing the requested subtree.</returns> public virtual IEnumerable <SitemapItem> GetNavigationSubtree(string sitemapItemId, NavigationFilter filter, ILocalization localization) { using (new Tracer(sitemapItemId, filter, localization)) { if (string.IsNullOrEmpty(sitemapItemId)) { return(ExpandTaxonomyRoots(filter, localization)); } // Extract Taxonomy TCM UI, Keyword TCM URI and/or Page TCM URI from the Sitemap Item ID string taxonomyId; string keywordId; string pageId; ParseSitemapItemId(sitemapItemId, out taxonomyId, out keywordId, out pageId); string taxonomyUri = localization.GetCmUri(taxonomyId, (int)ItemType.Category); string keywordUri = string.IsNullOrEmpty(keywordId) ? taxonomyUri : localization.GetCmUri(keywordId, (int)ItemType.Keyword); string pageUri = localization.GetCmUri(pageId, (int)ItemType.Page); IEnumerable <SitemapItem> result = new SitemapItem[0]; if (filter.IncludeAncestors) { TaxonomyNode taxonomyRoot = null; if (!string.IsNullOrEmpty(keywordId)) { taxonomyRoot = ExpandAncestorsForKeyword(keywordUri, taxonomyUri, filter, localization); } else if (!string.IsNullOrEmpty(pageId)) { taxonomyRoot = ExpandAncestorsForPage(pageUri, taxonomyUri, filter, localization); } if (taxonomyRoot != null) { if (filter.DescendantLevels != 0) { AddDescendants(taxonomyRoot, filter, localization); } result = new[] { taxonomyRoot }; } } else if (filter.DescendantLevels != 0 && string.IsNullOrEmpty(pageId)) { result = ExpandDescendants(keywordUri, taxonomyUri, filter, localization); } return(result); } }
protected virtual object MapKeyword(KeywordModelData keywordModelData, Type targetType, ILocalization localization) { if (typeof(KeywordModel).IsAssignableFrom(targetType)) { KeywordModel result; if (keywordModelData.SchemaId == null) { result = new KeywordModel { ExtensionData = keywordModelData.ExtensionData }; } else { MappingData keywordMappingData = new MappingData { SourceViewModel = keywordModelData, ModelType = targetType, PropertyValidation = new Validation { MainSchema = SemanticMapping.GetSchema(keywordModelData.SchemaId, localization), InheritedSchemas = GetInheritedSemanticSchemas(keywordModelData as ViewModelData, localization) }, MetadataFields = keywordModelData.Metadata, Localization = localization }; result = (KeywordModel)CreateViewModel(keywordMappingData); } result.Id = keywordModelData.Id; result.Title = keywordModelData.Title; result.Description = keywordModelData.Description ?? string.Empty; result.Key = keywordModelData.Key ?? string.Empty; result.TaxonomyId = keywordModelData.TaxonomyId; return(result); } if (targetType == typeof(Tag)) { return(new Tag { DisplayText = GetKeywordDisplayText(keywordModelData), Key = keywordModelData.Key, TagCategory = localization.GetCmUri(keywordModelData.TaxonomyId, (int)ItemType.Category) }); } if (targetType == typeof(bool)) { string key = string.IsNullOrEmpty(keywordModelData.Key) ? keywordModelData.Title : keywordModelData.Key; return(Convert.ToBoolean(key)); } return(GetKeywordDisplayText(keywordModelData)); }
protected virtual IEnumerable <string> GetFieldValuesAsStrings(object fieldValues, MappingData mappingData, bool resolveComponentLinks) { if (!resolveComponentLinks) { // Handle Component Links here, because standard model mapping will resolve them. ILocalization localization = mappingData.Localization; if (fieldValues is EntityModelData) { return(new[] { localization.GetCmUri(((EntityModelData)fieldValues).Id) }); } if (fieldValues is EntityModelData[]) { return(((EntityModelData[])fieldValues).Select(emd => localization.GetCmUri(emd.Id))); } } // Use standard model mapping to map the field to a list of strings. return((IEnumerable <string>)MapField(fieldValues, typeof(List <string>), null, mappingData)); }
protected virtual SitemapItem[] ExpandClassifiedPages(Keyword keyword, string taxonomyId, ILocalization localization) { using (new Tracer(keyword.KeywordUri, taxonomyId, localization)) { // Return SitemapItems for all classified Pages (ordered by Page Title, including sequence prefix if any) PageMetaFactory pageMetaFactory = new PageMetaFactory(localization.GetCmUri()); IPageMeta[] classifiedPageMetas = pageMetaFactory.GetTaxonomyPages(keyword, includeBranchedFacets: false); SitemapItem[] result = classifiedPageMetas.Select(pageMeta => CreateSitemapItem(pageMeta, taxonomyId)).ToArray(); return(result); } }
protected virtual string GetLinkUrl(EntityModelData entityModelData, ILocalization localization) { if (entityModelData.LinkUrl != null) { return(entityModelData.LinkUrl); } Log.Debug($"Link URL for Entity Model '{entityModelData.Id}' not resolved by Model Service."); string componentUri = localization.GetCmUri(entityModelData.Id); return(SiteConfiguration.LinkResolver.ResolveLink(componentUri)); }
protected virtual IEnumerable <SitemapItem> ExpandTaxonomyRoots(NavigationFilter filter, ILocalization localization) { using (new Tracer(filter, localization)) { TaxonomyFactory taxonomyFactory = new TaxonomyFactory(); string[] taxonomyIds = taxonomyFactory.GetTaxonomies(localization.GetCmUri()); int depth = filter.DescendantLevels > 0 ? (filter.DescendantLevels - 1) : filter.DescendantLevels; TaxonomyFilter taxonomyFilter = new DepthFilter(depth, DepthFilter.FilterDown); IEnumerable <Keyword> taxonomyRoots = taxonomyIds.Select(id => taxonomyFactory.GetTaxonomyKeywords(id, taxonomyFilter)); return(taxonomyRoots.Select(kw => CreateTaxonomyNode(kw, depth, filter, localization))); } }
private static ResultSet ExecuteSmartTargetQuery(SmartTargetPageModel smartTargetPageModel, ILocalization localization) { using (new Tracer(smartTargetPageModel, localization)) { TcmUri pageUri = new TcmUri(localization.GetCmUri(smartTargetPageModel.Id, (int)ItemType.Page)); TcmUri publicationUri = new TcmUri(localization.GetCmUri()); ClaimStore claimStore = AmbientDataContext.CurrentClaimStore; string triggers = AmbientDataHelper.GetTriggers(claimStore); QueryBuilder queryBuilder = new QueryBuilder(); queryBuilder.Parse(triggers); queryBuilder.AddCriteria(new PublicationCriteria(publicationUri)); queryBuilder.AddCriteria(new PageCriteria(pageUri)); // Adding all the page regions to the query for having only 1 query a page foreach (SmartTargetRegion region in smartTargetPageModel.Regions.OfType <SmartTargetRegion>()) { queryBuilder.AddCriteria(new RegionCriteria(region.Name)); } return(queryBuilder.Execute()); } }
/// <summary> /// Gets the cached local file for a given binary Id. /// </summary> /// <param name="binaryId">The binary Id.</param> /// <param name="localization">The Localization.</param> /// <returns>The path to the local file.</returns> internal string GetCachedFile(int binaryId, ILocalization localization) { string baseDir = AppDomain.CurrentDomain.BaseDirectory; string localFilePath = $"{baseDir}/{localization.BinaryCacheFolder}"; using (new Tracer(binaryId, localization, localFilePath)) { string publicationUri = localization.GetCmUri(); if (!localization.IsXpmEnabled) { try { string[] files = Directory.GetFiles(localFilePath, $"{binaryId}_*", SearchOption.TopDirectoryOnly); if (files.Length > 0) { localFilePath = files[0]; if (IsCached(() => GetBinaryLastPublishDate(binaryId, localization), localFilePath, localization)) { return(localFilePath); } } } catch (Exception) { // Our binary cache folder probably doesn't exist. } } // Binary does not exist or cached binary is out-of-date BinaryMeta binaryMeta = GetBinaryMeta(binaryId, localization); if (binaryMeta == null) { throw new DxaItemNotFoundException(binaryId.ToString(), localization.Id); } BinaryFactory binaryFactory = new BinaryFactory(); BinaryData binaryData = binaryFactory.GetBinary(GetPublicationId(publicationUri), binaryMeta.Id, binaryMeta.VariantId); string ext = Path.GetExtension(binaryMeta.Path) ?? ""; localFilePath = $"{localFilePath}/{localization.Id}-{binaryId}{ext}"; WriteBinaryToFile(binaryData.Bytes, localFilePath, null); return(localFilePath); } }
protected virtual string ResolveNavigationTaxonomyUri(ILocalization localization) { using (new Tracer(localization)) { TaxonomyFactory taxonomyFactory = new TaxonomyFactory(); string[] taxonomyIds = taxonomyFactory.GetTaxonomies(localization.GetCmUri()); Keyword navTaxonomyRoot = taxonomyIds.Select(id => taxonomyFactory.GetTaxonomyKeyword(id)).FirstOrDefault(tax => tax.KeywordName.Contains(TaxonomyNavigationMarker)); if (navTaxonomyRoot == null) { Log.Warn("No Navigation Taxonomy Found in Localization [{0}]. Ensure a Taxonomy with '{1}' in its title is published.", localization, TaxonomyNavigationMarker); return(string.Empty); } Log.Debug("Resolved Navigation Taxonomy: {0} ('{1}')", navTaxonomyRoot.TaxonomyUri, navTaxonomyRoot.KeywordName); return(navTaxonomyRoot.TaxonomyUri); } }
/// <summary> /// Gets the cached local file for a given URL path. /// </summary> /// <param name="urlPath">The URL path.</param> /// <param name="localization">The Localization.</param> /// <returns>The path to the local file.</returns> internal string GetCachedFile(string urlPath, ILocalization localization) { string baseDir = AppDomain.CurrentDomain.BaseDirectory; string localFilePath = $"{baseDir}/{urlPath}"; if (File.Exists(localFilePath)) { // If our resource exists on the filesystem we can assume static content that is // manually added to web application. return(localFilePath); } // Attempt cache location with fallback to retrieval from CIL. Note we don't check cache // when running under XPM localFilePath = $"{baseDir}/{localization.BinaryCacheFolder}/{urlPath}"; using (new Tracer(urlPath, localization, localFilePath)) { Dimensions dimensions; urlPath = StripDimensions(urlPath, out dimensions); string publicationUri = localization.GetCmUri(); if (!localization.IsXpmEnabled && File.Exists(localFilePath)) { if (IsCached(() => GetBinaryLastPublishDate(urlPath, publicationUri), localFilePath, localization)) { return(localFilePath); } } // Binary does not exist or cached binary is out-of-date BinaryMeta binaryMeta = GetBinaryMeta(urlPath, publicationUri); if (binaryMeta == null) { throw new DxaItemNotFoundException(urlPath, localization.Id); } BinaryFactory binaryFactory = new BinaryFactory(); BinaryData binaryData = binaryFactory.GetBinary(GetPublicationId(publicationUri), binaryMeta.Id, binaryMeta.VariantId); WriteBinaryToFile(binaryData.Bytes, localFilePath, dimensions); return(localFilePath); } }
private void PopulateSmartTargetRegions(SmartTargetPageModel smartTargetPageModel, ILocalization localization) { // Execute a ST Query for all SmartTargetRegions on the Page. ResultSet resultSet = ExecuteSmartTargetQuery(smartTargetPageModel, localization); Log.Debug($"SmartTarget query returned {resultSet.Promotions.Count} Promotions."); string promotionViewName = localization.GetConfigValue(PromotionViewNameConfig); if (String.IsNullOrEmpty(promotionViewName)) { Log.Warn($"No View name for SmartTarget Promotions is configured on CM-side ({PromotionViewNameConfig})"); promotionViewName = "SmartTarget:Entity:Promotion"; } Log.Debug($"Using Promotion View '{promotionViewName}'"); // TODO: we shouldn't access HttpContext in a Model Builder. HttpContext httpContext = HttpContext.Current; if (httpContext == null) { throw new DxaException("HttpContext is not available."); } List <string> itemsAlreadyOnPage = new List <string>(); ExperimentCookies existingExperimentCookies = CookieProcessor.GetExperimentCookies(httpContext.Request); ExperimentCookies newExperimentCookies = new ExperimentCookies(); // Filter the Promotions for each SmartTargetRegion foreach (SmartTargetRegion smartTargetRegion in smartTargetPageModel.Regions.OfType <SmartTargetRegion>()) { string regionName = smartTargetRegion.Name; List <string> itemsOutputInRegion = new List <string>(); ExperimentDimensions experimentDimensions; List <Promotion> promotions = new List <Promotion>(resultSet.Promotions); ResultSet.FilterPromotions(promotions, regionName, smartTargetRegion.MaxItems, smartTargetPageModel.AllowDuplicates, itemsOutputInRegion, itemsAlreadyOnPage, ref existingExperimentCookies, ref newExperimentCookies, out experimentDimensions); if (experimentDimensions != null) { // The SmartTarget API doesn't set all ExperimentDimensions properties, but they are required by the ExperimentTrackingHandler (see CRQ-1667). experimentDimensions.PublicationId = localization.GetCmUri(); experimentDimensions.PageId = localization.GetCmUri(smartTargetPageModel.Id, (int)ItemType.Page); experimentDimensions.Region = smartTargetRegion.Name; } if (localization.IsXpmEnabled) { // The SmartTarget API provides the entire XPM markup tag; put it in XpmMetadata["Query"]. See SmartTargetRegion.GetStartQueryXpmMarkup. smartTargetRegion.XpmMetadata = new Dictionary <string, object> { { "Query", ResultSet.GetExperienceManagerMarkup(smartTargetRegion.Name, smartTargetRegion.MaxItems, promotions) } }; } // Create SmartTargetPromotion Entity Models for visible Promotions in the current SmartTargetRegion. // It seems that ResultSet.FilterPromotions doesn't really filter on Region name, so we do post-filtering here. foreach (Promotion promotion in promotions.Where(promotion => promotion.Visible && promotion.Regions.Contains(regionName))) { SmartTargetPromotion smartTargetPromotion = CreatePromotionEntity(promotion, promotionViewName, smartTargetRegion.Name, localization, experimentDimensions); if (!smartTargetRegion.HasSmartTargetContent) { // Discard any fallback content coming from Content Manager smartTargetRegion.Entities.Clear(); smartTargetRegion.HasSmartTargetContent = true; } smartTargetRegion.Entities.Add(smartTargetPromotion); } } if (newExperimentCookies.Count > 0) { smartTargetPageModel.ExperimentCookies = newExperimentCookies; } }
/// <summary> /// Populates a Dynamic List by executing the query it specifies. /// </summary> /// <param name="dynamicList">The Dynamic List which specifies the query and is to be populated.</param> /// <param name="localization">The context Localization.</param> public virtual void PopulateDynamicList(DynamicList dynamicList, ILocalization localization) { using (new Tracer(dynamicList, localization)) { SimpleBrokerQuery simpleBrokerQuery = dynamicList.GetQuery(localization) as SimpleBrokerQuery; if (simpleBrokerQuery == null) { throw new DxaException($"Unexpected result from {dynamicList.GetType().Name}.GetQuery: {dynamicList.GetQuery(localization)}"); } Common.Interfaces.IQueryProvider brokerQuery = new BrokerQueryProvider(); string[] componentUris = brokerQuery.ExecuteQuery(simpleBrokerQuery).ToArray(); Log.Debug($"Broker Query returned {componentUris.Length} results. HasMore={brokerQuery.HasMore}"); if (componentUris.Length > 0) { Type resultType = dynamicList.ResultType; ComponentMetaFactory componentMetaFactory = new ComponentMetaFactory(localization.GetCmUri()); dynamicList.QueryResults = componentUris .Select(c => ModelBuilderPipeline.CreateEntityModel(CreateEntityModelData(componentMetaFactory.GetMeta(c)), resultType, localization)) .ToList(); } dynamicList.HasMore = brokerQuery.HasMore; } }
private static string GetPublicationUri(Tridion.ContentManager.TcmUri tcmUri, ILocalization localization) => (localization == null) ? $"tcm:0-{tcmUri.PublicationId}-1" : localization.GetCmUri();