diff --git a/Packages.props b/Packages.props index 087ac209..540b179e 100644 --- a/Packages.props +++ b/Packages.props @@ -38,5 +38,6 @@ + diff --git a/src/Feature/Sitemap/Sitemap.module.json b/src/Feature/Sitemap/Sitemap.module.json new file mode 100644 index 00000000..0c776196 --- /dev/null +++ b/src/Feature/Sitemap/Sitemap.module.json @@ -0,0 +1,13 @@ +{ + "namespace": "Feature.Sitemap", + "items": { + "includes": [ + { + "name": "templates", + "path": "/sitecore/templates/Feature/Sitemap", + "allowedPushOperations": "createUpdateAndDelete", + "scope": "itemAndDescendants" + } + ] + } +} \ No newline at end of file diff --git a/src/Feature/Sitemap/items/templates/Sitemap.yml b/src/Feature/Sitemap/items/templates/Sitemap.yml new file mode 100644 index 00000000..b7f8e682 --- /dev/null +++ b/src/Feature/Sitemap/items/templates/Sitemap.yml @@ -0,0 +1,31 @@ +--- +ID: "51273b02-674d-4a04-947f-d249f2871bcd" +Parent: "8f343079-3cc5-4ef7-bc27-32addb46f45e" +Template: "0437fee2-44c9-46a6-abe9-28858d9fee8c" +Path: /sitecore/templates/Feature/Sitemap +Languages: +- Language: en + Versions: + - Version: 1 + Fields: + - ID: "25bed78c-4957-4165-998a-ca1b52f67497" + Hint: __Created + Value: 20231212T005121Z + - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103" + Hint: __Owner + Value: | + sitecore\qDWz4GMo2o + - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f" + Hint: __Created by + Value: | + sitecore\qDWz4GMo2o + - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" + Hint: __Revision + Value: "61b184a4-32b9-46ae-a09a-b765d21b4b7a" + - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" + Hint: __Updated by + Value: | + sitecore\qDWz4GMo2o + - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" + Hint: __Updated + Value: 20231212T005449Z diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml new file mode 100644 index 00000000..87d14d10 --- /dev/null +++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData.yml @@ -0,0 +1,37 @@ +--- +ID: "00f7955a-eb3d-4659-94f9-9202865e39de" +Parent: "51273b02-674d-4a04-947f-d249f2871bcd" +Template: "ab86861a-6030-46c5-b394-e8f99e8b87db" +Path: /sitecore/templates/Feature/Sitemap/_SitemapData +SharedFields: +- ID: "12c33f3f-86c5-43a5-aeb4-5598cec45116" + Hint: __Base template + Value: | + {1930BBEB-7805-471A-A3BE-4858AC7CF696} + {4414A1F9-826A-4647-8DF4-ED6A95E64C43} +Languages: +- Language: en + Versions: + - Version: 1 + Fields: + - ID: "25bed78c-4957-4165-998a-ca1b52f67497" + Hint: __Created + Value: 20231212T000336Z + - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103" + Hint: __Owner + Value: | + sitecore\qDWz4GMo2o + - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f" + Hint: __Created by + Value: | + sitecore\qDWz4GMo2o + - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" + Hint: __Revision + Value: "d85a32fd-cf94-4e5f-92f1-440bb8062c4b" + - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" + Hint: __Updated by + Value: | + sitecore\qDWz4GMo2o + - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" + Hint: __Updated + Value: 20231212T005128Z diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml new file mode 100644 index 00000000..595722fb --- /dev/null +++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings.yml @@ -0,0 +1,31 @@ +--- +ID: "f1cda39f-65de-4cde-a59b-bcd97968f090" +Parent: "00f7955a-eb3d-4659-94f9-9202865e39de" +Template: "e269fbb5-3750-427a-9149-7aa950b49301" +Path: /sitecore/templates/Feature/Sitemap/_SitemapData/Sitemap Settings +Languages: +- Language: en + Versions: + - Version: 1 + Fields: + - ID: "25bed78c-4957-4165-998a-ca1b52f67497" + Hint: __Created + Value: 20231212T000540Z + - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103" + Hint: __Owner + Value: | + sitecore\qDWz4GMo2o + - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f" + Hint: __Created by + Value: | + sitecore\qDWz4GMo2o + - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" + Hint: __Revision + Value: "ae77877a-f036-42ac-ae2a-09cb0f49f373" + - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" + Hint: __Updated by + Value: | + sitecore\qDWz4GMo2o + - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" + Hint: __Updated + Value: 20231212T000718Z diff --git a/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml new file mode 100644 index 00000000..242bff92 --- /dev/null +++ b/src/Feature/Sitemap/items/templates/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap.yml @@ -0,0 +1,48 @@ +--- +ID: "e319ae64-c32a-4e79-b102-256f8c869dae" +Parent: "f1cda39f-65de-4cde-a59b-bcd97968f090" +Template: "455a3e98-a627-4b40-8035-e683a0331ac7" +Path: /sitecore/templates/Feature/Sitemap/_SitemapData/Sitemap Settings/IncludeinSitemap +SharedFields: +- ID: "ab162cc0-dc80-4abf-8871-998ee5d7ba32" + Hint: Type + Value: Checkbox +- ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e" + Hint: __Sortorder + Value: 100 +- ID: "be351a73-fcb0-4213-93fa-c302d8ab4f51" + Hint: Shared + Value: 1 +Languages: +- Language: en + Fields: + - ID: "19a69332-a23e-4e70-8d16-b2640cb24cc8" + Hint: Title + Value: Include in Sitemap + - ID: "b5e02ad9-d56f-4c41-a065-a133db87bdeb" + Hint: __Display name + Value: Include in Sitemap + Versions: + - Version: 1 + Fields: + - ID: "25bed78c-4957-4165-998a-ca1b52f67497" + Hint: __Created + Value: 20231212T000541Z + - ID: "52807595-0f8f-4b20-8d2a-cb71d28c6103" + Hint: __Owner + Value: | + sitecore\qDWz4GMo2o + - ID: "5dd74568-4d4b-44c1-b513-0af5f4cda34f" + Hint: __Created by + Value: | + sitecore\qDWz4GMo2o + - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" + Hint: __Revision + Value: "b83eade9-b538-40ac-943f-5e5bbdc0051a" + - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" + Hint: __Updated by + Value: | + sitecore\qDWz4GMo2o + - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" + Hint: __Updated + Value: 20231212T001324Z diff --git a/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs b/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs index 6913a395..20c6592c 100644 --- a/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs +++ b/src/Foundation/Configuration/rendering/AppSettings/MvpSiteSettings.cs @@ -10,8 +10,14 @@ public class MvpSiteSettings public string? DefaultSiteName { get; set; } + public string? RootItemId { get; set; } + public string? NotFoundPage { get; set; } + public string? DefaultAcceptLanguageHeader { get; set; } + + public string? DefaultLanguage { get; set; } + public Uri? RenderingHostUri { get; set; } public bool EnableExperienceEditor { get; set; } diff --git a/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs b/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs index ed6232ff..16dccee9 100644 --- a/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs +++ b/src/Foundation/DataFetching/rendering/GraphQL/GraphQLRequestBuilder.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Configuration; using Mvp.Foundation.Configuration.Rendering.AppSettings; -using Mvp.Foundation.DataFetching.GraphQL; using System.Collections.Generic; namespace Mvp.Foundation.DataFetching.GraphQL diff --git a/src/Project/MvpSite/items/content/MvpSite/Home.yml b/src/Project/MvpSite/items/content/MvpSite/Home.yml index d19a285b..cfa31483 100644 --- a/src/Project/MvpSite/items/content/MvpSite/Home.yml +++ b/src/Project/MvpSite/items/content/MvpSite/Home.yml @@ -7,6 +7,9 @@ SharedFields: - ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e" Hint: __Sortorder Value: 100 +- ID: "e319ae64-c32a-4e79-b102-256f8c869dae" + Hint: IncludeinSitemap + Value: 1 - ID: "f1a1fe9e-a60c-4ddb-a3a0-bb5b29fe732e" Hint: __Renderings Value: | @@ -143,7 +146,7 @@ Languages: Value: MVP, Most Valuable Professional - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" Hint: __Revision - Value: "198fd8d5-7f00-4749-9c29-b7e4bd29ff1f" + Value: "7bfb35cf-92df-47a0-b476-3021107d291e" - ID: "986ff3ab-18cd-47d7-b294-9a091f0e8cea" Hint: OgType Value: article @@ -160,13 +163,16 @@ Languages: - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" Hint: __Updated by Value: | - sitecore\sebw@sitecore.net + sitecore\qDWz4GMo2o - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" Hint: __Updated - Value: 20221004T072522Z + Value: 20231212T000936Z - ID: "e08359cc-7bf5-4866-81a6-1e1d07226667" Hint: MetaDescription Value: MVP Home Description - ID: "eeb29922-a760-44a8-a5ab-f28efbdc641c" Hint: OgDescription Value: MVP Home Description + - ID: "efc0a3c7-6993-47d2-ba85-10b44961916e" + Hint: IncludeInMenu + Value: 1 diff --git a/src/Project/MvpSite/items/content/MvpSite/Home/About.yml b/src/Project/MvpSite/items/content/MvpSite/Home/About.yml index 097db65e..d038cf42 100644 --- a/src/Project/MvpSite/items/content/MvpSite/Home/About.yml +++ b/src/Project/MvpSite/items/content/MvpSite/Home/About.yml @@ -7,6 +7,9 @@ SharedFields: - ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e" Hint: __Sortorder Value: 100 +- ID: "e319ae64-c32a-4e79-b102-256f8c869dae" + Hint: IncludeinSitemap + Value: 1 - ID: "f1a1fe9e-a60c-4ddb-a3a0-bb5b29fe732e" Hint: __Renderings Value: | @@ -77,14 +80,14 @@ Languages: Value: 20200604T042230Z - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f" Hint: __Revision - Value: "94e9fd25-7606-41b5-9ea0-012b3f9065ba" + Value: "a2655e6a-c3ac-48d7-8446-4422faad31a0" - ID: "b1ece12f-b2c9-44e6-92a3-c5dfd6514b59" Hint: MenuTitle Value: About - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a" Hint: __Updated by Value: | - sitecore\iva@sitecore.net + sitecore\qDWz4GMo2o - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522" Hint: __Updated - Value: 20220928T162952Z + Value: 20231212T000919Z diff --git a/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml b/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml index 2e043425..05276979 100644 --- a/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml +++ b/src/Project/MvpSite/items/content/MvpSite/Home/Application.yml @@ -8,6 +8,12 @@ SharedFields: - ID: "06d5295c-ed2f-4a54-9bf2-26228d113318" Hint: __Icon Value: office/32x32/desktop.png +- ID: "508c54c0-cd02-4266-8b68-d71f88de1aa9" + Hint: ChangeFrequency + Value: +- ID: "76fb6ffd-4487-4028-a1cf-705fbe360cba" + Hint: Priority + Value: - ID: "ba3f86a2-4a1c-4d78-b63d-91c2779c1b5e" Hint: __Sortorder Value: 200 @@ -23,7 +29,7 @@ SharedFields: p:before="*" s:ds="{5C0D2E63-B9A6-49BF-81B1-E25DF54CB76E}" s:id="{13175655-0158-41FA-B796-AC2663CFED2A}" - s:par="CSSStyles" + s:par="" s:ph="/main/column-container-{413EB6EB-522B-4E53-825B-21992D7DD3F3}-0" s:ccb="Clear on publish" /> _logger; + private readonly SitemapBuilder _sitemap; - public DefaultController(ILogger logger) + public DefaultController(ILogger logger, SitemapBuilder sitemap) { _logger = logger; + _sitemap = sitemap; } // Inject Sitecore rendering middleware for this controller action @@ -78,5 +81,12 @@ public IActionResult Healthz() // TODO: Do we want to add logic here to confirm connectivity with SC etc? return Ok("Healthy"); } + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IResult SiteMap() + { + var xml = _sitemap.GenerateAsync(); + return Results.Stream(xml.Result, "text/xml"); + } } } \ No newline at end of file diff --git a/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs b/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs new file mode 100644 index 00000000..5516a2f7 --- /dev/null +++ b/src/Project/MvpSite/rendering/Middleware/CustomGraphQlLayoutServiceHandler.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Configuration; +using Mvp.Foundation.Configuration.Rendering.AppSettings; +using Mvp.Foundation.DataFetching.GraphQL; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Mvp.Project.MvpSite.Middleware +{ + public class CustomGraphQlLayoutServiceHandler + { + private readonly IGraphQLRequestBuilder _graphQLRequestBuilder; + private readonly IGraphQLClientFactory _graphQLClientFactory; + private readonly MvpSiteSettings _configuration; + + public CustomGraphQlLayoutServiceHandler(IConfiguration configuration, IGraphQLRequestBuilder graphQLRequestBuilder, IGraphQLClientFactory graphQLClientFactory) + { + _graphQLRequestBuilder = graphQLRequestBuilder; + _graphQLClientFactory = graphQLClientFactory; + _configuration = configuration.GetSection(MvpSiteSettings.Key).Get(); + } + + public async Task> GetSitemap() + { + var client = _graphQLClientFactory.CreateGraphQlClient(); + var query = Constants.GraphQlQueries.GetSitemapQuery; + var variables = (object)new + { + rootItemId = _configuration.RootItemId, + language = _configuration.DefaultLanguage + }; + + var request = _graphQLRequestBuilder.BuildRequest(query, variables); + var graphQlResponse = await client.SendQueryAsync(request); + + return graphQlResponse.Data.Search.Results; + } + } +} + + + diff --git a/src/Project/MvpSite/rendering/Models/SitemapModel.cs b/src/Project/MvpSite/rendering/Models/SitemapModel.cs new file mode 100644 index 00000000..d1594686 --- /dev/null +++ b/src/Project/MvpSite/rendering/Models/SitemapModel.cs @@ -0,0 +1,60 @@ +// Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse); +using System.Collections.Generic; + +public class ChangeFrequency +{ + public TargetItem TargetItem { get; set; } +} + +public class SitemapData +{ + public SearchData Search { get; set; } +} + +public class PageInfo +{ + public string endCursor { get; set; } + public bool hasNext { get; set; } +} + +public class Priority +{ + public TargetItem TargetItem { get; set; } +} + +public class Result +{ + public Updateddatetime UpdatedDatetime { get; set; } + public Url Url { get; set; } + public string Name { get; set; } + public Priority Priority { get; set; } + public ChangeFrequency ChangeFrequency { get; set; } +} + +public class Root +{ + public SitemapData Data { get; set; } +} + +public class SearchData +{ + public int total { get; set; } + public PageInfo pageInfo { get; set; } + public List Results { get; set; } +} + +public class TargetItem +{ + public string DisplayName { get; set; } +} + +public class Updateddatetime +{ + public string Value { get; set; } +} + +public class Url +{ + public string Path { get; set; } +} + diff --git a/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj b/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj index 1b76d1ce..1eccff47 100644 --- a/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj +++ b/src/Project/MvpSite/rendering/Mvp.Project.MvpSite.Rendering.csproj @@ -35,6 +35,7 @@ + diff --git a/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs b/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs new file mode 100644 index 00000000..689bf1f6 --- /dev/null +++ b/src/Project/MvpSite/rendering/Sitemap/Providers/ISitemapUrlProvider.cs @@ -0,0 +1,10 @@ +using DotnetSitemapGenerator; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Mvp.Project.MvpSite.Rendering; + +public interface ISitemapUrlProvider +{ + Task> GetNodes(); +} \ No newline at end of file diff --git a/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs b/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs new file mode 100644 index 00000000..423880a8 --- /dev/null +++ b/src/Project/MvpSite/rendering/Sitemap/Providers/MvpSitemapUrlProvider.cs @@ -0,0 +1,100 @@ +using DotnetSitemapGenerator; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Mvp.Foundation.DataFetching.GraphQL; +using Mvp.Project.MvpSite.Middleware; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading.Tasks; + +namespace Mvp.Project.MvpSite.Rendering; + +public class Mvp +{ + public int Id { get; set; } + public string Name { get; set; } + public string Path { get; set; } +} + +public class MvpSitemapUrlProvider : ISitemapUrlProvider +{ + private readonly LinkGenerator _linkGenerator; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ILogger _logger; + private readonly IGraphQLClientFactory _graphQLClientFactory; + private readonly IGraphQLRequestBuilder _graphQLRequestBuilder; + private readonly IConfiguration _configuration; + + public MvpSitemapUrlProvider( + LinkGenerator linkGenerator, + IHttpContextAccessor httpContextAccessor, + ILogger logger, + IGraphQLClientFactory graphQLClientFactory, + IGraphQLRequestBuilder graphQLRequestBuilder, + IConfiguration configuration) + { + _linkGenerator = linkGenerator; + _httpContextAccessor = httpContextAccessor; + _logger = logger; + _graphQLClientFactory = graphQLClientFactory; + _graphQLRequestBuilder = graphQLRequestBuilder; + _configuration = configuration; + } + + private static DotnetSitemapGenerator.ChangeFrequency GetChangeFrequency(string changefreq) + { + if (string.IsNullOrWhiteSpace(changefreq)) { return DotnetSitemapGenerator.ChangeFrequency.Never; } + + switch (changefreq.ToLowerInvariant()) + { + case "always": + return DotnetSitemapGenerator.ChangeFrequency.Always; + case "daily": + return DotnetSitemapGenerator.ChangeFrequency.Daily; + case "weekly": + return DotnetSitemapGenerator.ChangeFrequency.Weekly; + case "yearly": + return DotnetSitemapGenerator.ChangeFrequency.Yearly; + case "hourly": + return DotnetSitemapGenerator.ChangeFrequency.Hourly; + case "never": + return DotnetSitemapGenerator.ChangeFrequency.Never; + } + + return DotnetSitemapGenerator.ChangeFrequency.Never; + } + + public Task> GetNodes() + { + var nodes = new List(); + var results = GetSiteMap(); + + foreach (var result in results) + { + var url = _httpContextAccessor.HttpContext.Request.Scheme + "://" + _httpContextAccessor.HttpContext.Request.Host.Value + result.Url.Path; + + _logger.LogInformation("Adding product: {URL}", url); + + SitemapNode node = new(url) + { + LastModificationDate = DateTime.ParseExact(result.UpdatedDatetime?.Value, + "yyyyMMdd'T'HHmmss'Z'", + CultureInfo.InvariantCulture), + Priority = Convert.ToDecimal(result.Priority?.TargetItem?.DisplayName), + ChangeFrequency = GetChangeFrequency(result.ChangeFrequency?.TargetItem?.DisplayName) + }; + nodes.Add(node); + } + + return Task.FromResult>(nodes); + } + + private List GetSiteMap() + { + CustomGraphQlLayoutServiceHandler customGraphQlLayoutServiceHandler = new(_configuration, _graphQLRequestBuilder, _graphQLClientFactory); + return customGraphQlLayoutServiceHandler.GetSitemap().Result; + } +} \ No newline at end of file diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs new file mode 100644 index 00000000..61bdda09 --- /dev/null +++ b/src/Project/MvpSite/rendering/Sitemap/SitemapBuilder.cs @@ -0,0 +1,33 @@ +using DotnetSitemapGenerator; +using DotnetSitemapGenerator.Serialization; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Mvp.Project.MvpSite.Rendering; + +public class SitemapBuilder +{ + private readonly IEnumerable _providers; + + public SitemapBuilder(IEnumerable providers) + { + _providers = providers; + } + + public async Task GenerateAsync() + { + var nodes = new List(); + foreach (var provider in _providers) + { + nodes.AddRange(await provider.GetNodes()); + } + + IXmlSerializer sitemapProvider = new XmlSerializer(); + var memory = new MemoryStream(); + sitemapProvider.SerializeToStream(new SitemapModel(nodes), memory); + // reset the stream to the start + memory.Position = 0; + return memory; + } +} \ No newline at end of file diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs new file mode 100644 index 00000000..5780e7bd --- /dev/null +++ b/src/Project/MvpSite/rendering/Sitemap/SitemapExtensions.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Mvp.Project.MvpSite.Rendering; + +public static class SitemapExtensions +{ + public static void AddSitemap(this IServiceCollection services) + { + // add sitemap services + services.AddScoped(); + services.AddScoped(); + } +} \ No newline at end of file diff --git a/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs b/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs new file mode 100644 index 00000000..898cb7d4 --- /dev/null +++ b/src/Project/MvpSite/rendering/Sitemap/SitemapResponse.cs @@ -0,0 +1,20 @@ +using System.Text.Json; + +namespace Mvp.Project.MvpSite.Sitemap +{ + public class SitemapQueryResponse + { + // + // Summary: + // Gets or sets Layout Service GraphQL Response. + public SitemapModel SiteMap { get; set; } + } + + public class SitemapModel + { + // + // Summary: + // Gets or sets Layout Service GraphQL Response. + public JsonElement? Sitemap { get; set; } + } +} diff --git a/src/Project/MvpSite/rendering/Startup.cs b/src/Project/MvpSite/rendering/Startup.cs index 13a0c61f..5bcda33a 100644 --- a/src/Project/MvpSite/rendering/Startup.cs +++ b/src/Project/MvpSite/rendering/Startup.cs @@ -58,6 +58,8 @@ public void ConfigureServices(IServiceCollection services) .AddGraphQlHandler("default", Configuration.DefaultSiteName!, Configuration.ExperienceEdgeToken!, Configuration.LayoutServiceUri!) .AsDefaultHandler(); + services.AddHttpContextAccessor(); + services.AddSitemap(); services.AddFeatureUser(DotNetConfiguration); // Register the Sitecore Rendering Engine services. @@ -141,8 +143,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Enable Authentication & Authorization app.UseAuthentication(); - app.UseAuthorization(); - + app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( @@ -155,6 +156,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) "healthz", "healthz", new { controller = "Default", action = "Healthz" } + ); + + endpoints.MapControllerRoute( + "Sitemap", + "sitemap.xml", + new { controller = "Default", action = "SiteMap" } ); endpoints.MapOktaSigninRoute(); diff --git a/src/Project/MvpSite/rendering/appsettings.Development.json b/src/Project/MvpSite/rendering/appsettings.Development.json index 3dae2617..a26661b8 100644 --- a/src/Project/MvpSite/rendering/appsettings.Development.json +++ b/src/Project/MvpSite/rendering/appsettings.Development.json @@ -3,7 +3,6 @@ "InstanceUri": "https://xmcloudcm.localhost/", "LayoutServicePath": "/sitecore/api/graph/edge", "DefaultSiteName": "mvp-site", - "NotFoundPage": "/404", "ExperienceEdgeToken": "{E2F3D43E-B1FD-495E-B4B1-84579892422A}", "MvpDirectoryGraphQLQueryPageSize": 1000, "MvpDirectoryGraphQLQueryCacheTimeout": 1 @@ -16,7 +15,7 @@ } }, "AllowedHosts": "*", - "Okta" : { + "Okta": { "OktaDomain": "<>", "ClientId": "<>", "ClientSecret": "<>", diff --git a/src/Project/MvpSite/rendering/appsettings.json b/src/Project/MvpSite/rendering/appsettings.json index 56ebfc56..d672c768 100644 --- a/src/Project/MvpSite/rendering/appsettings.json +++ b/src/Project/MvpSite/rendering/appsettings.json @@ -4,6 +4,8 @@ "LayoutServicePath": "/api/graphql/v1", "DefaultSiteName": "mvp-site", "NotFoundPage": "/404", + "RootItemId": "A43C669260F44743A1BE6424DE611DFA", + "DefaultLanguage": "en", "ExperienceEdgeToken": "<>", "MvpDirectoryGraphQLQueryPageSize": 1000, "MvpDirectoryGraphQLQueryCacheTimeout": 60,