diff --git a/.gitignore b/.gitignore
index 0a930af7e..ac3ff56de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -500,4 +500,6 @@ build/
.vscode/
contentful/migration-scripts/config.json
-contentful/migration-scripts/contentful-export-*.json
\ No newline at end of file
+contentful/migration-scripts/contentful-export-*.json
+
+.sonarqube/
\ No newline at end of file
diff --git a/src/Dfe.PlanTech.Domain/Content/Interfaces/IHasSlug.cs b/src/Dfe.PlanTech.Domain/Content/Interfaces/IHasSlug.cs
index e1ba8a213..44c67d32d 100644
--- a/src/Dfe.PlanTech.Domain/Content/Interfaces/IHasSlug.cs
+++ b/src/Dfe.PlanTech.Domain/Content/Interfaces/IHasSlug.cs
@@ -2,5 +2,5 @@ namespace Dfe.PlanTech.Domain.Content.Interfaces;
public interface IHasSlug
{
- public string Slug { get; set; }
+ public string Slug { get; }
}
diff --git a/src/Dfe.PlanTech.Domain/Content/Interfaces/INavigationLink.cs b/src/Dfe.PlanTech.Domain/Content/Interfaces/INavigationLink.cs
index 57724d526..076470dc3 100644
--- a/src/Dfe.PlanTech.Domain/Content/Interfaces/INavigationLink.cs
+++ b/src/Dfe.PlanTech.Domain/Content/Interfaces/INavigationLink.cs
@@ -26,7 +26,7 @@ public interface INavigationLink
///
/// Does this link contain all necessary information (Href + DisplayText)?
///
- public bool IsValid => !string.IsNullOrEmpty(DisplayText) && !string.IsNullOrEmpty(Href);
+ public bool IsValid => !string.IsNullOrEmpty(DisplayText) && !(string.IsNullOrEmpty(Href) && ContentToLinkTo == null);
///
/// The content to link to.
diff --git a/src/Dfe.PlanTech.Domain/Content/Interfaces/IPage.cs b/src/Dfe.PlanTech.Domain/Content/Interfaces/IPage.cs
index 41e0274fe..0e4d22006 100644
--- a/src/Dfe.PlanTech.Domain/Content/Interfaces/IPage.cs
+++ b/src/Dfe.PlanTech.Domain/Content/Interfaces/IPage.cs
@@ -2,12 +2,10 @@
namespace Dfe.PlanTech.Domain.Content.Interfaces;
-public interface IPage
+public interface IPage : IHasSlug
{
public string InternalName { get; }
- public string Slug { get; }
-
public bool DisplayBackButton { get; }
public bool DisplayHomeButton { get; }
diff --git a/src/Dfe.PlanTech.Infrastructure.Contentful/Persistence/EntityResolver.cs b/src/Dfe.PlanTech.Infrastructure.Contentful/Persistence/EntityResolver.cs
index 0bfebc937..00f6c51a4 100644
--- a/src/Dfe.PlanTech.Infrastructure.Contentful/Persistence/EntityResolver.cs
+++ b/src/Dfe.PlanTech.Infrastructure.Contentful/Persistence/EntityResolver.cs
@@ -1,6 +1,7 @@
using Contentful.Core.Configuration;
using Dfe.PlanTech.Domain.Content.Interfaces;
using Dfe.PlanTech.Domain.Content.Models;
+using Dfe.PlanTech.Domain.Helpers;
using Microsoft.Extensions.Logging;
namespace Dfe.PlanTech.Infrastructure.Contentful;
@@ -15,8 +16,7 @@ public class EntityResolver(ILogger logger) : IContentTypeResolv
private readonly ILogger _logger = logger;
- private readonly Dictionary _types = typeof(IContentComponent).Assembly.GetTypes()
- .Where(type => type.IsAssignableTo(typeof(IContentComponent)))
+ private readonly Dictionary _types = ReflectionHelpers.GetTypesInheritingFrom()
.ToDictionary(type => type.Name.ToLower());
///
diff --git a/src/Dfe.PlanTech.Web/Models/Content/ContentBase.cs b/src/Dfe.PlanTech.Web/Models/Content/ContentBase.cs
index 2e5495a15..0633aaa75 100644
--- a/src/Dfe.PlanTech.Web/Models/Content/ContentBase.cs
+++ b/src/Dfe.PlanTech.Web/Models/Content/ContentBase.cs
@@ -1,12 +1,15 @@
using System.Diagnostics.CodeAnalysis;
+using Dfe.PlanTech.Domain.Content.Interfaces;
+using Dfe.PlanTech.Domain.Content.Models;
namespace Dfe.PlanTech.Web.Models.Content;
[ExcludeFromCodeCoverage]
-public class ContentBase : Contentful.Core.Models.Entry
+public class ContentBase : Contentful.Core.Models.Entry, IContentComponent, IHasSlug
{
public string InternalName { get; set; } = null!;
public string Slug { get; set; } = null!;
public string? Title { get; set; }
public string? Subtitle { get; set; }
+ public SystemDetails Sys { get; set; } = null!;
}
diff --git a/src/Dfe.PlanTech.Web/Models/Content/ContentSupportPage.cs b/src/Dfe.PlanTech.Web/Models/Content/ContentSupportPage.cs
index 1f65da2d3..1c4414273 100644
--- a/src/Dfe.PlanTech.Web/Models/Content/ContentSupportPage.cs
+++ b/src/Dfe.PlanTech.Web/Models/Content/ContentSupportPage.cs
@@ -3,7 +3,7 @@
namespace Dfe.PlanTech.Web.Models.Content;
[ExcludeFromCodeCoverage]
-public class ContentSupportPage : ContentBase
+public class ContentSupportPage : ContentBase, IContentSupportPage
{
public Heading Heading { get; init; } = null!;
public List Content { get; init; } = [];
@@ -13,5 +13,4 @@ public class ContentSupportPage : ContentBase
public bool HasFeedbackBanner { get; init; }
public bool HasPrint { get; init; }
public bool ShowVerticalNavigation { get; init; }
-
}
diff --git a/src/Dfe.PlanTech.Web/Models/Content/IContentSupportPage.cs b/src/Dfe.PlanTech.Web/Models/Content/IContentSupportPage.cs
new file mode 100644
index 000000000..5082b41a6
--- /dev/null
+++ b/src/Dfe.PlanTech.Web/Models/Content/IContentSupportPage.cs
@@ -0,0 +1,20 @@
+using Dfe.PlanTech.Domain.Content.Interfaces;
+
+namespace Dfe.PlanTech.Web.Models.Content;
+
+public interface IContentSupportPage : IContentSupportPage
+where TContent : class
+{
+ List Content { get; }
+}
+
+public interface IContentSupportPage : IContentComponent, IHasSlug
+{
+ Heading Heading { get; }
+ bool IsSitemap { get; }
+ bool HasCitation { get; }
+ bool HasBackToTop { get; }
+ bool HasFeedbackBanner { get; }
+ bool HasPrint { get; }
+ bool ShowVerticalNavigation { get; }
+}
diff --git a/src/Dfe.PlanTech.Web/Models/Content/Mapped/CsPage.cs b/src/Dfe.PlanTech.Web/Models/Content/Mapped/CsPage.cs
index 80b547cda..4dc84f9c2 100644
--- a/src/Dfe.PlanTech.Web/Models/Content/Mapped/CsPage.cs
+++ b/src/Dfe.PlanTech.Web/Models/Content/Mapped/CsPage.cs
@@ -1,10 +1,12 @@
using System.Diagnostics.CodeAnalysis;
+using Dfe.PlanTech.Domain.Content.Models;
namespace Dfe.PlanTech.Web.Models.Content.Mapped;
[ExcludeFromCodeCoverage]
-public class CsPage
+public class CsPage : IContentSupportPage
{
+ public SystemDetails Sys { get; set; } = null!;
public Heading Heading { get; set; } = null!;
public string Slug { get; set; } = null!;
public bool IsSitemap { get; set; }
diff --git a/src/Dfe.PlanTech.Web/TagHelpers/FooterLinkTagHelper.cs b/src/Dfe.PlanTech.Web/TagHelpers/FooterLinkTagHelper.cs
index 46e6e44e6..de296991a 100644
--- a/src/Dfe.PlanTech.Web/TagHelpers/FooterLinkTagHelper.cs
+++ b/src/Dfe.PlanTech.Web/TagHelpers/FooterLinkTagHelper.cs
@@ -1,8 +1,6 @@
-using System.Text;
using Dfe.PlanTech.Domain.Content.Interfaces;
using Dfe.PlanTech.Domain.Content.Models;
using Dfe.PlanTech.Web.Models.Content;
-using Dfe.PlanTech.Web.Models.Content.Mapped;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Dfe.PlanTech.Web.TagHelpers;
@@ -17,46 +15,41 @@ public class FooterLinkTagHelper(ILogger logger) : TagHelpe
public override void Process(TagHelperContext context, TagHelperOutput output)
{
- if (Link == null || !Link.IsValid)
+ if (Link == null || !Link.IsValid || !TryBuildElement(output))
{
- logger.LogWarning("Missing {link}", nameof(Link));
+ output.TagName = null;
+ output.Content.SetHtmlContent("");
+ logger.LogWarning("Missing or invalid {Name} {Link}", nameof(NavigationLink), Link);
return;
}
- var html = GetHtml();
-
- output.TagName = null;
+ output.TagName = "a";
output.TagMode = TagMode.StartTagAndEndTag;
- output.Content.SetHtmlContent(html);
}
- public string GetHtml()
+ ///
+ /// Adds attributes to element
+ ///
+ ///
+ /// True; valid element. False; invalid
+ public bool TryBuildElement(TagHelperOutput output)
{
- var stringBuilder = new StringBuilder();
- AppendOpenTag(stringBuilder);
- stringBuilder.Append(Link!.DisplayText);
- AppendCloseTag(stringBuilder);
-
- return stringBuilder.ToString();
- }
+ var href = GetHref();
- private static void AppendCloseTag(StringBuilder stringBuilder)
- {
- stringBuilder.Append("");
- }
+ if (string.IsNullOrEmpty(href))
+ {
+ return false;
+ }
- private void AppendOpenTag(StringBuilder stringBuilder)
- {
- stringBuilder.Append("""