using System.Text; using System.Xml; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PlotLine.Models; using PlotLine.Services; namespace PlotLine.Controllers; [AllowAnonymous] public sealed class SitemapController(IHelpService help, IConfiguration configuration) : Controller { [HttpGet("/sitemap.xml")] public IActionResult Index() { var urls = new List { new("/", "weekly", "1.0"), new("/features", "weekly", "0.9"), new("/pricing", "weekly", "0.8"), new("/help", "weekly", "0.7"), new("/about", "monthly", "0.6"), new("/contact", "monthly", "0.5"), new("/privacy", "yearly", "0.3"), new("/terms", "yearly", "0.3") }; var articles = help.GetAllArticles(); urls.AddRange(articles .Where(article => !string.IsNullOrWhiteSpace(article.CategorySlug)) .GroupBy(article => article.CategorySlug, StringComparer.OrdinalIgnoreCase) .OrderBy(group => group.Key, StringComparer.OrdinalIgnoreCase) .Select(group => new SitemapUrl( $"/help/{group.Key}", "monthly", "0.6", group.Max(article => article.LastModifiedUtc)))); urls.AddRange(articles .Where(article => !string.IsNullOrWhiteSpace(article.CategorySlug) && !string.IsNullOrWhiteSpace(article.Slug)) .OrderBy(article => article.CategorySlug, StringComparer.OrdinalIgnoreCase) .ThenBy(article => article.Slug, StringComparer.OrdinalIgnoreCase) .Select(article => new SitemapUrl( article.Url, "monthly", "0.5", article.LastModifiedUtc))); return Content(BuildXml(urls), "application/xml", Encoding.UTF8); } private string BuildXml(IEnumerable urls) { var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false), Indent = true, OmitXmlDeclaration = false }; using var writer = new Utf8StringWriter(); using var xml = XmlWriter.Create(writer, settings); xml.WriteStartDocument(); xml.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); foreach (var url in urls) { xml.WriteStartElement("url"); xml.WriteElementString("loc", PublicSeo.AbsoluteUrl(configuration, url.Path)); if (url.LastModifiedUtc is DateTime lastModifiedUtc && lastModifiedUtc != default) { xml.WriteElementString("lastmod", lastModifiedUtc.ToString("yyyy-MM-dd")); } xml.WriteElementString("changefreq", url.ChangeFrequency); xml.WriteElementString("priority", url.Priority); xml.WriteEndElement(); } xml.WriteEndElement(); xml.WriteEndDocument(); xml.Flush(); return writer.ToString(); } private sealed record SitemapUrl(string Path, string ChangeFrequency, string Priority, DateTime? LastModifiedUtc = null); private sealed class Utf8StringWriter : StringWriter { public override Encoding Encoding => Encoding.UTF8; } }