diff --git a/src/Dfe.EarlyYearsQualification.Content/Entities/DetailsPage.cs b/src/Dfe.EarlyYearsQualification.Content/Entities/DetailsPage.cs index da3af969..757bf548 100644 --- a/src/Dfe.EarlyYearsQualification.Content/Entities/DetailsPage.cs +++ b/src/Dfe.EarlyYearsQualification.Content/Entities/DetailsPage.cs @@ -39,4 +39,6 @@ public class DetailsPage public Document? RequirementsText { get; init; } public NavigationLink? CheckAnotherQualificationLink { get; init; } + + public string PrintButtonText { get; init; } = string.Empty; } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs b/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs index 77a89edf..9d3152af 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs @@ -307,7 +307,8 @@ await govUkInsetTextRenderer.ToHtml(content.CheckAnotherQualificationText), RequirementsText = await htmlRenderer.ToHtml(content.RequirementsText), RatiosHeading = content.RatiosHeading, RatiosText = await htmlRenderer.ToHtml(content.RatiosText), - CheckAnotherQualificationLink = MapToNavigationLinkModel(content.CheckAnotherQualificationLink) + CheckAnotherQualificationLink = MapToNavigationLinkModel(content.CheckAnotherQualificationLink), + PrintButtonText = content.PrintButtonText, } }; } diff --git a/src/Dfe.EarlyYearsQualification.Web/Models/Content/DetailsPageModel.cs b/src/Dfe.EarlyYearsQualification.Web/Models/Content/DetailsPageModel.cs index 0458af74..409ce87a 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Models/Content/DetailsPageModel.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Models/Content/DetailsPageModel.cs @@ -35,4 +35,6 @@ public class DetailsPageModel public string FurtherInfoText { get; init; } = string.Empty; public NavigationLinkModel? CheckAnotherQualificationLink { get; init; } + + public string PrintButtonText { get; init; } = string.Empty; } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Security/SecureHeaderConfiguration.cs b/src/Dfe.EarlyYearsQualification.Web/Security/SecureHeaderConfiguration.cs index e9bf8ecd..4eb00622 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Security/SecureHeaderConfiguration.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Security/SecureHeaderConfiguration.cs @@ -74,6 +74,12 @@ public static SecureHeadersMiddlewareConfiguration CustomConfiguration() var ga4CspElement = new ContentSecurityPolicyElement { CommandType = CspCommandType.Uri, DirectiveOrUri = "*.google-analytics.com" }; + + var windowPrint = new ContentSecurityPolicyElement + { + CommandType = CspCommandType.Directive, + DirectiveOrUri = "sha256-/rCCQAYo5nH3kqWMvdaSato3ShxLfLrkODJIMZPKHSg=" + }; configuration.ContentSecurityPolicyConfiguration.ScriptSrc.Add(backButtonShaCspElement); configuration.ContentSecurityPolicyConfiguration.ScriptSrc.Add(cookiesPageShaCspElement); @@ -86,7 +92,8 @@ public static SecureHeadersMiddlewareConfiguration CustomConfiguration() configuration.ContentSecurityPolicyConfiguration.ScriptSrc.Add(gtmCspElement); configuration.ContentSecurityPolicyConfiguration.ScriptSrc.Add(gtmInjectedScriptCspElement); configuration.ContentSecurityPolicyConfiguration.ConnectSrc.Add(ga4CspElement); - + configuration.ContentSecurityPolicyConfiguration.ScriptSrc.Add(windowPrint); + return configuration; } } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Index.cshtml b/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Index.cshtml index aae48409..0a10c16e 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Index.cshtml +++ b/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Index.cshtml @@ -132,9 +132,16 @@ } } +

@Model.Content!.RequirementsHeading

+ @Html.Raw(Model.Content!.RequirementsText) -

+ +

+ +
+ +

@Model.Content.CheckAnotherQualificationLink?.DisplayText

diff --git a/src/Dfe.EarlyYearsQualification.Web/wwwroot/assets/images/icon-print.png b/src/Dfe.EarlyYearsQualification.Web/wwwroot/assets/images/icon-print.png new file mode 100644 index 00000000..5a879f9b Binary files /dev/null and b/src/Dfe.EarlyYearsQualification.Web/wwwroot/assets/images/icon-print.png differ diff --git a/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css b/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css index e7416ac8..2ed39ff7 100644 --- a/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css +++ b/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css @@ -61,4 +61,15 @@ body { .govuk-skip-link:focus { margin-bottom: 0!important; +} + +.print-button { + background: url(../assets/images/icon-print.png) no-repeat 10px 50%; + background-size: 16px 18px; + padding: 10px 10px 10px 36px; + text-decoration: none; + border: 1px solid #b1b4b6; + color: #1d70b8; + cursor: pointer; + margin: 0; } \ No newline at end of file diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-details-spec.cy.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-details-spec.cy.js index fbd25ea7..fcb7a01d 100644 --- a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-details-spec.cy.js +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-details-spec.cy.js @@ -76,4 +76,20 @@ describe("A spec used to test the qualification details page", () => { cy.get(".govuk-tag").eq(3).should("have.class", "govuk-tag--red"); cy.get(".govuk-tag").eq(4).should("have.class", "govuk-tag--red"); }) -}) \ No newline at end of file + + it("Clicking the print button brings up the print dialog", () => { + cy.setCookie('user_journey', '%7B%22WhereWasQualificationAwarded%22%3A%22england%22%2C%22WhenWasQualificationAwarded%22%3A%227%2F2015%22%2C%22LevelOfQualification%22%3A%223%22%2C%22WhatIsTheAwardingOrganisation%22%3A%22NCFE%22%2C%22SearchCriteria%22%3A%22%22%2C%22AdditionalQuestionsAnswers%22%3A%7B%22Test%20question%22%3A%22yes%22%2C%22Test%20question%202%22%3A%22no%22%7D%7D'); + cy.visit("/qualifications/qualification-details/eyq-240"); + + var printStub; + + cy.window().then(win => { + printStub = cy.stub(win, 'print') + }) + + cy.get("#print-button").click(); + cy.window().then(win => { + expect(printStub).to.be.calledOnce + }) + }); +}); \ No newline at end of file diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/security-header-spec.cy.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/security-header-spec.cy.js index e687a460..fc128e59 100644 --- a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/security-header-spec.cy.js +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/security-header-spec.cy.js @@ -21,7 +21,7 @@ describe("A spec that checks for security headers in the response", () => { ); expect(response.headers).to.have.property( "content-security-policy", - "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" + "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' 'sha256-/rCCQAYo5nH3kqWMvdaSato3ShxLfLrkODJIMZPKHSg=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" ); expect(response.headers).to.have.property( "cross-origin-resource-policy", @@ -62,7 +62,7 @@ describe("A spec that checks for security headers in the response", () => { ); expect(response.headers).to.have.property( "content-security-policy", - "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" + "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' 'sha256-/rCCQAYo5nH3kqWMvdaSato3ShxLfLrkODJIMZPKHSg=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" ); expect(response.headers).to.have.property( "cross-origin-resource-policy", @@ -97,7 +97,7 @@ describe("A spec that checks for security headers in the response", () => { ); expect(response.headers).to.have.property( "content-security-policy", - "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" + "script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-ibd3+9XjZn7Vg7zojLQbgAN/fA220kK9gifwVI944SI=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-pwrEcsLN2o+4gQQDR/0sGCITSf0nhhLAzP4h73+5foc=' 'sha256-/rCCQAYo5nH3kqWMvdaSato3ShxLfLrkODJIMZPKHSg=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com;block-all-mixed-content;upgrade-insecure-requests;" ); expect(response.headers).to.have.property( "cross-origin-resource-policy",