@studyportals/fawkes 8.5.0 → 8.5.1-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.
- package/README.md +176 -176
- package/dist/sitemap-generator-seo/index.d.ts +1 -0
- package/dist/sitemap-generator-seo/index.js +1 -0
- package/dist/src/enums/PageTypes.d.ts +4 -0
- package/dist/src/enums/PageTypes.js +5 -0
- 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/DisciplineArea.d.ts +1 -1
- package/dist/src/programmes/policies/DisciplineArea.js +1 -1
- package/dist/src/programmes/policies/DisciplineCountryEducationalForm.js +1 -1
- package/dist/src/programmes/policies/DisciplineEducationalForm.js +1 -1
- package/dist/src/programmes/rules/ErasmusOrJointSpecialProgrammesRule.js +2 -2
- package/dist/src/structured-data/SearchStructuredDataFactory.d.ts +2 -1
- package/dist/src/structured-data/SearchStructuredDataFactory.js +8 -2
- package/package.json +105 -105
- package/dist/src/enums/AttendanceFilterOptionValue.d.ts +0 -5
- package/dist/src/enums/AttendanceFilterOptionValue.js +0 -6
- package/dist/src/enums/DegreeTypeFilterOptionValue.d.ts +0 -29
- package/dist/src/enums/DegreeTypeFilterOptionValue.js +0 -30
- package/dist/src/enums/DurationFilterOptionValue.d.ts +0 -16
- package/dist/src/enums/DurationFilterOptionValue.js +0 -17
- package/dist/src/enums/EducationalFormFilterOptionValue.d.ts +0 -8
- package/dist/src/enums/EducationalFormFilterOptionValue.js +0 -9
- package/dist/src/enums/FilterKey.d.ts +0 -21
- package/dist/src/enums/FilterKey.js +0 -22
- package/dist/src/enums/FormatFilterOptionValue.d.ts +0 -4
- package/dist/src/enums/FormatFilterOptionValue.js +0 -5
- package/dist/src/enums/SpecialProgrammesFilterOptionValue.d.ts +0 -5
- package/dist/src/enums/SpecialProgrammesFilterOptionValue.js +0 -6
- package/dist/src/enums/TuitionFeeFilterOptionValue.d.ts +0 -3
- package/dist/src/enums/TuitionFeeFilterOptionValue.js +0 -4
- package/dist/src/organisations/policies/our-picks/City.d.ts +0 -12
- package/dist/src/organisations/policies/our-picks/City.js +0 -35
- package/dist/src/organisations/policies/ranked/RankedCountryAreaCity.d.ts +0 -11
- package/dist/src/organisations/policies/ranked/RankedCountryAreaCity.js +0 -42
- package/dist/src/organisations/policies/ranked/RankedCountryCity.d.ts +0 -11
- package/dist/src/organisations/policies/ranked/RankedCountryCity.js +0 -36
- package/dist/src/organisations/rules/AtLeastTwoRankedResultsRule.d.ts +0 -13
- package/dist/src/organisations/rules/AtLeastTwoRankedResultsRule.js +0 -26
- package/dist/src/organisations/rules/OnlyFullLocationFiltersSelectedRule.d.ts +0 -10
- package/dist/src/organisations/rules/OnlyFullLocationFiltersSelectedRule.js +0 -31
- package/dist/src/programmes/rules/AtLeastSevenResultsRule.d.ts +0 -15
- package/dist/src/programmes/rules/AtLeastSevenResultsRule.js +0 -30
package/README.md
CHANGED
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
# fawkes
|
|
2
|
-
|
|
3
|
-
This project is used to centralize indexability logic for our Search
|
|
4
|
-
microservices and Sitemap Generator. The main purpose is to completely remove
|
|
5
|
-
discrepancies between pages indexed by Search and page URLs stored in Sitemap.
|
|
6
|
-
|
|
7
|
-
Link to documentation: https://studyportals.atlassian.net/wiki/x/BwAdvw
|
|
8
|
-
|
|
9
|
-
## Base structure
|
|
10
|
-
|
|
11
|
-
- organisations-seo (used by Organisation Search)
|
|
12
|
-
- scholarships-seo (used by Scholarship Search)
|
|
13
|
-
- sitemap-generator-seo (used by Sitemap Generator)
|
|
14
|
-
- src
|
|
15
|
-
- common
|
|
16
|
-
- organisations
|
|
17
|
-
- scholarships
|
|
18
|
-
- sitemap-generator
|
|
19
|
-
|
|
20
|
-
# Automatic Documentation System
|
|
21
|
-
|
|
22
|
-
## Overview
|
|
23
|
-
|
|
24
|
-
This system automatically generates and maintains documentation for Fawkes
|
|
25
|
-
indexing rules across multiple projects. It creates a hierarchical structure of
|
|
26
|
-
Confluence pages that document all indexing policies and rules, ensuring that
|
|
27
|
-
the documentation is always up-to-date with the actual codebase.
|
|
28
|
-
|
|
29
|
-
Link to documentation:
|
|
30
|
-
[Fawkes Indexing Rules Documentation](https://studyportals.atlassian.net/wiki/spaces/T/pages/3494969354/Fawkes+Indexing+Rules+Documentation)
|
|
31
|
-
|
|
32
|
-
## Features
|
|
33
|
-
|
|
34
|
-
- **Dynamic Documentation**: Automatically extracts indexing rules and policies
|
|
35
|
-
directly from the codebase
|
|
36
|
-
- **Multi-Page Structure**: Creates a main index page with separate pages for
|
|
37
|
-
each project
|
|
38
|
-
- **Hierarchical Organization**: Structures content as Projects → Policies →
|
|
39
|
-
Rules
|
|
40
|
-
- **Automatic Page Creation**: Intelligently creates or updates pages as needed
|
|
41
|
-
- **Cross-Page Navigation**: Provides intuitive navigation between all pages
|
|
42
|
-
|
|
43
|
-
## Architecture
|
|
44
|
-
|
|
45
|
-
The system follows SOLID design principles to ensure maintainability and
|
|
46
|
-
extensibility:
|
|
47
|
-
|
|
48
|
-
- **Single Responsibility**: Each class has one specific responsibility
|
|
49
|
-
- **Open/Closed**: Easily extendable without modifying existing code
|
|
50
|
-
- **Liskov Substitution**: Interchangeable components through well-defined
|
|
51
|
-
interfaces
|
|
52
|
-
- **Interface Segregation**: Clean, focused interfaces
|
|
53
|
-
- **Dependency Inversion**: High-level modules depend on abstractions
|
|
54
|
-
|
|
55
|
-
### Key Components
|
|
56
|
-
|
|
57
|
-
1. **Content Builder**: Extracts project, policy, and rule data from the Fawkes
|
|
58
|
-
system
|
|
59
|
-
2. **Policy Fetchers**: Project-specific components that fetch and format policy
|
|
60
|
-
data
|
|
61
|
-
3. **Document Builder**: Generates structured HTML content for Confluence pages
|
|
62
|
-
4. **Confluence Updater**: Handles creation and updating of Confluence pages
|
|
63
|
-
5. **Token Retriever**: Securely retrieves API token for Confluence access
|
|
64
|
-
|
|
65
|
-
## How It Works
|
|
66
|
-
|
|
67
|
-
1. The system starts by collecting all project data using the `ContentBuilder`
|
|
68
|
-
2. For each project, it extracts policies and rules using project-specific
|
|
69
|
-
fetchers
|
|
70
|
-
3. The `DocumentBuilder` generates the content for the main index page and each
|
|
71
|
-
project page
|
|
72
|
-
4. The `ConfluenceUpdater` creates or updates pages in Confluence as needed
|
|
73
|
-
5. Each project page links back to the main index, and the main index links to
|
|
74
|
-
all project pages
|
|
75
|
-
|
|
76
|
-
## Setup and Configuration
|
|
77
|
-
|
|
78
|
-
### Environment Variables
|
|
79
|
-
|
|
80
|
-
The system requires the following environment variables:
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
CONFLUENCE_EMAIL=your-email@example.com
|
|
84
|
-
CONFLUENCE_API_TOKEN=your-api-token
|
|
85
|
-
CONFLUENCE_BASE_URL=https://your-instance.atlassian.net
|
|
86
|
-
CONFLUENCE_SPACE_KEY=YOUR_SPACE_KEY
|
|
87
|
-
CONFLUENCE_MAIN_PAGE_TITLE=Fawkes Indexing Rules Documentation
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
> **Important Note on Credentials**: Currently, the system uses personal
|
|
91
|
-
> credentials (email and API token) for Confluence access. This is a temporary
|
|
92
|
-
> solution and should be replaced with a team or service account in the future
|
|
93
|
-
> to avoid dependency on a specific individual's account.
|
|
94
|
-
|
|
95
|
-
### Deployment and Triggering
|
|
96
|
-
|
|
97
|
-
The system runs as an AWS Lambda function and is automatically triggered as part
|
|
98
|
-
of the CI/CD pipeline. This ensures documentation is always updated whenever new
|
|
99
|
-
code is deployed:
|
|
100
|
-
|
|
101
|
-
```yaml
|
|
102
|
-
# buildspec.yml (excerpt)
|
|
103
|
-
post_build:
|
|
104
|
-
commands:
|
|
105
|
-
- |
|
|
106
|
-
if [ -z "$PR_ID" ]; then
|
|
107
|
-
LAMBDA_NAME="FawkesConfluenceUpdater-$STAGE"
|
|
108
|
-
echo "Invoking Lambda function $LAMBDA_NAME"
|
|
109
|
-
echo '{"source":"cicd-pipeline","timestamp":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"}' > payload.json
|
|
110
|
-
aws lambda invoke --function-name $LAMBDA_NAME --invocation-type Event --payload fileb://payload.json response.json || echo "Lambda invocation failed, but continuing"
|
|
111
|
-
fi
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Trigger Flow:**
|
|
115
|
-
|
|
116
|
-
1. When code is pushed to the `main` branch, the CI/CD pipeline is triggered
|
|
117
|
-
2. After successful deployment of a new Fawkes version, the post-build phase
|
|
118
|
-
executes
|
|
119
|
-
3. The Lambda function is invoked with a simple payload containing the source
|
|
120
|
-
and timestamp
|
|
121
|
-
4. The Lambda function authenticates with Confluence and executes the
|
|
122
|
-
documentation generation process
|
|
123
|
-
5. This only happens for production deployments (not PR builds)
|
|
124
|
-
|
|
125
|
-
This automated approach ensures documentation stays in sync with the actual
|
|
126
|
-
codebase without manual intervention.
|
|
127
|
-
|
|
128
|
-
## Scalability and Extension
|
|
129
|
-
|
|
130
|
-
### Adding New Projects
|
|
131
|
-
|
|
132
|
-
To add documentation for a new project:
|
|
133
|
-
|
|
134
|
-
1. Create a new class that implements the `IPolicyFetcher` interface
|
|
135
|
-
2. Implement the `getProjectName()` and `fetchPolicies()` methods
|
|
136
|
-
3. Register the new fetcher in the `ContentBuilder` constructor
|
|
137
|
-
|
|
138
|
-
Example:
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
export class NewProjectPolicyFetcher implements IPolicyFetcher {
|
|
142
|
-
getProjectName(): string {
|
|
143
|
-
return 'New Project Name';
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
fetchPolicies(): IPolicy[] {
|
|
147
|
-
// Implement policy fetching logic
|
|
148
|
-
return [...policies];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Then update ContentBuilder:
|
|
153
|
-
constructor(fetchers?: IPolicyFetcher[]) {
|
|
154
|
-
this.policyFetchers = fetchers || [
|
|
155
|
-
// Existing fetchers
|
|
156
|
-
new NewProjectPolicyFetcher()
|
|
157
|
-
];
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Customizing Page Content
|
|
162
|
-
|
|
163
|
-
The `DocumentBuilder` class contains methods for generating page content. To
|
|
164
|
-
customize the format:
|
|
165
|
-
|
|
166
|
-
1. Modify the `buildMainDocument()` method for changes to the main index page
|
|
167
|
-
2. Modify the `buildProjectDocument()` method for changes to project pages
|
|
168
|
-
3. Modify the `buildPolicySection()` and `buildRulesTable()` methods for changes
|
|
169
|
-
to policy and rule sections
|
|
170
|
-
|
|
171
|
-
## Conclusion
|
|
172
|
-
|
|
173
|
-
This documentation system ensures that Fawkes indexing rules are always
|
|
174
|
-
well-documented and accessible to the team. By automatically generating
|
|
175
|
-
documentation directly from the codebase, it eliminates the risk of
|
|
176
|
-
documentation becoming outdated or inconsistent with the actual implementation.
|
|
1
|
+
# fawkes
|
|
2
|
+
|
|
3
|
+
This project is used to centralize indexability logic for our Search
|
|
4
|
+
microservices and Sitemap Generator. The main purpose is to completely remove
|
|
5
|
+
discrepancies between pages indexed by Search and page URLs stored in Sitemap.
|
|
6
|
+
|
|
7
|
+
Link to documentation: https://studyportals.atlassian.net/wiki/x/BwAdvw
|
|
8
|
+
|
|
9
|
+
## Base structure
|
|
10
|
+
|
|
11
|
+
- organisations-seo (used by Organisation Search)
|
|
12
|
+
- scholarships-seo (used by Scholarship Search)
|
|
13
|
+
- sitemap-generator-seo (used by Sitemap Generator)
|
|
14
|
+
- src
|
|
15
|
+
- common
|
|
16
|
+
- organisations
|
|
17
|
+
- scholarships
|
|
18
|
+
- sitemap-generator
|
|
19
|
+
|
|
20
|
+
# Automatic Documentation System
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
This system automatically generates and maintains documentation for Fawkes
|
|
25
|
+
indexing rules across multiple projects. It creates a hierarchical structure of
|
|
26
|
+
Confluence pages that document all indexing policies and rules, ensuring that
|
|
27
|
+
the documentation is always up-to-date with the actual codebase.
|
|
28
|
+
|
|
29
|
+
Link to documentation:
|
|
30
|
+
[Fawkes Indexing Rules Documentation](https://studyportals.atlassian.net/wiki/spaces/T/pages/3494969354/Fawkes+Indexing+Rules+Documentation)
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **Dynamic Documentation**: Automatically extracts indexing rules and policies
|
|
35
|
+
directly from the codebase
|
|
36
|
+
- **Multi-Page Structure**: Creates a main index page with separate pages for
|
|
37
|
+
each project
|
|
38
|
+
- **Hierarchical Organization**: Structures content as Projects → Policies →
|
|
39
|
+
Rules
|
|
40
|
+
- **Automatic Page Creation**: Intelligently creates or updates pages as needed
|
|
41
|
+
- **Cross-Page Navigation**: Provides intuitive navigation between all pages
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
The system follows SOLID design principles to ensure maintainability and
|
|
46
|
+
extensibility:
|
|
47
|
+
|
|
48
|
+
- **Single Responsibility**: Each class has one specific responsibility
|
|
49
|
+
- **Open/Closed**: Easily extendable without modifying existing code
|
|
50
|
+
- **Liskov Substitution**: Interchangeable components through well-defined
|
|
51
|
+
interfaces
|
|
52
|
+
- **Interface Segregation**: Clean, focused interfaces
|
|
53
|
+
- **Dependency Inversion**: High-level modules depend on abstractions
|
|
54
|
+
|
|
55
|
+
### Key Components
|
|
56
|
+
|
|
57
|
+
1. **Content Builder**: Extracts project, policy, and rule data from the Fawkes
|
|
58
|
+
system
|
|
59
|
+
2. **Policy Fetchers**: Project-specific components that fetch and format policy
|
|
60
|
+
data
|
|
61
|
+
3. **Document Builder**: Generates structured HTML content for Confluence pages
|
|
62
|
+
4. **Confluence Updater**: Handles creation and updating of Confluence pages
|
|
63
|
+
5. **Token Retriever**: Securely retrieves API token for Confluence access
|
|
64
|
+
|
|
65
|
+
## How It Works
|
|
66
|
+
|
|
67
|
+
1. The system starts by collecting all project data using the `ContentBuilder`
|
|
68
|
+
2. For each project, it extracts policies and rules using project-specific
|
|
69
|
+
fetchers
|
|
70
|
+
3. The `DocumentBuilder` generates the content for the main index page and each
|
|
71
|
+
project page
|
|
72
|
+
4. The `ConfluenceUpdater` creates or updates pages in Confluence as needed
|
|
73
|
+
5. Each project page links back to the main index, and the main index links to
|
|
74
|
+
all project pages
|
|
75
|
+
|
|
76
|
+
## Setup and Configuration
|
|
77
|
+
|
|
78
|
+
### Environment Variables
|
|
79
|
+
|
|
80
|
+
The system requires the following environment variables:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
CONFLUENCE_EMAIL=your-email@example.com
|
|
84
|
+
CONFLUENCE_API_TOKEN=your-api-token
|
|
85
|
+
CONFLUENCE_BASE_URL=https://your-instance.atlassian.net
|
|
86
|
+
CONFLUENCE_SPACE_KEY=YOUR_SPACE_KEY
|
|
87
|
+
CONFLUENCE_MAIN_PAGE_TITLE=Fawkes Indexing Rules Documentation
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> **Important Note on Credentials**: Currently, the system uses personal
|
|
91
|
+
> credentials (email and API token) for Confluence access. This is a temporary
|
|
92
|
+
> solution and should be replaced with a team or service account in the future
|
|
93
|
+
> to avoid dependency on a specific individual's account.
|
|
94
|
+
|
|
95
|
+
### Deployment and Triggering
|
|
96
|
+
|
|
97
|
+
The system runs as an AWS Lambda function and is automatically triggered as part
|
|
98
|
+
of the CI/CD pipeline. This ensures documentation is always updated whenever new
|
|
99
|
+
code is deployed:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
# buildspec.yml (excerpt)
|
|
103
|
+
post_build:
|
|
104
|
+
commands:
|
|
105
|
+
- |
|
|
106
|
+
if [ -z "$PR_ID" ]; then
|
|
107
|
+
LAMBDA_NAME="FawkesConfluenceUpdater-$STAGE"
|
|
108
|
+
echo "Invoking Lambda function $LAMBDA_NAME"
|
|
109
|
+
echo '{"source":"cicd-pipeline","timestamp":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"}' > payload.json
|
|
110
|
+
aws lambda invoke --function-name $LAMBDA_NAME --invocation-type Event --payload fileb://payload.json response.json || echo "Lambda invocation failed, but continuing"
|
|
111
|
+
fi
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Trigger Flow:**
|
|
115
|
+
|
|
116
|
+
1. When code is pushed to the `main` branch, the CI/CD pipeline is triggered
|
|
117
|
+
2. After successful deployment of a new Fawkes version, the post-build phase
|
|
118
|
+
executes
|
|
119
|
+
3. The Lambda function is invoked with a simple payload containing the source
|
|
120
|
+
and timestamp
|
|
121
|
+
4. The Lambda function authenticates with Confluence and executes the
|
|
122
|
+
documentation generation process
|
|
123
|
+
5. This only happens for production deployments (not PR builds)
|
|
124
|
+
|
|
125
|
+
This automated approach ensures documentation stays in sync with the actual
|
|
126
|
+
codebase without manual intervention.
|
|
127
|
+
|
|
128
|
+
## Scalability and Extension
|
|
129
|
+
|
|
130
|
+
### Adding New Projects
|
|
131
|
+
|
|
132
|
+
To add documentation for a new project:
|
|
133
|
+
|
|
134
|
+
1. Create a new class that implements the `IPolicyFetcher` interface
|
|
135
|
+
2. Implement the `getProjectName()` and `fetchPolicies()` methods
|
|
136
|
+
3. Register the new fetcher in the `ContentBuilder` constructor
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
export class NewProjectPolicyFetcher implements IPolicyFetcher {
|
|
142
|
+
getProjectName(): string {
|
|
143
|
+
return 'New Project Name';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fetchPolicies(): IPolicy[] {
|
|
147
|
+
// Implement policy fetching logic
|
|
148
|
+
return [...policies];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Then update ContentBuilder:
|
|
153
|
+
constructor(fetchers?: IPolicyFetcher[]) {
|
|
154
|
+
this.policyFetchers = fetchers || [
|
|
155
|
+
// Existing fetchers
|
|
156
|
+
new NewProjectPolicyFetcher()
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Customizing Page Content
|
|
162
|
+
|
|
163
|
+
The `DocumentBuilder` class contains methods for generating page content. To
|
|
164
|
+
customize the format:
|
|
165
|
+
|
|
166
|
+
1. Modify the `buildMainDocument()` method for changes to the main index page
|
|
167
|
+
2. Modify the `buildProjectDocument()` method for changes to project pages
|
|
168
|
+
3. Modify the `buildPolicySection()` and `buildRulesTable()` methods for changes
|
|
169
|
+
to policy and rule sections
|
|
170
|
+
|
|
171
|
+
## Conclusion
|
|
172
|
+
|
|
173
|
+
This documentation system ensures that Fawkes indexing rules are always
|
|
174
|
+
well-documented and accessible to the team. By automatically generating
|
|
175
|
+
documentation directly from the codebase, it eliminates the risk of
|
|
176
|
+
documentation becoming outdated or inconsistent with the actual implementation.
|
|
@@ -7,6 +7,7 @@ export { OrganisationsSitemapUrlGeneratorManager } from '../src/sitemap-generato
|
|
|
7
7
|
export { ScholarshipsSitemapUrlGeneratorManager } from '../src/sitemap-generator/ScholarshipsSitemapUrlGeneratorManager';
|
|
8
8
|
export { ProgrammesSitemapUrlGeneratorManager } from '../src/sitemap-generator/ProgrammesSitemapUrlGeneratorManager';
|
|
9
9
|
export { FilterCombinations } from '../src/enums/FilterCombinations';
|
|
10
|
+
export { PageTypes } from '../src/enums/PageTypes';
|
|
10
11
|
export { ISitemapUrlGenerator } from '../src/common/ISitemapUrlGenerator';
|
|
11
12
|
export { FilterKeyValuesMap } from '../src/common/FilterKeyValuesMap';
|
|
12
13
|
export { IPresenter } from '../src/common';
|
|
@@ -2,3 +2,4 @@ export { OrganisationsSitemapUrlGeneratorManager } from '../src/sitemap-generato
|
|
|
2
2
|
export { ScholarshipsSitemapUrlGeneratorManager } from '../src/sitemap-generator/ScholarshipsSitemapUrlGeneratorManager';
|
|
3
3
|
export { ProgrammesSitemapUrlGeneratorManager } from '../src/sitemap-generator/ProgrammesSitemapUrlGeneratorManager';
|
|
4
4
|
export { FilterCombinations } from '../src/enums/FilterCombinations';
|
|
5
|
+
export { PageTypes } from '../src/enums/PageTypes';
|
|
@@ -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 = [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FilterKey } from
|
|
1
|
+
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
2
2
|
import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
|
|
3
3
|
import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
|
|
4
4
|
import { FilterCombinations } from '../../enums/FilterCombinations';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FilterKey } from
|
|
1
|
+
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
2
2
|
import { OnlyFiltersSelectedRule } from '../../common/rules/OnlyFiltersSelectedRule';
|
|
3
3
|
import { SingleValueSelectedForFilterRule } from '../../common/rules/SingleValueSelectedForFilterRule';
|
|
4
4
|
import { FilterCombinations } from '../../enums/FilterCombinations';
|
|
@@ -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 = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FilterKey } from
|
|
1
|
+
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
2
|
+
import { SpecialProgrammesFilterOptionValue } from '@studyportals/search-filters/server-side';
|
|
2
3
|
import { BaseProgrammeRule } from '../BaseProgrammeRule';
|
|
3
|
-
import { SpecialProgrammesFilterOptionValue } from "../../enums/SpecialProgrammesFilterOptionValue";
|
|
4
4
|
export class ErasmusOrJointSpecialProgrammesRule extends BaseProgrammeRule {
|
|
5
5
|
forSearch(dependencies) {
|
|
6
6
|
const { seoInfoBase, filterState } = dependencies;
|
|
@@ -5,8 +5,9 @@ import { EntityDTO } from './dto/EntityDTO';
|
|
|
5
5
|
import { FAQItemDto } from './dto/FAQItemDto';
|
|
6
6
|
import { BreadcrumbDTO } from './dto/BreadcrumbDTO';
|
|
7
7
|
import { PaywallDTO } from './dto/PaywallDTO';
|
|
8
|
+
import { PageTypes } from '../enums/PageTypes';
|
|
8
9
|
export declare abstract class SearchStructuredDataFactory<TCard> {
|
|
9
|
-
buildStructuredData(title: string, description: string, cards: TCard[], faqItems?: FAQItemDto[], breadcrumbs?: BreadcrumbDTO[], listItemStructure?: boolean): Promise<WithContext<SearchResultsPage | WebPage>>;
|
|
10
|
+
buildStructuredData(title: string, description: string, cards: TCard[], faqItems?: FAQItemDto[], breadcrumbs?: BreadcrumbDTO[], listItemStructure?: boolean, pageType?: PageTypes): Promise<WithContext<SearchResultsPage | WebPage>>;
|
|
10
11
|
private generateMainEntities;
|
|
11
12
|
protected abstract buildStructuredDataForCard(entity: EntityDTO<TCard>): Promise<Thing | undefined> | Thing | undefined;
|
|
12
13
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { PageTypes } from '../enums/PageTypes';
|
|
1
2
|
export class SearchStructuredDataFactory {
|
|
2
|
-
async buildStructuredData(title, description, cards, faqItems = [], breadcrumbs = [], listItemStructure) {
|
|
3
|
+
async buildStructuredData(title, description, cards, faqItems = [], breadcrumbs = [], listItemStructure = false, pageType) {
|
|
3
4
|
const entities = [];
|
|
4
5
|
const ratings = [];
|
|
5
6
|
const offersData = [];
|
|
@@ -12,10 +13,15 @@ export class SearchStructuredDataFactory {
|
|
|
12
13
|
offersData.push(offer);
|
|
13
14
|
entities.push({ card, offer, reviewRating });
|
|
14
15
|
}
|
|
16
|
+
const pageTypeToUse = pageType
|
|
17
|
+
? pageType
|
|
18
|
+
: listItemStructure
|
|
19
|
+
? PageTypes.WEB_PAGE
|
|
20
|
+
: PageTypes.SEARCH_RESULTS_PAGE;
|
|
15
21
|
const mainEntities = await this.generateMainEntities(entities, listItemStructure);
|
|
16
22
|
const data = {
|
|
17
23
|
'@context': 'https://schema.org',
|
|
18
|
-
'@type':
|
|
24
|
+
'@type': pageTypeToUse,
|
|
19
25
|
'name': title,
|
|
20
26
|
description,
|
|
21
27
|
'mainEntity': mainEntities
|
package/package.json
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@studyportals/fawkes",
|
|
3
|
-
"version": "8.5.
|
|
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": "7.1.0",
|
|
94
|
-
"@studyportals/ranking-api-interface": "^1.3.12",
|
|
95
|
-
"@studyportals/search-filters": "^6.3.1",
|
|
96
|
-
"@studyportals/static-domain-data": "^6.1.0"
|
|
97
|
-
},
|
|
98
|
-
"optionalDependencies": {
|
|
99
|
-
"@rollup/rollup-linux-x64-gnu": "4.24.0"
|
|
100
|
-
},
|
|
101
|
-
"engines": {
|
|
102
|
-
"node": ">=18 <=24",
|
|
103
|
-
"npm": ">=8 <=11"
|
|
104
|
-
}
|
|
105
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@studyportals/fawkes",
|
|
3
|
+
"version": "8.5.1-1",
|
|
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": "7.1.0",
|
|
94
|
+
"@studyportals/ranking-api-interface": "^1.3.12",
|
|
95
|
+
"@studyportals/search-filters": "^6.3.1",
|
|
96
|
+
"@studyportals/static-domain-data": "^6.1.0"
|
|
97
|
+
},
|
|
98
|
+
"optionalDependencies": {
|
|
99
|
+
"@rollup/rollup-linux-x64-gnu": "4.24.0"
|
|
100
|
+
},
|
|
101
|
+
"engines": {
|
|
102
|
+
"node": ">=18 <=24",
|
|
103
|
+
"npm": ">=8 <=11"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export var AttendanceFilterOptionValue;
|
|
2
|
-
(function (AttendanceFilterOptionValue) {
|
|
3
|
-
AttendanceFilterOptionValue["FACE_2_FACE"] = "face2face";
|
|
4
|
-
AttendanceFilterOptionValue["ONLINE"] = "online";
|
|
5
|
-
AttendanceFilterOptionValue["BLENDED"] = "blended";
|
|
6
|
-
})(AttendanceFilterOptionValue || (AttendanceFilterOptionValue = {}));
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export declare enum DegreeTypeFilterOptionValue {
|
|
2
|
-
PHD = "phd",
|
|
3
|
-
DBA = "dba",
|
|
4
|
-
DOCTORATE = "doct",
|
|
5
|
-
MSC = "msc",
|
|
6
|
-
MA = "ma",
|
|
7
|
-
MBA = "mba",
|
|
8
|
-
LLM = "llm",
|
|
9
|
-
MPHIL = "mphil",
|
|
10
|
-
MLITT = "mlitt",
|
|
11
|
-
MRES = "mres",
|
|
12
|
-
MED = "med",
|
|
13
|
-
MENG = "meng",
|
|
14
|
-
POSTGRADIP = "postgraddip",
|
|
15
|
-
POSTGRADCERT = "postgradcert",
|
|
16
|
-
PREMASTER = "premaster",
|
|
17
|
-
BSC = "bsc",
|
|
18
|
-
BA = "ba",
|
|
19
|
-
LLB = "llb",
|
|
20
|
-
BENG = "beng",
|
|
21
|
-
BBA = "bba",
|
|
22
|
-
ASSOCIATE_DEGREE = "ad",
|
|
23
|
-
ACADEMY_PROFESSION = "ap",
|
|
24
|
-
ADVANCED_DIPLOMA = "adiploma",
|
|
25
|
-
GRADUATE_CERTTIFICATE = "gcertificate",
|
|
26
|
-
GRADUATE_DIPLOMA = "gdiploma",
|
|
27
|
-
PREBACHELOR = "prebachelor",
|
|
28
|
-
CERTIFICATE = "certificate"
|
|
29
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export var DegreeTypeFilterOptionValue;
|
|
2
|
-
(function (DegreeTypeFilterOptionValue) {
|
|
3
|
-
DegreeTypeFilterOptionValue["PHD"] = "phd";
|
|
4
|
-
DegreeTypeFilterOptionValue["DBA"] = "dba";
|
|
5
|
-
DegreeTypeFilterOptionValue["DOCTORATE"] = "doct";
|
|
6
|
-
DegreeTypeFilterOptionValue["MSC"] = "msc";
|
|
7
|
-
DegreeTypeFilterOptionValue["MA"] = "ma";
|
|
8
|
-
DegreeTypeFilterOptionValue["MBA"] = "mba";
|
|
9
|
-
DegreeTypeFilterOptionValue["LLM"] = "llm";
|
|
10
|
-
DegreeTypeFilterOptionValue["MPHIL"] = "mphil";
|
|
11
|
-
DegreeTypeFilterOptionValue["MLITT"] = "mlitt";
|
|
12
|
-
DegreeTypeFilterOptionValue["MRES"] = "mres";
|
|
13
|
-
DegreeTypeFilterOptionValue["MED"] = "med";
|
|
14
|
-
DegreeTypeFilterOptionValue["MENG"] = "meng";
|
|
15
|
-
DegreeTypeFilterOptionValue["POSTGRADIP"] = "postgraddip";
|
|
16
|
-
DegreeTypeFilterOptionValue["POSTGRADCERT"] = "postgradcert";
|
|
17
|
-
DegreeTypeFilterOptionValue["PREMASTER"] = "premaster";
|
|
18
|
-
DegreeTypeFilterOptionValue["BSC"] = "bsc";
|
|
19
|
-
DegreeTypeFilterOptionValue["BA"] = "ba";
|
|
20
|
-
DegreeTypeFilterOptionValue["LLB"] = "llb";
|
|
21
|
-
DegreeTypeFilterOptionValue["BENG"] = "beng";
|
|
22
|
-
DegreeTypeFilterOptionValue["BBA"] = "bba";
|
|
23
|
-
DegreeTypeFilterOptionValue["ASSOCIATE_DEGREE"] = "ad";
|
|
24
|
-
DegreeTypeFilterOptionValue["ACADEMY_PROFESSION"] = "ap";
|
|
25
|
-
DegreeTypeFilterOptionValue["ADVANCED_DIPLOMA"] = "adiploma";
|
|
26
|
-
DegreeTypeFilterOptionValue["GRADUATE_CERTTIFICATE"] = "gcertificate";
|
|
27
|
-
DegreeTypeFilterOptionValue["GRADUATE_DIPLOMA"] = "gdiploma";
|
|
28
|
-
DegreeTypeFilterOptionValue["PREBACHELOR"] = "prebachelor";
|
|
29
|
-
DegreeTypeFilterOptionValue["CERTIFICATE"] = "certificate";
|
|
30
|
-
})(DegreeTypeFilterOptionValue || (DegreeTypeFilterOptionValue = {}));
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare enum DurationFilterOptionValue {
|
|
2
|
-
LESS_THAN_ONE_MONTH = "[-1,29]",
|
|
3
|
-
ONE_TO_THREE_MONTHS = "[30,90]",
|
|
4
|
-
MORE_THAN_THREE_MONTHS = "[91,-1]",
|
|
5
|
-
LESS_THAN_ONE_YEAR = "[-1,359]",
|
|
6
|
-
ONE_YEAR = "[360,360]",
|
|
7
|
-
ONE_AND_A_HALF_YEARS = "[540,540]",
|
|
8
|
-
LESS_THAN_TWO_YEARS = "[-1,719]",
|
|
9
|
-
MORE_THAN_TWO_YEARS = "[721,-1]",
|
|
10
|
-
TWO_YEARS = "[720,720]",
|
|
11
|
-
TWO_AND_A_HALF_YEARS = "[900,900]",
|
|
12
|
-
THREE_YEARS = "[1080,1080]",
|
|
13
|
-
THREE_AND_A_HALF_YEARS = "[1260,1260]",
|
|
14
|
-
FOUR_YEARS = "[1440,1440]",
|
|
15
|
-
MORE_THAN_FOUR_YEARS = "[1441,-1]"
|
|
16
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export var DurationFilterOptionValue;
|
|
2
|
-
(function (DurationFilterOptionValue) {
|
|
3
|
-
DurationFilterOptionValue["LESS_THAN_ONE_MONTH"] = "[-1,29]";
|
|
4
|
-
DurationFilterOptionValue["ONE_TO_THREE_MONTHS"] = "[30,90]";
|
|
5
|
-
DurationFilterOptionValue["MORE_THAN_THREE_MONTHS"] = "[91,-1]";
|
|
6
|
-
DurationFilterOptionValue["LESS_THAN_ONE_YEAR"] = "[-1,359]";
|
|
7
|
-
DurationFilterOptionValue["ONE_YEAR"] = "[360,360]";
|
|
8
|
-
DurationFilterOptionValue["ONE_AND_A_HALF_YEARS"] = "[540,540]";
|
|
9
|
-
DurationFilterOptionValue["LESS_THAN_TWO_YEARS"] = "[-1,719]";
|
|
10
|
-
DurationFilterOptionValue["MORE_THAN_TWO_YEARS"] = "[721,-1]";
|
|
11
|
-
DurationFilterOptionValue["TWO_YEARS"] = "[720,720]";
|
|
12
|
-
DurationFilterOptionValue["TWO_AND_A_HALF_YEARS"] = "[900,900]";
|
|
13
|
-
DurationFilterOptionValue["THREE_YEARS"] = "[1080,1080]";
|
|
14
|
-
DurationFilterOptionValue["THREE_AND_A_HALF_YEARS"] = "[1260,1260]";
|
|
15
|
-
DurationFilterOptionValue["FOUR_YEARS"] = "[1440,1440]";
|
|
16
|
-
DurationFilterOptionValue["MORE_THAN_FOUR_YEARS"] = "[1441,-1]";
|
|
17
|
-
})(DurationFilterOptionValue || (DurationFilterOptionValue = {}));
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare enum EducationalFormFilterOptionValue {
|
|
2
|
-
ACADEMIC_COURSE = "academic",
|
|
3
|
-
CONFERENCE_SEMINAR = "conference",
|
|
4
|
-
SUMMER_SCHOOL = "summer_school",
|
|
5
|
-
WINTER_SCHOOL = "winter_school",
|
|
6
|
-
SEMESTER_STUDY_ABROAD = "semester",
|
|
7
|
-
SKILL_PROFESSIONAL_COURSE = "skill"
|
|
8
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export var EducationalFormFilterOptionValue;
|
|
2
|
-
(function (EducationalFormFilterOptionValue) {
|
|
3
|
-
EducationalFormFilterOptionValue["ACADEMIC_COURSE"] = "academic";
|
|
4
|
-
EducationalFormFilterOptionValue["CONFERENCE_SEMINAR"] = "conference";
|
|
5
|
-
EducationalFormFilterOptionValue["SUMMER_SCHOOL"] = "summer_school";
|
|
6
|
-
EducationalFormFilterOptionValue["WINTER_SCHOOL"] = "winter_school";
|
|
7
|
-
EducationalFormFilterOptionValue["SEMESTER_STUDY_ABROAD"] = "semester";
|
|
8
|
-
EducationalFormFilterOptionValue["SKILL_PROFESSIONAL_COURSE"] = "skill";
|
|
9
|
-
})(EducationalFormFilterOptionValue || (EducationalFormFilterOptionValue = {}));
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export declare enum FilterKey {
|
|
2
|
-
KEYWORD_WHAT = "kw-what",
|
|
3
|
-
KEYWORD_WHERE = "kw-where",
|
|
4
|
-
KEYWORD = "kw",
|
|
5
|
-
ORGANISATIONS = "oi",
|
|
6
|
-
DISCIPLINES = "di",
|
|
7
|
-
EDUCATION_LEVEL = "lv",
|
|
8
|
-
CONTINENT = "rg",
|
|
9
|
-
COUNTRY = "ci",
|
|
10
|
-
AREA = "ae",
|
|
11
|
-
TUITION_FEE = "tr",
|
|
12
|
-
DURATION = "dur",
|
|
13
|
-
ATTENDANCE = "de",
|
|
14
|
-
DELIVERY_METHOD = "mh",
|
|
15
|
-
DEGREE_TYPE = "dg",
|
|
16
|
-
EDUCATIONAL_FORM = "ef",
|
|
17
|
-
SPECIAL_PROGRAMMES = "sps",
|
|
18
|
-
USER_COUNTRY = "uc",
|
|
19
|
-
USER_REGION = "ur",
|
|
20
|
-
CURRENCY = "tc"
|
|
21
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export var FilterKey;
|
|
2
|
-
(function (FilterKey) {
|
|
3
|
-
FilterKey["KEYWORD_WHAT"] = "kw-what";
|
|
4
|
-
FilterKey["KEYWORD_WHERE"] = "kw-where";
|
|
5
|
-
FilterKey["KEYWORD"] = "kw";
|
|
6
|
-
FilterKey["ORGANISATIONS"] = "oi";
|
|
7
|
-
FilterKey["DISCIPLINES"] = "di";
|
|
8
|
-
FilterKey["EDUCATION_LEVEL"] = "lv";
|
|
9
|
-
FilterKey["CONTINENT"] = "rg";
|
|
10
|
-
FilterKey["COUNTRY"] = "ci";
|
|
11
|
-
FilterKey["AREA"] = "ae";
|
|
12
|
-
FilterKey["TUITION_FEE"] = "tr";
|
|
13
|
-
FilterKey["DURATION"] = "dur";
|
|
14
|
-
FilterKey["ATTENDANCE"] = "de";
|
|
15
|
-
FilterKey["DELIVERY_METHOD"] = "mh";
|
|
16
|
-
FilterKey["DEGREE_TYPE"] = "dg";
|
|
17
|
-
FilterKey["EDUCATIONAL_FORM"] = "ef";
|
|
18
|
-
FilterKey["SPECIAL_PROGRAMMES"] = "sps";
|
|
19
|
-
FilterKey["USER_COUNTRY"] = "uc";
|
|
20
|
-
FilterKey["USER_REGION"] = "ur";
|
|
21
|
-
FilterKey["CURRENCY"] = "tc";
|
|
22
|
-
})(FilterKey || (FilterKey = {}));
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export var SpecialProgrammesFilterOptionValue;
|
|
2
|
-
(function (SpecialProgrammesFilterOptionValue) {
|
|
3
|
-
SpecialProgrammesFilterOptionValue["EXECUTIVE_PROGRAMMES"] = "executive";
|
|
4
|
-
SpecialProgrammesFilterOptionValue["JOINT_PROGRAMMES"] = "joint";
|
|
5
|
-
SpecialProgrammesFilterOptionValue["ERASMUS_MUNDUS"] = "erasmus";
|
|
6
|
-
})(SpecialProgrammesFilterOptionValue || (SpecialProgrammesFilterOptionValue = {}));
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
2
|
-
import { SortingOptions } from '../../../enums/SortingOptions';
|
|
3
|
-
import { OrganisationsSeoIndexabilityPolicy } from '../../../organisations/policies/OrganisationsSeoIndexabilityPolicy';
|
|
4
|
-
import { OnlyFullLocationFiltersSelectedRule } from '../../../organisations/rules/OnlyFullLocationFiltersSelectedRule';
|
|
5
|
-
export declare class City extends OrganisationsSeoIndexabilityPolicy {
|
|
6
|
-
readonly name: string;
|
|
7
|
-
readonly description: string;
|
|
8
|
-
protected readonly sortingOption = SortingOptions.OUR_PICKS;
|
|
9
|
-
protected readonly baseRules: OnlyFullLocationFiltersSelectedRule[];
|
|
10
|
-
protected generateUrls(): Promise<string[]>;
|
|
11
|
-
get filterCombination(): FilterCombinations;
|
|
12
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
2
|
-
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
3
|
-
import { SortingOptions } from '../../../enums/SortingOptions';
|
|
4
|
-
import { OrganisationsSeoIndexabilityPolicy } from '../../../organisations/policies/OrganisationsSeoIndexabilityPolicy';
|
|
5
|
-
import { CityPresenter } from '../../../presenters/CityPresenter';
|
|
6
|
-
import { OnlyFullLocationFiltersSelectedRule } from '../../../organisations/rules/OnlyFullLocationFiltersSelectedRule';
|
|
7
|
-
export class City extends OrganisationsSeoIndexabilityPolicy {
|
|
8
|
-
name = 'City Policy';
|
|
9
|
-
description = 'Controls indexing of pages filtered by geographic cities, ensuring only SEO-valuable regional content with sufficient search volume is indexed.';
|
|
10
|
-
sortingOption = SortingOptions.OUR_PICKS;
|
|
11
|
-
baseRules = [
|
|
12
|
-
new OnlyFullLocationFiltersSelectedRule()
|
|
13
|
-
];
|
|
14
|
-
async generateUrls() {
|
|
15
|
-
const cityFragments = await CityPresenter
|
|
16
|
-
.getInstance(this.dependencies.searchApiClient)
|
|
17
|
-
.getFragments();
|
|
18
|
-
const paths = [];
|
|
19
|
-
for (const city of cityFragments) {
|
|
20
|
-
const filterKeyValues = new Map([
|
|
21
|
-
[FilterKey.CITY, [city.id]],
|
|
22
|
-
[FilterKey.AREA, [city.areaId]],
|
|
23
|
-
[FilterKey.COUNTRY, [city.countryId]]
|
|
24
|
-
]);
|
|
25
|
-
const result = await this.checkRulesForSitemap(filterKeyValues);
|
|
26
|
-
if (result) {
|
|
27
|
-
paths.push(this.getPathWithSortingOption(city.path));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return paths;
|
|
31
|
-
}
|
|
32
|
-
get filterCombination() {
|
|
33
|
-
return FilterCombinations.CITY;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { OnlyFiltersSelectedRule } from "../../../common/rules/OnlyFiltersSelectedRule";
|
|
2
|
-
import { SingleValueSelectedForFilterRule } from "../../../common/rules/SingleValueSelectedForFilterRule";
|
|
3
|
-
import { RankedOrganisationsSeoIndexabilityPolicy } from "../RankedOrganisationsSeoIndexabilityPolicy";
|
|
4
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
5
|
-
export declare class RankedCountryAreaCity extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
6
|
-
readonly name: string;
|
|
7
|
-
readonly description: string;
|
|
8
|
-
protected readonly baseRules: (SingleValueSelectedForFilterRule | OnlyFiltersSelectedRule)[];
|
|
9
|
-
protected generateUrls(): Promise<string[]>;
|
|
10
|
-
get filterCombination(): FilterCombinations;
|
|
11
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { OnlyFiltersSelectedRule } from "../../../common/rules/OnlyFiltersSelectedRule";
|
|
2
|
-
import { SingleValueSelectedForFilterRule } from "../../../common/rules/SingleValueSelectedForFilterRule";
|
|
3
|
-
import { FilterKey } from "@studyportals/search-filters/server-side";
|
|
4
|
-
import { RankedOrganisationsSeoIndexabilityPolicy } from "../RankedOrganisationsSeoIndexabilityPolicy";
|
|
5
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
6
|
-
import { CityPresenter } from "../../../presenters/CityPresenter";
|
|
7
|
-
export class RankedCountryAreaCity extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
8
|
-
name = 'Ranked Country Area City Policy';
|
|
9
|
-
description = 'Manages indexability of ranking-sorted country and area-specific city pages, applying rules to prioritize regions where quality-based sorting adds search value.';
|
|
10
|
-
baseRules = [
|
|
11
|
-
new SingleValueSelectedForFilterRule(FilterKey.CITY),
|
|
12
|
-
new SingleValueSelectedForFilterRule(FilterKey.COUNTRY),
|
|
13
|
-
new OnlyFiltersSelectedRule([FilterKey.CITY, FilterKey.COUNTRY])
|
|
14
|
-
];
|
|
15
|
-
async generateUrls() {
|
|
16
|
-
const cityFragments = await CityPresenter
|
|
17
|
-
.getInstance(this.dependencies.searchApiClient)
|
|
18
|
-
.getFragmentsAsync();
|
|
19
|
-
const paths = [];
|
|
20
|
-
console.warn(`Total city fragments fetched: ${cityFragments.length}`);
|
|
21
|
-
const filteredFragmentsForCountryAreaCity = cityFragments.filter(city => city.areaId !== null && city.areaId !== undefined);
|
|
22
|
-
for (const city of filteredFragmentsForCountryAreaCity) {
|
|
23
|
-
const areaId = city.areaId?.toString() || '';
|
|
24
|
-
if (areaId === '') {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
const filterKeyValues = new Map([
|
|
28
|
-
[FilterKey.CITY, [city.id]],
|
|
29
|
-
[FilterKey.AREA, [areaId]],
|
|
30
|
-
[FilterKey.COUNTRY, [city.countryId]]
|
|
31
|
-
]);
|
|
32
|
-
const result = await this.checkRulesForSitemap(filterKeyValues);
|
|
33
|
-
if (result) {
|
|
34
|
-
paths.push(this.getPathWithSortingOption(city.path));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return paths;
|
|
38
|
-
}
|
|
39
|
-
get filterCombination() {
|
|
40
|
-
return FilterCombinations.RANKED_COUNTRY_AREA_CITY;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { OnlyFiltersSelectedRule } from "../../../common/rules/OnlyFiltersSelectedRule";
|
|
2
|
-
import { SingleValueSelectedForFilterRule } from "../../../common/rules/SingleValueSelectedForFilterRule";
|
|
3
|
-
import { RankedOrganisationsSeoIndexabilityPolicy } from "../RankedOrganisationsSeoIndexabilityPolicy";
|
|
4
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
5
|
-
export declare class RankedCountryCity extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
6
|
-
readonly name: string;
|
|
7
|
-
readonly description: string;
|
|
8
|
-
protected readonly baseRules: (SingleValueSelectedForFilterRule | OnlyFiltersSelectedRule)[];
|
|
9
|
-
protected generateUrls(): Promise<string[]>;
|
|
10
|
-
get filterCombination(): FilterCombinations;
|
|
11
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { OnlyFiltersSelectedRule } from "../../../common/rules/OnlyFiltersSelectedRule";
|
|
2
|
-
import { SingleValueSelectedForFilterRule } from "../../../common/rules/SingleValueSelectedForFilterRule";
|
|
3
|
-
import { FilterKey } from "@studyportals/search-filters/server-side";
|
|
4
|
-
import { RankedOrganisationsSeoIndexabilityPolicy } from "../RankedOrganisationsSeoIndexabilityPolicy";
|
|
5
|
-
import { FilterCombinations } from '../../../enums/FilterCombinations';
|
|
6
|
-
import { CityPresenter } from "../../../presenters/CityPresenter";
|
|
7
|
-
export class RankedCountryCity extends RankedOrganisationsSeoIndexabilityPolicy {
|
|
8
|
-
name = 'Ranked Country City Policy';
|
|
9
|
-
description = 'Manages indexability of ranking-sorted country and city-specific pages, applying rules to prioritize regions where quality-based sorting adds search value.';
|
|
10
|
-
baseRules = [
|
|
11
|
-
new SingleValueSelectedForFilterRule(FilterKey.CITY),
|
|
12
|
-
new SingleValueSelectedForFilterRule(FilterKey.COUNTRY),
|
|
13
|
-
new OnlyFiltersSelectedRule([FilterKey.CITY, FilterKey.COUNTRY])
|
|
14
|
-
];
|
|
15
|
-
async generateUrls() {
|
|
16
|
-
const cityFragments = await CityPresenter
|
|
17
|
-
.getInstance(this.dependencies.searchApiClient)
|
|
18
|
-
.getFragmentsAsync();
|
|
19
|
-
const paths = [];
|
|
20
|
-
const filteredFragmentsForCountryCity = cityFragments.filter(city => city.areaId === null || city.areaId === undefined);
|
|
21
|
-
for (const city of filteredFragmentsForCountryCity) {
|
|
22
|
-
const filterKeyValues = new Map([
|
|
23
|
-
[FilterKey.CITY, [city.id]],
|
|
24
|
-
[FilterKey.COUNTRY, [city.countryId]]
|
|
25
|
-
]);
|
|
26
|
-
const result = await this.checkRulesForSitemap(filterKeyValues);
|
|
27
|
-
if (result) {
|
|
28
|
-
paths.push(this.getPathWithSortingOption(city.path));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return paths;
|
|
32
|
-
}
|
|
33
|
-
get filterCombination() {
|
|
34
|
-
return FilterCombinations.RANKED_COUNTRY_CITY;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { IRule } from '../../common/IRule';
|
|
2
|
-
import { IOrganisationSearchDependencies } from '../types/IOrganisationSearchDependencies';
|
|
3
|
-
import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
|
|
4
|
-
import { IRankingApiClient } from '../../sitemap-generator/IRankingApiClient';
|
|
5
|
-
export declare class AtLeastTwoRankedResultsRule implements IRule {
|
|
6
|
-
private readonly minimumRankedResultsCount;
|
|
7
|
-
private readonly rankingApiClient?;
|
|
8
|
-
constructor(rankingApiClient?: IRankingApiClient);
|
|
9
|
-
forSearch(dependencies: IOrganisationSearchDependencies): Promise<boolean>;
|
|
10
|
-
forSitemapGenerator(filterKeyValues: FilterKeyValuesMap): Promise<boolean>;
|
|
11
|
-
getName(): string;
|
|
12
|
-
getDescription(): string;
|
|
13
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { DependencyMissingError } from '../../errors/DependencyMissingError';
|
|
2
|
-
export class AtLeastTwoRankedResultsRule {
|
|
3
|
-
minimumRankedResultsCount = 2;
|
|
4
|
-
rankingApiClient;
|
|
5
|
-
constructor(rankingApiClient) {
|
|
6
|
-
this.rankingApiClient = rankingApiClient;
|
|
7
|
-
}
|
|
8
|
-
forSearch(dependencies) {
|
|
9
|
-
const { applicationState } = dependencies;
|
|
10
|
-
const rankedResultsCount = applicationState.getRankedResultsCount();
|
|
11
|
-
return Promise.resolve(rankedResultsCount >= this.minimumRankedResultsCount);
|
|
12
|
-
}
|
|
13
|
-
async forSitemapGenerator(filterKeyValues) {
|
|
14
|
-
if (!this.rankingApiClient) {
|
|
15
|
-
throw new DependencyMissingError('RankingApiClient');
|
|
16
|
-
}
|
|
17
|
-
const rankedResultsCount = await this.rankingApiClient.getRankedOrganisationCount(filterKeyValues);
|
|
18
|
-
return rankedResultsCount >= this.minimumRankedResultsCount;
|
|
19
|
-
}
|
|
20
|
-
getName() {
|
|
21
|
-
return 'AtLeastTwoRankedResultsRule';
|
|
22
|
-
}
|
|
23
|
-
getDescription() {
|
|
24
|
-
return `At least ${this.minimumRankedResultsCount} ranked results are available`;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { IRule } from '../../common/IRule';
|
|
2
|
-
import { ISearchDependencies } from '../../common/ISearchDependencies';
|
|
3
|
-
export declare class OnlyFullLocationFiltersSelectedRule implements IRule {
|
|
4
|
-
private readonly COUNTRIES_WITH_AREAS;
|
|
5
|
-
getName(): string;
|
|
6
|
-
forSearch(dependencies: ISearchDependencies): Promise<boolean>;
|
|
7
|
-
forSitemapGenerator(): Promise<boolean>;
|
|
8
|
-
getDescription(): string;
|
|
9
|
-
private isEligible;
|
|
10
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { FilterKey } from '@studyportals/search-filters/server-side';
|
|
2
|
-
export class OnlyFullLocationFiltersSelectedRule {
|
|
3
|
-
COUNTRIES_WITH_AREAS = ["30", "82", "202"]; //UK, US, AU
|
|
4
|
-
getName() {
|
|
5
|
-
return `OnlyFullLocationFiltersSelectedRule`;
|
|
6
|
-
}
|
|
7
|
-
async forSearch(dependencies) {
|
|
8
|
-
return await this.isEligible(dependencies);
|
|
9
|
-
}
|
|
10
|
-
forSitemapGenerator() {
|
|
11
|
-
return Promise.resolve(true);
|
|
12
|
-
}
|
|
13
|
-
getDescription() {
|
|
14
|
-
return `Only city, country and area (if US, UK or AU) filters are selected`;
|
|
15
|
-
}
|
|
16
|
-
async isEligible(dependencies) {
|
|
17
|
-
const seoInfoBase = dependencies.seoInfoBase;
|
|
18
|
-
const filterState = dependencies.filterState;
|
|
19
|
-
const singleCitySelected = await seoInfoBase.singleSelectionFor(FilterKey.CITY, filterState);
|
|
20
|
-
const singleAreaSelected = await seoInfoBase.singleSelectionFor(FilterKey.AREA, filterState);
|
|
21
|
-
const singleCountrySelected = await seoInfoBase.singleSelectionFor(FilterKey.COUNTRY, filterState);
|
|
22
|
-
const needArea = filterState.getSelectedValuesFor(FilterKey.COUNTRY)
|
|
23
|
-
.some((countryId) => this.COUNTRIES_WITH_AREAS.includes(countryId));
|
|
24
|
-
if (needArea) {
|
|
25
|
-
const cityAreaAndCountryOnly = await seoInfoBase.selectionOnlyFor([FilterKey.CITY, FilterKey.COUNTRY, FilterKey.AREA], filterState);
|
|
26
|
-
return singleCitySelected && singleCountrySelected && singleAreaSelected && cityAreaAndCountryOnly;
|
|
27
|
-
}
|
|
28
|
-
const cityAndCountryOnly = await seoInfoBase.selectionOnlyFor([FilterKey.CITY, FilterKey.COUNTRY], filterState);
|
|
29
|
-
return singleCitySelected && singleCountrySelected && cityAndCountryOnly;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ISearchDependencies } from '../../common/ISearchDependencies';
|
|
2
|
-
import { FilterKeyValuesMap } from '../../common/FilterKeyValuesMap';
|
|
3
|
-
import { ISearchApiClient } from '../../sitemap-generator/ISearchApiClient';
|
|
4
|
-
import { IProgrammeRule } from '../IProgrammeRule';
|
|
5
|
-
export declare class AtLeastSevenResultsRule implements IProgrammeRule {
|
|
6
|
-
private readonly minimumResultsCount;
|
|
7
|
-
private readonly maximumPageSize;
|
|
8
|
-
private readonly searchApiClient?;
|
|
9
|
-
constructor(searchApiClient?: ISearchApiClient);
|
|
10
|
-
forSearch(dependencies: ISearchDependencies): Promise<boolean>;
|
|
11
|
-
forSitemapGeneratorWithPageNumber(filterKeyValues: FilterKeyValuesMap, pageNumber: number): Promise<boolean>;
|
|
12
|
-
forSitemapGenerator(): Promise<boolean>;
|
|
13
|
-
getName(): string;
|
|
14
|
-
getDescription(): string;
|
|
15
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { DependencyMissingError } from '../../errors/DependencyMissingError';
|
|
2
|
-
export class AtLeastSevenResultsRule {
|
|
3
|
-
minimumResultsCount = 7;
|
|
4
|
-
maximumPageSize = 20;
|
|
5
|
-
searchApiClient;
|
|
6
|
-
constructor(searchApiClient) {
|
|
7
|
-
this.searchApiClient = searchApiClient;
|
|
8
|
-
}
|
|
9
|
-
forSearch(dependencies) {
|
|
10
|
-
const { applicationState } = dependencies;
|
|
11
|
-
const resultCount = applicationState.getNumberOfResults();
|
|
12
|
-
return Promise.resolve(resultCount >= this.minimumResultsCount);
|
|
13
|
-
}
|
|
14
|
-
async forSitemapGeneratorWithPageNumber(filterKeyValues, pageNumber) {
|
|
15
|
-
if (!this.searchApiClient) {
|
|
16
|
-
throw new DependencyMissingError('SearchApiClient');
|
|
17
|
-
}
|
|
18
|
-
const count = await this.searchApiClient.getProgrammeCount(filterKeyValues);
|
|
19
|
-
return count >= (pageNumber - 1) * this.maximumPageSize + this.minimumResultsCount;
|
|
20
|
-
}
|
|
21
|
-
forSitemapGenerator() {
|
|
22
|
-
throw new Error('Method not implemented.');
|
|
23
|
-
}
|
|
24
|
-
getName() {
|
|
25
|
-
return 'AtLeastSevenResultsRule';
|
|
26
|
-
}
|
|
27
|
-
getDescription() {
|
|
28
|
-
return 'Is indexable if there are at least 7 results.';
|
|
29
|
-
}
|
|
30
|
-
}
|