@studyportals/fawkes 7.2.0 → 7.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/src/organisations/policies/OrganisationsSeoIndexabilityPolicy.d.ts +5 -1
  2. package/dist/src/organisations/policies/OrganisationsSeoIndexabilityPolicy.js +6 -3
  3. package/dist/src/organisations/policies/RankedOrganisationsSeoIndexabilityPolicy.js +1 -1
  4. package/dist/src/organisations/policies/our-picks/Area.d.ts +1 -3
  5. package/dist/src/organisations/policies/our-picks/Area.js +1 -5
  6. package/dist/src/organisations/policies/our-picks/AreaAttendance.d.ts +1 -3
  7. package/dist/src/organisations/policies/our-picks/AreaAttendance.js +1 -5
  8. package/dist/src/organisations/policies/our-picks/Attendance.d.ts +1 -3
  9. package/dist/src/organisations/policies/our-picks/Attendance.js +1 -5
  10. package/dist/src/organisations/policies/our-picks/Continent.d.ts +1 -3
  11. package/dist/src/organisations/policies/our-picks/Continent.js +1 -5
  12. package/dist/src/organisations/policies/our-picks/Country.d.ts +1 -3
  13. package/dist/src/organisations/policies/our-picks/Country.js +1 -5
  14. package/dist/src/organisations/policies/our-picks/CountryAttendance.d.ts +1 -3
  15. package/dist/src/organisations/policies/our-picks/CountryAttendance.js +1 -5
  16. package/dist/src/organisations/policies/our-picks/Unfiltered.d.ts +1 -3
  17. package/dist/src/organisations/policies/our-picks/Unfiltered.js +1 -5
  18. package/dist/src/organisations/policies/ranked/RankedArea.d.ts +1 -1
  19. package/dist/src/organisations/policies/ranked/RankedArea.js +1 -2
  20. package/dist/src/organisations/policies/ranked/RankedAreaDiscipline.d.ts +1 -1
  21. package/dist/src/organisations/policies/ranked/RankedAreaDiscipline.js +1 -2
  22. package/dist/src/organisations/policies/ranked/RankedAttendance.d.ts +1 -1
  23. package/dist/src/organisations/policies/ranked/RankedAttendance.js +1 -2
  24. package/dist/src/organisations/policies/ranked/RankedAttendanceDiscipline.d.ts +1 -1
  25. package/dist/src/organisations/policies/ranked/RankedAttendanceDiscipline.js +1 -2
  26. package/dist/src/organisations/policies/ranked/RankedContinent.d.ts +1 -1
  27. package/dist/src/organisations/policies/ranked/RankedContinent.js +1 -2
  28. package/dist/src/organisations/policies/ranked/RankedContinentAttendance.d.ts +1 -1
  29. package/dist/src/organisations/policies/ranked/RankedContinentAttendance.js +1 -2
  30. package/dist/src/organisations/policies/ranked/RankedCountry.d.ts +1 -1
  31. package/dist/src/organisations/policies/ranked/RankedCountry.js +1 -2
  32. package/dist/src/organisations/policies/ranked/RankedCountryAttendance.d.ts +1 -1
  33. package/dist/src/organisations/policies/ranked/RankedCountryAttendance.js +1 -2
  34. package/dist/src/organisations/policies/ranked/RankedCountryDiscipline.d.ts +1 -1
  35. package/dist/src/organisations/policies/ranked/RankedCountryDiscipline.js +1 -2
  36. package/dist/src/organisations/policies/ranked/RankedDiscipline.d.ts +1 -1
  37. package/dist/src/organisations/policies/ranked/RankedDiscipline.js +1 -2
  38. package/dist/src/organisations/policies/ranked/RankedUnfiltered.d.ts +1 -1
  39. package/dist/src/organisations/policies/ranked/RankedUnfiltered.js +1 -2
  40. package/dist/src/programmes/policies/DegreeAttendanceDiscipline.d.ts +17 -0
  41. package/dist/src/programmes/policies/DegreeAttendanceDiscipline.js +61 -0
  42. package/dist/src/programmes/policies/DegreeCountryAttendance.d.ts +19 -0
  43. package/dist/src/programmes/policies/DegreeCountryAttendance.js +98 -0
  44. package/dist/src/programmes/policies/DegreeCountryDiscipline.d.ts +17 -0
  45. package/dist/src/programmes/policies/DegreeCountryDiscipline.js +75 -0
  46. package/dist/src/programmes/policies/DegreeCountryTuitionFee.d.ts +18 -0
  47. package/dist/src/programmes/policies/DegreeCountryTuitionFee.js +81 -0
  48. package/dist/src/programmes/rules/DegreeAttendanceDisciplineRule.d.ts +11 -0
  49. package/dist/src/programmes/rules/DegreeAttendanceDisciplineRule.js +45 -0
  50. package/dist/src/programmes/rules/DegreeAttendanceDisciplineSpecificRule.d.ts +11 -0
  51. package/dist/src/programmes/rules/DegreeAttendanceDisciplineSpecificRule.js +41 -0
  52. package/dist/src/programmes/rules/DegreeAttendanceSpecificRule.d.ts +10 -0
  53. package/dist/src/programmes/rules/DegreeAttendanceSpecificRule.js +42 -0
  54. package/dist/src/programmes/rules/DegreeCountryAttendanceSpecificRule.d.ts +10 -0
  55. package/dist/src/programmes/rules/DegreeCountryAttendanceSpecificRule.js +34 -0
  56. package/dist/src/programmes/rules/DegreeCountrySpecificRule.d.ts +10 -0
  57. package/dist/src/programmes/rules/DegreeCountrySpecificRule.js +42 -0
  58. package/dist/src/programmes/rules/DegreeCountryTuitionFeeRule.d.ts +11 -0
  59. package/dist/src/programmes/rules/DegreeCountryTuitionFeeRule.js +45 -0
  60. package/dist/src/programmes/rules/DegreeCountryTuitionFeeSpecificRule.d.ts +10 -0
  61. package/dist/src/programmes/rules/DegreeCountryTuitionFeeSpecificRule.js +33 -0
  62. package/dist/src/programmes/rules/DegreeDisciplineRule.d.ts +20 -0
  63. package/dist/src/programmes/rules/DegreeDisciplineRule.js +171 -0
  64. package/dist/src/programmes/rules/MBACountryAttendanceRule.d.ts +11 -0
  65. package/dist/src/programmes/rules/MBACountryAttendanceRule.js +44 -0
  66. package/dist/src/programmes/rules/MasterOfArtsDisciplineRule.d.ts +10 -0
  67. package/dist/src/programmes/rules/MasterOfArtsDisciplineRule.js +41 -0
  68. package/dist/src/programmes/rules/MasterOfEducationCountryDisciplineRule.d.ts +11 -0
  69. package/dist/src/programmes/rules/MasterOfEducationCountryDisciplineRule.js +75 -0
  70. package/dist/src/programmes/rules/MasterOfLawsCountryAttendanceRule.d.ts +12 -0
  71. package/dist/src/programmes/rules/MasterOfLawsCountryAttendanceRule.js +48 -0
  72. package/dist/src/programmes/rules/MasterOfLawsCountryTuitionFeeRule.d.ts +12 -0
  73. package/dist/src/programmes/rules/MasterOfLawsCountryTuitionFeeRule.js +49 -0
  74. package/dist/src/programmes/rules/MasterOfPhilosophyCountryAttendanceRule.d.ts +12 -0
  75. package/dist/src/programmes/rules/MasterOfPhilosophyCountryAttendanceRule.js +48 -0
  76. package/dist/src/programmes/rules/MasterOfScienceDisciplineRule.d.ts +10 -0
  77. package/dist/src/programmes/rules/MasterOfScienceDisciplineRule.js +41 -0
  78. package/dist/src/scholarships/policies/Area.d.ts +3 -5
  79. package/dist/src/scholarships/policies/Area.js +4 -6
  80. package/dist/src/scholarships/policies/Country.d.ts +3 -6
  81. package/dist/src/scholarships/policies/Country.js +4 -9
  82. package/dist/src/scholarships/policies/Discipline.d.ts +3 -6
  83. package/dist/src/scholarships/policies/Discipline.js +4 -9
  84. package/dist/src/scholarships/policies/DisciplineCountry.d.ts +3 -6
  85. package/dist/src/scholarships/policies/DisciplineCountry.js +4 -9
  86. package/dist/src/scholarships/policies/ScholarshipSeoIndexabilityPolicy.d.ts +7 -0
  87. package/dist/src/scholarships/policies/ScholarshipSeoIndexabilityPolicy.js +7 -0
  88. package/dist/src/scholarships/policies/Unfiltered.d.ts +3 -6
  89. package/dist/src/scholarships/policies/Unfiltered.js +4 -9
  90. package/dist/src/scholarships/policies/UniversityCountry.d.ts +3 -6
  91. package/dist/src/scholarships/policies/UniversityCountry.js +4 -9
  92. package/package.json +1 -1
@@ -0,0 +1,61 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { DegreeAttendanceDisciplineRule } from '../rules/DegreeAttendanceDisciplineRule';
6
+ import { DegreeAttendanceDisciplineSpecificRule } from '../rules/DegreeAttendanceDisciplineSpecificRule';
7
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
8
+ import { DegreePresenter } from '../../presenters/DegreePresenter';
9
+ import { AttendancePresenter } from '../../presenters/AttendancePresenter';
10
+ import { DisciplinePresenter } from '../../presenters/DisciplinePresenter';
11
+ export class DegreeAttendanceDiscipline extends ProgrammesBaseIndexabilityPolicy {
12
+ name = 'Degree Attendance Discipline Policy';
13
+ description = 'Determines indexing rules for pages filtered by degree type, attendance, and discipline.';
14
+ filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.DELIVERY_METHOD, FilterKey.DISCIPLINES];
15
+ rules = [
16
+ new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
17
+ new SingleValueSelectedForFilterRule(FilterKey.DELIVERY_METHOD),
18
+ new SingleValueSelectedForFilterRule(FilterKey.DISCIPLINES),
19
+ new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.DELIVERY_METHOD, FilterKey.DISCIPLINES]),
20
+ new DegreeAttendanceDisciplineSpecificRule(),
21
+ new DegreeAttendanceDisciplineRule()
22
+ ];
23
+ constructor(dependencies) {
24
+ super(dependencies);
25
+ this.initateBaseRules();
26
+ }
27
+ async generateUrls() {
28
+ const degreeFragments = DegreePresenter.getInstance().getFragments();
29
+ const attendanceFragments = AttendancePresenter.getInstance().getFragments();
30
+ const disciplineFragments = DisciplinePresenter.getInstance().getFragments();
31
+ const paths = [];
32
+ // Process Master of Science, Master of Arts, and Master of Business Administration degrees with online attendance
33
+ const allowedDegreeIds = ['master-of-science', 'master-of-arts', 'master-of-business-administration'];
34
+ const onlineAttendance = attendanceFragments.find(a => a.id === 'online');
35
+ if (!onlineAttendance) {
36
+ return paths;
37
+ }
38
+ for (const pageNumber of this.indexablePageNumbers) {
39
+ for (const degreeId of allowedDegreeIds) {
40
+ const degree = degreeFragments.find(d => d.id === degreeId);
41
+ if (!degree)
42
+ continue;
43
+ for (const discipline of disciplineFragments) {
44
+ const filterKeyValues = new Map([
45
+ [FilterKey.DEGREE_TYPE, [degree.id]],
46
+ [FilterKey.DELIVERY_METHOD, [onlineAttendance.id]],
47
+ [FilterKey.DISCIPLINES, [discipline.id]]
48
+ ]);
49
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
50
+ if (result) {
51
+ paths.push(this.getPathWithPageNumber(`${degree.path}/${onlineAttendance.path}/${discipline.path}`, pageNumber));
52
+ }
53
+ }
54
+ }
55
+ }
56
+ return paths;
57
+ }
58
+ get filterCombination() {
59
+ return FilterCombinations.DEGREE_ATTENDANCE_DISCIPLINE;
60
+ }
61
+ }
@@ -0,0 +1,19 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { MBACountryAttendanceRule } from '../rules/MBACountryAttendanceRule';
6
+ import { MasterOfLawsCountryAttendanceRule } from '../rules/MasterOfLawsCountryAttendanceRule';
7
+ import { MasterOfPhilosophyCountryAttendanceRule } from '../rules/MasterOfPhilosophyCountryAttendanceRule';
8
+ import { DegreeCountryAttendanceSpecificRule } from '../rules/DegreeCountryAttendanceSpecificRule';
9
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
10
+ import { IProgrammeSeoDependencies } from '../types/IProgrammeSeoDependencies';
11
+ export declare class DegreeCountryAttendance extends ProgrammesBaseIndexabilityPolicy {
12
+ readonly name: string;
13
+ readonly description: string;
14
+ readonly filterKeys: FilterKey[];
15
+ protected readonly rules: (SingleValueSelectedForFilterRule | OnlyFiltersSelectedRule | MBACountryAttendanceRule | MasterOfLawsCountryAttendanceRule | MasterOfPhilosophyCountryAttendanceRule | DegreeCountryAttendanceSpecificRule)[];
16
+ constructor(dependencies: IProgrammeSeoDependencies);
17
+ protected generateUrls(): Promise<string[]>;
18
+ get filterCombination(): FilterCombinations;
19
+ }
@@ -0,0 +1,98 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { MBACountryAttendanceRule } from '../rules/MBACountryAttendanceRule';
6
+ import { MasterOfLawsCountryAttendanceRule } from '../rules/MasterOfLawsCountryAttendanceRule';
7
+ import { MasterOfPhilosophyCountryAttendanceRule } from '../rules/MasterOfPhilosophyCountryAttendanceRule';
8
+ import { DegreeCountryAttendanceSpecificRule } from '../rules/DegreeCountryAttendanceSpecificRule';
9
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
10
+ import { DegreePresenter } from '../../presenters/DegreePresenter';
11
+ import { CountryPresenter } from '../../presenters/CountryPresenter';
12
+ import { AttendancePresenter } from '../../presenters/AttendancePresenter';
13
+ export class DegreeCountryAttendance extends ProgrammesBaseIndexabilityPolicy {
14
+ name = 'Degree Country Attendance Policy';
15
+ description = 'Determines indexing rules for pages filtered by degree type, country, and attendance.';
16
+ filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.DELIVERY_METHOD];
17
+ rules = [
18
+ new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
19
+ new SingleValueSelectedForFilterRule(FilterKey.COUNTRY),
20
+ new SingleValueSelectedForFilterRule(FilterKey.DELIVERY_METHOD),
21
+ new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.DELIVERY_METHOD]),
22
+ new DegreeCountryAttendanceSpecificRule(),
23
+ new MBACountryAttendanceRule(),
24
+ new MasterOfLawsCountryAttendanceRule(),
25
+ new MasterOfPhilosophyCountryAttendanceRule()
26
+ ];
27
+ constructor(dependencies) {
28
+ super(dependencies);
29
+ this.initateBaseRules();
30
+ }
31
+ async generateUrls() {
32
+ const degreeFragments = DegreePresenter.getInstance().getFragments();
33
+ const countryFragments = CountryPresenter.getInstance().getFragments();
34
+ const attendanceFragments = AttendancePresenter.getInstance().getFragments();
35
+ const paths = [];
36
+ // Get degree fragments
37
+ const mba = degreeFragments.find(d => d.id === 'master-of-business-administration');
38
+ const llm = degreeFragments.find(d => d.id === 'master-of-laws');
39
+ const mphil = degreeFragments.find(d => d.id === 'master-of-philosophy');
40
+ const onlineAttendance = attendanceFragments.find(a => a.id === 'online');
41
+ if (!onlineAttendance) {
42
+ return paths;
43
+ }
44
+ // Allowed countries for specific degrees
45
+ const llmAllowedCountryIds = ['82', '30', '32', '108']; // USA, UK, Canada, India
46
+ const mphilAllowedCountryIds = ['82', '30', '108']; // USA, UK, India
47
+ for (const pageNumber of this.indexablePageNumbers) {
48
+ // MBA + online attendance accepts all countries
49
+ if (mba) {
50
+ for (const country of countryFragments) {
51
+ const filterKeyValues = new Map([
52
+ [FilterKey.DEGREE_TYPE, [mba.id]],
53
+ [FilterKey.COUNTRY, [country.id]],
54
+ [FilterKey.DELIVERY_METHOD, [onlineAttendance.id]]
55
+ ]);
56
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
57
+ if (result) {
58
+ paths.push(this.getPathWithPageNumber(`${mba.path}/${country.path}/${onlineAttendance.path}`, pageNumber));
59
+ }
60
+ }
61
+ }
62
+ // Master of Laws + online attendance accepts specific countries
63
+ if (llm) {
64
+ const llmCountries = countryFragments.filter(c => llmAllowedCountryIds.includes(c.id));
65
+ for (const country of llmCountries) {
66
+ const filterKeyValues = new Map([
67
+ [FilterKey.DEGREE_TYPE, [llm.id]],
68
+ [FilterKey.COUNTRY, [country.id]],
69
+ [FilterKey.DELIVERY_METHOD, [onlineAttendance.id]]
70
+ ]);
71
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
72
+ if (result) {
73
+ paths.push(this.getPathWithPageNumber(`${llm.path}/${country.path}/${onlineAttendance.path}`, pageNumber));
74
+ }
75
+ }
76
+ }
77
+ // Master of Philosophy + online attendance accepts specific countries
78
+ if (mphil) {
79
+ const mphilCountries = countryFragments.filter(c => mphilAllowedCountryIds.includes(c.id));
80
+ for (const country of mphilCountries) {
81
+ const filterKeyValues = new Map([
82
+ [FilterKey.DEGREE_TYPE, [mphil.id]],
83
+ [FilterKey.COUNTRY, [country.id]],
84
+ [FilterKey.DELIVERY_METHOD, [onlineAttendance.id]]
85
+ ]);
86
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
87
+ if (result) {
88
+ paths.push(this.getPathWithPageNumber(`${mphil.path}/${country.path}/${onlineAttendance.path}`, pageNumber));
89
+ }
90
+ }
91
+ }
92
+ }
93
+ return paths;
94
+ }
95
+ get filterCombination() {
96
+ return FilterCombinations.DEGREE_COUNTRY_ATTENDANCE;
97
+ }
98
+ }
@@ -0,0 +1,17 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { DegreeCountrySpecificRule } from '../rules/DegreeCountrySpecificRule';
6
+ import { MasterOfEducationCountryDisciplineRule } from '../rules/MasterOfEducationCountryDisciplineRule';
7
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
8
+ import { IProgrammeSeoDependencies } from '../types/IProgrammeSeoDependencies';
9
+ export declare class DegreeCountryDiscipline extends ProgrammesBaseIndexabilityPolicy {
10
+ readonly name: string;
11
+ readonly description: string;
12
+ readonly filterKeys: FilterKey[];
13
+ protected readonly rules: (SingleValueSelectedForFilterRule | OnlyFiltersSelectedRule | DegreeCountrySpecificRule | MasterOfEducationCountryDisciplineRule)[];
14
+ constructor(dependencies: IProgrammeSeoDependencies);
15
+ protected generateUrls(): Promise<string[]>;
16
+ get filterCombination(): FilterCombinations;
17
+ }
@@ -0,0 +1,75 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { DegreeCountrySpecificRule } from '../rules/DegreeCountrySpecificRule';
6
+ import { MasterOfEducationCountryDisciplineRule } from '../rules/MasterOfEducationCountryDisciplineRule';
7
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
8
+ import { DegreePresenter } from '../../presenters/DegreePresenter';
9
+ import { CountryPresenter } from '../../presenters/CountryPresenter';
10
+ import { DisciplinePresenter } from '../../presenters/DisciplinePresenter';
11
+ export class DegreeCountryDiscipline extends ProgrammesBaseIndexabilityPolicy {
12
+ name = 'Degree Country Discipline Policy';
13
+ description = 'Determines indexing rules for pages filtered by degree type, country, and discipline with specific degree-country combinations.';
14
+ filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.DISCIPLINES];
15
+ rules = [
16
+ new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
17
+ new SingleValueSelectedForFilterRule(FilterKey.COUNTRY),
18
+ new SingleValueSelectedForFilterRule(FilterKey.DISCIPLINES),
19
+ new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.DISCIPLINES]),
20
+ new DegreeCountrySpecificRule(),
21
+ new MasterOfEducationCountryDisciplineRule()
22
+ ];
23
+ constructor(dependencies) {
24
+ super(dependencies);
25
+ this.initateBaseRules();
26
+ }
27
+ async generateUrls() {
28
+ const degreeFragments = DegreePresenter.getInstance().getFragments();
29
+ const countryFragments = CountryPresenter.getInstance().getFragments();
30
+ const disciplineFragments = DisciplinePresenter.getInstance().getFragments();
31
+ const paths = [];
32
+ // Define allowed degrees and their corresponding country IDs
33
+ const degreeCountryMap = {
34
+ 'master-of-science': ['82', '32', '11', '30'], // USA, Canada, Germany, UK
35
+ 'master-of-business-administration': ['82', '30'], // USA, UK
36
+ 'master-of-education': ['202', '32'] // Australia, Canada
37
+ };
38
+ // Education discipline IDs for Master of Education
39
+ const educationDisciplineIds = [
40
+ '289', '290', '360', '291', '292', '333', '8', '349',
41
+ '293', '98', '371', '363', '355', '370', '348', '97',
42
+ '359', '345', '295', '358'
43
+ ];
44
+ for (const pageNumber of this.indexablePageNumbers) {
45
+ for (const [degreeId, allowedCountryIds] of Object.entries(degreeCountryMap)) {
46
+ const degree = degreeFragments.find(d => d.id === degreeId);
47
+ if (!degree)
48
+ continue;
49
+ const allowedCountries = countryFragments.filter(c => allowedCountryIds.includes(c.id));
50
+ // Filter disciplines based on degree type
51
+ let allowedDisciplines = disciplineFragments;
52
+ if (degreeId === 'master-of-education') {
53
+ allowedDisciplines = disciplineFragments.filter(d => educationDisciplineIds.includes(d.id));
54
+ }
55
+ for (const country of allowedCountries) {
56
+ for (const discipline of allowedDisciplines) {
57
+ const filterKeyValues = new Map([
58
+ [FilterKey.DEGREE_TYPE, [degree.id]],
59
+ [FilterKey.COUNTRY, [country.id]],
60
+ [FilterKey.DISCIPLINES, [discipline.id]]
61
+ ]);
62
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
63
+ if (result) {
64
+ paths.push(this.getPathWithPageNumber(`${degree.path}/${country.path}/${discipline.path}`, pageNumber));
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ return paths;
71
+ }
72
+ get filterCombination() {
73
+ return FilterCombinations.DEGREE_COUNTRY_DISCIPLINE;
74
+ }
75
+ }
@@ -0,0 +1,18 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
3
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
4
+ import { FilterCombinations } from '../../enums/FilterCombinations';
5
+ import { DegreeCountryTuitionFeeRule } from '../rules/DegreeCountryTuitionFeeRule';
6
+ import { MasterOfLawsCountryTuitionFeeRule } from '../rules/MasterOfLawsCountryTuitionFeeRule';
7
+ import { DegreeCountryTuitionFeeSpecificRule } from '../rules/DegreeCountryTuitionFeeSpecificRule';
8
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
9
+ import { IProgrammeSeoDependencies } from '../types/IProgrammeSeoDependencies';
10
+ export declare class DegreeCountryTuitionFee extends ProgrammesBaseIndexabilityPolicy {
11
+ readonly name: string;
12
+ readonly description: string;
13
+ readonly filterKeys: FilterKey[];
14
+ protected readonly rules: (SingleValueSelectedForFilterRule | OnlyFiltersSelectedRule | DegreeCountryTuitionFeeRule | MasterOfLawsCountryTuitionFeeRule | DegreeCountryTuitionFeeSpecificRule)[];
15
+ constructor(dependencies: IProgrammeSeoDependencies);
16
+ protected generateUrls(): Promise<string[]>;
17
+ get filterCombination(): FilterCombinations;
18
+ }
@@ -0,0 +1,81 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { TuitionFeeFilterOptionValue } from '@studyportals/search-filters';
3
+ import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
4
+ import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
5
+ import { FilterCombinations } from '../../enums/FilterCombinations';
6
+ import { DegreeCountryTuitionFeeRule } from '../rules/DegreeCountryTuitionFeeRule';
7
+ import { MasterOfLawsCountryTuitionFeeRule } from '../rules/MasterOfLawsCountryTuitionFeeRule';
8
+ import { DegreeCountryTuitionFeeSpecificRule } from '../rules/DegreeCountryTuitionFeeSpecificRule';
9
+ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
10
+ import { DegreePresenter } from '../../presenters/DegreePresenter';
11
+ import { CountryPresenter } from '../../presenters/CountryPresenter';
12
+ import { TuitionFeePresenter } from '../../presenters/TuitionFeePresenter';
13
+ export class DegreeCountryTuitionFee extends ProgrammesBaseIndexabilityPolicy {
14
+ name = 'Degree Country Tuition Fee Policy';
15
+ description = 'Determines indexing rules for pages filtered by degree type, country, and tuition fee.';
16
+ filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.TUITION_FEE];
17
+ rules = [
18
+ new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
19
+ new SingleValueSelectedForFilterRule(FilterKey.COUNTRY),
20
+ new SingleValueSelectedForFilterRule(FilterKey.TUITION_FEE),
21
+ new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.COUNTRY, FilterKey.TUITION_FEE]),
22
+ new DegreeCountryTuitionFeeSpecificRule(),
23
+ new DegreeCountryTuitionFeeRule(),
24
+ new MasterOfLawsCountryTuitionFeeRule()
25
+ ];
26
+ constructor(dependencies) {
27
+ super(dependencies);
28
+ this.initateBaseRules();
29
+ }
30
+ async generateUrls() {
31
+ const degreeFragments = DegreePresenter.getInstance().getFragments();
32
+ const countryFragments = CountryPresenter.getInstance().getFragments();
33
+ const tuitionFeeFragments = TuitionFeePresenter.getInstance().getFragments();
34
+ const paths = [];
35
+ // Process MBA with affordable tuition fee (all countries)
36
+ const mba = degreeFragments.find(d => d.id === 'master-of-business-administration');
37
+ // Process Master of Laws with affordable tuition fee (specific countries)
38
+ const llm = degreeFragments.find(d => d.id === 'master-of-laws');
39
+ const affordableTuition = tuitionFeeFragments.find(t => t.id === TuitionFeeFilterOptionValue.ZERO_TO_TWO_THOUSAND_FIVE_HUNDRED);
40
+ if (!affordableTuition) {
41
+ return paths;
42
+ }
43
+ // Allowed countries for Master of Laws
44
+ const llmAllowedCountryIds = ['82', '30', '32', '108']; // USA, UK, Canada, India
45
+ for (const pageNumber of this.indexablePageNumbers) {
46
+ // MBA + affordable tuition accepts all countries
47
+ if (mba) {
48
+ for (const country of countryFragments) {
49
+ const filterKeyValues = new Map([
50
+ [FilterKey.DEGREE_TYPE, [mba.id]],
51
+ [FilterKey.COUNTRY, [country.id]],
52
+ [FilterKey.TUITION_FEE, [affordableTuition.id]]
53
+ ]);
54
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
55
+ if (result) {
56
+ paths.push(this.getPathWithPageNumber(`${mba.path}/${country.path}/${affordableTuition.path}`, pageNumber));
57
+ }
58
+ }
59
+ }
60
+ // Master of Laws + affordable tuition accepts specific countries
61
+ if (llm) {
62
+ const llmCountries = countryFragments.filter(c => llmAllowedCountryIds.includes(c.id));
63
+ for (const country of llmCountries) {
64
+ const filterKeyValues = new Map([
65
+ [FilterKey.DEGREE_TYPE, [llm.id]],
66
+ [FilterKey.COUNTRY, [country.id]],
67
+ [FilterKey.TUITION_FEE, [affordableTuition.id]]
68
+ ]);
69
+ const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
70
+ if (result) {
71
+ paths.push(this.getPathWithPageNumber(`${llm.path}/${country.path}/${affordableTuition.path}`, pageNumber));
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return paths;
77
+ }
78
+ get filterCombination() {
79
+ return FilterCombinations.DEGREE_COUNTRY_TUITION_FEE;
80
+ }
81
+ }
@@ -0,0 +1,11 @@
1
+ import { ISearchDependencies } from '../../common/ISearchDependencies';
2
+ import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
3
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
4
+ export declare class DegreeAttendanceDisciplineRule extends BaseProgrammeRule {
5
+ private readonly allowedDegrees;
6
+ private readonly attendanceValue;
7
+ getName(): string;
8
+ getDescription(): string;
9
+ forSearch(dependencies: ISearchDependencies): Promise<boolean>;
10
+ forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
11
+ }
@@ -0,0 +1,45 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
3
+ export class DegreeAttendanceDisciplineRule extends BaseProgrammeRule {
4
+ // Degrees with online attendance that accept all disciplines
5
+ allowedDegrees = ['master-of-arts', 'master-of-science', 'master-of-business-administration'];
6
+ attendanceValue = 'online';
7
+ getName() {
8
+ return 'DegreeAttendanceDisciplineRule';
9
+ }
10
+ getDescription() {
11
+ return 'Indexes: master-of-arts (online) + all disciplines; master-of-science (online) + all disciplines; master-of-business-administration (online) + all disciplines';
12
+ }
13
+ forSearch(dependencies) {
14
+ const { seoInfoBase, filterState } = dependencies;
15
+ const degreeTypeValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DEGREE_TYPE, filterState);
16
+ const attendanceValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DELIVERY_METHOD, filterState);
17
+ const disciplineValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DISCIPLINES, filterState);
18
+ // This rule only applies to allowed degrees + online
19
+ if (!degreeTypeValue || !attendanceValue || !this.allowedDegrees.includes(degreeTypeValue) || attendanceValue !== this.attendanceValue) {
20
+ return Promise.resolve(true); // Rule doesn't apply to other combinations
21
+ }
22
+ // Must have a discipline selected
23
+ if (!disciplineValue) {
24
+ return Promise.resolve(false);
25
+ }
26
+ // Allowed degrees + online accept all disciplines
27
+ return Promise.resolve(true);
28
+ }
29
+ forSitemapGenerator(filterKeyValues) {
30
+ const degreeTypeValues = filterKeyValues.get(FilterKey.DEGREE_TYPE);
31
+ const attendanceValues = filterKeyValues.get(FilterKey.DELIVERY_METHOD);
32
+ const disciplineValues = filterKeyValues.get(FilterKey.DISCIPLINES);
33
+ if (!degreeTypeValues?.length || !attendanceValues?.length || !disciplineValues?.length) {
34
+ return Promise.resolve(false);
35
+ }
36
+ const degreeTypeValue = degreeTypeValues[0];
37
+ const attendanceValue = attendanceValues[0];
38
+ // This rule only applies to allowed degrees + online
39
+ if (!degreeTypeValue || !attendanceValue || !this.allowedDegrees.includes(degreeTypeValue) || attendanceValue !== this.attendanceValue) {
40
+ return Promise.resolve(true); // Rule doesn't apply to other combinations
41
+ }
42
+ // Allowed degrees + online accept all disciplines
43
+ return Promise.resolve(true);
44
+ }
45
+ }
@@ -0,0 +1,11 @@
1
+ import { ISearchDependencies } from '../../common/ISearchDependencies';
2
+ import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
3
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
4
+ export declare class DegreeAttendanceDisciplineSpecificRule extends BaseProgrammeRule {
5
+ private readonly allowedDegrees;
6
+ private readonly allowedAttendance;
7
+ getName(): string;
8
+ getDescription(): string;
9
+ forSearch(dependencies: ISearchDependencies): Promise<boolean>;
10
+ forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
11
+ }
@@ -0,0 +1,41 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
3
+ export class DegreeAttendanceDisciplineSpecificRule extends BaseProgrammeRule {
4
+ // Only specific degree types are allowed for this policy
5
+ allowedDegrees = [
6
+ 'master-of-science',
7
+ 'master-of-arts',
8
+ 'master-of-business-administration'
9
+ ];
10
+ // Only online attendance is allowed
11
+ allowedAttendance = 'online';
12
+ getName() {
13
+ return 'DegreeAttendanceDisciplineSpecificRule';
14
+ }
15
+ getDescription() {
16
+ return 'Only allows MSc, MA, and MBA degrees with online attendance for attendance+discipline combinations';
17
+ }
18
+ forSearch(dependencies) {
19
+ const { seoInfoBase, filterState } = dependencies;
20
+ const degreeTypeValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DEGREE_TYPE, filterState);
21
+ const attendanceValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DELIVERY_METHOD, filterState);
22
+ if (!degreeTypeValue || !attendanceValue) {
23
+ return Promise.resolve(false);
24
+ }
25
+ // Only allow specific degrees with online attendance
26
+ return Promise.resolve(this.allowedDegrees.includes(degreeTypeValue) &&
27
+ attendanceValue === this.allowedAttendance);
28
+ }
29
+ forSitemapGenerator(filterKeyValues) {
30
+ const degreeTypeValues = filterKeyValues.get(FilterKey.DEGREE_TYPE);
31
+ const attendanceValues = filterKeyValues.get(FilterKey.DELIVERY_METHOD);
32
+ if (!degreeTypeValues?.length || !attendanceValues?.length) {
33
+ return Promise.resolve(false);
34
+ }
35
+ const degreeTypeValue = degreeTypeValues[0];
36
+ const attendanceValue = attendanceValues[0];
37
+ // Only allow specific degrees with online attendance
38
+ return Promise.resolve(this.allowedDegrees.includes(degreeTypeValue) &&
39
+ attendanceValue === this.allowedAttendance);
40
+ }
41
+ }
@@ -0,0 +1,10 @@
1
+ import { ISearchDependencies } from '../../common/ISearchDependencies';
2
+ import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
3
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
4
+ export declare class DegreeAttendanceSpecificRule extends BaseProgrammeRule {
5
+ private readonly validCombinations;
6
+ getName(): string;
7
+ getDescription(): string;
8
+ forSearch(dependencies: ISearchDependencies): Promise<boolean>;
9
+ forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
10
+ }
@@ -0,0 +1,42 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
3
+ export class DegreeAttendanceSpecificRule extends BaseProgrammeRule {
4
+ validCombinations = {
5
+ 'master-of-science': ['online'], // MSc with online attendance
6
+ 'master-of-arts': ['online'], // MA with online attendance
7
+ 'master-of-business-administration': ['online'] // MBA with online attendance
8
+ };
9
+ getName() {
10
+ return 'DegreeAttendanceSpecificRule';
11
+ }
12
+ getDescription() {
13
+ return 'Indexes: master-of-science (online); master-of-arts (online); master-of-business-administration (online)';
14
+ }
15
+ forSearch(dependencies) {
16
+ const { seoInfoBase, filterState } = dependencies;
17
+ const degreeTypeValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DEGREE_TYPE, filterState);
18
+ const attendanceValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DELIVERY_METHOD, filterState);
19
+ if (!degreeTypeValue || !attendanceValue) {
20
+ return Promise.resolve(false);
21
+ }
22
+ const allowedAttendance = this.validCombinations[degreeTypeValue];
23
+ if (!allowedAttendance) {
24
+ return Promise.resolve(false);
25
+ }
26
+ return Promise.resolve(allowedAttendance.includes(attendanceValue));
27
+ }
28
+ forSitemapGenerator(filterKeyValues) {
29
+ const degreeTypeValues = filterKeyValues.get(FilterKey.DEGREE_TYPE);
30
+ const attendanceValues = filterKeyValues.get(FilterKey.DELIVERY_METHOD);
31
+ if (!degreeTypeValues?.length || !attendanceValues?.length) {
32
+ return Promise.resolve(false);
33
+ }
34
+ const degreeTypeValue = degreeTypeValues[0];
35
+ const attendanceValue = attendanceValues[0];
36
+ const allowedAttendance = this.validCombinations[degreeTypeValue];
37
+ if (!allowedAttendance) {
38
+ return Promise.resolve(false);
39
+ }
40
+ return Promise.resolve(allowedAttendance.includes(attendanceValue));
41
+ }
42
+ }
@@ -0,0 +1,10 @@
1
+ import { ISearchDependencies } from '../../common/ISearchDependencies';
2
+ import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
3
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
4
+ export declare class DegreeCountryAttendanceSpecificRule extends BaseProgrammeRule {
5
+ private readonly allowedDegrees;
6
+ getName(): string;
7
+ getDescription(): string;
8
+ forSearch(dependencies: ISearchDependencies): Promise<boolean>;
9
+ forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
10
+ }
@@ -0,0 +1,34 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
3
+ export class DegreeCountryAttendanceSpecificRule extends BaseProgrammeRule {
4
+ // Only specific degree types are allowed for this policy
5
+ allowedDegrees = [
6
+ 'master-of-business-administration',
7
+ 'master-of-laws',
8
+ 'master-of-philosophy'
9
+ ];
10
+ getName() {
11
+ return 'DegreeCountryAttendanceSpecificRule';
12
+ }
13
+ getDescription() {
14
+ return 'Only allows MBA, LLM, and MPhil degrees for country+attendance combinations';
15
+ }
16
+ forSearch(dependencies) {
17
+ const { seoInfoBase, filterState } = dependencies;
18
+ const degreeTypeValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DEGREE_TYPE, filterState);
19
+ if (!degreeTypeValue) {
20
+ return Promise.resolve(false);
21
+ }
22
+ // Only allow specific degrees
23
+ return Promise.resolve(this.allowedDegrees.includes(degreeTypeValue));
24
+ }
25
+ forSitemapGenerator(filterKeyValues) {
26
+ const degreeTypeValues = filterKeyValues.get(FilterKey.DEGREE_TYPE);
27
+ if (!degreeTypeValues?.length) {
28
+ return Promise.resolve(false);
29
+ }
30
+ const degreeTypeValue = degreeTypeValues[0];
31
+ // Only allow specific degrees
32
+ return Promise.resolve(this.allowedDegrees.includes(degreeTypeValue));
33
+ }
34
+ }
@@ -0,0 +1,10 @@
1
+ import { ISearchDependencies } from '../../common/ISearchDependencies';
2
+ import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
3
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
4
+ export declare class DegreeCountrySpecificRule extends BaseProgrammeRule {
5
+ private readonly validCombinations;
6
+ getName(): string;
7
+ getDescription(): string;
8
+ forSearch(dependencies: ISearchDependencies): Promise<boolean>;
9
+ forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
10
+ }
@@ -0,0 +1,42 @@
1
+ import { FilterKey } from '@studyportals/search-filters';
2
+ import { BaseProgrammeRule } from '../BaseProgrammeRule';
3
+ export class DegreeCountrySpecificRule extends BaseProgrammeRule {
4
+ validCombinations = {
5
+ 'master-of-science': ['82', '32', '11', '30'], // USA, Canada, Germany, UK
6
+ 'master-of-business-administration': ['82', '30'], // USA, UK
7
+ 'master-of-education': ['202', '32'] // Australia, Canada
8
+ };
9
+ getName() {
10
+ return 'DegreeCountrySpecificRule';
11
+ }
12
+ getDescription() {
13
+ return 'Indexes: master-of-science (USA, Canada, Germany, UK); master-of-business-administration (USA, UK); master-of-education (Australia, Canada)';
14
+ }
15
+ forSearch(dependencies) {
16
+ const { seoInfoBase, filterState } = dependencies;
17
+ const degreeTypeValue = seoInfoBase.getFilterOptionValueBy(FilterKey.DEGREE_TYPE, filterState);
18
+ const countryValue = seoInfoBase.getFilterOptionValueBy(FilterKey.COUNTRY, filterState);
19
+ if (!degreeTypeValue || !countryValue) {
20
+ return Promise.resolve(false);
21
+ }
22
+ const allowedCountries = this.validCombinations[degreeTypeValue];
23
+ if (!allowedCountries) {
24
+ return Promise.resolve(false);
25
+ }
26
+ return Promise.resolve(allowedCountries.includes(countryValue));
27
+ }
28
+ forSitemapGenerator(filterKeyValues) {
29
+ const degreeTypeValues = filterKeyValues.get(FilterKey.DEGREE_TYPE);
30
+ const countryValues = filterKeyValues.get(FilterKey.COUNTRY);
31
+ if (!degreeTypeValues?.length || !countryValues?.length) {
32
+ return Promise.resolve(false);
33
+ }
34
+ const degreeTypeValue = degreeTypeValues[0];
35
+ const countryValue = countryValues[0];
36
+ const allowedCountries = this.validCombinations[degreeTypeValue];
37
+ if (!allowedCountries) {
38
+ return Promise.resolve(false);
39
+ }
40
+ return Promise.resolve(allowedCountries.includes(countryValue));
41
+ }
42
+ }