/// <summary>
        /// Get markup for a specific campaign
        /// </summary>
        /// <param name="campaignContentZip"></param>
        /// <param name="localization"></param>
        /// <returns></returns>
        public CampaignContentMarkup GetCampaignContentMarkup(CampaignContentZIP campaignContentZip, Localization localization)
        {
            StaticContentItem     zipItem = GetZipItem(campaignContentZip, localization);
            CampaignContentMarkup campaignContentMarkup;

            //SiteConfiguration.CacheProvider.TryGet<CampaignContentMarkup>(campaignContentZip.Id, "CampaignContent", out campaignContentMarkup);

            string cacheKey = GetMarkupCacheKey(campaignContentZip.Id, localization);

            cachedMarkup.TryGetValue(cacheKey, out campaignContentMarkup);
            string campaignBaseDir = GetBaseDir(localization, campaignContentZip.Id);

            if (campaignContentMarkup == null || !Directory.Exists(campaignBaseDir) || Directory.GetFiles(campaignBaseDir).Length == 0)
            {
                Log.Info("Extracting campaign " + campaignContentZip.Id + ", last modified = " + zipItem.LastModified);
                ExtractZip(zipItem, campaignBaseDir, zipItem.LastModified);
                campaignContentMarkup = GetMarkup(campaignBaseDir);
                campaignContentMarkup.LastModified = zipItem.LastModified;
                //SiteConfiguration.CacheProvider.Store<CampaignContentMarkup>(campaignContentZip.Id, "CampaignContent", campaignContentMarkup);
                cachedMarkup[cacheKey] = campaignContentMarkup;
            }
            else if (campaignContentMarkup == null)
            {
                campaignContentMarkup = GetMarkup(campaignBaseDir);
                campaignContentMarkup.LastModified = zipItem.LastModified;
                cachedMarkup[cacheKey]             = campaignContentMarkup;
            }

            return(campaignContentMarkup);
        }
        /// <summary>
        /// Get ZIP item.
        /// </summary>
        /// <param name="campaignContentZip"></param>
        /// <returns></returns>
        protected ZipItem GetZipItem(CampaignContentZIP campaignContentZip, Localization localization)
        {
            var item = SiteConfiguration.ContentProvider.GetStaticContentItem(campaignContentZip.Url, localization);

            return(new ZipItem
            {
                ContentItem = item,
                UrlPath = campaignContentZip.Url,
                LocalFileName = GetBinaryLocalFileName(campaignContentZip.Url, localization)
            });
        }
Esempio n. 3
0
        /// <summary>
        /// Assembly Content
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="containerSize"></param>
        /// <returns></returns>
        public ActionResult AssemblyContent(EntityModel entity, int containerSize = 0)
        {
            SetupViewData(entity, containerSize);

            CampaignContentZIP contentZip = (CampaignContentZIP)entity;

            // Process markup
            //
            ProcessMarkup(contentZip);

            return(View(entity.MvcData.ViewName, entity));
        }
Esempio n. 4
0
        /// <summary>
        /// Process markup. Blend the markup in the ZIP file and CMS content.
        /// </summary>
        /// <param name="campaignContentZip"></param>
        protected void ProcessMarkup(CampaignContentZIP campaignContentZip)
        {
            CampaignContentMarkup campaignContentMarkup = CampaignAssetProvider.Instance.GetCampaignContentMarkup(campaignContentZip, WebRequestContext.Localization);

            // Throw exception if main HTML is not found
            //
            if (campaignContentMarkup.MainHtml == null)
            {
                throw new DxaException("No markup defined for campaign with ID: " + campaignContentZip.Id);
            }

            var htmlDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.MainHtml + "</body>");

            // Remove all nodes that are marked as Preview Only
            //
            if (!WebRequestContext.IsPreview)
            {
                foreach (var element in htmlDoc.Body.Select("[data-preview-only=true]"))
                {
                    element.Remove();
                }
            }

            // Inject content into placeholders in the markup
            //
            if (campaignContentZip.TaggedContent != null)
            {
                int index = 1;
                foreach (var taggedContent in campaignContentZip.TaggedContent)
                {
                    foreach (var element in htmlDoc.Body.Select("[data-content-name=" + taggedContent.Name + "]"))
                    {
                        String contentMarkup = taggedContent.Content?.ToString() ?? string.Empty;

                        if (WebRequestContext.IsPreview)
                        {
                            contentMarkup = "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedContent[" +
                                            index +
                                            "]/custom:content[1]\"} -->" + contentMarkup;
                        }

                        element.Html(contentMarkup);
                    }
                    index++;
                }
            }

            // Inject tagged properties
            //
            if (campaignContentZip.TaggedProperties != null)
            {
                int index = 1;
                foreach (var taggedProperty in campaignContentZip.TaggedProperties)
                {
                    var indexSuffix = taggedProperty.Index != null && taggedProperty.Index > 1 ? "-" + taggedProperty.Index : "";
                    foreach (var element in htmlDoc.Body.Select("[data-property-name" + indexSuffix + "=" + taggedProperty.Name + "]"))
                    {
                        var propertyValue          = taggedProperty.Value;
                        var containsUrlPlaceholder = propertyValue.Contains("%URL%");
                        if (taggedProperty.Image != null)
                        {
                            propertyValue = propertyValue.Replace("%URL%", taggedProperty.Image.Url);
                            if (element.TagName().Equals("img", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(taggedProperty.ImageAltText))
                            {
                                element.Attr("alt", taggedProperty.ImageAltText);
                            }

                            if (element.Attr("data-property-sibling-replace") == "true")
                            {
                                foreach (var sibling in element.SiblingElements)
                                {
                                    var siblingPropertyValue = sibling.Attr(taggedProperty.Target) ?? string.Empty;
                                    siblingPropertyValue = siblingPropertyValue.Replace("%URL%", taggedProperty.Image.Url);
                                    sibling.Attr(taggedProperty.Target, siblingPropertyValue);
                                    if (!string.IsNullOrEmpty(taggedProperty.ImageAltText) && sibling.TagName().Equals("img", StringComparison.OrdinalIgnoreCase))
                                    {
                                        sibling.Attr("alt", taggedProperty.ImageAltText);
                                    }
                                }
                            }
                        }
                        element.Attr(taggedProperty.Target, propertyValue ?? string.Empty);

                        // Generate image XPM markup if tagged property can contain/contains an image URL
                        //
                        if (WebRequestContext.IsPreview && containsUrlPlaceholder)
                        {
                            string xpmMarkup =
                                "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedProperties[" +
                                index +
                                "]/custom:image[1]\"} -->";
                            element.Prepend(xpmMarkup);
                        }
                    }
                    index++;
                }
            }

            // Inject tagged links
            //
            if (campaignContentZip.TaggedLinks != null)
            {
                int index = 1;
                foreach (var taggedLink in campaignContentZip.TaggedLinks)
                {
                    foreach (var element in htmlDoc.Body.Select("[data-link-name=" + taggedLink.Name + "]"))
                    {
                        var link = taggedLink.ComponentLink ?? taggedLink.Url;
                        element.Attr("href", link ?? "#");
                        if (!string.IsNullOrEmpty(taggedLink.Target))
                        {
                            element.Attr("target", taggedLink.Target);
                        }
                        if (WebRequestContext.IsPreview)
                        {
                            var    fieldName = taggedLink.ComponentLink != null || string.IsNullOrWhiteSpace(taggedLink.Url) ? "componentLink" : "url";
                            string xpmMarkup =
                                "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedLinks[" +
                                index +
                                "]/custom:" + fieldName + "[1]\"} -->";
                            element.Prepend(xpmMarkup);
                        }
                    }
                    index++;
                }
            }
            string assetBaseDir = this.GetAssetBaseDir(campaignContentZip);

            // Process assets
            //
            this.ProcessAssetLinks(htmlDoc, assetBaseDir, "href");
            this.ProcessAssetLinks(htmlDoc, assetBaseDir, "src");

            // Inject tagged images
            //
            if (campaignContentZip.TaggedImages != null)
            {
                int index = 1;
                foreach (var taggedImage in campaignContentZip.TaggedImages)
                {
                    foreach (var element in htmlDoc.Body.Select("[data-image-name=" + taggedImage.Name + "]"))
                    {
                        var imageUrl = string.Empty;
                        if (taggedImage.Image != null && taggedImage.Image.Url != null)
                        {
                            imageUrl = taggedImage.Image.Url;
                        }
                        else if (taggedImage.ImageUrl != null)
                        {
                            imageUrl = taggedImage.ImageUrl;
                        }
                        if (taggedImage.Parameters != null &&
                            (taggedImage.Image == null ||
                             (taggedImage.Image != null && _useUrlParametersForLocalImages)))
                        {
                            imageUrl += "?" + taggedImage.Parameters;
                        }
                        element.Attr("src", imageUrl);

                        if (!string.IsNullOrEmpty(taggedImage.AltText))
                        {
                            element.Attr("alt", taggedImage.AltText);
                        }

                        if (WebRequestContext.IsPreview)
                        {
                            string xpmMarkup =
                                "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedImages[" +
                                index +
                                "]/custom:image[1]\"} -->";

                            if (taggedImage.Image != null)
                            {
                                element.Before(xpmMarkup);
                            }
                            else
                            {
                                // Surround the XPM markup in an additional span. This to avoid that the
                                // image with absolute URL will not disappear as soon you click on it.
                                //
                                element.Before("<span>" + xpmMarkup + "</span>");
                            }
                        }
                    }
                    index++;
                }
            }

            // Insert header markup (JS, CSS etc)
            //
            if (campaignContentMarkup.HeaderHtml != null)
            {
                var headerDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.HeaderHtml + "</body>");
                this.ProcessAssetLinks(headerDoc, assetBaseDir, "src");
                this.ProcessAssetLinks(headerDoc, assetBaseDir, "href");
                PluggableMarkup.RegisterMarkup("css", headerDoc.Body.Html());
                // TODO: Should it be called top-js?? Or have a top-css injection point as well
            }

            // Insert footer markup (JS etc)
            //
            if (campaignContentMarkup.FooterHtml != null)
            {
                var footerDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.FooterHtml + "</body>");
                this.ProcessAssetLinks(footerDoc, assetBaseDir, "src");
                PluggableMarkup.RegisterMarkup("bottom-js", footerDoc.Body.Html());
            }

            campaignContentZip.ProcessedContent = new RichTextFragment(htmlDoc.Body.Html()).ToHtml();
        }
Esempio n. 5
0
 /// <summary>
 /// Get asset base dir (which are exposed on the web page) for the specified campaign ZIP
 /// </summary>
 /// <param name="campaignContentZip"></param>
 /// <returns></returns>
 protected String GetAssetBaseDir(CampaignContentZIP campaignContentZip)
 {
     return(_siteBaseUrlProvider.GetSiteBaseUrl() + "/assets/campaign/" + campaignContentZip.Id);
 }
 /// <summary>
 /// Get ZIP item.
 /// </summary>
 /// <param name="campaignContentZip"></param>
 /// <returns></returns>
 protected StaticContentItem GetZipItem(CampaignContentZIP campaignContentZip, Localization localization)
 {
     return(SiteConfiguration.ContentProvider.GetStaticContentItem(campaignContentZip.Url, localization));
 }
        /// <summary>
        /// Process markup. Blend the markup in the ZIP file and CMS content.
        /// </summary>
        /// <param name="campaignContentZip"></param>
        protected void ProcessMarkup(CampaignContentZIP campaignContentZip)
        {
            CampaignContentMarkup campaignContentMarkup = CampaignAssetProvider.Instance.GetCampaignContentMarkup(campaignContentZip, WebRequestContext.Localization);

            // Throw exception if main HTML is not found
            //
            if (campaignContentMarkup.MainHtml == null)
            {
                throw new DxaException("No markup defined for campaign with ID: " + campaignContentZip.Id);
            }

            var htmlDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.MainHtml + "</body>");

            // Inject content into placeholders in the markup
            //
            if (campaignContentZip.TaggedContent != null)
            {
                int index = 1;
                foreach (var taggedContent in campaignContentZip.TaggedContent)
                {
                    foreach (var element in htmlDoc.Body.Select("[data-content-name=" + taggedContent.Name + "]"))
                    {
                        String contentMarkup =
                            "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedContent[" +
                            index +
                            "]/custom:content[1]\"} -->" +
                            taggedContent.Content.ToString();
                        element.Html(contentMarkup);
                    }
                    index++;
                }
            }

            // Inject tagged properties
            //
            if (campaignContentZip.TaggedProperties != null)
            {
                foreach (var taggedProperty in campaignContentZip.TaggedProperties)
                {
                    var indexSuffix = taggedProperty.Index != null && taggedProperty.Index > 1 ? "-" + taggedProperty.Index : "";
                    foreach (var element in htmlDoc.Body.Select("[data-property-name" + indexSuffix + "=" + taggedProperty.Name + "]"))
                    {
                        element.Attr(taggedProperty.Target, taggedProperty.Value);
                    }
                }
            }

            string assetBaseDir = this.GetAssetBaseDir(campaignContentZip);

            // Process assets
            //
            this.ProcessAssetLinks(htmlDoc, assetBaseDir, "href");
            this.ProcessAssetLinks(htmlDoc, assetBaseDir, "src");

            // Inject tagged images
            //
            if (campaignContentZip.TaggedImages != null)
            {
                int index = 1;
                foreach (var taggedImage in campaignContentZip.TaggedImages)
                {
                    foreach (var element in htmlDoc.Body.Select("[data-image-name=" + taggedImage.Name + "]"))
                    {
                        String xpmMarkup =
                            "<!-- Start Component Field: {\"XPath\":\"tcm:Metadata/custom:Metadata/custom:taggedImages[" +
                            index +
                            "]/custom:image[1]\"} -->";
                        element.Attr("src", taggedImage.Image.Url);
                        element.Before(xpmMarkup);
                    }
                    index++;
                }
            }

            // Insert header markup (JS, CSS etc)
            //
            if (campaignContentMarkup.HeaderHtml != null)
            {
                var headerDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.HeaderHtml + "</body>");
                this.ProcessAssetLinks(headerDoc, assetBaseDir, "src");
                this.ProcessAssetLinks(headerDoc, assetBaseDir, "href");
                PluggableMarkup.RegisterMarkup("css", headerDoc.Body.Html());
                // TODO: Should it be called top-js?? Or have a top-css injection point as well
            }

            // Insert footer markup (JS etc)
            //
            if (campaignContentMarkup.FooterHtml != null)
            {
                var footerDoc = NSoupClient.Parse("<body>" + campaignContentMarkup.FooterHtml + "</body>");
                this.ProcessAssetLinks(footerDoc, assetBaseDir, "src");
                PluggableMarkup.RegisterMarkup("bottom-js", footerDoc.Body.Html());
            }

            campaignContentZip.ProcessedContent = new RichTextFragment(htmlDoc.Body.Html()).ToHtml();
        }
        /// <summary>
        /// Load markup for a specific campaign
        /// </summary>
        /// <param name="campaignContentZip"></param>
        /// <param name="campaignId"></param>
        /// <param name="localization"></param>
        /// <returns></returns>
        protected CampaignContentMarkup LoadCampaignContentMarkup(CampaignContentZIP campaignContentZip, string campaignId, Localization localization)
        {
            CampaignContentMarkup campaignContentMarkup;
            string cacheKey = GetMarkupCacheKey(campaignId, localization);

            CachedMarkup.TryGetValue(cacheKey, out campaignContentMarkup);
            string campaignBaseDir = GetBaseDir(localization, campaignId);

            if (campaignContentMarkup != null)
            {
                var zipFileLastModified = File.GetLastWriteTime(campaignContentMarkup.ZipFileName);
                if (!localization.IsXpmEnabled && zipFileLastModified > campaignContentMarkup.LastModified ||
                    localization.IsXpmEnabled && campaignContentMarkup.LastModified.AddSeconds(stagingCacheTime) < DateTime.Now)
                {
                    Log.Info("Zip has changed. Extracting campaign " + campaignId + ", last modified = " + zipFileLastModified);

                    var fileLock = GetFileSemaphore(campaignBaseDir);

                    // If no other thread is already working on it. Else keep using the existing version until the new one is available.
                    //
                    if (fileLock.CurrentCount > 0)
                    {
                        using (fileLock.UseWait())
                        {
                            try
                            {
                                var zipItem = campaignContentZip != null?GetZipItem(campaignContentZip, localization) : GetZipItem(campaignId, localization);

                                if (ExtractZip(zipItem.ContentItem, campaignBaseDir, zipItem.ContentItem.LastModified))
                                {
                                    campaignContentMarkup = GetMarkup(campaignBaseDir);
                                    campaignContentMarkup.LastModified = zipItem.ContentItem.LastModified;
                                    campaignContentMarkup.ZipFileName  = zipItem.LocalFileName;
                                    CachedMarkup[cacheKey]             = campaignContentMarkup;
                                }
                            }
                            catch (Exception e)
                            {
                                Log.Error($"Could not get/extract ZIP file. Retry next time the campaign is accessed. \nException: {e}");
                            }
                        }
                    }
                }
            }
            else
            {
                var fileLock = GetFileSemaphore(campaignBaseDir);
                using (fileLock.UseWait())
                {
                    var zipItem = campaignContentZip != null?GetZipItem(campaignContentZip, localization) : GetZipItem(campaignId, localization);

                    if (zipItem == null)
                    {
                        // Non-existing campaign.
                        //
                        return(null);
                    }
                    if (!Directory.Exists(campaignBaseDir) || zipItem.ContentItem.LastModified > File.GetLastWriteTime(campaignBaseDir) || Directory.GetFiles(campaignBaseDir).Length == 0)
                    {
                        Log.Info("Extracting campaign " + campaignId + ", last modified = " + zipItem.ContentItem.LastModified);
                        if (!ExtractZip(zipItem.ContentItem, campaignBaseDir, zipItem.ContentItem.LastModified))
                        {
                            throw new DxaException($"Could not extract campaign with ID: {campaignId}");
                        }
                    }

                    campaignContentMarkup = GetMarkup(campaignBaseDir);
                    campaignContentMarkup.LastModified = zipItem.ContentItem.LastModified;
                    campaignContentMarkup.ZipFileName  = zipItem.LocalFileName;
                    CachedMarkup[cacheKey]             = campaignContentMarkup;
                }
            }

            return(campaignContentMarkup);
        }
 /// <summary>
 /// Get markup for a specific campaign
 /// </summary>
 /// <param name="campaignContentZip"></param>
 /// <param name="localization"></param>
 /// <returns></returns>
 public CampaignContentMarkup GetCampaignContentMarkup(CampaignContentZIP campaignContentZip, Localization localization)
 {
     return(LoadCampaignContentMarkup(campaignContentZip, campaignContentZip.Id, localization));
 }