@studyportals/fawkes 8.7.2 → 9.0.0
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.
- package/README.md +176 -176
- package/dist/sitemap-generator-seo/index.d.ts +1 -1
- package/dist/src/common/FilterKeyToFilterTypeMap.d.ts +2 -0
- package/dist/src/common/FilterKeyToFilterTypeMap.js +14 -0
- package/dist/src/common/FilterTypeMap.d.ts +2 -0
- package/dist/src/common/FilterTypeMap.js +1 -0
- package/dist/src/organisations/SearchIndexabilityManager.js +1 -2
- package/dist/src/organisations/policies/RankedOrganisationsSeoIndexabilityPolicy.js +1 -1
- package/dist/src/organisations/policies/index.d.ts +0 -1
- package/dist/src/organisations/policies/index.js +0 -1
- package/dist/src/organisations/policies/our-picks/AreaAttendance.js +16 -14
- package/dist/src/organisations/policies/our-picks/CountryAttendance.js +15 -13
- package/dist/src/organisations/policies/ranked/RankedArea.js +1 -1
- package/dist/src/organisations/policies/ranked/RankedAreaDiscipline.d.ts +1 -0
- package/dist/src/organisations/policies/ranked/RankedAreaDiscipline.js +1 -0
- package/dist/src/organisations/policies/ranked/RankedAttendance.js +3 -1
- package/dist/src/organisations/policies/ranked/RankedAttendanceDiscipline.js +2 -1
- package/dist/src/organisations/policies/ranked/RankedContinent.js +3 -1
- package/dist/src/organisations/policies/ranked/RankedContinentAttendance.js +15 -13
- package/dist/src/organisations/policies/ranked/RankedCountry.js +3 -1
- package/dist/src/organisations/policies/ranked/RankedCountryAttendance.js +1 -0
- package/dist/src/organisations/policies/ranked/RankedCountryDiscipline.js +30 -14
- package/dist/src/organisations/policies/ranked/RankedDiscipline.js +14 -8
- package/dist/src/organisations/policies/ranked/RankedUnfiltered.js +10 -4
- package/dist/src/organisations/rules/MinimumAmountOfRankedResultsRule.d.ts +3 -4
- package/dist/src/organisations/rules/MinimumAmountOfRankedResultsRule.js +12 -8
- package/dist/src/organisations/types/IOrganisationsSitemapDependencies.d.ts +0 -2
- package/dist/src/programmes/policies/CountryAttendanceDegree.js +1 -1
- package/dist/src/programmes/policies/CountryDurationDegree.js +1 -1
- package/dist/src/programmes/policies/CountryEducationalForm.js +1 -1
- package/dist/src/programmes/policies/DegreeAttendanceTuitionFee.d.ts +1 -1
- package/dist/src/programmes/policies/DegreeAttendanceTuitionFee.js +6 -6
- package/dist/src/programmes/policies/DegreeContinentTuitionFee.d.ts +1 -1
- package/dist/src/programmes/policies/DegreeContinentTuitionFee.js +6 -6
- package/dist/src/programmes/policies/DegreeFormatTuitionFee.js +5 -5
- package/dist/src/programmes/policies/DisciplineCountryEducationalForm.js +1 -1
- package/dist/src/programmes/policies/DisciplineEducationalForm.js +1 -1
- package/dist/src/sitemap-generator/ISearchApiClient.d.ts +1 -0
- package/dist/src/sitemap-generator/OrganisationsSitemapUrlGeneratorManager.d.ts +1 -2
- package/dist/src/sitemap-generator/OrganisationsSitemapUrlGeneratorManager.js +2 -4
- package/package.json +106 -105
|
@@ -5,6 +5,7 @@ import { OnlyFiltersSelectedRule } from '../../../common/rules/OnlyFiltersSelect
|
|
|
5
5
|
import { CountryPresenter } from '../../../presenters/CountryPresenter';
|
|
6
6
|
import { DisciplinePresenter } from '../../../presenters/DisciplinePresenter';
|
|
7
7
|
import { RankedOrganisationsSeoIndexabilityPolicy } from '../RankedOrganisationsSeoIndexabilityPolicy';
|
|
8
|
+
const DEFAULT_CONCURRENT_REQUESTS = 20; // Maximum number of concurrent requests to avoid rate limiting
|
|
8
9
|
export class RankedCountryDiscipline extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
9
10
|
name = 'Ranked Country Discipline Policy';
|
|
10
11
|
description = 'Determines which ranking-sorted pages at the intersection of country and discipline filters qualify for indexing based on search value.';
|
|
@@ -17,22 +18,37 @@ export class RankedCountryDiscipline extends RankedOrganisationsSeoIndexabilityP
|
|
|
17
18
|
super(dependencies);
|
|
18
19
|
}
|
|
19
20
|
async generateUrls() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
21
|
+
try {
|
|
22
|
+
const countryFragments = CountryPresenter.getInstance().getFragments();
|
|
23
|
+
const disciplineFragments = DisciplinePresenter.getInstance().getFragments();
|
|
24
|
+
const paths = [];
|
|
25
|
+
const configuredConcurrency = Number.parseInt(process.env.SITEMAP_COMBINATION_CONCURRENCY
|
|
26
|
+
|| DEFAULT_CONCURRENT_REQUESTS.toString(), 10);
|
|
27
|
+
const concurrencyLimit = Math.max(1, configuredConcurrency); // Ensure at least 1
|
|
28
|
+
// Create all combinations
|
|
29
|
+
const combinations = countryFragments.flatMap(country => disciplineFragments.map(discipline => ({ country, discipline })));
|
|
30
|
+
// Process in batches to respect API rate limits
|
|
31
|
+
for (let i = 0; i < combinations.length; i += concurrencyLimit) {
|
|
32
|
+
const batch = combinations.slice(i, i + concurrencyLimit);
|
|
33
|
+
const results = await Promise.all(batch.map(async ({ country, discipline }) => {
|
|
34
|
+
const filterKeyValues = new Map([
|
|
35
|
+
[FilterKey.COUNTRY, [country.id]],
|
|
36
|
+
[FilterKey.DISCIPLINES, [discipline.id]]
|
|
37
|
+
]);
|
|
38
|
+
const result = await this.checkRulesForSitemap(filterKeyValues);
|
|
39
|
+
if (result) {
|
|
40
|
+
return this.getPathWithSortingOption(`${country.path}/${discipline.path}`);
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}));
|
|
44
|
+
paths.push(...results.filter((path) => path !== null));
|
|
33
45
|
}
|
|
46
|
+
return paths;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error('Error generating URLs for RankedCountryDiscipline:', error);
|
|
50
|
+
return [];
|
|
34
51
|
}
|
|
35
|
-
return paths;
|
|
36
52
|
}
|
|
37
53
|
get filterCombination() {
|
|
38
54
|
return FilterCombinations.RANKED_DISCIPLINE_COUNTRY;
|
|
@@ -15,16 +15,22 @@ export class RankedDiscipline extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
|
15
15
|
super(dependencies);
|
|
16
16
|
}
|
|
17
17
|
async generateUrls() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
try {
|
|
19
|
+
const disciplineFragments = DisciplinePresenter.getInstance().getFragments();
|
|
20
|
+
const paths = [];
|
|
21
|
+
for (const discipline of disciplineFragments) {
|
|
22
|
+
const filterKeyValues = new Map([[FilterKey.DISCIPLINES, [discipline.id]]]);
|
|
23
|
+
const result = await this.checkRulesForSitemap(filterKeyValues);
|
|
24
|
+
if (result) {
|
|
25
|
+
paths.push(this.getPathWithSortingOption(discipline.path));
|
|
26
|
+
}
|
|
25
27
|
}
|
|
28
|
+
return paths;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('Error generating URLs for RankedDiscipline:', error);
|
|
32
|
+
return [];
|
|
26
33
|
}
|
|
27
|
-
return paths;
|
|
28
34
|
}
|
|
29
35
|
get filterCombination() {
|
|
30
36
|
return FilterCombinations.RANKED_DISCIPLINE;
|
|
@@ -9,11 +9,17 @@ export class RankedUnfiltered extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
|
9
9
|
super(dependencies);
|
|
10
10
|
}
|
|
11
11
|
async generateUrls() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
try {
|
|
13
|
+
const filterKeyValues = new Map([]);
|
|
14
|
+
if (await this.checkRulesForSitemap(filterKeyValues)) {
|
|
15
|
+
return [this.getPathWithSortingOption('')];
|
|
16
|
+
}
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.error('Error generating URLs for RankedUnfiltered:', error);
|
|
21
|
+
return [];
|
|
15
22
|
}
|
|
16
|
-
return [];
|
|
17
23
|
}
|
|
18
24
|
get filterCombination() {
|
|
19
25
|
return FilterCombinations.RANKED_UNFILTERED;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { IRule } from '../../common/IRule';
|
|
2
2
|
import { IOrganisationSearchDependencies } from '../types/IOrganisationSearchDependencies';
|
|
3
|
-
import { FilterKeyValuesMap } from '
|
|
4
|
-
import { IRankingApiClient } from '../../sitemap-generator/IRankingApiClient';
|
|
3
|
+
import { FilterKeyValuesMap, ISearchApiClient } from '../../../sitemap-generator-seo';
|
|
5
4
|
export declare class MinimumAmountOfRankedResultsRule implements IRule {
|
|
6
5
|
private readonly minimumRankedResultsCount;
|
|
7
|
-
private readonly
|
|
8
|
-
constructor(
|
|
6
|
+
private readonly searchApiClient?;
|
|
7
|
+
constructor(searchApiClient?: ISearchApiClient);
|
|
9
8
|
forSearch(dependencies: IOrganisationSearchDependencies): Promise<boolean>;
|
|
10
9
|
forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
|
|
11
10
|
getName(): string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DependencyMissingError } from '../../errors/DependencyMissingError';
|
|
2
2
|
export class MinimumAmountOfRankedResultsRule {
|
|
3
|
-
minimumRankedResultsCount =
|
|
4
|
-
|
|
5
|
-
constructor(
|
|
6
|
-
this.
|
|
3
|
+
minimumRankedResultsCount = 4;
|
|
4
|
+
searchApiClient;
|
|
5
|
+
constructor(searchApiClient) {
|
|
6
|
+
this.searchApiClient = searchApiClient;
|
|
7
7
|
}
|
|
8
8
|
forSearch(dependencies) {
|
|
9
9
|
const { applicationState } = dependencies;
|
|
@@ -11,14 +11,18 @@ export class MinimumAmountOfRankedResultsRule {
|
|
|
11
11
|
return Promise.resolve(rankedResultsCount >= this.minimumRankedResultsCount);
|
|
12
12
|
}
|
|
13
13
|
async forSitemapGenerator(filterKeyValues) {
|
|
14
|
-
if (!this.
|
|
15
|
-
throw new DependencyMissingError('
|
|
14
|
+
if (!this.searchApiClient) {
|
|
15
|
+
throw new DependencyMissingError('SearchApiClient');
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
if (!this.searchApiClient.getCountWithRankings) {
|
|
18
|
+
const filterKeys = [...filterKeyValues.keys()];
|
|
19
|
+
throw new DependencyMissingError(`CountwithRankings ${filterKeys.join(',')}`);
|
|
20
|
+
}
|
|
21
|
+
const rankedResultsCount = await this.searchApiClient.getCountWithRankings(filterKeyValues);
|
|
18
22
|
return rankedResultsCount >= this.minimumRankedResultsCount;
|
|
19
23
|
}
|
|
20
24
|
getName() {
|
|
21
|
-
return '
|
|
25
|
+
return 'AtLeastFourRankedResultsRule';
|
|
22
26
|
}
|
|
23
27
|
getDescription() {
|
|
24
28
|
return `At least ${this.minimumRankedResultsCount} ranked results are available`;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { ISitemapDependencies } from '../../common/ISitemapDependencies';
|
|
2
|
-
import { IRankingApiClient } from '../../sitemap-generator/IRankingApiClient';
|
|
3
2
|
import { PortalType } from '@studyportals/domain-client';
|
|
4
3
|
import { IOrganisationsClient } from '../../sitemap-generator/IOrganisationsClient';
|
|
5
4
|
export interface IOrganisationsSitemapDependencies extends ISitemapDependencies {
|
|
6
5
|
organisationsClient: IOrganisationsClient;
|
|
7
6
|
portalType: PortalType;
|
|
8
|
-
rankingApiClient: IRankingApiClient;
|
|
9
7
|
}
|
|
@@ -10,7 +10,7 @@ import { AttendancePresenter } from '../../presenters/AttendancePresenter';
|
|
|
10
10
|
import { DegreePresenter } from '../../presenters/DegreePresenter';
|
|
11
11
|
export class CountryAttendanceDegree extends ProgrammesBaseIndexabilityPolicy {
|
|
12
12
|
name = 'Country Attendance Degree Policy';
|
|
13
|
-
description = `Determines indexing rules for pages filtered by country,
|
|
13
|
+
description = `Determines indexing rules for pages filtered by country,
|
|
14
14
|
study format (online, on-campus, etc.), and degree type.`;
|
|
15
15
|
filterKeys = [FilterKey.COUNTRY, FilterKey.DELIVERY_METHOD, FilterKey.DEGREE_TYPE];
|
|
16
16
|
rules = [
|
|
@@ -10,7 +10,7 @@ import { DegreePresenter } from '../../presenters/DegreePresenter';
|
|
|
10
10
|
import { DurationPresenter } from '../../presenters/DurationPresenter';
|
|
11
11
|
export class CountryDurationDegree extends ProgrammesBaseIndexabilityPolicy {
|
|
12
12
|
name = 'Country Duration Degree Policy';
|
|
13
|
-
description = `Determines indexing rules for pages filtered by country,
|
|
13
|
+
description = `Determines indexing rules for pages filtered by country,
|
|
14
14
|
duration (1 year, 2 years, etc.), and degree type.`;
|
|
15
15
|
filterKeys = [FilterKey.COUNTRY, FilterKey.DURATION, FilterKey.DEGREE_TYPE];
|
|
16
16
|
rules = [
|
|
@@ -8,7 +8,7 @@ import { CountryPresenter } from '../../presenters/CountryPresenter';
|
|
|
8
8
|
import { EducationalFormPresenter } from '../../presenters/EducationalFormPresenter';
|
|
9
9
|
export class CountryEducationalForm extends ProgrammesBaseIndexabilityPolicy {
|
|
10
10
|
name = 'Country Educational Form Policy';
|
|
11
|
-
description = `Determines indexing rules for pages filtered by both country,
|
|
11
|
+
description = `Determines indexing rules for pages filtered by both country,
|
|
12
12
|
and educational form (academic, semester, summer school, etc.).`;
|
|
13
13
|
filterKeys = [FilterKey.COUNTRY, FilterKey.EDUCATIONAL_FORM];
|
|
14
14
|
rules;
|
|
@@ -3,7 +3,7 @@ import { FilterCombinations } from '../../enums/FilterCombinations';
|
|
|
3
3
|
import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
|
|
4
4
|
import { IProgrammeSeoDependencies } from '../types/IProgrammeSeoDependencies';
|
|
5
5
|
import { IRule } from '../../common/IRule';
|
|
6
|
-
export declare class
|
|
6
|
+
export declare class DegreeTuitionFeeAttendance extends ProgrammesBaseIndexabilityPolicy {
|
|
7
7
|
readonly name: string;
|
|
8
8
|
readonly description: string;
|
|
9
9
|
readonly filterKeys: FilterKey[];
|
|
@@ -10,19 +10,19 @@ import { AttendancePresenter } from '../../presenters/AttendancePresenter';
|
|
|
10
10
|
import { OnlineAttendanceRule } from '../../common/rules/OnlineAttendanceRule';
|
|
11
11
|
import { IndexableDegreeRule } from '../rules/IndexableDegreeRule';
|
|
12
12
|
import { AffordableTuitionFeeRule } from '../rules/AffordableTuitionFeeRule';
|
|
13
|
-
export class
|
|
13
|
+
export class DegreeTuitionFeeAttendance extends ProgrammesBaseIndexabilityPolicy {
|
|
14
14
|
name = 'Tuition Fee Attendance Degree Policy';
|
|
15
15
|
description = 'Determines indexing rules for pages filtered by tuition fee, attendance, and degree type.';
|
|
16
|
-
filterKeys = [FilterKey.
|
|
16
|
+
filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.DELIVERY_METHOD];
|
|
17
17
|
rules;
|
|
18
18
|
constructor(dependencies) {
|
|
19
19
|
super(dependencies);
|
|
20
20
|
const portalType = dependencies.portalType;
|
|
21
21
|
this.rules = [
|
|
22
22
|
new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
|
|
23
|
-
new SingleValueSelectedForFilterRule(FilterKey.DELIVERY_METHOD),
|
|
24
23
|
new SingleValueSelectedForFilterRule(FilterKey.TUITION_FEE),
|
|
25
|
-
new
|
|
24
|
+
new SingleValueSelectedForFilterRule(FilterKey.DELIVERY_METHOD),
|
|
25
|
+
new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.DELIVERY_METHOD]),
|
|
26
26
|
new IndexableDegreeRule(portalType),
|
|
27
27
|
new OnlineAttendanceRule(),
|
|
28
28
|
new AffordableTuitionFeeRule()
|
|
@@ -42,9 +42,9 @@ export class DegreeAttendanceTuitionFee extends ProgrammesBaseIndexabilityPolicy
|
|
|
42
42
|
for (const degree of degreeFragments) {
|
|
43
43
|
for (const attendance of attendanceFragments) {
|
|
44
44
|
const filterKeyValues = new Map([
|
|
45
|
-
[FilterKey.DELIVERY_METHOD, [attendance.id]],
|
|
46
45
|
[FilterKey.DEGREE_TYPE, [degree.id]],
|
|
47
|
-
[FilterKey.TUITION_FEE, [affordableTuition.id]]
|
|
46
|
+
[FilterKey.TUITION_FEE, [affordableTuition.id]],
|
|
47
|
+
[FilterKey.DELIVERY_METHOD, [attendance.id]]
|
|
48
48
|
]);
|
|
49
49
|
const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
|
|
50
50
|
if (result) {
|
|
@@ -3,7 +3,7 @@ import { FilterCombinations } from '../../enums/FilterCombinations';
|
|
|
3
3
|
import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityPolicy';
|
|
4
4
|
import { IProgrammeSeoDependencies } from '../types/IProgrammeSeoDependencies';
|
|
5
5
|
import { IRule } from '../../common/IRule';
|
|
6
|
-
export declare class
|
|
6
|
+
export declare class DegreeTuitionFeeContinent extends ProgrammesBaseIndexabilityPolicy {
|
|
7
7
|
readonly name: string;
|
|
8
8
|
readonly description: string;
|
|
9
9
|
readonly filterKeys: FilterKey[];
|
|
@@ -7,10 +7,10 @@ import { ProgrammesBaseIndexabilityPolicy } from '../ProgrammesBaseIndexabilityP
|
|
|
7
7
|
import { DegreePresenter } from '../../presenters/DegreePresenter';
|
|
8
8
|
import { ContinentPresenter } from '../../presenters/ContinentPresenter';
|
|
9
9
|
import { TuitionFeePresenter } from '../../presenters/TuitionFeePresenter';
|
|
10
|
-
export class
|
|
11
|
-
name = 'Degree
|
|
12
|
-
description = 'Determines indexing rules for pages filtered by degree type,
|
|
13
|
-
filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.
|
|
10
|
+
export class DegreeTuitionFeeContinent extends ProgrammesBaseIndexabilityPolicy {
|
|
11
|
+
name = 'Degree Tuition Fee Continent Policy';
|
|
12
|
+
description = 'Determines indexing rules for pages filtered by degree type, tuition fee, and continent.';
|
|
13
|
+
filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.CONTINENT];
|
|
14
14
|
rules;
|
|
15
15
|
constructor(dependencies) {
|
|
16
16
|
super(dependencies);
|
|
@@ -19,7 +19,7 @@ export class DegreeContinentTuitionFee extends ProgrammesBaseIndexabilityPolicy
|
|
|
19
19
|
new SingleValueSelectedForFilterRule(FilterKey.CONTINENT),
|
|
20
20
|
new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
|
|
21
21
|
new SingleValueSelectedForFilterRule(FilterKey.TUITION_FEE),
|
|
22
|
-
new OnlyFiltersSelectedRule([FilterKey.
|
|
22
|
+
new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.CONTINENT]),
|
|
23
23
|
new IndexableDegreeRule(portalType)
|
|
24
24
|
];
|
|
25
25
|
this.initateBaseRules();
|
|
@@ -34,9 +34,9 @@ export class DegreeContinentTuitionFee extends ProgrammesBaseIndexabilityPolicy
|
|
|
34
34
|
for (const degree of degreeFragments) {
|
|
35
35
|
for (const tuitionFee of tuitionFeeFragments) {
|
|
36
36
|
const filterKeyValues = new Map([
|
|
37
|
-
[FilterKey.CONTINENT, [continent.id]],
|
|
38
37
|
[FilterKey.DEGREE_TYPE, [degree.id]],
|
|
39
38
|
[FilterKey.TUITION_FEE, [tuitionFee.id]],
|
|
39
|
+
[FilterKey.CONTINENT, [continent.id]],
|
|
40
40
|
]);
|
|
41
41
|
const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
|
|
42
42
|
if (result) {
|
|
@@ -12,16 +12,16 @@ import { PartTimeFormatRule } from '../rules/PartTimeFormatRule';
|
|
|
12
12
|
export class DegreeFormatTuitionFee extends ProgrammesBaseIndexabilityPolicy {
|
|
13
13
|
name = 'Degree Format Tuition Fee Policy';
|
|
14
14
|
description = 'Determines indexing rules for pages filtered by degree type, format and tuition fee.';
|
|
15
|
-
filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.
|
|
15
|
+
filterKeys = [FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.ATTENDANCE];
|
|
16
16
|
rules;
|
|
17
17
|
constructor(dependencies) {
|
|
18
18
|
super(dependencies);
|
|
19
19
|
const portalType = dependencies.portalType;
|
|
20
20
|
this.rules = [
|
|
21
|
-
new SingleValueSelectedForFilterRule(FilterKey.ATTENDANCE),
|
|
22
21
|
new SingleValueSelectedForFilterRule(FilterKey.DEGREE_TYPE),
|
|
23
22
|
new SingleValueSelectedForFilterRule(FilterKey.TUITION_FEE),
|
|
24
|
-
new
|
|
23
|
+
new SingleValueSelectedForFilterRule(FilterKey.ATTENDANCE),
|
|
24
|
+
new OnlyFiltersSelectedRule([FilterKey.DEGREE_TYPE, FilterKey.TUITION_FEE, FilterKey.ATTENDANCE]),
|
|
25
25
|
new IndexableDegreeRule(portalType),
|
|
26
26
|
new AffordableTuitionFeeRule(),
|
|
27
27
|
new PartTimeFormatRule()
|
|
@@ -38,9 +38,9 @@ export class DegreeFormatTuitionFee extends ProgrammesBaseIndexabilityPolicy {
|
|
|
38
38
|
for (const degree of degreeFragments) {
|
|
39
39
|
for (const tuitionFee of tuitionFeeFragments) {
|
|
40
40
|
const filterKeyValues = new Map([
|
|
41
|
-
[FilterKey.ATTENDANCE, [format.id]],
|
|
42
41
|
[FilterKey.DEGREE_TYPE, [degree.id]],
|
|
43
|
-
[FilterKey.TUITION_FEE, [tuitionFee.id]]
|
|
42
|
+
[FilterKey.TUITION_FEE, [tuitionFee.id]],
|
|
43
|
+
[FilterKey.ATTENDANCE, [format.id]],
|
|
44
44
|
]);
|
|
45
45
|
const result = await this.checkRulesForSitemapWithPageNumber(filterKeyValues, pageNumber);
|
|
46
46
|
if (result) {
|
|
@@ -9,7 +9,7 @@ import { CountryPresenter } from '../../presenters/CountryPresenter';
|
|
|
9
9
|
import { EducationalFormPresenter } from '../../presenters/EducationalFormPresenter';
|
|
10
10
|
export class DisciplineCountryEducationalForm extends ProgrammesBaseIndexabilityPolicy {
|
|
11
11
|
name = 'Discipline Country Educational Form Policy';
|
|
12
|
-
description = `Determines indexing rules for pages filtered by discipline,
|
|
12
|
+
description = `Determines indexing rules for pages filtered by discipline,
|
|
13
13
|
country, and educational form (academic, semester, summer school, etc.).`;
|
|
14
14
|
filterKeys = [FilterKey.DISCIPLINES, FilterKey.COUNTRY, FilterKey.EDUCATIONAL_FORM];
|
|
15
15
|
rules;
|
|
@@ -8,7 +8,7 @@ import { DisciplinePresenter } from '../../presenters/DisciplinePresenter';
|
|
|
8
8
|
import { EducationalFormPresenter } from '../../presenters/EducationalFormPresenter';
|
|
9
9
|
export class DisciplineEducationalForm extends ProgrammesBaseIndexabilityPolicy {
|
|
10
10
|
name = 'Discipline Educational Form Policy';
|
|
11
|
-
description = `Determines indexing rules for pages filtered by both discipline,
|
|
11
|
+
description = `Determines indexing rules for pages filtered by both discipline,
|
|
12
12
|
and educational form (academic, semester, summer school, etc.).`;
|
|
13
13
|
filterKeys = [FilterKey.DISCIPLINES, FilterKey.EDUCATIONAL_FORM];
|
|
14
14
|
rules;
|
|
@@ -11,4 +11,5 @@ export interface ISearchApiClient {
|
|
|
11
11
|
}[]>;
|
|
12
12
|
getProgrammeCount?(filterKeyValues: FilterKeyValuesMap): Promise<number>;
|
|
13
13
|
getCount(filterKeyValues: FilterKeyValuesMap): Promise<number>;
|
|
14
|
+
getCountWithRankings?(filterKeyValues: FilterKeyValuesMap): Promise<number>;
|
|
14
15
|
}
|
|
@@ -3,12 +3,11 @@ import { IOrganisationsClient } from '../sitemap-generator/IOrganisationsClient'
|
|
|
3
3
|
import { ISearchApiClient } from '../sitemap-generator/ISearchApiClient';
|
|
4
4
|
import { BaseSitemapUrlGeneratorManager } from './BaseSitemapUrlGeneratorManager';
|
|
5
5
|
import { PortalType } from '@studyportals/domain-client';
|
|
6
|
-
import { IRankingApiClient } from './IRankingApiClient';
|
|
7
6
|
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
8
7
|
import { IPresenter } from '../common';
|
|
9
8
|
export declare class OrganisationsSitemapUrlGeneratorManager extends BaseSitemapUrlGeneratorManager {
|
|
10
9
|
readonly portalType: PortalType;
|
|
11
10
|
readonly policies: ISitemapUrlGenerator[];
|
|
12
11
|
readonly presenters: Map<FilterKey, IPresenter>;
|
|
13
|
-
constructor(portalType: PortalType, searchApiClient: ISearchApiClient, organisationsClient: IOrganisationsClient
|
|
12
|
+
constructor(portalType: PortalType, searchApiClient: ISearchApiClient, organisationsClient: IOrganisationsClient);
|
|
14
13
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DependencyTypes } from '../enums/DependencyTypes';
|
|
2
2
|
import { BaseSitemapUrlGeneratorManager } from './BaseSitemapUrlGeneratorManager';
|
|
3
|
-
import { Area, AreaAttendance, Attendance, Continent, Country, CountryCity, CountryAttendance, RankedArea,
|
|
3
|
+
import { Area, AreaAttendance, Attendance, Continent, Country, CountryCity, CountryAttendance, RankedArea, RankedAttendance, RankedAttendanceDiscipline, RankedContinent, RankedContinentAttendance, RankedCountry, RankedCountryAttendance, RankedCountryDiscipline, RankedDiscipline, RankedUnfiltered, Unfiltered } from '../organisations/policies';
|
|
4
4
|
import { AreaPresenter } from '../presenters/AreaPresenter';
|
|
5
5
|
import { AttendancePresenter } from '../presenters/AttendancePresenter';
|
|
6
6
|
import { ContinentPresenter } from '../presenters/ContinentPresenter';
|
|
@@ -12,7 +12,7 @@ export class OrganisationsSitemapUrlGeneratorManager extends BaseSitemapUrlGener
|
|
|
12
12
|
portalType;
|
|
13
13
|
policies;
|
|
14
14
|
presenters = new Map();
|
|
15
|
-
constructor(portalType, searchApiClient, organisationsClient
|
|
15
|
+
constructor(portalType, searchApiClient, organisationsClient) {
|
|
16
16
|
super();
|
|
17
17
|
this.portalType = portalType;
|
|
18
18
|
const dependencies = {
|
|
@@ -20,7 +20,6 @@ export class OrganisationsSitemapUrlGeneratorManager extends BaseSitemapUrlGener
|
|
|
20
20
|
portalType,
|
|
21
21
|
searchApiClient,
|
|
22
22
|
organisationsClient,
|
|
23
|
-
rankingApiClient
|
|
24
23
|
};
|
|
25
24
|
this.policies = [
|
|
26
25
|
new CountryCity(dependencies),
|
|
@@ -33,7 +32,6 @@ export class OrganisationsSitemapUrlGeneratorManager extends BaseSitemapUrlGener
|
|
|
33
32
|
new CountryAttendance(dependencies),
|
|
34
33
|
new Unfiltered(dependencies),
|
|
35
34
|
new RankedArea(dependencies),
|
|
36
|
-
new RankedAreaDiscipline(dependencies),
|
|
37
35
|
new RankedAttendance(dependencies),
|
|
38
36
|
new RankedAttendanceDiscipline(dependencies),
|
|
39
37
|
new RankedContinent(dependencies),
|
package/package.json
CHANGED
|
@@ -1,105 +1,106 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@studyportals/fawkes",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A package to centralize SEO related logic for SBLP and Sitemap Generator.",
|
|
5
|
-
"files": [
|
|
6
|
-
"./dist"
|
|
7
|
-
],
|
|
8
|
-
"scripts": {
|
|
9
|
-
"prepush": "npm run test",
|
|
10
|
-
"precommit": "npm run lint",
|
|
11
|
-
"compile": "npx tsc && tsc-alias && rm -r ./dist/tests",
|
|
12
|
-
"build": "npm run clean && npm run compile",
|
|
13
|
-
"clean": "rimraf \"!(node_modules)/**/dist\"",
|
|
14
|
-
"prepare-deployment": "npm run test && npm run build",
|
|
15
|
-
"publish-major": "npm run prepare-deployment && npm version major && npm publish",
|
|
16
|
-
"publish-beta": "npm run prepare-deployment && npm version prerelease && npm publish --tag beta --access=public",
|
|
17
|
-
"publish-patch": "npm run prepare-deployment && npm version patch && npm publish",
|
|
18
|
-
"publish-minor": "npm run prepare-deployment && npm version minor && npm publish",
|
|
19
|
-
"prepare": "husky install",
|
|
20
|
-
"test": "vitest run --coverage",
|
|
21
|
-
"test:dev": "vitest --coverage tests/programmes",
|
|
22
|
-
"lint": "eslint . --ext .ts",
|
|
23
|
-
"lint:fix": "eslint . --ext .ts --fix",
|
|
24
|
-
"prettier:fix": "npx prettier --use-tabs --ignore-path .gitignore --write ."
|
|
25
|
-
},
|
|
26
|
-
"exports": {
|
|
27
|
-
"./organisations-search-seo": {
|
|
28
|
-
"import": "./dist/organisations-seo/index.js",
|
|
29
|
-
"require": "./dist/organisations-seo/index.js",
|
|
30
|
-
"types": "./dist/organisations-seo/index.d.ts"
|
|
31
|
-
},
|
|
32
|
-
"./programmes-search-seo": {
|
|
33
|
-
"import": "./dist/programmes-seo/index.js",
|
|
34
|
-
"require": "./dist/programmes-seo/index.js",
|
|
35
|
-
"types": "./dist/programmes-seo/index.d.ts"
|
|
36
|
-
},
|
|
37
|
-
"./scholarships-search-seo": {
|
|
38
|
-
"import": "./dist/scholarships-seo/index.js",
|
|
39
|
-
"require": "./dist/scholarships-seo/index.js",
|
|
40
|
-
"types": "./dist/scholarships-seo/index.d.ts"
|
|
41
|
-
},
|
|
42
|
-
"./sitemap-generator-seo": {
|
|
43
|
-
"import": "./dist/sitemap-generator-seo/index.js",
|
|
44
|
-
"require": "./dist/sitemap-generator-seo/index.js",
|
|
45
|
-
"types": "./dist/sitemap-generator-seo/index.d.ts"
|
|
46
|
-
},
|
|
47
|
-
"./structured-data-seo": {
|
|
48
|
-
"import": "./dist/structured-data-seo/index.js",
|
|
49
|
-
"require": "./dist/structured-data-seo/index.js",
|
|
50
|
-
"types": "./dist/structured-data-seo/index.d.ts"
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"typesVersions": {
|
|
54
|
-
"*": {
|
|
55
|
-
"organisations-search-seo": [
|
|
56
|
-
"dist/organisations-seo/index.d.ts"
|
|
57
|
-
],
|
|
58
|
-
"programmes-search-seo": [
|
|
59
|
-
"dist/programmes-seo/index.d.ts"
|
|
60
|
-
],
|
|
61
|
-
"scholarships-search-seo": [
|
|
62
|
-
"dist/scholarships-seo/index.d.ts"
|
|
63
|
-
],
|
|
64
|
-
"sitemap-generator-seo": [
|
|
65
|
-
"dist/sitemap-generator-seo/index.d.ts"
|
|
66
|
-
],
|
|
67
|
-
"structured-data-seo": [
|
|
68
|
-
"dist/structured-data-seo/index.d.ts"
|
|
69
|
-
],
|
|
70
|
-
"*": [
|
|
71
|
-
"dist/index.d.ts"
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"author": "The Jedi Council",
|
|
76
|
-
"license": "ISC",
|
|
77
|
-
"devDependencies": {
|
|
78
|
-
"@adobe/structured-data-validator": "^1.4.1",
|
|
79
|
-
"@studyportals/code-style": "^2.2.1",
|
|
80
|
-
"@studyportals/webpack-helper": "^6.0.6",
|
|
81
|
-
"@vitest/coverage-istanbul": "^2.1.8",
|
|
82
|
-
"husky": "^8.0.3",
|
|
83
|
-
"jsdom": "^26.0.0",
|
|
84
|
-
"prettier": "^3.5.3",
|
|
85
|
-
"schema-dts": "^1.1.5",
|
|
86
|
-
"ts-loader": "^9.5.2",
|
|
87
|
-
"tsc-alias": "^1.8.11",
|
|
88
|
-
"typemoq": "^2.1.0",
|
|
89
|
-
"typescript": "^5.7.3",
|
|
90
|
-
"vitest": "^2.1.8"
|
|
91
|
-
},
|
|
92
|
-
"dependencies": {
|
|
93
|
-
"@studyportals/domain-client": "^8.
|
|
94
|
-
"@studyportals/ranking-api-interface": "^
|
|
95
|
-
"@studyportals/search-
|
|
96
|
-
"@studyportals/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@studyportals/fawkes",
|
|
3
|
+
"version": "9.0.0",
|
|
4
|
+
"description": "A package to centralize SEO related logic for SBLP and Sitemap Generator.",
|
|
5
|
+
"files": [
|
|
6
|
+
"./dist"
|
|
7
|
+
],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"prepush": "npm run test",
|
|
10
|
+
"precommit": "npm run lint",
|
|
11
|
+
"compile": "npx tsc && tsc-alias && rm -r ./dist/tests",
|
|
12
|
+
"build": "npm run clean && npm run compile",
|
|
13
|
+
"clean": "rimraf \"!(node_modules)/**/dist\"",
|
|
14
|
+
"prepare-deployment": "npm run test && npm run build",
|
|
15
|
+
"publish-major": "npm run prepare-deployment && npm version major && npm publish",
|
|
16
|
+
"publish-beta": "npm run prepare-deployment && npm version prerelease && npm publish --tag beta --access=public",
|
|
17
|
+
"publish-patch": "npm run prepare-deployment && npm version patch && npm publish",
|
|
18
|
+
"publish-minor": "npm run prepare-deployment && npm version minor && npm publish",
|
|
19
|
+
"prepare": "husky install",
|
|
20
|
+
"test": "vitest run --coverage",
|
|
21
|
+
"test:dev": "vitest --coverage tests/programmes",
|
|
22
|
+
"lint": "eslint . --ext .ts",
|
|
23
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
24
|
+
"prettier:fix": "npx prettier --use-tabs --ignore-path .gitignore --write ."
|
|
25
|
+
},
|
|
26
|
+
"exports": {
|
|
27
|
+
"./organisations-search-seo": {
|
|
28
|
+
"import": "./dist/organisations-seo/index.js",
|
|
29
|
+
"require": "./dist/organisations-seo/index.js",
|
|
30
|
+
"types": "./dist/organisations-seo/index.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./programmes-search-seo": {
|
|
33
|
+
"import": "./dist/programmes-seo/index.js",
|
|
34
|
+
"require": "./dist/programmes-seo/index.js",
|
|
35
|
+
"types": "./dist/programmes-seo/index.d.ts"
|
|
36
|
+
},
|
|
37
|
+
"./scholarships-search-seo": {
|
|
38
|
+
"import": "./dist/scholarships-seo/index.js",
|
|
39
|
+
"require": "./dist/scholarships-seo/index.js",
|
|
40
|
+
"types": "./dist/scholarships-seo/index.d.ts"
|
|
41
|
+
},
|
|
42
|
+
"./sitemap-generator-seo": {
|
|
43
|
+
"import": "./dist/sitemap-generator-seo/index.js",
|
|
44
|
+
"require": "./dist/sitemap-generator-seo/index.js",
|
|
45
|
+
"types": "./dist/sitemap-generator-seo/index.d.ts"
|
|
46
|
+
},
|
|
47
|
+
"./structured-data-seo": {
|
|
48
|
+
"import": "./dist/structured-data-seo/index.js",
|
|
49
|
+
"require": "./dist/structured-data-seo/index.js",
|
|
50
|
+
"types": "./dist/structured-data-seo/index.d.ts"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"typesVersions": {
|
|
54
|
+
"*": {
|
|
55
|
+
"organisations-search-seo": [
|
|
56
|
+
"dist/organisations-seo/index.d.ts"
|
|
57
|
+
],
|
|
58
|
+
"programmes-search-seo": [
|
|
59
|
+
"dist/programmes-seo/index.d.ts"
|
|
60
|
+
],
|
|
61
|
+
"scholarships-search-seo": [
|
|
62
|
+
"dist/scholarships-seo/index.d.ts"
|
|
63
|
+
],
|
|
64
|
+
"sitemap-generator-seo": [
|
|
65
|
+
"dist/sitemap-generator-seo/index.d.ts"
|
|
66
|
+
],
|
|
67
|
+
"structured-data-seo": [
|
|
68
|
+
"dist/structured-data-seo/index.d.ts"
|
|
69
|
+
],
|
|
70
|
+
"*": [
|
|
71
|
+
"dist/index.d.ts"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"author": "The Jedi Council",
|
|
76
|
+
"license": "ISC",
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@adobe/structured-data-validator": "^1.4.1",
|
|
79
|
+
"@studyportals/code-style": "^2.2.1",
|
|
80
|
+
"@studyportals/webpack-helper": "^6.0.6",
|
|
81
|
+
"@vitest/coverage-istanbul": "^2.1.8",
|
|
82
|
+
"husky": "^8.0.3",
|
|
83
|
+
"jsdom": "^26.0.0",
|
|
84
|
+
"prettier": "^3.5.3",
|
|
85
|
+
"schema-dts": "^1.1.5",
|
|
86
|
+
"ts-loader": "^9.5.2",
|
|
87
|
+
"tsc-alias": "^1.8.11",
|
|
88
|
+
"typemoq": "^2.1.0",
|
|
89
|
+
"typescript": "^5.7.3",
|
|
90
|
+
"vitest": "^2.1.8"
|
|
91
|
+
},
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"@studyportals/domain-client": "^8.1.0",
|
|
94
|
+
"@studyportals/ranking-api-interface": "^2.4.0",
|
|
95
|
+
"@studyportals/search-api-interface": "5.9.3-0",
|
|
96
|
+
"@studyportals/search-filters": "^6.3.1",
|
|
97
|
+
"@studyportals/static-domain-data": "^6.1.0"
|
|
98
|
+
},
|
|
99
|
+
"optionalDependencies": {
|
|
100
|
+
"@rollup/rollup-linux-x64-gnu": "4.24.0"
|
|
101
|
+
},
|
|
102
|
+
"engines": {
|
|
103
|
+
"node": ">=18 <=24",
|
|
104
|
+
"npm": ">=8 <=11"
|
|
105
|
+
}
|
|
106
|
+
}
|