From e47d736d396a849b1c3c22a4ac851589b9466594 Mon Sep 17 00:00:00 2001 From: jack-hive <148866614+jack-hive@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:23:43 +0000 Subject: [PATCH] EES 5632 - Return the Release redirects from the `api/redirects` endpoint (#5391) * EES-5632 Adding release redirects to the Redirects Cache, and returning it in the `RedirectViewModel` in the `/redirects` endpoint * EES-5632 Adding integration tests * EES-5632 Addressing PR comments --- .../MethodologyApprovalServiceTests.cs | 5 +- .../Methodologies/MethodologyServiceTests.cs | 35 ++- .../Services/PublicationServiceTests.cs | 16 +- .../Controllers/RedirectsControllerTests.cs | 222 ++++++++++++++++++ .../MethodologyGeneratorExtensions.cs | 49 +++- .../MethodologyRedirectGeneratorExtensions.cs | 49 ++++ .../MethodologyVersionGeneratorExtensions.cs | 11 + .../PublicationRedirectGeneratorExtensions.cs | 49 ++++ .../ReleaseRedirectGeneratorExtensions.cs | 49 ++++ .../RedirectsService.cs | 12 +- .../RedirectViewModels.cs | 3 +- 11 files changed, 476 insertions(+), 24 deletions(-) create mode 100644 src/GovUk.Education.ExploreEducationStatistics.Content.Api.Tests/Controllers/RedirectsControllerTests.cs create mode 100644 src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyRedirectGeneratorExtensions.cs create mode 100644 src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/PublicationRedirectGeneratorExtensions.cs create mode 100644 src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/ReleaseRedirectGeneratorExtensions.cs diff --git a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyApprovalServiceTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyApprovalServiceTests.cs index 38a167d25c6..bf25fb5f09f 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyApprovalServiceTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyApprovalServiceTests.cs @@ -680,7 +680,10 @@ public async Task UpdateApprovalStatus_ApprovingUsingImmediateStrategy() new List())); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); await using (var context = InMemoryApplicationDbContext(contentDbContextId)) { diff --git a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyServiceTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyServiceTests.cs index 20e83050f45..17499e9130b 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyServiceTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/Methodologies/MethodologyServiceTests.cs @@ -3599,7 +3599,10 @@ public async Task PublicationTitleOrSlugChanged() { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -3658,7 +3661,10 @@ public async Task PublicationTitleOrSlugChanged_NoMethodologyRedirectAsMethodolo { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -3738,7 +3744,10 @@ await contentDbContext.PublicationMethodologies.AddRangeAsync( { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -3837,7 +3846,10 @@ public async Task PublicationTitleOrSlugChanged_MethodologySlugIsAlternativeSlug { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -3904,7 +3916,10 @@ public async Task PublicationTitleOrSlugChanged_MethodologyIsLive() { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -3988,7 +4003,10 @@ public async Task { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); @@ -4091,7 +4109,10 @@ public async Task { var redirectsCacheService = new Mock(MockBehavior.Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) - .ReturnsAsync(new RedirectsViewModel(new List(), new List())); + .ReturnsAsync(new RedirectsViewModel( + Publications: [], + Methodologies: [], + Releases: [])); var service = SetupMethodologyService(contentDbContext, redirectsCacheService: redirectsCacheService.Object); diff --git a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/PublicationServiceTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/PublicationServiceTests.cs index 0355e6fba5d..9c493f09b50 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/PublicationServiceTests.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Admin.Tests/Services/PublicationServiceTests.cs @@ -1127,7 +1127,9 @@ public async Task UpdatePublication_AlreadyPublished() redirectsCacheService.Setup(mock => mock.UpdateRedirects()) .ReturnsAsync(new RedirectsViewModel( - new List(), new List())); + Publications: [], + Methodologies: [], + Releases: [])); var publicationService = BuildPublicationService(context, methodologyService: methodologyService.Object, @@ -1270,7 +1272,9 @@ public async Task UpdatePublication_TitleChangesPublicationAndMethodologySlug() redirectsCacheService.Setup(mock => mock.UpdateRedirects()) .ReturnsAsync(new RedirectsViewModel( - new List(), new List())); + Publications: [], + Methodologies: [], + Releases: [])); var publicationService = BuildPublicationService(context, methodologyService: methodologyService.Object, @@ -1575,7 +1579,9 @@ public async Task UpdatePublication_CreateRedirectIfLiveSlugChanged() var redirectsCacheService = new Mock(Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) .ReturnsAsync(new RedirectsViewModel( - new List(), new List())); + Publications: [], + Methodologies: [], + Releases: [])); var publicationService = BuildPublicationService(context, methodologyService: methodologyService.Object, @@ -1672,7 +1678,9 @@ public async Task UpdatePublication_ChangeBackToPreviousLiveSlug() var redirectsCacheService = new Mock(Strict); redirectsCacheService.Setup(mock => mock.UpdateRedirects()) .ReturnsAsync(new RedirectsViewModel( - new List(), new List())); + Publications: [], + Methodologies: [], + Releases: [])); var publicationService = BuildPublicationService(context, methodologyService: methodologyService.Object, diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Api.Tests/Controllers/RedirectsControllerTests.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Api.Tests/Controllers/RedirectsControllerTests.cs new file mode 100644 index 00000000000..7577fb5075c --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Api.Tests/Controllers/RedirectsControllerTests.cs @@ -0,0 +1,222 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using GovUk.Education.ExploreEducationStatistics.Common.Services.Interfaces; +using GovUk.Education.ExploreEducationStatistics.Common.Tests.Extensions; +using GovUk.Education.ExploreEducationStatistics.Content.Api.Tests.Fixtures; +using GovUk.Education.ExploreEducationStatistics.Content.Model; +using GovUk.Education.ExploreEducationStatistics.Content.Model.Database; +using GovUk.Education.ExploreEducationStatistics.Content.Model.Tests.Fixtures; +using GovUk.Education.ExploreEducationStatistics.Content.Services.Cache; +using GovUk.Education.ExploreEducationStatistics.Content.ViewModels; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace GovUk.Education.ExploreEducationStatistics.Content.Api.Tests.Controllers; + +public abstract class RedirectsControllerTests(TestApplicationFactory testApp) : IntegrationTestFixture(testApp) +{ + public class ListTests(TestApplicationFactory testApp) : RedirectsControllerTests(testApp) + { + public override async Task InitializeAsync() => await TestApp.StartAzurite(); + + [Fact] + public async Task RedirectsExist_Returns200WithRedirects() + { + var publicationRedirects = DataFixture.DefaultPublicationRedirect() + .WithPublication(DataFixture.DefaultPublication()) + .GenerateList(3); + + var releaseRedirects = DataFixture.DefaultReleaseRedirect() + .WithRelease(DataFixture.DefaultRelease()) + .GenerateList(3); + + var methodologyVersions = DataFixture.DefaultMethodologyVersion() + .ForIndex(3, s => s.SetPublished(DateTime.UtcNow)) + .GenerateList(4); + + Methodology methodology = DataFixture.DefaultMethodology() + .WithMethodologyVersions(methodologyVersions) + .WithLatestPublishedVersion(methodologyVersions.Last()); + + var methodologyRedirects = DataFixture.DefaultMethodologyRedirect() + .ForIndex(0, s => s.SetMethodologyVersion(methodologyVersions[0])) + .ForIndex(1, s => s.SetMethodologyVersion(methodologyVersions[1])) + .ForIndex(2, s => s.SetMethodologyVersion(methodologyVersions[2])) + .GenerateList(3); + + await TestApp.AddTestData(context => + { + context.PublicationRedirects.AddRange(publicationRedirects); + context.ReleaseRedirects.AddRange(releaseRedirects); + context.MethodologyRedirects.AddRange(methodologyRedirects); + }); + + var response = await ListRedirects(); + + var viewModel = response.AssertOk(); + + Assert.All( + publicationRedirects, + pr => Assert.Contains( + viewModel.Publications, + rvm => pr.Slug == rvm.FromSlug && pr.Publication.Slug == rvm.ToSlug)); + Assert.All( + releaseRedirects, + rr => Assert.Contains( + viewModel.Releases, + rvm => rr.Slug == rvm.FromSlug && rr.Release.Slug == rvm.ToSlug)); + Assert.All( + methodologyRedirects, + mr => Assert.Contains( + viewModel.Methodologies, + rvm => mr.Slug == rvm.FromSlug && mr.MethodologyVersion.Methodology.OwningPublicationSlug == rvm.ToSlug)); + } + + [Fact] + public async Task RedirectsExist_RedirectsAreCached() + { + var publicationRedirects = DataFixture.DefaultPublicationRedirect() + .WithPublication(DataFixture.DefaultPublication()) + .GenerateList(3); + + var releaseRedirects = DataFixture.DefaultReleaseRedirect() + .WithRelease(DataFixture.DefaultRelease()) + .GenerateList(3); + + var methodologyVersions = DataFixture.DefaultMethodologyVersion() + .ForIndex(3, s => s.SetPublished(DateTime.UtcNow)) + .GenerateList(4); + + Methodology methodology = DataFixture.DefaultMethodology() + .WithMethodologyVersions(methodologyVersions) + .WithLatestPublishedVersion(methodologyVersions.Last()); + + var methodologyRedirects = DataFixture.DefaultMethodologyRedirect() + .ForIndex(0, s => s.SetMethodologyVersion(methodologyVersions[0])) + .ForIndex(1, s => s.SetMethodologyVersion(methodologyVersions[1])) + .ForIndex(2, s => s.SetMethodologyVersion(methodologyVersions[2])) + .GenerateList(3); + + await TestApp.AddTestData(context => + { + context.PublicationRedirects.AddRange(publicationRedirects); + context.ReleaseRedirects.AddRange(releaseRedirects); + context.MethodologyRedirects.AddRange(methodologyRedirects); + }); + + var app = BuildApp(); + var client = app.CreateClient(); + + await ListRedirects(client); + + var blobCacheService = app.Services.GetRequiredService(); + + var cachedValue = await blobCacheService.GetItemAsync(new RedirectsCacheKey(), typeof(RedirectsViewModel)); + var cachedRedirectsViewModel = Assert.IsType(cachedValue); + + Assert.All( + publicationRedirects, + pr => Assert.Contains( + cachedRedirectsViewModel.Publications, + rvm => pr.Slug == rvm.FromSlug && pr.Publication.Slug == rvm.ToSlug)); + Assert.All( + releaseRedirects, + rr => Assert.Contains( + cachedRedirectsViewModel.Releases, + rvm => rr.Slug == rvm.FromSlug && rr.Release.Slug == rvm.ToSlug)); + Assert.All( + methodologyRedirects, + mr => Assert.Contains( + cachedRedirectsViewModel.Methodologies, + rvm => mr.Slug == rvm.FromSlug && mr.MethodologyVersion.Methodology.OwningPublicationSlug == rvm.ToSlug)); + } + + [Fact] + public async Task RedirectsExistInCache_Returns200WithRedirects() + { + var app = BuildApp(); + var client = app.CreateClient(); + + var blobCacheService = app.Services.GetRequiredService(); + + var cachedPublicationRedirects = new List() + { + new(FromSlug: "publication_fromSlug_1", ToSlug: "publication_toSlug_1"), + new(FromSlug: "publication_fromSlug_2", ToSlug: "publication_toSlug_2"), + new(FromSlug: "publication_fromSlug_3", ToSlug: "publication_toSlug_3") + }; + + var cachedReleaseRedirects = new List() + { + new(FromSlug: "release_fromSlug_1", ToSlug: "release_toSlug_1"), + new(FromSlug: "release_fromSlug_2", ToSlug: "release_toSlug_2"), + new(FromSlug: "release_fromSlug_3", ToSlug: "release_toSlug_3") + }; + + var cachedMethodologyRedirects = new List() + { + new(FromSlug: "methodology_fromSlug_1", ToSlug: "methodology_toSlug_1"), + new(FromSlug: "methodology_fromSlug_2", ToSlug: "methodology_toSlug_2"), + new(FromSlug: "methodology_fromSlug_3", ToSlug: "methodology_toSlug_3") + }; + + var cachedViewModel = new RedirectsViewModel( + Publications: cachedPublicationRedirects, + Releases: cachedReleaseRedirects, + Methodologies: cachedMethodologyRedirects); + + await blobCacheService.SetItemAsync(new RedirectsCacheKey(), cachedViewModel); + + var response = await ListRedirects(client); + + var viewModel = response.AssertOk(); + + Assert.All( + cachedPublicationRedirects, + cpr => Assert.Contains( + viewModel.Publications, + rvm => cpr.FromSlug == rvm.FromSlug && cpr.ToSlug == rvm.ToSlug)); + Assert.All( + cachedReleaseRedirects, + crr => Assert.Contains( + viewModel.Releases, + rvm => crr.FromSlug == rvm.FromSlug && crr.ToSlug == rvm.ToSlug)); + Assert.All( + cachedMethodologyRedirects, + cmr => Assert.Contains( + viewModel.Methodologies, + rvm => cmr.FromSlug == rvm.FromSlug && cmr.ToSlug == rvm.ToSlug)); + } + + [Fact] + public async Task NoRedirectsExist_Returns200WithNoRedirects() + { + var response = await ListRedirects(); + + var viewModel = response.AssertOk(); + + Assert.Empty(viewModel.Publications); + Assert.Empty(viewModel.Releases); + Assert.Empty(viewModel.Methodologies); + } + + private async Task ListRedirects( + HttpClient? client = null) + { + client ??= BuildApp().CreateClient(); + + return await client.GetAsync("/api/redirects"); + } + } + + private WebApplicationFactory BuildApp() + { + return TestApp + .WithAzurite(enabled: true); + } +} diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyGeneratorExtensions.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyGeneratorExtensions.cs index eef5b92e9d3..12c6dc1bc79 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyGeneratorExtensions.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyGeneratorExtensions.cs @@ -18,32 +18,42 @@ public static InstanceSetters SetDefaults(this InstanceSetters m.Id) .SetDefault(m => m.OwningPublicationTitle) .SetDefault(m => m.OwningPublicationSlug); - + public static Generator WithOwningPublication( this Generator generator, Publication publication) => generator.ForInstance(s => s.SetOwningPublication(publication)); - + public static Generator WithAdoptingPublication( this Generator generator, Publication publication) => generator.ForInstance(s => s.SetAdoptingPublication(publication)); - + public static Generator WithMethodologyVersions( this Generator generator, IEnumerable methodologyVersions) => generator.ForInstance(s => s.SetMethodologyVersions(methodologyVersions)); - + public static Generator WithMethodologyVersions( this Generator generator, Func> methodologyVersions) => generator.ForInstance(s => s.SetMethodologyVersions(methodologyVersions.Invoke)); - + + public static Generator WithLatestPublishedVersion( + this Generator generator, + MethodologyVersion latestPublishedVersion) + => generator.ForInstance(s => s.SetLatestPublishedVersion(latestPublishedVersion)); + + public static Generator WithLatestPublishedVersionId( + this Generator generator, + Guid latestPublishedVersionId) + => generator.ForInstance(s => s.SetLatestPublishedVersionId(latestPublishedVersionId)); + public static InstanceSetters SetMethodologyVersions( this InstanceSetters setters, - IEnumerable methodologyVersions) + IEnumerable methodologyVersions) => setters.SetMethodologyVersions(_ => methodologyVersions); - + private static InstanceSetters SetMethodologyVersions( this InstanceSetters setters, Func> methodologyVersions) @@ -59,16 +69,35 @@ private static InstanceSetters SetMethodologyVersions( } ); + private static InstanceSetters SetLatestPublishedVersion( + this InstanceSetters setters, + MethodologyVersion latestPublishedVersion) + => setters.Set( + m => m.LatestPublishedVersion, + (_, methodology) => + { + latestPublishedVersion.Methodology = methodology; + + return latestPublishedVersion; + } + ) + .SetLatestPublishedVersionId(latestPublishedVersion.Id); + + private static InstanceSetters SetLatestPublishedVersionId( + this InstanceSetters setters, + Guid latestPublishedVersionId) + => setters.Set(m => m.LatestPublishedVersionId, latestPublishedVersionId); + public static InstanceSetters SetOwningPublication( this InstanceSetters setters, - Publication publication) + Publication publication) => setters.SetPublication(_ => publication, owner: true); public static InstanceSetters SetAdoptingPublication( this InstanceSetters setters, - Publication publication) + Publication publication) => setters.SetPublication(_ => publication, owner: false); - + private static InstanceSetters SetPublication( this InstanceSetters setters, Func publication, diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyRedirectGeneratorExtensions.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyRedirectGeneratorExtensions.cs new file mode 100644 index 00000000000..f81b516a742 --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyRedirectGeneratorExtensions.cs @@ -0,0 +1,49 @@ +using GovUk.Education.ExploreEducationStatistics.Common.Tests.Fixtures; +using System; + +namespace GovUk.Education.ExploreEducationStatistics.Content.Model.Tests.Fixtures; + +public static class MethodologyRedirectGeneratorExtensions +{ + public static Generator DefaultMethodologyRedirect(this DataFixture fixture) + => fixture.Generator().WithDefaults(); + + public static Generator WithDefaults(this Generator generator) + => generator.ForInstance(d => d.SetDefaults()); + + public static InstanceSetters SetDefaults(this InstanceSetters setters) + => setters + .SetDefault(p => p.Slug) + .SetDefault(p => p.Created); + + public static Generator WithSlug( + this Generator generator, + string slug) + => generator.ForInstance(s => s.SetSlug(slug)); + + public static Generator WithMethodologyVersion( + this Generator generator, + MethodologyVersion methodologyVersion) + => generator.ForInstance(s => s.SetMethodologyVersion(methodologyVersion)); + + public static Generator WithMethodologyVersionId( + this Generator generator, + Guid methodologyVersionId) + => generator.ForInstance(s => s.SetMethodologyVersionId(methodologyVersionId)); + + public static InstanceSetters SetSlug( + this InstanceSetters setters, + string slug) + => setters.Set(mr => mr.Slug, slug); + + public static InstanceSetters SetMethodologyVersion( + this InstanceSetters setters, + MethodologyVersion methodologyVersion) + => setters.Set(mr => mr.MethodologyVersion, methodologyVersion) + .SetMethodologyVersionId(methodologyVersion.Id); + + public static InstanceSetters SetMethodologyVersionId( + this InstanceSetters setters, + Guid methodologyVersionId) + => setters.Set(mr => mr.MethodologyVersionId, methodologyVersionId); +} diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyVersionGeneratorExtensions.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyVersionGeneratorExtensions.cs index 36285a33ca6..4c909e32735 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyVersionGeneratorExtensions.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/MethodologyVersionGeneratorExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using GovUk.Education.ExploreEducationStatistics.Common.Extensions; using GovUk.Education.ExploreEducationStatistics.Common.Tests.Fixtures; @@ -32,6 +33,11 @@ public static Generator WithApprovalStatuses( return generator; } + public static Generator WithPublished( + this Generator generator, + DateTime published) + => generator.ForInstance(d => d.SetPublished(published)); + public static InstanceSetters SetDefaults(this InstanceSetters setters) => setters .SetDefault(p => p.Id) @@ -49,4 +55,9 @@ public static InstanceSetters SetApprovalStatus( this InstanceSetters setters, MethodologyApprovalStatus approvalStatus) => setters.Set(mv => mv.Status, approvalStatus); + + public static InstanceSetters SetPublished( + this InstanceSetters setters, + DateTime published) + => setters.Set(mv => mv.Published, published); } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/PublicationRedirectGeneratorExtensions.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/PublicationRedirectGeneratorExtensions.cs new file mode 100644 index 00000000000..2f002ddbbee --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/PublicationRedirectGeneratorExtensions.cs @@ -0,0 +1,49 @@ +using GovUk.Education.ExploreEducationStatistics.Common.Tests.Fixtures; +using System; + +namespace GovUk.Education.ExploreEducationStatistics.Content.Model.Tests.Fixtures; + +public static class PublicationRedirectGeneratorExtensions +{ + public static Generator DefaultPublicationRedirect(this DataFixture fixture) + => fixture.Generator().WithDefaults(); + + public static Generator WithDefaults(this Generator generator) + => generator.ForInstance(d => d.SetDefaults()); + + public static InstanceSetters SetDefaults(this InstanceSetters setters) + => setters + .SetDefault(p => p.Slug) + .SetDefault(p => p.Created); + + public static Generator WithSlug( + this Generator generator, + string slug) + => generator.ForInstance(s => s.SetSlug(slug)); + + public static Generator WithPublication( + this Generator generator, + Publication publication) + => generator.ForInstance(s => s.SetPublication(publication)); + + public static Generator WithPublicationId( + this Generator generator, + Guid publicationId) + => generator.ForInstance(s => s.SetPublicationId(publicationId)); + + public static InstanceSetters SetSlug( + this InstanceSetters setters, + string slug) + => setters.Set(pr => pr.Slug, slug); + + public static InstanceSetters SetPublication( + this InstanceSetters setters, + Publication publication) + => setters.Set(pr => pr.Publication, publication) + .SetPublicationId(publication.Id); + + public static InstanceSetters SetPublicationId( + this InstanceSetters setters, + Guid publicationId) + => setters.Set(pr => pr.PublicationId, publicationId); +} diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/ReleaseRedirectGeneratorExtensions.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/ReleaseRedirectGeneratorExtensions.cs new file mode 100644 index 00000000000..99d35b57b0c --- /dev/null +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Model.Tests/Fixtures/ReleaseRedirectGeneratorExtensions.cs @@ -0,0 +1,49 @@ +using GovUk.Education.ExploreEducationStatistics.Common.Tests.Fixtures; +using System; + +namespace GovUk.Education.ExploreEducationStatistics.Content.Model.Tests.Fixtures; + +public static class ReleaseRedirectGeneratorExtensions +{ + public static Generator DefaultReleaseRedirect(this DataFixture fixture) + => fixture.Generator().WithDefaults(); + + public static Generator WithDefaults(this Generator generator) + => generator.ForInstance(d => d.SetDefaults()); + + public static InstanceSetters SetDefaults(this InstanceSetters setters) + => setters + .SetDefault(p => p.Slug) + .SetDefault(p => p.Created); + + public static Generator WithSlug( + this Generator generator, + string slug) + => generator.ForInstance(s => s.SetSlug(slug)); + + public static Generator WithRelease( + this Generator generator, + Release release) + => generator.ForInstance(s => s.SetRelease(release)); + + public static Generator WithReleaseId( + this Generator generator, + Guid releaseId) + => generator.ForInstance(s => s.SetReleaseId(releaseId)); + + public static InstanceSetters SetSlug( + this InstanceSetters setters, + string slug) + => setters.Set(rr => rr.Slug, slug); + + public static InstanceSetters SetRelease( + this InstanceSetters setters, + Release release) + => setters.Set(rr => rr.Release, release) + .SetReleaseId(release.Id); + + public static InstanceSetters SetReleaseId( + this InstanceSetters setters, + Guid releaseId) + => setters.Set(rr => rr.ReleaseId, releaseId); +} diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.Services/RedirectsService.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.Services/RedirectsService.cs index 0588cfa70f7..10a392a8be3 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Content.Services/RedirectsService.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.Services/RedirectsService.cs @@ -64,8 +64,18 @@ public async Task> List() .Distinct() .ToList(); + var releaseRedirectViewModels = await _contentDbContext.ReleaseRedirects + .Where(rr => rr.Slug != rr.Release.Slug) // don't use redirects to the current live slug + .Distinct() + .Select(rr => new RedirectViewModel( + rr.Slug, + rr.Release.Slug + )) + .ToListAsync(); + return new RedirectsViewModel( publicationRedirectViewModels, - methodologyRedirectViewModels); + methodologyRedirectViewModels, + releaseRedirectViewModels); } } diff --git a/src/GovUk.Education.ExploreEducationStatistics.Content.ViewModels/RedirectViewModels.cs b/src/GovUk.Education.ExploreEducationStatistics.Content.ViewModels/RedirectViewModels.cs index b83b445e09a..e211a620400 100644 --- a/src/GovUk.Education.ExploreEducationStatistics.Content.ViewModels/RedirectViewModels.cs +++ b/src/GovUk.Education.ExploreEducationStatistics.Content.ViewModels/RedirectViewModels.cs @@ -2,7 +2,8 @@ namespace GovUk.Education.ExploreEducationStatistics.Content.ViewModels; public record RedirectsViewModel( List Publications, - List Methodologies); + List Methodologies, + List Releases); public record RedirectViewModel( string FromSlug,