private IEnumerable<SyndicationItem> GetFeedItemsFromPage(PageModel page) { List<SyndicationItem> items = new List<SyndicationItem>(); foreach (RegionModel region in page.Regions) { foreach (EntityModel entity in region.Entities) { items.AddRange(GetFeedItemsFromEntity(entity)); } } return items; }
public void ExtensionData_Success() { const string testExtensionDataKey = "TestExtensionData"; const int testExtensionDataValue = 666; ViewModel testViewModel = new PageModel("666"); Assert.IsNull(testViewModel.ExtensionData, "testViewModel.ExtensionData (before)"); testViewModel.SetExtensionData(testExtensionDataKey, testExtensionDataValue); OutputJson(testViewModel); Assert.IsNotNull(testViewModel.ExtensionData, "testViewModel.ExtensionData"); Assert.AreEqual(1, testViewModel.ExtensionData.Count, "testViewModel.ExtensionData.Count"); Assert.AreEqual(testExtensionDataValue, testViewModel.ExtensionData[testExtensionDataKey], "testViewModel.ExtensionData[testExtensionDataKey]"); }
internal SmartTargetPageModel(PageModel pageModel) : base(pageModel.Id) { Title = pageModel.Title; Url = pageModel.Url; MvcData = pageModel.MvcData; HtmlClasses = pageModel.HtmlClasses; Regions.UnionWith(pageModel.Regions); XpmMetadata = pageModel.XpmMetadata; foreach (KeyValuePair<string, string> metaKeyValuePair in pageModel.Meta) { Meta.Add(metaKeyValuePair); } }
public void DeepCopy_Success() { Article testArticle = new Article() { Id = "666-666" }; testArticle.XpmPropertyMetadata = new Dictionary<string, string> { { "xxx", "yyy" } }; RegionModel testRegionModel = new RegionModel("test"); testRegionModel.Entities.Add(testArticle); PageModel testPageModel = new PageModel("666") { Url = "/test" }; testPageModel.Regions.Add(testRegionModel); testPageModel.Meta.Add("aaa", "bbb"); testPageModel.XpmMetadata = new Dictionary<string, object> { {"ccc", "ddd"}, {"eee", 666} }; testPageModel.ExtensionData = new Dictionary<string, object> { { "fff", "ggg" }, { "hhh", 6666 } }; OutputJson(testPageModel); PageModel clonedPageModel = testPageModel.DeepCopy() as PageModel; Assert.IsNotNull(clonedPageModel, "clonedPageModel"); OutputJson(clonedPageModel); Assert.AreNotSame(testPageModel, clonedPageModel, "clonedPageModel"); Assert.AreEqual(testPageModel.Id, clonedPageModel.Id, "clonedPageModel.Id"); Assert.AreEqual(testPageModel.Url, clonedPageModel.Url, "clonedPageModel.Url"); AssertEqualCollections(testPageModel.Meta, clonedPageModel.Meta, "clonedPageModel.Meta"); AssertEqualCollections(testPageModel.XpmMetadata, clonedPageModel.XpmMetadata, "clonedPageModel.XpmMetadata"); AssertEqualCollections(testPageModel.ExtensionData, clonedPageModel.ExtensionData, "clonedPageModel.ExtensionData"); AssertEqualCollections(testPageModel.Regions, clonedPageModel.Regions, "clonedPageModel.Regions"); RegionModel clonedRegionModel = clonedPageModel.Regions[testRegionModel.Name]; Assert.IsNotNull(clonedRegionModel, "clonedRegionModel"); Assert.AreNotSame(testRegionModel, clonedRegionModel, "clonedRegionModel"); AssertEqualCollections(testRegionModel.Entities, clonedRegionModel.Entities, "clonedRegionModel.Entities"); AssertEqualCollections(testRegionModel.Regions, clonedRegionModel.Regions, "clonedRegionModel.Regions"); Article clonedArticle = clonedRegionModel.Entities[0] as Article; Assert.IsNotNull(clonedArticle, "clonedArticle"); Assert.AreNotSame(testArticle, clonedArticle, "clonedArticle"); Assert.AreEqual(testArticle.Id, clonedArticle.Id, "clonedArticle.Id"); AssertEqualCollections(testArticle.XpmPropertyMetadata, clonedArticle.XpmPropertyMetadata, "clonedArticle.XpmPropertyMetadata"); }
/// <summary> /// Post-processes the Page Model constructed by the <see cref="DefaultModelBuilder"/>. /// </summary> /// <remarks> /// This implementation relies on the <see cref="DefaultModelBuilder"/> already having constructed Region Models of type <see cref="SmartTargetRegion"/>. /// We "upgrade" the Page Model to type <see cref="SmartTargetPageModel"/> and populate the ST Regions <see cref="SmartTargetPromotion"/> Entities. /// </remarks> public void BuildPageModel(ref PageModel pageModel, IPage page, IEnumerable<IPage> includes, Localization localization) { using (new Tracer(pageModel, page, includes, localization)) { if (pageModel == null || !pageModel.Regions.OfType<SmartTargetRegion>().Any()) { Log.Debug("No SmartTarget Regions on Page."); return; } if (page == null || page.PageTemplate == null || page.PageTemplate.MetadataFields == null || !page.PageTemplate.MetadataFields.ContainsKey("regions")) { Log.Debug("No Regions metadata found."); return; } // "Upgrade" the PageModel to a SmartTargetPageModel, so we can store AllowDuplicates in the Page Model. SmartTargetPageModel smartTargetPageModel = new SmartTargetPageModel(pageModel) { AllowDuplicates = GetAllowDuplicatesOnSamePage(page.PageTemplate, localization), NoCache = true // Don't cache the Page Model, because its contents are dynamic. }; pageModel = smartTargetPageModel; // Set SmartTargetRegionModel.MaxItem based on the Region Metadata in the Page Template. foreach (IFieldSet smartTargetRegionField in page.PageTemplate.MetadataFields["regions"].EmbeddedValues) { string regionName; IField regionNameField; if (smartTargetRegionField.TryGetValue("name", out regionNameField) && !String.IsNullOrEmpty(regionNameField.Value)) { regionName = regionNameField.Value; } else { regionName = new MvcData(smartTargetRegionField["view"].Value).ViewName; } SmartTargetRegion smartTargetRegion = smartTargetPageModel.Regions[regionName] as SmartTargetRegion; if (smartTargetRegion != null) { int maxItems = 100; // Default IField maxItemsField; if (smartTargetRegionField.TryGetValue("maxItems", out maxItemsField)) { maxItems = Convert.ToInt32(maxItemsField.NumericValues[0]); } smartTargetRegion.MaxItems = maxItems; } } // Execute a ST Query for all SmartTargetRegions on the Page. ResultSet resultSet = ExecuteSmartTargetQuery(smartTargetPageModel, localization); Log.Debug("SmartTarget query returned {0} Promotions.", resultSet.Promotions.Count); string promotionViewName = localization.GetConfigValue(PromotionViewNameConfig); if (String.IsNullOrEmpty(promotionViewName)) { Log.Warn("No View name for SmartTarget Promotions is configured on CM-side ({0})", PromotionViewNameConfig); promotionViewName = "SmartTarget:Entity:Promotion"; } Log.Debug("Using Promotion View '{0}'", 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 = string.Format("tcm:0-{0}-1", localization.LocalizationId); experimentDimensions.PageId = string.Format("tcm:{0}-{1}-64", localization.LocalizationId, smartTargetPageModel.Id); experimentDimensions.Region = smartTargetRegion.Name; } if (localization.IsStaging) { // 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> /// Enriches all the Region/Entity Models embedded in the given Page Model. /// </summary> /// <param name="model">The Page Model to enrich.</param> /// <remarks>Used by <see cref="FormatDataAttribute"/> to get all embedded Models enriched without rendering any Views.</remarks> internal void EnrichEmbeddedModels(PageModel model) { using (new Tracer(model)) { if (model == null) { return; } foreach (RegionModel region in model.Regions) { // NOTE: Currently not enriching the Region Model itself, because we don't support custom Region Controllers (yet). for (int i = 0; i < region.Entities.Count; i++) { EntityModel entity = region.Entities[i]; if (entity == null || entity.MvcData == null) { continue; } EntityModel enrichedEntityModel; try { enrichedEntityModel = EnrichEntityModel(entity); } catch (Exception ex) { // If there is a problem enriching an Entity, we replace it with an ExceptionEntity which holds the error details and carry on. Log.Error(ex); enrichedEntityModel = new ExceptionEntity(ex); } region.Entities[i] = enrichedEntityModel; } } } }
public void BuildPageModel(ref PageModel pageModel, IPage page, IEnumerable<IPage> includes, Localization localization) { // Nothing to do here }
public void ExtractSyndicationFeedItems_Teasers_Success() { Localization testLocalization = TestFixture.ParentLocalization; Teaser testTeaser1 = new Teaser { Headline = "Test Teaser 1", Text = new RichText("This is the text of Test Teaser 1."), Link = new Link() { Url = "http://www.sdl.com/" } }; Teaser testTeaser2 = new Teaser { Headline = "Test Teaser 2", }; RegionModel testRegion1 = new RegionModel("test1"); testRegion1.Entities.Add(testTeaser1); RegionModel testRegion2 = new RegionModel("test2"); testRegion2.Entities.Add(testTeaser2); PageModel testPageModel = new PageModel("666"); testPageModel.Regions.Add(testRegion1); testPageModel.Regions.Add(testRegion2); OutputJson(testPageModel); SyndicationItem[] syndicationItems = testPageModel.ExtractSyndicationFeedItems(testLocalization).ToArray(); Assert.IsNotNull(syndicationItems); Assert.AreEqual(2, syndicationItems.Length, "syndicationItems.Length"); SyndicationItem firstSyndicationItem = syndicationItems[0]; Assert.IsNotNull(firstSyndicationItem, "firstSyndicationItem"); Assert.IsNotNull(firstSyndicationItem.Title, "firstSyndicationItem.Title"); Assert.IsNotNull(firstSyndicationItem.Summary, "firstSyndicationItem.Summary"); Assert.IsNotNull(firstSyndicationItem.Links, "firstSyndicationItem.Links"); Assert.AreEqual(testTeaser1.Headline, firstSyndicationItem.Title.Text, "firstSyndicationItem.Title.Text"); Assert.AreEqual(testTeaser1.Text.ToString(), firstSyndicationItem.Summary.Text, "firstSyndicationItem.Summary.Text"); Assert.AreEqual(1, firstSyndicationItem.Links.Count, "firstSyndicationItem.Links.Count"); Assert.AreEqual(testTeaser1.Link.Url, firstSyndicationItem.Links[0].Uri.ToString(), "firstSyndicationItem.Links[0].Uri"); SyndicationItem secondSyndicationItem = syndicationItems[1]; Assert.IsNotNull(secondSyndicationItem, "secondSyndicationItem"); Assert.IsNotNull(secondSyndicationItem.Title, "secondSyndicationItem.Title"); Assert.IsNull(secondSyndicationItem.Summary, "secondSyndicationItem.Summary"); Assert.IsNotNull(secondSyndicationItem.Links, "secondSyndicationItem.Links"); Assert.AreEqual(testTeaser2.Headline, secondSyndicationItem.Title.Text, "secondSyndicationItem.Title.Text"); Assert.AreEqual(0, secondSyndicationItem.Links.Count, "secondSyndicationItem.Links.Count"); }
public void ExtractSyndicationFeedItems_None_Success() { Localization testLocalization = TestFixture.ParentLocalization; PageModel testPageModel = new PageModel("666"); OutputJson(testPageModel); SyndicationItem[] syndicationItems = testPageModel.ExtractSyndicationFeedItems(testLocalization).ToArray(); Assert.IsNotNull(syndicationItems); Assert.AreEqual(0, syndicationItems.Length, "syndicationItems.Length"); }
/// <summary> /// Enriches all the Region/Entity Models embedded in the given Page Model. /// </summary> /// <param name="model">The Page Model to enrich.</param> /// <remarks>Used by <see cref="FormatDataAttribute"/> to get all embedded Models enriched without rendering any Views.</remarks> internal void EnrichEmbeddedModels(PageModel model) { using (new Tracer(model)) { if (model == null) { return; } foreach (RegionModel region in model.Regions) { // NOTE: Currently not enriching the Region Model itself, because we don't support custom Region Controllers (yet). for (int i = 0; i < region.Entities.Count; i++) { EntityModel entity = region.Entities[i]; if (entity != null && entity.MvcData != null) { region.Entities[i] = EnrichEntityModel(entity); } } } } }
private PageModel CreatePageModel(IPage page, Localization localization) { MvcData pageMvcData = GetMvcData(page); Type pageModelType = ModelTypeRegistry.GetViewModelType(pageMvcData); string pageId = GetDxaIdentifierFromTcmUri(page.Id); ISchema pageMetadataSchema = page.Schema; PageModel pageModel; if (pageModelType == typeof(PageModel)) { // Standard Page Model pageModel = new PageModel(pageId); } else if (pageMetadataSchema == null) { // Custom Page Model but no Page metadata that can be mapped; simply create a Page Model instance of the right type. pageModel = (PageModel)Activator.CreateInstance(pageModelType, pageId); } else { // Custom Page Model and Page metadata is present; do full-blown model mapping. string[] schemaTcmUriParts = pageMetadataSchema.Id.Split('-'); SemanticSchema semanticSchema = SemanticMapping.GetSchema(schemaTcmUriParts[1], localization); MappingData mappingData = new MappingData { TargetType = pageModelType, SemanticSchema = semanticSchema, EntityNames = semanticSchema.GetEntityNames(), TargetEntitiesByPrefix = GetEntityDataFromType(pageModelType), Meta = page.MetadataFields, ModelId = pageId, Localization = localization }; pageModel = (PageModel) CreateViewModel(mappingData); } pageModel.MvcData = pageMvcData; pageModel.XpmMetadata = GetXpmMetadata(page); pageModel.Title = page.Title; // add html classes to model from metadata // TODO: move to CreateViewModel so it can be merged with the same code for a Component/ComponentTemplate IPageTemplate template = page.PageTemplate; if (template.MetadataFields != null && template.MetadataFields.ContainsKey("htmlClasses")) { // strip illegal characters to ensure valid html in the view (allow spaces for multiple classes) pageModel.HtmlClasses = template.MetadataFields["htmlClasses"].Value.StripIllegalCharacters(@"[^\w\-\ ]"); } return pageModel; }
public virtual void BuildPageModel(ref PageModel pageModel, IPage page, IEnumerable<IPage> includes, Localization localization) { using (new Tracer(pageModel, page, includes, localization)) { pageModel = CreatePageModel(page, localization); RegionModelSet regions = pageModel.Regions; // Create predefined Regions from Page Template Metadata CreatePredefinedRegions(regions, page.PageTemplate); // Create Regions/Entities from Component Presentations IConditionalEntityEvaluator conditionalEntityEvaluator = SiteConfiguration.ConditionalEntityEvaluator; foreach (IComponentPresentation cp in page.ComponentPresentations) { MvcData cpRegionMvcData = GetRegionMvcData(cp); RegionModel region; if (regions.TryGetValue(cpRegionMvcData.ViewName, out region)) { // Region already exists in Page Model; MVC data should match. if (!region.MvcData.Equals(cpRegionMvcData)) { Log.Warn("Region '{0}' is defined with conflicting MVC data: [{1}] and [{2}]. Using the former.", region.Name, region.MvcData, cpRegionMvcData); } } else { // Region does not exist in Page Model yet; create Region Model and add it. region = CreateRegionModel(cpRegionMvcData); regions.Add(region); } EntityModel entity; try { entity = ModelBuilderPipeline.CreateEntityModel(cp, localization); } catch (Exception ex) { //if there is a problem mapping the item, we replace it with an exception entity //and carry on processing - this should not cause a failure in the rendering of //the page as a whole Log.Error(ex); entity = new ExceptionEntity(ex) { MvcData = GetMvcData(cp) // TODO: The regular View won't expect an ExceptionEntity model. Should use an Exception View (?) }; } if (conditionalEntityEvaluator == null || conditionalEntityEvaluator.IncludeEntity(entity)) { region.Entities.Add(entity); } } // Create Regions from Include Pages if (includes != null) { foreach (IPage includePage in includes) { PageModel includePageModel = ModelBuilderPipeline.CreatePageModel(includePage, null, localization); // Model Include Page as Region: RegionModel includePageRegion = GetRegionFromIncludePage(includePage); RegionModel existingRegion; if (regions.TryGetValue(includePageRegion.Name, out existingRegion)) { // Region with same name already exists; merge include Page Region. existingRegion.Regions.UnionWith(includePageModel.Regions); if (existingRegion.XpmMetadata != null) { existingRegion.XpmMetadata.Remove(RegionModel.IncludedFromPageIdXpmMetadataKey); existingRegion.XpmMetadata.Remove(RegionModel.IncludedFromPageTitleXpmMetadataKey); existingRegion.XpmMetadata.Remove(RegionModel.IncludedFromPageFileNameXpmMetadataKey); } Log.Info("Merged Include Page [{0}] into Region [{1}]. Note that merged Regions can't be edited properly in XPM (yet).", includePageModel, existingRegion); } else { includePageRegion.Regions.UnionWith(includePageModel.Regions); regions.Add(includePageRegion); } #pragma warning disable 618 // Legacy WebPage.Includes support: pageModel.Includes.Add(includePage.Title, includePageModel); #pragma warning restore 618 } if (pageModel.MvcData.ViewName != "IncludePage") { pageModel.Title = ProcessPageMetadata(page, pageModel.Meta, localization); } } } }