From 7603c3eb6d4f0f922446a4488e483e1630e38f04 Mon Sep 17 00:00:00 2001 From: cairnsj <51908793+cairnsj@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:25:34 +0100 Subject: [PATCH 1/8] Create attribute for requiring configuration value in an environment. --- .../ConfigurationInformationTests.cs | 72 +++++++++ .../RequiredForEnvironmentTests.cs | 133 +++++++++++++++++ .../Configuration/TestConfigurationMock.cs | 60 ++++++++ .../Controllers/AppInfoControllerTests.cs | 78 ---------- .../Controllers/ApplicationControllerTests.cs | 140 ++++++++++++++++++ Childrens-Social-Care-CPD/AppEnvironment.cs | 9 -- .../Configuration/ApplicationEnvironment.cs | 12 ++ .../Configuration/ConfigurationInformation.cs | 57 +++++++ .../IApplicationConfiguration.cs | 33 ++++- .../RequiredForEnvironmentAttribute.cs | 56 +++++++ ...Controller.cs => ApplicationController.cs} | 20 ++- .../Models/ApplicationInfo.cs | 4 +- Childrens-Social-Care-CPD/SiteConstants.cs | 14 -- .../Views/Application/Configuration.cshtml | 62 ++++++++ .../Shared/_GoogleAnalyticsPartial.cshtml | 4 +- 15 files changed, 647 insertions(+), 107 deletions(-) create mode 100644 Childrens-Social-Care-CPD-Tests/Configuration/ConfigurationInformationTests.cs create mode 100644 Childrens-Social-Care-CPD-Tests/Configuration/RequiredForEnvironmentTests.cs create mode 100644 Childrens-Social-Care-CPD-Tests/Configuration/TestConfigurationMock.cs delete mode 100644 Childrens-Social-Care-CPD-Tests/Controllers/AppInfoControllerTests.cs create mode 100644 Childrens-Social-Care-CPD-Tests/Controllers/ApplicationControllerTests.cs delete mode 100644 Childrens-Social-Care-CPD/AppEnvironment.cs create mode 100644 Childrens-Social-Care-CPD/Configuration/ApplicationEnvironment.cs create mode 100644 Childrens-Social-Care-CPD/Configuration/ConfigurationInformation.cs create mode 100644 Childrens-Social-Care-CPD/Configuration/RequiredForEnvironmentAttribute.cs rename Childrens-Social-Care-CPD/Controllers/{AppInfoController.cs => ApplicationController.cs} (52%) delete mode 100644 Childrens-Social-Care-CPD/SiteConstants.cs create mode 100644 Childrens-Social-Care-CPD/Views/Application/Configuration.cshtml diff --git a/Childrens-Social-Care-CPD-Tests/Configuration/ConfigurationInformationTests.cs b/Childrens-Social-Care-CPD-Tests/Configuration/ConfigurationInformationTests.cs new file mode 100644 index 00000000..b2ba9586 --- /dev/null +++ b/Childrens-Social-Care-CPD-Tests/Configuration/ConfigurationInformationTests.cs @@ -0,0 +1,72 @@ +using NUnit.Framework; +using Childrens_Social_Care_CPD.Configuration; +using FluentAssertions; +using System.Linq; + +namespace Childrens_Social_Care_CPD_Tests.Configuration; + +public partial class ConfigurationInformationTests +{ + [Test] + public void Required_Values_Are_Detected() + { + // arrange + var config = new TestConfigurationMock(); + config._appVersion = "foo"; + + // act + var sut = new ConfigurationInformation(config); + var actual = sut.ConfigurationInfo.Single(x => x.Name == "AppVersion"); + + // assert + actual.Required.Should().BeTrue(); + actual.HasValue.Should().BeTrue(); + } + + [TestCase("")] + [TestCase(null)] + public void Missing_Values_Are_Detected(string value) + { + // arrange + var config = new TestConfigurationMock(); + config._azureEnvironment = value; + + // act + var sut = new ConfigurationInformation(config); + var actual = sut.ConfigurationInfo.Single(x => x.Name == "AzureEnvironment"); + + // assert + actual.Required.Should().BeTrue(); + actual.HasValue.Should().BeFalse(); + } + + [Test] + public void Extraneous_Values_Are_Detected() + { + // arrange + var config = new TestConfigurationMock(); + config._clarityProjectId = "foo"; + + // act + var sut = new ConfigurationInformation(config); + var actual = sut.ConfigurationInfo.Single(x => x.Name == "ClarityProjectId"); + + // assert + actual.Required.Should().BeFalse(); + actual.Extraneous.Should().BeTrue(); + } + + [Test] + public void Ignored_Values_Are_Detected() + { + // arrange + var config = new TestConfigurationMock(); + + // act + var sut = new ConfigurationInformation(config); + var actual = sut.ConfigurationInfo.SingleOrDefault(x => x.Name == "ContentfulDeliveryApiKey"); + + // assert + actual.Should().BeNull(); + } +} diff --git a/Childrens-Social-Care-CPD-Tests/Configuration/RequiredForEnvironmentTests.cs b/Childrens-Social-Care-CPD-Tests/Configuration/RequiredForEnvironmentTests.cs new file mode 100644 index 00000000..7539ec60 --- /dev/null +++ b/Childrens-Social-Care-CPD-Tests/Configuration/RequiredForEnvironmentTests.cs @@ -0,0 +1,133 @@ +using NUnit.Framework; +using Childrens_Social_Care_CPD.Configuration; +using FluentAssertions; +using System.Linq; + +namespace Childrens_Social_Care_CPD_Tests.Configuration; + +public class RequiredForEnvironmentTests +{ + private class TestConfiguration + { + public string PropertyHasNoRules { get; set; } + + [RequiredForEnvironment("dev")] + public string PropertyHasSingleEnv { get; set; } + + [RequiredForEnvironment("*")] + public string PropertyHasAllEnv { get; set; } + + [RequiredForEnvironment("dev")] + [RequiredForEnvironment("test")] + [RequiredForEnvironment("prod")] + public string PropertyHasMultipleEnv { get; set; } + + [RequiredForEnvironment("dev", Hidden = false)] + [RequiredForEnvironment("*")] + public string PropertyHasEnvironmentOverrideValue { get; set; } + } + + [Test] + public void No_Rule_Property_Is_Ignored() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment("dev"); + var actual = sut.Where(x => x.Key.Name == "PropertyHasNoRules"); + + // assert + actual.Should().HaveCount(0); + } + + [Test] + public void Single_Environment_Property_Returns_Rule_For_Correct_Environment() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment("dev"); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasSingleEnv"); + + // assert + actual.Value.Should().NotBeNull(); + } + + [Test] + public void Single_Environment_Property_Returns_No_Rule_For_Wrong_Environment() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment(" "); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasSingleEnv"); + + // assert + actual.Value.Should().BeNull(); + } + + [Test] + public void Asterisk_Matches_Any_Environment() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment("test"); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasAllEnv"); + + // assert + actual.Value.Should().NotBeNull(); + } + + [TestCase("dev")] + [TestCase("test")] + [TestCase("prod")] + public void Multiple_Rules_For_Different_Environments_For_Same_Property_Return_Single_Rule(string env) + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment(env); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasMultipleEnv"); + + // assert + actual.Value.Should().NotBeNull(); + } + + [Test] + public void All_Environment_Matcher_Can_Be_Overidden() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment("dev"); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasEnvironmentOverrideValue"); + + // assert + actual.Value.Should().NotBeNull(); + actual.Value.Environment.Should().Be("dev"); + actual.Value.Hidden.Should().Be(false); + } + + [Test] + public void Override_For_Non_Matching_Environment_Does_Not_Override_Catchall_Rule() + { + // arrange + var config = new TestConfiguration(); + + // act + var sut = config.RulesForEnvironment("text"); + var actual = sut.SingleOrDefault(x => x.Key.Name == "PropertyHasEnvironmentOverrideValue"); + + // assert + actual.Value.Should().NotBeNull(); + actual.Value.Environment.Should().Be("*"); + actual.Value.Hidden.Should().Be(true); + } +} diff --git a/Childrens-Social-Care-CPD-Tests/Configuration/TestConfigurationMock.cs b/Childrens-Social-Care-CPD-Tests/Configuration/TestConfigurationMock.cs new file mode 100644 index 00000000..810820b6 --- /dev/null +++ b/Childrens-Social-Care-CPD-Tests/Configuration/TestConfigurationMock.cs @@ -0,0 +1,60 @@ +using Childrens_Social_Care_CPD.Configuration; + +namespace Childrens_Social_Care_CPD_Tests.Configuration; + +/* + * Create a mock and re-apply the attributes we want for testing as custom attributes cannot be accessed on the + * object outside of the assembly the class was declared in. + * See https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/accessing-custom-attributes for more info. + */ +public class TestConfigurationMock : IApplicationConfiguration +{ + public string _appInsightsConnectionString; + public string _appVersion; + public string _azureEnvironment; + public string _clarityProjectId; + public string _contentfulDeliveryApiKey; + public string _contentfulEnvironment; + public string _contentfulPreviewHost; + public string _contentfulPreviewId; + public string _contentfulSpaceId; + public bool _disableSecureCookies; + public int _featurePollingInterval; + public string _gitHash; + public string _googleTagManagerKey; + + public string AppInsightsConnectionString => _appInsightsConnectionString; + [RequiredForEnvironment("*", Hidden = false, Obfuscate = false)] + public string AppVersion => _appVersion; + [RequiredForEnvironment("*", Hidden = false, Obfuscate = false)] + public string AzureEnvironment => _azureEnvironment; + [RequiredForEnvironment("prod", Hidden = false, Obfuscate = true)] + public string ClarityProjectId => _clarityProjectId; + [RequiredForEnvironment("prod", Hidden = false, Obfuscate = true)] + public string ContentfulDeliveryApiKey => _contentfulDeliveryApiKey; + public string ContentfulEnvironment => _contentfulEnvironment; + public string ContentfulPreviewHost => _contentfulPreviewHost; + public string ContentfulPreviewId => _contentfulPreviewId; + public string ContentfulSpaceId => _contentfulSpaceId; + public bool DisableSecureCookies => _disableSecureCookies; + public int FeaturePollingInterval => _featurePollingInterval; + public string GitHash => _gitHash; + public string GoogleTagManagerKey => _googleTagManagerKey; + + public TestConfigurationMock() + { + _appInsightsConnectionString = ""; + _appVersion = ""; + _azureEnvironment = ""; + _clarityProjectId = ""; + _contentfulDeliveryApiKey = ""; + _contentfulEnvironment = ""; + _contentfulPreviewHost = ""; + _contentfulPreviewId = ""; + _contentfulSpaceId = ""; + _disableSecureCookies = false; + _featurePollingInterval = 0; + _gitHash = ""; + _googleTagManagerKey = ""; + } +} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD-Tests/Controllers/AppInfoControllerTests.cs b/Childrens-Social-Care-CPD-Tests/Controllers/AppInfoControllerTests.cs deleted file mode 100644 index 3e37e54a..00000000 --- a/Childrens-Social-Care-CPD-Tests/Controllers/AppInfoControllerTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Childrens_Social_Care_CPD.Configuration; -using Childrens_Social_Care_CPD.Controllers; -using Childrens_Social_Care_CPD.Models; -using FluentAssertions; -using Microsoft.AspNetCore.Mvc; -using NSubstitute; -using NUnit.Framework; - -namespace Childrens_Social_Care_CPD_Tests.Controllers; - -public class AppInfoControllerTests -{ - private AppInfoController _controller; - private IApplicationConfiguration _applicationConfiguration; - - [SetUp] - public void Setup() - { - _applicationConfiguration = Substitute.For(); - _controller = new AppInfoController(_applicationConfiguration); - } - - [Test] - public void AppInfo_Includes_Contentful_Environment() - { - // arrange - var value = "foo"; - _applicationConfiguration.ContentfulEnvironment.Returns(value); - - // act - var actual = _controller.AppInfo().Value as ApplicationInfo; - - // assert - actual.ContentfulEnvironment.Should().Be(value); - } - - [Test] - public void AppInfo_Includes_Azure_Environment() - { - // arrange - var value = "foo"; - _applicationConfiguration.AzureEnvironment.Returns(value); - - // act - var actual = _controller.AppInfo().Value as ApplicationInfo; - - // assert - actual.Environment.Should().Be(value); - } - - [Test] - public void AppInfo_Includes_Git_Hash() - { - // arrange - var value = "foo"; - _applicationConfiguration.GitHash.Returns(value); - - // act - var actual = _controller.AppInfo().Value as ApplicationInfo; - - // assert - actual.GitShortHash.Should().Be(value); - } - - [Test] - public void AppInfo_Includes_App_Version() - { - // arrange - var value = "foo"; - _applicationConfiguration.AppVersion.Returns(value); - - // act - var actual = _controller.AppInfo().Value as ApplicationInfo; - - // assert - actual.Version.Should().Be(value); - } -} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD-Tests/Controllers/ApplicationControllerTests.cs b/Childrens-Social-Care-CPD-Tests/Controllers/ApplicationControllerTests.cs new file mode 100644 index 00000000..3598c53d --- /dev/null +++ b/Childrens-Social-Care-CPD-Tests/Controllers/ApplicationControllerTests.cs @@ -0,0 +1,140 @@ +using Childrens_Social_Care_CPD.Configuration; +using Childrens_Social_Care_CPD.Controllers; +using Childrens_Social_Care_CPD.Models; +using FluentAssertions; +using NSubstitute; +using NUnit.Framework; +using Childrens_Social_Care_CPD_Tests.Configuration; +using Microsoft.AspNetCore.Mvc; +using Childrens_Social_Care_CPD.Contentful; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using System.Net; +using System.Net.Mime; +using Microsoft.Extensions.Primitives; + +namespace Childrens_Social_Care_CPD_Tests.Controllers; + +public class ApplicationControllerTests +{ + private ApplicationController _controller; + private IApplicationConfiguration _applicationConfiguration; + + [SetUp] + public void Setup() + { + _applicationConfiguration = Substitute.For(); + _controller = new ApplicationController(_applicationConfiguration); + } + + [Test] + public void ApplicationController_Includes_Contentful_Environment() + { + // arrange + var value = "foo"; + _applicationConfiguration.ContentfulEnvironment.Returns(value); + + // act + var actual = _controller.AppInfo().Value as ApplicationInfo; + + // assert + actual.ContentfulEnvironment.Should().Be(value); + } + + [Test] + public void ApplicationController_Includes_Azure_Environment() + { + // arrange + var value = "foo"; + _applicationConfiguration.AzureEnvironment.Returns(value); + + // act + var actual = _controller.AppInfo().Value as ApplicationInfo; + + // assert + actual.Environment.Should().Be(value); + } + + [Test] + public void ApplicationController_Includes_Git_Hash() + { + // arrange + var value = "foo"; + _applicationConfiguration.GitHash.Returns(value); + + // act + var actual = _controller.AppInfo().Value as ApplicationInfo; + + // assert + actual.GitShortHash.Should().Be(value); + } + + [Test] + public void ApplicationController_Includes_App_Version() + { + // arrange + var value = "foo"; + _applicationConfiguration.AppVersion.Returns(value); + + // act + var actual = _controller.AppInfo().Value as ApplicationInfo; + + // assert + actual.Version.Should().Be(value); + } + + + [Test] + public void ApplicationController_Configuration_Returns_Json() + { + // arrange + var httpRequest = Substitute.For(); + httpRequest.Headers.Accept.Returns(new StringValues(MediaTypeNames.Application.Json)); + + var httpContext = Substitute.For(); + httpContext.Request.Returns(httpRequest); + + var controllerContext = Substitute.For(); + controllerContext.HttpContext = httpContext; + + var mockConfig = new TestConfigurationMock(); + var controller = new ApplicationController(mockConfig) + { + ControllerContext = controllerContext, + TempData = Substitute.For() + }; + + // act + var actual = controller.Configuration() as JsonResult; + + // assert + actual.Should().NotBeNull(); + } + + [Test] + public void ApplicationController_Configuration_Returns_Html() + { + // arrange + var httpRequest = Substitute.For(); + httpRequest.Headers.Accept.Returns(new StringValues(MediaTypeNames.Text.Html)); + + var httpContext = Substitute.For(); + httpContext.Request.Returns(httpRequest); + + var controllerContext = Substitute.For(); + controllerContext.HttpContext = httpContext; + + var mockConfig = new TestConfigurationMock(); + var controller = new ApplicationController(mockConfig) + { + ControllerContext = controllerContext, + TempData = Substitute.For() + }; + + // act + var actual = controller.Configuration() as ViewResult; + + // assert + actual.Should().NotBeNull(); + } +} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/AppEnvironment.cs b/Childrens-Social-Care-CPD/AppEnvironment.cs deleted file mode 100644 index 083b412b..00000000 --- a/Childrens-Social-Care-CPD/AppEnvironment.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Childrens_Social_Care_CPD; - -public enum AppEnvironment -{ - dev, - test, - preprod, - prod -} diff --git a/Childrens-Social-Care-CPD/Configuration/ApplicationEnvironment.cs b/Childrens-Social-Care-CPD/Configuration/ApplicationEnvironment.cs new file mode 100644 index 00000000..e6fb8553 --- /dev/null +++ b/Childrens-Social-Care-CPD/Configuration/ApplicationEnvironment.cs @@ -0,0 +1,12 @@ +namespace Childrens_Social_Care_CPD.Configuration; + +public static class ApplicationEnvironment +{ + public const string Development = "dev"; + public const string Integration = "dev-integration"; + public const string LoadTest = "load-test"; + public const string Test = "test"; + public const string PreProduction = "pre-prod"; + public const string Production = "prod"; + public const string All = "*"; +} diff --git a/Childrens-Social-Care-CPD/Configuration/ConfigurationInformation.cs b/Childrens-Social-Care-CPD/Configuration/ConfigurationInformation.cs new file mode 100644 index 00000000..b7bf0e9a --- /dev/null +++ b/Childrens-Social-Care-CPD/Configuration/ConfigurationInformation.cs @@ -0,0 +1,57 @@ +using System.Collections.ObjectModel; +using System.Reflection; + +namespace Childrens_Social_Care_CPD.Configuration; + +public record ConfigurationItemInfo(string Name, bool Required, bool Obfuscated, bool Hidden, bool HasValue, string Value, bool Extraneous); + +public class ConfigurationInformation +{ + public string Environment { get; set; } + public ReadOnlyCollection ConfigurationInfo { get; set; } + + public ConfigurationInformation(IApplicationConfiguration applicationConfiguration) + { + Environment = applicationConfiguration.AzureEnvironment; + ExtractInfo(applicationConfiguration); + } + + private void ExtractInfo(IApplicationConfiguration applicationConfiguration) + { + var properties = applicationConfiguration.RulesForEnvironment(Environment); + + var list = new List(); + foreach (var propertyPair in properties) + { + var property = propertyPair.Key; + var rule = propertyPair.Value; + var value = property.GetValue(applicationConfiguration); + var hasValue = HasValue(property, value); + var displayValue = rule == null + ? (hasValue ? "Set" : "Not set") + : (rule.Obfuscate + ? (hasValue ? "Set" : "Not set") + : value?.ToString() ?? null); + + // Don't add extraneous values that haven't been set + if (rule == null && !hasValue) continue; + + list.Add(new ConfigurationItemInfo( + Name: property.Name, + Required: rule != null, + Obfuscated: rule?.Obfuscate ?? true, + Hidden: rule?.Hidden ?? false, + HasValue: hasValue, + Value: displayValue, + Extraneous: rule == null)); + } + + ConfigurationInfo = new ReadOnlyCollection(list); + } + + private static bool HasValue(PropertyInfo propertyInfo, object value) + { + if (propertyInfo.PropertyType != typeof(string)) return true; + return !string.IsNullOrEmpty(value as string); + } +} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/Configuration/IApplicationConfiguration.cs b/Childrens-Social-Care-CPD/Configuration/IApplicationConfiguration.cs index 07535fc0..51b31779 100644 --- a/Childrens-Social-Care-CPD/Configuration/IApplicationConfiguration.cs +++ b/Childrens-Social-Care-CPD/Configuration/IApplicationConfiguration.cs @@ -1,18 +1,49 @@ -namespace Childrens_Social_Care_CPD.Configuration; +using System.ComponentModel; + +namespace Childrens_Social_Care_CPD.Configuration; public interface IApplicationConfiguration { + [RequiredForEnvironment(ApplicationEnvironment.Test, Hidden = false)] + [RequiredForEnvironment(ApplicationEnvironment.PreProduction, Hidden = false)] + [RequiredForEnvironment(ApplicationEnvironment.Production, Hidden = false)] string AppInsightsConnectionString { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false, Obfuscate = false)] string AppVersion { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false, Obfuscate = false)] string AzureEnvironment { get; } + + [RequiredForEnvironment(ApplicationEnvironment.Production, Hidden = false)] string ClarityProjectId { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false)] string ContentfulDeliveryApiKey { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false)] string ContentfulEnvironment { get; } + + [RequiredForEnvironment(ApplicationEnvironment.PreProduction, Hidden = false)] string ContentfulPreviewHost { get; } + + [RequiredForEnvironment(ApplicationEnvironment.PreProduction, Hidden = false)] string ContentfulPreviewId { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false)] string ContentfulSpaceId { get; } + + [DefaultValue(false)] + [RequiredForEnvironment(ApplicationEnvironment.Integration, Hidden = false)] bool DisableSecureCookies { get; } + + [DefaultValue(0)] + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false, Obfuscate = false)] int FeaturePollingInterval { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false, Obfuscate = false)] string GitHash { get; } + + [RequiredForEnvironment(ApplicationEnvironment.All, Hidden = false)] string GoogleTagManagerKey { get; } } diff --git a/Childrens-Social-Care-CPD/Configuration/RequiredForEnvironmentAttribute.cs b/Childrens-Social-Care-CPD/Configuration/RequiredForEnvironmentAttribute.cs new file mode 100644 index 00000000..a46fa88a --- /dev/null +++ b/Childrens-Social-Care-CPD/Configuration/RequiredForEnvironmentAttribute.cs @@ -0,0 +1,56 @@ +using System.Collections.ObjectModel; +using System.Reflection; + +namespace Childrens_Social_Care_CPD.Configuration; + +[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] +public class RequiredForEnvironmentAttribute: Attribute +{ + public string Environment { get; } + public bool Hidden { get; set; } = true; + public bool Obfuscate { get; set; } = true; + + public RequiredForEnvironmentAttribute(string environment) + { + Environment = environment; + } +} + +public static class ObjectExtensions +{ + public static ReadOnlyDictionary RulesForEnvironment(this object source, string environment) + { + ArgumentNullException.ThrowIfNull(source); + + var dict = new Dictionary(); + PropertyInfo[] properties = source.GetType().GetProperties(); + + foreach (PropertyInfo property in properties) + { + var attributes = property.GetCustomAttributes(true); + if (attributes.Count() == 0) continue; + + var rule = RuleForCurrentEnvironment(environment, attributes); + dict.Add(property, rule); + } + + return new ReadOnlyDictionary(dict); + } + + private static RequiredForEnvironmentAttribute RuleForCurrentEnvironment(string environment, IEnumerable attributes) + { + var list = new List(); + foreach (var attribute in attributes) + { + if (attribute.Environment == "*") + { + list.Insert(0, attribute); + } + else if (attribute.Environment == environment) + { + list.Add(attribute); + } + } + return list.LastOrDefault(); + } +} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/Controllers/AppInfoController.cs b/Childrens-Social-Care-CPD/Controllers/ApplicationController.cs similarity index 52% rename from Childrens-Social-Care-CPD/Controllers/AppInfoController.cs rename to Childrens-Social-Care-CPD/Controllers/ApplicationController.cs index 09bdb5ca..4d751c12 100644 --- a/Childrens-Social-Care-CPD/Controllers/AppInfoController.cs +++ b/Childrens-Social-Care-CPD/Controllers/ApplicationController.cs @@ -1,14 +1,15 @@ using Childrens_Social_Care_CPD.Configuration; using Childrens_Social_Care_CPD.Models; using Microsoft.AspNetCore.Mvc; +using System.Net.Mime; namespace Childrens_Social_Care_CPD.Controllers; -public class AppInfoController : Controller +public class ApplicationController : Controller { private readonly IApplicationConfiguration _applicationConfiguration; - public AppInfoController(IApplicationConfiguration applicationConfiguration) + public ApplicationController(IApplicationConfiguration applicationConfiguration) { _applicationConfiguration = applicationConfiguration; } @@ -27,4 +28,19 @@ public JsonResult AppInfo() return Json(applicationInfo); } + + [HttpGet] + [Route("application/configuration")] + public IActionResult Configuration() + { + var configurationInformation = new ConfigurationInformation(_applicationConfiguration); + + if (Request.Headers.Accept == MediaTypeNames.Application.Json) + { + var info = configurationInformation.ConfigurationInfo.Where(x => !x.Hidden); + return Json(info.Select(x => new { x.Name, x.Extraneous, x.HasValue, x.Value, x.Obfuscated })); + } + + return View(configurationInformation.ConfigurationInfo); + } } \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/Models/ApplicationInfo.cs b/Childrens-Social-Care-CPD/Models/ApplicationInfo.cs index 9fe36720..5a8974ae 100644 --- a/Childrens-Social-Care-CPD/Models/ApplicationInfo.cs +++ b/Childrens-Social-Care-CPD/Models/ApplicationInfo.cs @@ -1,4 +1,6 @@ -namespace Childrens_Social_Care_CPD.Models; +using Childrens_Social_Care_CPD.Configuration; + +namespace Childrens_Social_Care_CPD.Models; public class ApplicationInfo { diff --git a/Childrens-Social-Care-CPD/SiteConstants.cs b/Childrens-Social-Care-CPD/SiteConstants.cs deleted file mode 100644 index 23e9a164..00000000 --- a/Childrens-Social-Care-CPD/SiteConstants.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Childrens_Social_Care_CPD; - -public static class SiteConstants -{ - public const string HEADING1 = "h1"; - public const string HEADING2 = "h2"; - public const string HEADING3 = "h3"; - public const string HEADING4 = "h4"; - public const string HEADING5 = "h5"; - public const string HEADING6 = "h6"; - public const string GOVUKHEADINGXL = "govuk-heading-xl"; - public const string GOVUKHEADINGL = "govuk-heading-l"; - public const string GOVUKHEADINGM = "govuk-heading-m"; -} \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/Views/Application/Configuration.cshtml b/Childrens-Social-Care-CPD/Views/Application/Configuration.cshtml new file mode 100644 index 00000000..0a5d413d --- /dev/null +++ b/Childrens-Social-Care-CPD/Views/Application/Configuration.cshtml @@ -0,0 +1,62 @@ +@using Childrens_Social_Care_CPD.Configuration; + +@model IReadOnlyCollection + +@{ + Layout = ""; +} + + + + + + + + + @{ + foreach (var item in Model) + { + if (item.Hidden) continue; + if (!item.HasValue && item.Extraneous) continue; + + var className = "normal"; + if (item.Extraneous && item.HasValue) + className = "extraneous"; + + if (!item.Extraneous && !item.HasValue) + className = "missing"; + + + + + + } + } +
@item.Name + @{ + if (item.Obfuscated) + { + @item.Value + } + else + { + @item.Value + } + } +
+ + \ No newline at end of file diff --git a/Childrens-Social-Care-CPD/Views/Shared/_GoogleAnalyticsPartial.cshtml b/Childrens-Social-Care-CPD/Views/Shared/_GoogleAnalyticsPartial.cshtml index d14fe464..d4b58902 100644 --- a/Childrens-Social-Care-CPD/Views/Shared/_GoogleAnalyticsPartial.cshtml +++ b/Childrens-Social-Care-CPD/Views/Shared/_GoogleAnalyticsPartial.cshtml @@ -6,7 +6,6 @@ var googleAnalyticsKey = applicationConfiguration.GoogleTagManagerKey; var googleAnalyticsUrl = string.Format("https://www.googletagmanager.com/gtag/js?id={0}", googleAnalyticsKey); var clarityProjectId = applicationConfiguration.ClarityProjectId; - var contentfulEnvironment = applicationConfiguration.ContentfulEnvironment; var pageName = (ViewBag.pageName ?? ViewBag.ContextModel?.Id) ?? "Homepage"; pageName = string.IsNullOrEmpty(pageName) ? "HomePage" : pageName; @@ -18,7 +17,8 @@ gtag('js', new Date()); gtag('config', '@googleAnalyticsKey'); - if (@contentfulEnvironment == AppEnvironment.test.ToString() || @contentfulEnvironment == AppEnvironment.prod.ToString()) + + if (applicationConfiguration.AzureEnvironment == ApplicationEnvironment.Test || applicationConfiguration.AzureEnvironment == ApplicationEnvironment.Production) {