Skip to content

Commit

Permalink
feat: add IContentComponent to C&S contents
Browse files Browse the repository at this point in the history
tests: add FooterLinkTagHelper changes unit tests

chore: Linted code for plan-technology-for-your-school.sln solution

chore: sonarcloud fix

chore: add .sonarqube to gitignore

fix: handle prefixed "/"

chore formatting

fix: expected url

fix: expected url

fix: test

fix: Look in all assemblies for IContentComponent types

wip

chore: add text

fix: unit tests, tweak validation
  • Loading branch information
jimwashbrook committed Nov 21, 2024
1 parent 32adb19 commit cf8ba9f
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 59 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -500,4 +500,6 @@ build/
.vscode/

contentful/migration-scripts/config.json
contentful/migration-scripts/contentful-export-*.json
contentful/migration-scripts/contentful-export-*.json

.sonarqube/
2 changes: 1 addition & 1 deletion src/Dfe.PlanTech.Domain/Content/Interfaces/IHasSlug.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ namespace Dfe.PlanTech.Domain.Content.Interfaces;

public interface IHasSlug
{
public string Slug { get; set; }
public string Slug { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface INavigationLink
/// <summary>
/// Does this link contain all necessary information (Href + DisplayText)?
/// </summary>
public bool IsValid => !string.IsNullOrEmpty(DisplayText) && !string.IsNullOrEmpty(Href);
public bool IsValid => !string.IsNullOrEmpty(DisplayText) && !(string.IsNullOrEmpty(Href) && ContentToLinkTo == null);

/// <summary>
/// The content to link to.
Expand Down
4 changes: 1 addition & 3 deletions src/Dfe.PlanTech.Domain/Content/Interfaces/IPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -15,8 +16,7 @@ public class EntityResolver(ILogger<EntityResolver> logger) : IContentTypeResolv

private readonly ILogger<EntityResolver> _logger = logger;

private readonly Dictionary<string, Type> _types = typeof(IContentComponent).Assembly.GetTypes()
.Where(type => type.IsAssignableTo(typeof(IContentComponent)))
private readonly Dictionary<string, Type> _types = ReflectionHelpers.GetTypesInheritingFrom<IContentComponent>()
.ToDictionary(type => type.Name.ToLower());

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion src/Dfe.PlanTech.Web/Models/Content/ContentBase.cs
Original file line number Diff line number Diff line change
@@ -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<ContentBase>
public class ContentBase : Contentful.Core.Models.Entry<ContentBase>, 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!;
}
3 changes: 1 addition & 2 deletions src/Dfe.PlanTech.Web/Models/Content/ContentSupportPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Dfe.PlanTech.Web.Models.Content;

[ExcludeFromCodeCoverage]
public class ContentSupportPage : ContentBase
public class ContentSupportPage : ContentBase, IContentSupportPage<Entry>
{
public Heading Heading { get; init; } = null!;
public List<Entry> Content { get; init; } = [];
Expand All @@ -13,5 +13,4 @@ public class ContentSupportPage : ContentBase
public bool HasFeedbackBanner { get; init; }
public bool HasPrint { get; init; }
public bool ShowVerticalNavigation { get; init; }

}
20 changes: 20 additions & 0 deletions src/Dfe.PlanTech.Web/Models/Content/IContentSupportPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Dfe.PlanTech.Domain.Content.Interfaces;

namespace Dfe.PlanTech.Web.Models.Content;

public interface IContentSupportPage<TContent> : IContentSupportPage
where TContent : class
{
List<TContent> 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; }
}
4 changes: 3 additions & 1 deletion src/Dfe.PlanTech.Web/Models/Content/Mapped/CsPage.cs
Original file line number Diff line number Diff line change
@@ -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<CsContentItem>
{
public SystemDetails Sys { get; set; } = null!;
public Heading Heading { get; set; } = null!;
public string Slug { get; set; } = null!;
public bool IsSitemap { get; set; }
Expand Down
66 changes: 35 additions & 31 deletions src/Dfe.PlanTech.Web/TagHelpers/FooterLinkTagHelper.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,46 +15,41 @@ public class FooterLinkTagHelper(ILogger<FooterLinkTagHelper> 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()
/// <summary>
/// Adds attributes to element
/// </summary>
/// <param name="output"></param>
/// <returns>True; valid element. False; invalid</returns>
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("</a>");
}
if (string.IsNullOrEmpty(href))
{
return false;
}

private void AppendOpenTag(StringBuilder stringBuilder)
{
stringBuilder.Append("""<a class="govuk-footer__link" """).Append(" href=\"");
stringBuilder.Append(GetHref());
stringBuilder.Append('"');
output.Attributes.Add("href", href);
output.Attributes.Add("class", "govuk-footer__link");

if (Link!.OpenInNewTab)
{
stringBuilder.Append(" target=\"_blank\"");
output.Attributes.Add("target", "_blank");
}

stringBuilder.Append('>');
return true;
}

private string GetHref()
Expand All @@ -77,18 +70,29 @@ private string GetHref()
return null;
}

if (Link.ContentToLinkTo is not IHasSlug hasSlug)
{
logger.LogError("Invalid content type received for Link. Expected {Interface} but type is {Concrete}", typeof(IHasSlug), Link.ContentToLinkTo.GetType());
return null;
}

var firstCharacterIsSlash = hasSlug.Slug[0] == '/';

var slug = firstCharacterIsSlash ? hasSlug.Slug.AsSpan(1) : hasSlug.Slug.AsSpan();

return Link.ContentToLinkTo switch
{
IPage page => $"/{page.Slug}",
CsPage csPage => $"/content/{csPage.Slug}",
ContentSupportPage contentSupportPage => $"/content/{contentSupportPage.Slug}",
IPage => $"/{slug}",
IContentSupportPage => $"/content/{slug}",
_ => LogInvalidContentTypeAndReturnNull(Link.ContentToLinkTo)
};
}



private string? LogInvalidContentTypeAndReturnNull(object content)
{
logger.LogError("Unsupported content type {ContentType} in {TagHelper}",
logger.LogError("Unsupported content type {ContentType} in {TagHelper}",
content.GetType().Name,
nameof(FooterLinkTagHelper));
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

<ul class="govuk-footer__inline-list">
@{
foreach (var link in Model)
foreach (var link in Model.Where(link => link.IsValid))
{
<li class="govuk-footer__inline-list-item">
<footer-link link=@link />
<footer-link link=@link>@link.DisplayText</footer-link>
</li>
}
}
Expand Down
Loading

0 comments on commit cf8ba9f

Please sign in to comment.