diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index f115caa284..9b257bf0a8 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -1,3 +1,18 @@ +## [1.181.2](https://github.com/oaknational/Oak-Web-Application/compare/v1.181.1...v1.181.2) (2023-05-11) + + +### Bug Fixes + +* add no theme into learning themes ([e6b3ff1](https://github.com/oaknational/Oak-Web-Application/commit/e6b3ff153b74987904359aa35347d641227a5e39)) +* type errors ([c02c502](https://github.com/oaknational/Oak-Web-Application/commit/c02c502d5c1bc51f57042144a9462da575037e52)) + +## [1.181.1](https://github.com/oaknational/Oak-Web-Application/compare/v1.181.0...v1.181.1) (2023-05-11) + + +### Bug Fixes + +* **security policy:** meet formatting standard ([be40d8d](https://github.com/oaknational/Oak-Web-Application/commit/be40d8d44110af4c398705c4a36d580d9e2feb50)) + # [1.181.0](https://github.com/oaknational/Oak-Web-Application/compare/v1.180.3...v1.181.0) (2023-05-11) diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt index d9f149f587..6126234f64 100644 --- a/public/.well-known/security.txt +++ b/public/.well-known/security.txt @@ -5,6 +5,7 @@ Hash: SHA256 # Please report any security vulnerabilities to us via the contact method(s) below, only after reading our security disclosure policy. Contact: mailto:security@thenational.academy +Contact: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability Preferred-Languages: en # Encrypt your messages to Oak National Academy using the PGP key below @@ -29,17 +30,17 @@ Hiring: https://jobs.thenational.academy # Please see https://securitytxt.org/ for details of the specification of this file -----BEGIN PGP SIGNATURE----- -iQIzBAEBCAAdFiEE6SUFh2S/HgValc+nlx8GIFG2C30FAmPihxMACgkQlx8GIFG2 -C31pAA//ds+Ytm1eqGx0a5PlrKdpajAr3HCgjYPetNfeid/fPcHuOUymUsAmS8h3 -hBzxdpRJfpH34tzJU0ZUz6jDpY2JqpIe7m+tc35q4IySmqxKwnAV/SfemNIxb2A+ -L04aekGp+GVaoBf+ZlHxlQEGgP2Z9ne7gO1Pc+HfkzU4vYeK5/9C+6pLk9bVnxau -LMs21/DZwIVxQ/LhfTAfHZo/SgqYlp3+Z4V6uG0JS+Sb/NhoTp+fSkB+qPEx5e3c -ei98edxzR7EG/2p9KNmOd0uhBQVhUred47cWyJz3yezpqW6BHjBNC4lmrQRmq54g -RZ91gS2FRNUzCKFKDFbQZZb1blqkWzaaP9fKPo/90pJ4ZF7ck1JBKB3iqGZUXcCL -3AQ5yAY+BuM00CCnIFkZO54mKvRclqk7biOkb4JUIXoYLj6+pkE1UIIoGfVXO5iV -orSmmkxHbEt9f5V0eqnpgw4+cl4QQ04iYIFAcFY9n0QO6eWbRD2arimljZ2hW0Rh -WL1ELeLU5Txfe13I+Py5m96JOJXYUmIdr2ZLYnqzozmvlQlV7MWEbcu3/yXws7hT -+W1VubwhIOkKUU2m+/bBPeA4JTB7U0swzTWqTWK8pPGgIEIeq7ZZHf2UQi5gT42i -TpF8nQv6yeULmdP0/PWk74vEEbBhaoFGkzsJLWL6YFvxEc5duUw= -=F882 ------END PGP SIGNATURE----- \ No newline at end of file +iQIzBAEBCAAdFiEE6SUFh2S/HgValc+nlx8GIFG2C30FAmRc/TEACgkQlx8GIFG2 +C33Y2A//d7GEtmMIwuyMnexEuOuc8xm/h1euvZo6shpzkZnpI21+uECVCKKRWyg9 +CNcIo6GcrcUHcneFcUfPazs/6c+9FZEm4GIj8GhrdGwiZruLfT6+Tgd2ZTcA4ikr +AtnG4NVHrOacs+ZlipCaT6c/uQ4Mz4CocVt++JomP8EEfpDFyraBXt9b7v3dqNOs +NqT1Fl+qH2CGNxNFVCy3aBqHgEJ7NCyFOzBro/yDR54pe3Udr7IUE1sLreOhVVhU +tEwlEj9OmguF8eH+qgyZXM64cNJA+h/Gj/aAkDzEV72hXNjoTKtDXBSGqP5UKUgJ +blsEp+Z6RPeQkjEZnTHBBxcOepx7XdeGtGtiJqcuBNglmZ3hJuDAzjf696IBLryz +6F5EBLCGGJCNK4Uonzc5jYIjcMdXzA9bHvcz+R4+VvzasAsk8SSTThThdtysQ5Do +cUoxOEU0fSbTW1VZ73g1+otILluXBA7ghTvKJyHCUi42ZmxneNLJqLjERZ7lmJLk +hgnhOLQ9f7WgMqD4LkxIaV1Tb8j/frxbd2JrQR8Ht3oUe5mfTWV8Oku8BsUJ5GhN +XuV3a9148NKBHtnB9pJsgqVo8TLGa8c7fQFaXOAQ68+GCYp/Dmy17sX9lTyruZIy +dJMGcpZ2HlP0LFQn1BBaNGDwKY44LFHnnNrTOZ12nrtLlDp3lNc= +=v60q +-----END PGP SIGNATURE----- diff --git a/src/components/Filters/LearningThemeFilters/LearningThemeFilters.tsx b/src/components/Filters/LearningThemeFilters/LearningThemeFilters.tsx index 121c7c21dc..7605305d04 100644 --- a/src/components/Filters/LearningThemeFilters/LearningThemeFilters.tsx +++ b/src/components/Filters/LearningThemeFilters/LearningThemeFilters.tsx @@ -11,8 +11,8 @@ export type LearningThemeSelectedTrackingProps = { }; export type LearningTheme = { - learningThemeSlug?: string; - learningThemeTitle?: string; + learningThemeSlug?: string | null; + learningThemeTitle?: string | null; }; export type LearningThemeFiltersProps = { @@ -48,12 +48,12 @@ const LearningThemeFilters = ({ .sort( ( a: { - label: string | undefined; - slug: string | undefined; + label: string | undefined | null; + slug: string | undefined | null; }, b: { - label: string | undefined; - slug: string | undefined; + label: string | undefined | null; + slug: string | undefined | null; } ) => { if (a?.slug === "no-theme") { diff --git a/src/node-lib/curriculum-api/fixtures/unitListing.fixture.ts b/src/node-lib/curriculum-api/fixtures/unitListing.fixture.ts index 1553061dac..5ce590a77d 100644 --- a/src/node-lib/curriculum-api/fixtures/unitListing.fixture.ts +++ b/src/node-lib/curriculum-api/fixtures/unitListing.fixture.ts @@ -268,7 +268,18 @@ const unitListingFixture = ( expiredLessonCount: 0, }, ], - learningThemes: [], + learningThemes: [ + { + learningThemeTitle: "The Canterbury Tales and paired texts", + learningThemeSlug: "the-canterbury-tales-and-paired-texts-39", + }, + { + learningThemeTitle: "The sonnet through time", + learningThemeSlug: "the-sonnet-through-time-24", + }, + + { learningThemeTitle: null, learningThemeSlug: "no-theme" }, + ], ...partial, }; }; diff --git a/src/node-lib/curriculum-api/index.test.ts b/src/node-lib/curriculum-api/index.test.ts index 4117f4b028..b058f52f19 100644 --- a/src/node-lib/curriculum-api/index.test.ts +++ b/src/node-lib/curriculum-api/index.test.ts @@ -136,6 +136,17 @@ describe("curriculum-api", () => { programmeSlug: "maths-secondary-ks4", }); }); + test("unitListing learningThemes contains 'no themes'", async () => { + const units = await curriculumApi.unitListing({ + programmeSlug: "maths-secondary-ks4", + }); + const hasThemes = + units.learningThemes?.filter( + (theme) => theme.learningThemeSlug === "no-theme" + ).length > 0; + + expect(hasThemes).toBe(true); + }); test("lessonListingPaths", async () => { await curriculumApi.lessonListingPaths(); expect(lessonListingPaths).toHaveBeenCalled(); diff --git a/src/node-lib/curriculum-api/index.ts b/src/node-lib/curriculum-api/index.ts index 0356b29dc7..ff738b21ea 100644 --- a/src/node-lib/curriculum-api/index.ts +++ b/src/node-lib/curriculum-api/index.ts @@ -316,8 +316,8 @@ const unitListingData = z.object({ units: unitsData, learningThemes: z.array( z.object({ - learningThemeTitle: z.string(), - learningThemeSlug: z.string(), + learningThemeTitle: z.string().nullable(), + learningThemeSlug: z.string().nullable(), }) ), }); @@ -419,34 +419,26 @@ const curriculumApi = { const { units = [], programmes = [], tiers = [] } = transformMVCase(res); const programme = getFirstResultOrWarnOrFail()({ results: programmes }); - const learningThemes = units - ?.filter((unit) => unit?.themeSlug !== "no-theme") - .map((unitWithTheme) => ({ - learningThemeSlug: unitWithTheme?.themeSlug || "", - learningThemeTitle: unitWithTheme?.themeTitle || "", - })) - .sort((a, b) => { - if (a.learningThemeTitle < b.learningThemeTitle) { - return -1; - } - if (a.learningThemeTitle > b.learningThemeTitle) { - return 1; - } - return 0; - }); + const learningThemes = units.map((unitWithTheme) => ({ + learningThemeSlug: unitWithTheme?.themeSlug, + learningThemeTitle: unitWithTheme?.themeTitle || "No theme", + })); // !Refactor index signature to be more specific - type LearningTheme = { - [key: string]: string; - }; - - const filteredDuplicatedLearningThemes = learningThemes.filter( - (learningTheme: LearningTheme, index, learningThemeToCompare) => - learningThemeToCompare.findIndex((lt: LearningTheme) => - ["learningThemeSlug"].every((l) => lt[l] === learningTheme[l]) - ) === index - ); + const filteredDuplicatedLearningThemes = [ + ...new Map( + learningThemes.map((theme) => [JSON.stringify(theme), theme]) + ).values(), + ].sort((a, b) => { + if (a.learningThemeTitle < b.learningThemeTitle) { + return -1; + } + if (a.learningThemeTitle > b.learningThemeTitle) { + return 1; + } + return 0; + }); return unitListingData.parse({ programmeSlug: programme?.programmeSlug,