diff --git a/content-management/.gitignore b/content-management/.gitignore index d0a3110..fc005ea 100644 --- a/content-management/.gitignore +++ b/content-management/.gitignore @@ -1,4 +1,5 @@ -/Sdl.Web.Templating/bin -/Sdl.Web.Templating/obj -/Sdl.Web.Templating/*.user -/Sdl.Web.Templating/*.suo +Sdl.Web.Templating/bin +Sdl.Web.Templating/obj +Sdl.Web.Templating/*.user +Sdl.Web.Templating/*.suo +_references/2013-sp1/*.dll diff --git a/content-management/Sdl.Web.Templating/Templates/ResolveRichText.cs b/content-management/Sdl.Web.Templating/Templates/ResolveRichText.cs index b306d6d..358b4de 100644 --- a/content-management/Sdl.Web.Templating/Templates/ResolveRichText.cs +++ b/content-management/Sdl.Web.Templating/Templates/ResolveRichText.cs @@ -69,7 +69,7 @@ private string ResolveXhtml(string input) { Component comp = (Component)Engine.GetObject(uri); // resolve youtube video - if (comp != null) + if (comp != null && comp.Metadata != null) { ItemFields fields = new ItemFields(comp.Metadata, comp.MetadataSchema); ProcessFields(fields, link); diff --git a/modules/SmartTarget-Module.zip b/modules/SmartTarget-Module.zip new file mode 100644 index 0000000..2039595 Binary files /dev/null and b/modules/SmartTarget-Module.zip differ diff --git a/web-application/.gitignore b/web-application/.gitignore index 94ad409..184fddb 100644 --- a/web-application/.gitignore +++ b/web-application/.gitignore @@ -3,6 +3,7 @@ obj bin *.user *.suo -Site/system/v*.*/ -packages/ +mod +packages Site/ClaimStore.aspx +Site/system/v*.*/ diff --git a/web-application/Modules/Modules.sln b/web-application/Modules/Modules.sln index 434019e..1ec1705 100644 --- a/web-application/Modules/Modules.sln +++ b/web-application/Modules/Modules.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30723.0 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.Web.Modules.Search", "Search\Sdl.Web.Modules.Search\Sdl.Web.Modules.Search.csproj", "{8FEFFF4C-0AE2-452F-89B1-36F7D2944032}" EndProject @@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.Web.Tridion", "..\Sdl.W EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.Web.DD4T", "..\Sdl.Web.DD4T\Sdl.Web.DD4T.csproj", "{360AEC0A-3367-486A-885F-7931F32234C1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.Web.Modules.SmartTarget", "SmartTarget\Sdl.Web.Modules.SmartTarget\Sdl.Web.Modules.SmartTarget.csproj", "{05ECDB04-EB87-4EC9-B13B-C3D5C100494C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.Web.Modules.SmartTarget.DD4T", "SmartTarget\Sdl.Web.Modules.SmartTarget.DD4T\Sdl.Web.Modules.SmartTarget.DD4T.csproj", "{DD3A7294-291F-420D-81B0-0058AB704B8D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -71,6 +75,22 @@ Global {360AEC0A-3367-486A-885F-7931F32234C1}.Tridion71Debug|Any CPU.Build.0 = Debug|Any CPU {360AEC0A-3367-486A-885F-7931F32234C1}.Tridion71Release|Any CPU.ActiveCfg = Release|Any CPU {360AEC0A-3367-486A-885F-7931F32234C1}.Tridion71Release|Any CPU.Build.0 = Release|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Release|Any CPU.Build.0 = Release|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Tridion71Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Tridion71Debug|Any CPU.Build.0 = Debug|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Tridion71Release|Any CPU.ActiveCfg = Release|Any CPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C}.Tridion71Release|Any CPU.Build.0 = Release|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Release|Any CPU.Build.0 = Release|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Tridion71Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Tridion71Debug|Any CPU.Build.0 = Debug|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Tridion71Release|Any CPU.ActiveCfg = Release|Any CPU + {DD3A7294-291F-420D-81B0-0058AB704B8D}.Tridion71Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/ComponentPresentationFactory.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/ComponentPresentationFactory.cs new file mode 100644 index 0000000..f13ff86 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/ComponentPresentationFactory.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DD4T.ContentModel; +using DD4T.ContentModel.Factories; +using Tridion.ContentDelivery.DynamicContent.Query; +using Tridion.ContentDelivery.Meta; + +namespace Sdl.Web.Modules.SmartTarget.DD4T.Factories +{ + public class ComponentPresentationFactory : IComponentPresentationFactory + { + private IComponentFactory _componentFactory; + + public ComponentPresentationFactory(IComponentFactory componentFactory) + { + _componentFactory = componentFactory; + } + + public IComponentPresentation GetComponentPresentation(string componentUri, string templateUri) + { + IComponent component = null; + if (_componentFactory.TryGetComponent(componentUri, out component, templateUri)) + { + var componentTcmUri = new TcmUri(componentUri); + var templateTcmUri = new TcmUri(templateUri); + + var publicationCriteria = new PublicationCriteria(templateTcmUri.PublicationId); + var itemReferenceCriteria = new ItemReferenceCriteria(templateTcmUri.ItemId); + var itemTypeTypeCriteria = new ItemTypeCriteria(32); + + var query = new Tridion.ContentDelivery.DynamicContent.Query.Query( + CriteriaFactory.And(new Criteria[] { publicationCriteria, itemReferenceCriteria, itemTypeTypeCriteria })); + + var results = query.ExecuteEntityQuery(); + if (results != null) + { + var templateMeta = (ITemplateMeta)results.FirstOrDefault(); + + var componentPresentation = new ComponentPresentation(); + componentPresentation.Component = component as Component; + componentPresentation.IsDynamic = true; + + var template = new ComponentTemplate() + { + Id = templateUri, + Title = templateMeta.Title, + OutputFormat = templateMeta.OutputFormat + }; + componentPresentation.ComponentTemplate = template; + return componentPresentation; + } + } + return null; + } + + public bool TryGetComponentPresentation(string componentUri, string templateUri, out IComponentPresentation componentPresentation) + { + componentPresentation = GetComponentPresentation(componentUri, templateUri); + return componentPresentation != null; + } + + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/IComponentPresentationFactory.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/IComponentPresentationFactory.cs new file mode 100644 index 0000000..febc521 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Factories/IComponentPresentationFactory.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DD4T.ContentModel; + +namespace Sdl.Web.Modules.SmartTarget.DD4T.Factories +{ + public interface IComponentPresentationFactory + { + IComponentPresentation GetComponentPresentation(string componentUri, string templateUri); + + bool TryGetComponentPresentation(string componentUri, string templateUri, out IComponentPresentation componentPresentation); + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Html/SmartTargetRenderer.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Html/SmartTargetRenderer.cs new file mode 100644 index 0000000..226021d --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Html/SmartTargetRenderer.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using System.Text; +using System.Web.Mvc; +using Sdl.Web.Common.Models; +using Sdl.Web.DD4T.Html; +using Sdl.Web.Modules.SmartTarget.Interfaces; +using Sdl.Web.Modules.SmartTarget.Models; +using Sdl.Web.Modules.SmartTarget.Analytics; +using Sdl.Web.Mvc.Configuration; + +namespace Sdl.Web.Modules.SmartTarget.DD4T.Html +{ + public class SmartTargetRenderer : DD4TRenderer, ISmartTargetRenderer + { + private const string _defaultSiteEditTag = "span"; + + public MvcHtmlString RenderSmartTargetQuery(SmartTargetRegion region, HtmlHelper helper, string siteEditTag = _defaultSiteEditTag) + { + var siteEditOpenTag = String.Format("<{0}>", siteEditTag); + var siteEditCloseTag = String.Format("", siteEditTag); + + var xmpMarkup = new StringBuilder(); + var isPreview = WebRequestContext.IsPreview; + if (isPreview) + { + xmpMarkup.AppendLine(siteEditOpenTag); + xmpMarkup.AppendLine(region.XpmMarkup); + } + if (region.HasSmartTargetContent) + { + foreach (var promotion in region.Items.Cast().Where(p => p.IsVisible)) + { + if (isPreview) + { + xmpMarkup.AppendLine(siteEditOpenTag); + xmpMarkup.AppendLine(promotion.XpmMarkup); + } + foreach (var item in promotion.Items.Where(i => i.IsVisible)) + { + xmpMarkup.AppendLine(RenderPromotionContent(promotion, helper)); + } + if (isPreview) + { + xmpMarkup.AppendLine(siteEditCloseTag); + } + } + } + else + { + // Fallback content + foreach (var item in region.Items) + { + xmpMarkup.AppendLine(RenderEntity(item, helper).ToHtmlString()); + } + } + if (isPreview) + { + xmpMarkup.AppendLine(siteEditCloseTag); + } + + return MvcHtmlString.Create(xmpMarkup.ToString()); + } + + public MvcHtmlString RenderSmartTargetPromotion(SmartTargetPromotion promotion, HtmlHelper helper) + { + return new MvcHtmlString(RenderPromotionContent(promotion, helper)); + } + + private string RenderPromotionContent(SmartTargetPromotion promotion, HtmlHelper helper) + { + var renderedContent = new StringBuilder(); + foreach (var item in promotion.Items.Where(i => i.IsVisible)) + { + renderedContent.AppendLine(RenderEntity(item.Entity, helper).ToHtmlString()); + } + + if (promotion is SmartTargetExperiment) + { + var experiment = promotion as SmartTargetExperiment; + string renderedContentWithTrackedLinks = SmartTargetAnalytics.AddTrackingToLinks(renderedContent.ToString(), experiment); + + SmartTargetAnalytics.TrackView(experiment); + SmartTargetAnalytics.SaveExperimentCookies(experiment); + + return renderedContentWithTrackedLinks; + } + else + { + return renderedContent.ToString(); + } + } + + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Mapping/SmartTargetModelBuilder.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Mapping/SmartTargetModelBuilder.cs new file mode 100644 index 0000000..e1aa2e2 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Mapping/SmartTargetModelBuilder.cs @@ -0,0 +1,118 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using DD4T.ContentModel; +using DD4T.ContentModel.Factories; +using Sdl.Web.Common.Interfaces; +using Sdl.Web.DD4T.Mapping; +using Sdl.Web.Modules.SmartTarget.DD4T.Factories; +using Sdl.Web.Modules.SmartTarget.Models; +using Sdl.Web.Modules.SmartTarget.Query; +using Sdl.Web.Modules.SmartTarget.Utils; + +namespace Sdl.Web.Modules.SmartTarget.DD4T.Mapping +{ + public class SmartTargetModelBuilder : DD4TModelBuilder + { + private IComponentPresentationFactory _componentPresentationFactory; + + public SmartTargetModelBuilder(ILinkFactory linkFactory, IContentResolver contentResolver, IComponentPresentationFactory componentPresentationFactory) + : base(linkFactory, contentResolver) + { + _componentPresentationFactory = componentPresentationFactory; + } + + protected override object CreatePage(object sourceEntity, Type type, List includes) + { + var page = base.CreatePage(sourceEntity, type, includes) as Sdl.Web.Common.Models.IPage; + if (page != null) + { + Dictionary moduleMap; + List regionConfigList; + if (TryGetSmartTargetRegionConfiguration(sourceEntity, out moduleMap, out regionConfigList)) + { + var queryResults = SmartTargetQuery.GetPagePromotions(regionConfigList); + foreach (var queryResult in queryResults) + { + var region = new SmartTargetRegion + { + Module = moduleMap[queryResult.RegionName], + Name = queryResult.RegionName, + XpmMarkup = queryResult.XpmMarkup, + HasSmartTargetContent = queryResult.HasSmartTargetContent + }; + + if (region.HasSmartTargetContent) + { + foreach (var promotion in queryResult.Promotions) + { + RetrievePromotionEntities(promotion); + region.Items.Add(promotion); + } + } + else + { + var fallbackContent = page.Regions.ContainsKey(region.Name) ? page.Regions[region.Name] : null; + if (fallbackContent != null) + { + region.Items = fallbackContent.Items; + } + } + page.Regions[region.Name] = region; + } + } + } + return page; + } + + private bool TryGetSmartTargetRegionConfiguration(object sourceEntity, out Dictionary moduleMap, out List regionConfigList) + { + moduleMap = new Dictionary(); + regionConfigList = new List(); + + IPage page = sourceEntity as IPage; + if (page != null && page.PageTemplate.MetadataFields.ContainsKey("smartTargetRegions")) + { + foreach (var smartTargetRegion in page.PageTemplate.MetadataFields["smartTargetRegions"].EmbeddedValues) + { + string module, regionName; + ViewUtils.ParseViewName(smartTargetRegion["regionName"].Value, out module, out regionName); //Mandatory field; regionName + moduleMap[regionName] = module; + + int maxItems = 0; + Int32.TryParse(smartTargetRegion["maxItems"].Value, out maxItems); //Mandatory field; maxItems + + bool allowDuplicates = AllowDuplicatesValueHelper.DefaultAllowDuplicates; + if (smartTargetRegion.ContainsKey("allowDuplicates")) + { + allowDuplicates = AllowDuplicatesValueHelper.Parse(smartTargetRegion["allowDuplicates"].Value); //Optional field; allowDuplicates + } + + var regionConfig = new SmartTargetRegionConfig + { + PageId = page.Id, + RegionName = regionName, + MaxItems = maxItems, + AllowDuplicates = allowDuplicates + }; + regionConfigList.Add(regionConfig); + } + return true; + } + return false; + } + + private void RetrievePromotionEntities(SmartTargetPromotion promotion) + { + foreach (var promotionItem in promotion.Items.Where(p => p.IsVisible)) + { + IComponentPresentation componentPresentation; + if (_componentPresentationFactory.TryGetComponentPresentation(promotionItem.ComponentUri, promotionItem.TemplateUri, out componentPresentation)) + { + promotionItem.Entity = componentPresentation; + } + } + } + + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Properties/AssemblyInfo.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f61efbb --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Sdl.Web.Modules.SmartTarget.DD4T")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Sdl.Web.Modules.SmartTarget.DD4T")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dd12c51d-8715-405e-9a44-4ad971821954")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Sdl.Web.Modules.SmartTarget.DD4T.csproj b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Sdl.Web.Modules.SmartTarget.DD4T.csproj new file mode 100644 index 0000000..bc18964 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/Sdl.Web.Modules.SmartTarget.DD4T.csproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + {DD3A7294-291F-420D-81B0-0058AB704B8D} + Library + Properties + Sdl.Web.Modules.SmartTarget.DD4T + Sdl.Web.Modules.SmartTarget.DD4T + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\DD4TFramework.1.31.0\lib\DD4T.ContentModel.dll + + + ..\..\..\packages\DD4TFramework.1.31.0\lib\DD4T.ContentModel.Contracts.dll + + + + + + False + ..\..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + + + + + + + + False + ..\..\..\_references\2013-sp1\Tridion.ContentDelivery.dll + + + + + + + + + + + + {21c08f9a-24c2-481a-95c3-a255be9771a7} + Sdl.Web.Common + + + {360aec0a-3367-486a-885f-7931f32234c1} + Sdl.Web.DD4T + + + {923b2009-9a0b-4425-88a5-bf7af25c8f8b} + Sdl.Web.Mvc + + + {05ecdb04-eb87-4ec9-b13b-c3d5c100494c} + Sdl.Web.Modules.SmartTarget + + + + + + + + rmdir "$(SolutionDir)..\mod\SmartTarget.DD4T\web\Site" /q /s +xcopy "$(TargetPath)" "$(SolutionDir)..\mod\SmartTarget.DD4T\web\Site\bin\" /Y /s +xcopy "$(SolutionDir)..\mod\SmartTarget.DD4T\web\Site\*" "$(SolutionDir)..\Site\" /Y /s + + + \ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/packages.config b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/packages.config new file mode 100644 index 0000000..ff067f2 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget.DD4T/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Analytics/SmartTargetAnalytics.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Analytics/SmartTargetAnalytics.cs new file mode 100644 index 0000000..e2bf6a4 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Analytics/SmartTargetAnalytics.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sdl.Web.Modules.SmartTarget.Models; +using Sdl.Web.Modules.SmartTarget.Utils; +using Tridion.SmartTarget.Analytics; +using Tridion.SmartTarget.Utils; + +namespace Sdl.Web.Modules.SmartTarget.Analytics +{ + public static class SmartTargetAnalytics + { + private static AnalyticsManager _analyticsManager = new AnalyticsManager(); + + public static void TrackView(SmartTargetExperiment experiment) + { + _analyticsManager.TrackView(experiment.ExperimentDimensions, new AnalyticsMetaData()); + } + + public static string AddTrackingToLinks(string content, SmartTargetExperiment experiment) + { + return _analyticsManager.AddTrackingToLinks(content, experiment.ExperimentDimensions, new AnalyticsMetaData()); + } + + public static void SaveExperimentCookies(SmartTargetExperiment experiment) + { + CookieProcessor.SaveExperimentCookies(WebContext.Response, null, experiment.NewExperimentCookies); + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset1.cshtml b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset1.cshtml new file mode 100644 index 0000000..746fca1 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset1.cshtml @@ -0,0 +1,4 @@ +@model Sdl.Web.Modules.SmartTarget.Models.SmartTargetRegion +
+ @ViewBag.Renderer.RenderSmartTargetQuery(Model, Html) +
\ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset2.cshtml b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset2.cshtml new file mode 100644 index 0000000..2cfc7df --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/Region/Inset2.cshtml @@ -0,0 +1,49 @@ +@model SmartTargetRegion +@using System.Linq +@using Sdl.Web.Modules.SmartTarget.Models; +
+ @if (SiteConfiguration.IsStaging) + { + + @Html.Raw(Model.XpmMarkup) + @if (Model.HasSmartTargetContent) + { + foreach (var promotion in Model.Items.Cast().Where(p => p.IsVisible)) + { + + @Html.Raw(promotion.XpmMarkup) +

@promotion.Title

+

@promotion.Slogan

+ @ViewBag.Renderer.RenderSmartTargetPromotion(promotion, Html) +
+ } + } + else + { + //Render fallback content + foreach (var item in Model.Items) + { + @ViewBag.Renderer.RenderEntity(item, Html) + } + } +
+ } + else + { + if (Model.HasSmartTargetContent) + { + foreach (var promotion in Model.Items.Cast().Where(p => p.IsVisible)) + { + @ViewBag.Renderer.RenderSmartTargetPromotion(promotion, Html) + } + } + else + { + //Render fallback content + foreach (var item in Model.Items) + { + @ViewBag.Renderer.RenderEntity(item, Html) + } + } + } +
\ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/web.config b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/web.config new file mode 100644 index 0000000..b56ec35 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Areas/SmartTarget/Views/web.config @@ -0,0 +1,35 @@ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Interfaces/ISmartTargetRenderer.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Interfaces/ISmartTargetRenderer.cs new file mode 100644 index 0000000..d21813a --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Interfaces/ISmartTargetRenderer.cs @@ -0,0 +1,15 @@ +using System; +using System.Web.Mvc; +using Sdl.Web.Common.Interfaces; +using Sdl.Web.Common.Models; +using Sdl.Web.Modules.SmartTarget.Models; + +namespace Sdl.Web.Modules.SmartTarget.Interfaces +{ + public interface ISmartTargetRenderer : IRenderer + { + MvcHtmlString RenderSmartTargetQuery(SmartTargetRegion region, HtmlHelper helper, string siteEditTag); + + MvcHtmlString RenderSmartTargetPromotion(SmartTargetPromotion promotion, HtmlHelper helper); + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetExperiment.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetExperiment.cs new file mode 100644 index 0000000..064a958 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetExperiment.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tridion.SmartTarget.Analytics; +using Tridion.SmartTarget.Query; + +namespace Sdl.Web.Modules.SmartTarget.Models +{ + public class SmartTargetExperiment : SmartTargetPromotion + { + public ExperimentDimensions ExperimentDimensions { get; set; } + + public ExperimentCookies NewExperimentCookies { get; set; } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetItem.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetItem.cs new file mode 100644 index 0000000..32f3480 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetItem.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sdl.Web.Modules.SmartTarget.Models +{ + public class SmartTargetItem + { + public string RegionName { get; set; } + + public string PromotionId { get; set; } + + public string ComponentUri { get; set; } + + public string TemplateUri { get; set; } + + public bool IsVisible { get; set; } + + // The raw entity that make up the promotion (eg Component Presentation) + public object Entity { get; set; } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetPromotion.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetPromotion.cs new file mode 100644 index 0000000..0d56b0b --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetPromotion.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sdl.Web.Modules.SmartTarget.Models +{ + public class SmartTargetPromotion + { + public const string _xpmMarkupFormat = ""; + + public string RegionName { get; set; } + + public string PromotionId { get; set; } + + public string Title { get; set; } + + public string Slogan { get; set; } + + public List Items { get; set; } + + public bool IsVisible { get; set; } + + public string XpmMarkup + { + get { return String.Format(_xpmMarkupFormat, PromotionId, RegionName); } + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegion.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegion.cs new file mode 100644 index 0000000..a515f1f --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegion.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sdl.Web.Common.Models; + +namespace Sdl.Web.Modules.SmartTarget.Models +{ + public class SmartTargetRegion : Region + { + public bool HasSmartTargetContent { get; set; } + + public string XpmMarkup { get; set; } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegionConfig.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegionConfig.cs new file mode 100644 index 0000000..14d8d16 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Models/SmartTargetRegionConfig.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sdl.Web.Modules.SmartTarget.Models +{ + public class SmartTargetRegionConfig + { + public string PageId { get; set; } + + public string RegionName { get; set; } + + public int MaxItems { get; set; } + + public int StartIndex { get; set; } + + public bool AllowDuplicates { get; set; } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Properties/AssemblyInfo.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2da8a30 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Sdl.Web.Modules.SmartTarget")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Sdl.Web.Modules.SmartTarget")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fd367611-b695-4c2a-a6d0-cc7780fa714a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQuery.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQuery.cs new file mode 100644 index 0000000..d830e04 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQuery.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using Sdl.Web.Modules.SmartTarget.Models; +using Sdl.Web.Modules.SmartTarget.Utils; +using Tridion.ContentDelivery.AmbientData; +using Tridion.SmartTarget.Analytics; +using Tridion.SmartTarget.Query; +using Tridion.SmartTarget.Query.Builder; +using Tridion.SmartTarget.Utils; + +namespace Sdl.Web.Modules.SmartTarget.Query +{ + public class SmartTargetQuery + { + public static List GetPagePromotions(List regionConfigList) + { + var queryResults = new List(); + + var itemsAlreadyOnPage = new List(); + foreach(var regionConfig in regionConfigList) + { + var queryResult = GetRegionPromotions(regionConfig, itemsAlreadyOnPage); + queryResults.Add(queryResult); + } + + return queryResults; + } + + public static SmartTargetQueryResult GetRegionPromotions(SmartTargetRegionConfig regionConfig, List itemsAlreadyOnPage) + { + var queryResult = new SmartTargetQueryResult(); + queryResult.RegionName = regionConfig.RegionName; + + var pageUri = new TcmUri(regionConfig.PageId); + var publicationUri = new TcmUri(0, pageUri.PublicationId, 1); + //TODO; via TRI?? + ClaimStore claimStore = AmbientDataContext.CurrentClaimStore; + string triggers = AmbientDataHelper.GetTriggers(claimStore); + + var queryBuilder = new QueryBuilder(); + queryBuilder.Parse(triggers); + queryBuilder.AddCriteria(new PublicationCriteria(publicationUri)); + queryBuilder.AddCriteria(new PageCriteria(pageUri)); + queryBuilder.AddCriteria(new RegionCriteria(regionConfig.RegionName)); + if (regionConfig.MaxItems > 0) + { + queryBuilder.MaxItems = regionConfig.MaxItems; + } + if (regionConfig.StartIndex > 0) + { + queryBuilder.StartIndex = regionConfig.StartIndex; + } + + ResultSet fredHopperResultset = queryBuilder.Execute(); + if (fredHopperResultset.Promotions.Count > 0) + { + queryResult.Promotions = ProcessRegionPromotions(fredHopperResultset.Promotions, publicationUri, pageUri, regionConfig.RegionName, regionConfig.MaxItems, regionConfig.AllowDuplicates, itemsAlreadyOnPage); + queryResult.HasSmartTargetContent = true; + } + + var xmpQueryMarkup = ResultSet.GetExperienceManagerMarkup(regionConfig.RegionName, regionConfig.MaxItems, fredHopperResultset.Promotions); + queryResult.XpmMarkup = xmpQueryMarkup; + + return queryResult; + } + + private static List ProcessRegionPromotions(List promotions, TcmUri publicationUri, TcmUri pageUri, string region, int maxItems, bool allowDuplicates, List itemsAlreadyOnPage) + { + var itemsOutputInRegion = new List(); + var existingExperimentCookies = CookieProcessor.GetExperimentCookies(WebContext.Request); + var newExperimentCookies = new ExperimentCookies(); + ExperimentDimensions experimentDimensions = null; + + //Method will populate experimentDimensions variable when an experiment is present. Also it will populate the newExperimentCookies variable when no existing experiment cookies are found + ResultSet.FilterPromotions(promotions, region, maxItems, allowDuplicates, itemsOutputInRegion, itemsAlreadyOnPage, ref existingExperimentCookies, ref newExperimentCookies, out experimentDimensions); + + var smartTargetPromotions = new List(); + foreach (var promotion in promotions) + { + var smartTargetPromotion = new SmartTargetPromotion(); + if (experimentDimensions != null && experimentDimensions.ExperimentId.Equals(promotion.PromotionId)) + { + //Populate the remaining emtpy properties + experimentDimensions.PublicationId = publicationUri.ToString(); + experimentDimensions.PageId = pageUri.ToString(); + experimentDimensions.Region = region; + + smartTargetPromotion = new SmartTargetExperiment() + { + ExperimentDimensions = experimentDimensions, + NewExperimentCookies = newExperimentCookies + }; + } + smartTargetPromotion.PromotionId = promotion.PromotionId; + smartTargetPromotion.RegionName = promotion.Region; + smartTargetPromotion.Title = promotion.Title; + smartTargetPromotion.Slogan = promotion.Slogan; + smartTargetPromotion.IsVisible = promotion.Visible; + + var smartTargetPromotionItems = new List(); + foreach (var item in promotion.Items) + { + var smartTargetItem = new SmartTargetItem + { + PromotionId = item.PromotionId, + RegionName = item.Region, + ComponentUri = item.ComponentUriAsString, + TemplateUri = item.TemplateUriAsString, + IsVisible = item.Visible + }; + smartTargetPromotionItems.Add(smartTargetItem); + } + smartTargetPromotion.Items = smartTargetPromotionItems; + smartTargetPromotions.Add(smartTargetPromotion); + } + return smartTargetPromotions; + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQueryResult.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQueryResult.cs new file mode 100644 index 0000000..b024771 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Query/SmartTargetQueryResult.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sdl.Web.Modules.SmartTarget.Models; + +namespace Sdl.Web.Modules.SmartTarget.Query +{ + public class SmartTargetQueryResult + { + public string RegionName { get; set; } + + public List Promotions { get; set; } + + public bool HasSmartTargetContent { get; set; } + + public string XpmMarkup { get; set; } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Sdl.Web.Modules.SmartTarget.csproj b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Sdl.Web.Modules.SmartTarget.csproj new file mode 100644 index 0000000..44a5817 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Sdl.Web.Modules.SmartTarget.csproj @@ -0,0 +1,119 @@ + + + + + Debug + AnyCPU + {05ECDB04-EB87-4EC9-B13B-C3D5C100494C} + Library + Properties + Sdl.Web.Modules.SmartTarget + Sdl.Web.Modules.SmartTarget + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + False + ..\..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + + + False + ..\..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll + + + False + ..\..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll + + + False + ..\..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + ..\..\..\_references\2013-sp1\Tridion.ContentDelivery.AmbientData.dll + + + ..\..\..\_references\st-2014-sp1\Tridion.SmartTarget.dll + + + + + + + + + + + + + + + + + + + + + {21c08f9a-24c2-481a-95c3-a255be9771a7} + Sdl.Web.Common + + + {923b2009-9a0b-4425-88a5-bf7af25c8f8b} + Sdl.Web.Mvc + + + + + + + + Designer + + + + + + rmdir "$(SolutionDir)..\mod\SmartTarget\web\Site" /q /s +xcopy "$(TargetPath)" "$(SolutionDir)..\mod\SmartTarget\web\Site\bin\" /Y +xcopy "$(ProjectDir)$(OutDir)Tridion.SmartTarget*.dll" "$(SolutionDir)..\mod\SmartTarget\web\Site\bin\" /Y +xcopy "$(ProjectDir)\Areas\*" "$(SolutionDir)..\mod\SmartTarget\web\Site\Areas\" /Y /s +xcopy "$(ProjectDir)\redirect\*" "$(SolutionDir)..\mod\SmartTarget\web\Site\redirect\" /Y /s +xcopy "$(SolutionDir)..\mod\SmartTarget\web\Site\*" "$(SolutionDir)..\Site\" /Y /s + + + \ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/AllowDuplicatesValueHelper.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/AllowDuplicatesValueHelper.cs new file mode 100644 index 0000000..dd5fc26 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/AllowDuplicatesValueHelper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tridion.SmartTarget.Utils; + +namespace Sdl.Web.Modules.SmartTarget.Utils +{ + public static class AllowDuplicatesValueHelper + { + public static bool DefaultAllowDuplicates + { + get + { + return ConfigurationUtility.DefaultAllowDuplicates; + } + } + + public static bool Parse(string value) + { + if ("No".Equals(value, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + else if ("Yes".Equals(value, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + return DefaultAllowDuplicates; + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/ViewUtils.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/ViewUtils.cs new file mode 100644 index 0000000..64bd5b0 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/ViewUtils.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Sdl.Web.Common.Configuration; + +namespace Sdl.Web.Modules.SmartTarget.Utils +{ + public static class ViewUtils + { + public static void ParseViewName(string value, out string moduleName, out string viewName) + { + moduleName = SiteConfiguration.GetDefaultModuleName();//Default module + viewName = null; + if (value != null) + { + var bits = value.Split(':'); + if (bits.Length > 1) + { + moduleName = bits[0].Trim(); + viewName = bits[1].Trim(); + } + else + { + viewName = bits[0].Trim(); + } + } + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/WebContext.cs b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/WebContext.cs new file mode 100644 index 0000000..0270ec5 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/Utils/WebContext.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Sdl.Web.Mvc.Configuration; + +namespace Sdl.Web.Modules.SmartTarget.Utils +{ + public static class WebContext + { + public static HttpRequest Request + { + get + { + return HttpContext.Current.Request; + } + } + + public static HttpResponse Response + { + get + { + return HttpContext.Current.Response; + } + } + } +} diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/packages.config b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/packages.config new file mode 100644 index 0000000..a6add84 --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/redirect/Web.config b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/redirect/Web.config new file mode 100644 index 0000000..774501c --- /dev/null +++ b/web-application/Modules/SmartTarget/Sdl.Web.Modules.SmartTarget/redirect/Web.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/web-application/Modules/Unity.config b/web-application/Modules/Unity.config index 3b862f7..c841ba7 100644 --- a/web-application/Modules/Unity.config +++ b/web-application/Modules/Unity.config @@ -13,6 +13,10 @@ + + + + @@ -51,13 +55,13 @@ - + - + @@ -81,7 +85,8 @@ - + + diff --git a/web-application/Sdl.Web.Common/Models/Navigation/SitemapItem.cs b/web-application/Sdl.Web.Common/Models/Navigation/SitemapItem.cs index af0e7de..bd0f4e4 100644 --- a/web-application/Sdl.Web.Common/Models/Navigation/SitemapItem.cs +++ b/web-application/Sdl.Web.Common/Models/Navigation/SitemapItem.cs @@ -6,6 +6,9 @@ namespace Sdl.Web.Common.Models { public class SitemapItem : EntityBase { + //TODO: Make this configurable since its dependend on framework implementation + private const string DefaultExtension = ".html"; + private string _url; public SitemapItem() @@ -29,7 +32,7 @@ public string Url private static string ProcessUrl(string value) { - return Path.HasExtension(value) ? value.Substring(0, value.Length - Path.GetExtension(value).Length) : value; + return Path.HasExtension(value) && DefaultExtension.Equals(Path.GetExtension(value)) ? value.Substring(0, value.Length - Path.GetExtension(value).Length) : value; } public string Type { get; set; } diff --git a/web-application/Sdl.Web.DD4T/Mapping/DD4TContentResolver.cs b/web-application/Sdl.Web.DD4T/Mapping/DD4TContentResolver.cs index bd9f4fe..ea66661 100644 --- a/web-application/Sdl.Web.DD4T/Mapping/DD4TContentResolver.cs +++ b/web-application/Sdl.Web.DD4T/Mapping/DD4TContentResolver.cs @@ -62,9 +62,11 @@ public virtual string ResolveLink(object linkData, object resolveInstruction = n if (url!=null && url.EndsWith(DefaultExtension)) { url = url.Substring(0, url.Length - DefaultExtension.Length); - if (url.EndsWith("/" + DefaultExtensionLessPageName)) + // Also strip the forward slash + var defaultPageNamePart = "/" + DefaultExtensionLessPageName; + if (url.EndsWith(defaultPageNamePart)) { - url = url.Substring(0, url.Length - DefaultExtensionLessPageName.Length); + url = url.Substring(0, url.Length - defaultPageNamePart.Length); } } } diff --git a/web-application/_references/st-2014-sp1/Tridion.SmartTarget.Interop.dll b/web-application/_references/st-2014-sp1/Tridion.SmartTarget.Interop.dll new file mode 100644 index 0000000..5fa9879 Binary files /dev/null and b/web-application/_references/st-2014-sp1/Tridion.SmartTarget.Interop.dll differ diff --git a/web-application/_references/st-2014-sp1/Tridion.SmartTarget.dll b/web-application/_references/st-2014-sp1/Tridion.SmartTarget.dll new file mode 100644 index 0000000..9fee4b0 Binary files /dev/null and b/web-application/_references/st-2014-sp1/Tridion.SmartTarget.dll differ