sr-npm 2.0.17 → 2.0.19
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/.github/workflows/update-sites.yml +2 -2
- package/backend/careersMultiBoxesPageIds.js +61 -0
- package/backend/collectionConsts.js +43 -1
- package/backend/consts.js +68 -14
- package/backend/data.js +164 -29
- package/backend/fetchPositionsFromSRAPI.js +2 -1
- package/backend/index.js +2 -0
- package/backend/queries.js +9 -5
- package/backend/secretsData.js +3 -3
- package/backend/utils.js +2 -1
- package/eslint.config.mjs +26 -0
- package/package.json +7 -2
- package/pages/boardPeoplePage.js +28 -0
- package/pages/brandPage.js +12 -0
- package/pages/careersMultiBoxesPage.js +560 -0
- package/pages/careersPage.js +120 -102
- package/pages/homePage.js +79 -8
- package/pages/index.js +6 -0
- package/pages/masterPage.js +35 -0
- package/pages/pagesUtils.js +232 -0
- package/pages/positionPage.js +93 -7
- package/pages/supportTeamsPage.js +92 -0
- package/public/selectors.js +53 -0
- package/public/utils.js +2 -1
- package/tests/brandPageTest.spec.js +45 -0
- package/tests/mockJobBuilder.js +290 -0
- package/tests/multiSearchBoxCareers.spec.js +371 -0
- package/tests/positionPageTest.spec.js +140 -0
|
@@ -5,14 +5,14 @@ on:
|
|
|
5
5
|
branches:
|
|
6
6
|
- main
|
|
7
7
|
workflow_dispatch:
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
permissions:
|
|
10
10
|
contents: write
|
|
11
11
|
packages: write
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
update-sites:
|
|
15
|
-
uses: psdevteamenterprise/ci-workflows/.github/workflows/
|
|
15
|
+
uses: psdevteamenterprise/ci-workflows/.github/workflows/update-and-notify.yml@main
|
|
16
16
|
with:
|
|
17
17
|
sites_to_update: "[{repo: 'psdevteamenterprise/tests-site', secret: 'WIX_PS_API_KEY'},
|
|
18
18
|
{repo: 'psdevteamenterprise/external-template', secret: 'WIX_SR_API_KEY'},
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const CAREERS_MULTI_BOXES_PAGE_CONSTS={
|
|
2
|
+
FILTER_REPEATER: '#filterReapter',
|
|
3
|
+
JOBS_REPEATER: '#jobsReapter',
|
|
4
|
+
JOBS_REPEATER_ITEM_TITLE: '#jobTitle',
|
|
5
|
+
JOBS_REPEATER_ITEM_LOCATION: '#locationLabel',
|
|
6
|
+
JOBS_REPEATER_ITEM_EMPLOYMENT_TYPE: '#employmentTypeLabel',
|
|
7
|
+
TotalJobsCountText: '#totalJobsCountText',
|
|
8
|
+
FILTER_LABEL: '#FilterTextInput',
|
|
9
|
+
FILTER_CHECKBOX_CONTAINER: '#FilterCheckBoxContainer',
|
|
10
|
+
FILTER_REPEATER_ITEM_CHECKBOX: '#filterCheckBox',
|
|
11
|
+
SELECTED_VALUES_REPEATER: '#selectedValuesReapter',
|
|
12
|
+
SELECTED_VALUES_REPEATER_ITEM_LABEL: '#selectedValueLabel',
|
|
13
|
+
DESELECT_BUTTON_ID: '#deselectFilterValueButton',
|
|
14
|
+
CLEAR_ALL_BUTTON_ID: '#clearAllButton',
|
|
15
|
+
PAGE_BUTTON_NEXT: '#nextPageButton',
|
|
16
|
+
PAGE_BUTTON_PREVIOUS: '#previousPageButton',
|
|
17
|
+
paginationCurrentText: '#paginationCurrent',
|
|
18
|
+
paginationTotalCountText: '#paginationTotalCount',
|
|
19
|
+
PRIMARY_SEARCH_RESULTS: '#resultsRepeater',
|
|
20
|
+
SEARCH_BUTTON: '#searchButton',
|
|
21
|
+
SECONDARY_SEARCH_INPUT: '#secondarySearchInput',
|
|
22
|
+
JOBS_MULTI_STATE_BOX:"#jobsMultiStateBox",
|
|
23
|
+
PRIMARY_SEARCH_INPUT: '#primarySearchInput',
|
|
24
|
+
JOB_RESULTS_REPEATER: '#jobResultsRepeater',
|
|
25
|
+
JOB_RESULTS_REPEATER_ITEM: '#jobResultsRepeaterItem',
|
|
26
|
+
CATEGORY_RESULTS_REPEATER: '#categoryResultsRepeater',
|
|
27
|
+
CATEGORY_RESULTS_REPEATER_ITEM: '#categoryResultsRepeaterItem',
|
|
28
|
+
PRIMARY_SEARCH_MULTI_BOX: '#primarySearchMultiBox',
|
|
29
|
+
PRIMARY_SEARCH_POSITION_BUTTON: '#primarySearchPositionButton',
|
|
30
|
+
PRIMARY_SEARCH_CATEGORY_BUTTON: '#primarySearchCategoryButton',
|
|
31
|
+
RESULTS_CONTAINER: '#resultsContainer',
|
|
32
|
+
PRIMARY_SEARCH_BUTTON: '#primarySearchButton',
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CATEGORY_CUSTOM_FIELD_ID_IN_CMS='5cd8c873c9e77c0008aa7d23';
|
|
37
|
+
|
|
38
|
+
const fieldTitlesInCMS={
|
|
39
|
+
"brand": "Brands",
|
|
40
|
+
category: "Category",
|
|
41
|
+
visibility: "Visibility",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const FiltersIds={
|
|
45
|
+
Category: 'Category',
|
|
46
|
+
"Company Segment": 'CompanySegment',
|
|
47
|
+
Location: 'Location',
|
|
48
|
+
"Store Name": 'StoreName',
|
|
49
|
+
"Employment Type": 'employmentType',
|
|
50
|
+
"Contract Type": 'contractType',
|
|
51
|
+
Brands: 'Brands',
|
|
52
|
+
Visibility: 'Visibility',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
CAREERS_MULTI_BOXES_PAGE_CONSTS,
|
|
58
|
+
FiltersIds,
|
|
59
|
+
fieldTitlesInCMS,
|
|
60
|
+
CATEGORY_CUSTOM_FIELD_ID_IN_CMS,
|
|
61
|
+
}
|
|
@@ -5,6 +5,11 @@ const COLLECTIONS = {
|
|
|
5
5
|
TEMPLATE_TYPE: 'templateType',
|
|
6
6
|
SECRET_MANAGER_MIRROR: 'SecretManagerMirror',
|
|
7
7
|
BRANDS: 'Brands',
|
|
8
|
+
CUSTOM_VALUES:'CustomValues',
|
|
9
|
+
CUSTOM_FIELDS:'CustomFields',
|
|
10
|
+
SITE_CONFIGS: 'SiteConfigs',
|
|
11
|
+
SUPPORT_TEAMS: 'SupportTeams',
|
|
12
|
+
|
|
8
13
|
}
|
|
9
14
|
const JOBS_COLLECTION_FIELDS = {
|
|
10
15
|
LOCATION: 'location',
|
|
@@ -23,12 +28,26 @@ const JOBS_COLLECTION_FIELDS = {
|
|
|
23
28
|
REFER_FRIEND_LINK: 'referFriendLink',
|
|
24
29
|
BRAND: 'brand',
|
|
25
30
|
BRAND_REF: 'brandRef',
|
|
31
|
+
MULTI_REF_JOBS_CUSTOM_VALUES: 'multiRefJobsCustomValues',
|
|
32
|
+
EMPLOYMENT_TYPE: 'employmentType',
|
|
33
|
+
RELEASED_DATE: 'releasedDate',
|
|
34
|
+
REF_ID: 'refId',
|
|
26
35
|
}
|
|
27
36
|
const AMOUNT_OF_JOBS_PER_DEPARTMENT_COLLECTION_FIELDS = {
|
|
28
37
|
TITLE: 'title',
|
|
29
38
|
COUNT: 'count',
|
|
30
39
|
IMAGE: 'image',
|
|
31
40
|
}
|
|
41
|
+
const CUSTOM_VALUES_COLLECTION_FIELDS = {
|
|
42
|
+
TITLE: 'title',
|
|
43
|
+
CUSTOM_FIELD: 'customField',
|
|
44
|
+
MULTI_REF_JOBS_CUSTOM_VALUES: 'multiRefJobsCustomValues',
|
|
45
|
+
count: 'count',
|
|
46
|
+
JOB_IDS: 'jobIds',
|
|
47
|
+
}
|
|
48
|
+
const CUSTOM_FIELDS_COLLECTION_FIELDS = {
|
|
49
|
+
TITLE: 'title',
|
|
50
|
+
}
|
|
32
51
|
const BRANDS_COLLECTION_FIELDS = {
|
|
33
52
|
TITLE: 'title',
|
|
34
53
|
COUNT: 'count',
|
|
@@ -39,6 +58,7 @@ const CITIES_COLLECTION_FIELDS = {
|
|
|
39
58
|
LOCATION_ADDRESS: 'locationAddress',
|
|
40
59
|
COUNT: 'count',
|
|
41
60
|
COUNTRY: 'country',
|
|
61
|
+
JOB_IDS: 'jobIds',
|
|
42
62
|
}
|
|
43
63
|
const COLLECTIONS_FIELDS = {
|
|
44
64
|
AMOUNT_OF_JOBS_PER_DEPARTMENT: [
|
|
@@ -52,6 +72,7 @@ const COLLECTIONS_FIELDS = {
|
|
|
52
72
|
{key:'locationAddress', type: 'ADDRESS'},
|
|
53
73
|
{key:'count', type: 'NUMBER'},
|
|
54
74
|
{key:'country', type: 'TEXT'},
|
|
75
|
+
{key:'jobIds', type: 'ARRAY'},
|
|
55
76
|
],
|
|
56
77
|
JOBS: [
|
|
57
78
|
{key:'location', type: 'OBJECT'},
|
|
@@ -62,6 +83,7 @@ const COLLECTIONS_FIELDS = {
|
|
|
62
83
|
{key:'language', type: 'TEXT'},
|
|
63
84
|
{key:'remote', type: 'BOOLEAN'},
|
|
64
85
|
{key:'jobDescription', type: 'OBJECT'},
|
|
86
|
+
{key:'multiRefJobsCustomValues', type: 'MULTI_REFERENCE', typeMetadata: { multiReference: { referencedCollectionId: COLLECTIONS.CUSTOM_VALUES,referencingFieldKey:JOBS_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES,referencingDisplayName:JOBS_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES } } },
|
|
65
87
|
{key:'cityText', type: 'TEXT'},
|
|
66
88
|
{key:'applyLink', type: 'URL'},
|
|
67
89
|
{key:'referFriendLink', type: 'URL'},
|
|
@@ -69,11 +91,18 @@ const COLLECTIONS_FIELDS = {
|
|
|
69
91
|
{key:'departmentref', type: 'REFERENCE', typeMetadata: { reference: { referencedCollectionId: COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT } } },
|
|
70
92
|
{key:'city', type: 'REFERENCE', typeMetadata: { reference: { referencedCollectionId: COLLECTIONS.CITIES } } },
|
|
71
93
|
{key:'brandRef', type: 'REFERENCE', typeMetadata: { reference: { referencedCollectionId: COLLECTIONS.BRANDS } } },
|
|
72
|
-
{
|
|
94
|
+
{key: 'image', type: 'IMAGE' },
|
|
95
|
+
{key:'employmentType', type: 'TEXT'},
|
|
96
|
+
{key:'releasedDate', type: 'TEXT'},
|
|
97
|
+
{key:'refId', type: 'TEXT'},
|
|
73
98
|
],
|
|
74
99
|
TEMPLATE_TYPE: [
|
|
75
100
|
{key:'templateType', type: 'TEXT'},
|
|
76
101
|
],
|
|
102
|
+
SITE_CONFIGS: [
|
|
103
|
+
{key:'onlyBrandKeywordUrlParams', type: 'TEXT'},
|
|
104
|
+
{key:'customFields', type: 'TEXT'},
|
|
105
|
+
],
|
|
77
106
|
SECRET_MANAGER_MIRROR: [
|
|
78
107
|
{key:'tokenName', type: 'TEXT'},
|
|
79
108
|
{key:'value', type: 'TEXT'},
|
|
@@ -82,6 +111,16 @@ const COLLECTIONS_FIELDS = {
|
|
|
82
111
|
{key:'title', type: 'TEXT'},
|
|
83
112
|
{ key: 'count', type: 'NUMBER' },
|
|
84
113
|
],
|
|
114
|
+
CUSTOM_VALUES: [
|
|
115
|
+
{key:'title', type: 'TEXT'},
|
|
116
|
+
{key:'customField', type: 'REFERENCE', typeMetadata: { reference: { referencedCollectionId: COLLECTIONS.CUSTOM_FIELDS } } },
|
|
117
|
+
{key:'count', type: 'NUMBER'},
|
|
118
|
+
{key:'multiRefJobsCustomValues', type: 'MULTI_REFERENCE', typeMetadata: { multiReference: { referencedCollectionId: COLLECTIONS.JOBS,referencingFieldKey:CUSTOM_VALUES_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES,referencingDisplayName:CUSTOM_VALUES_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES } } },
|
|
119
|
+
{key:'jobIds', type: 'ARRAY'},
|
|
120
|
+
],
|
|
121
|
+
CUSTOM_FIELDS: [
|
|
122
|
+
{key:'title', type: 'TEXT'},
|
|
123
|
+
],
|
|
85
124
|
};
|
|
86
125
|
|
|
87
126
|
|
|
@@ -104,6 +143,9 @@ const COLLECTIONS_FIELDS = {
|
|
|
104
143
|
AMOUNT_OF_JOBS_PER_DEPARTMENT_COLLECTION_FIELDS,
|
|
105
144
|
CITIES_COLLECTION_FIELDS,
|
|
106
145
|
BRANDS_COLLECTION_FIELDS,
|
|
146
|
+
CUSTOM_FIELDS_COLLECTION_FIELDS,
|
|
147
|
+
CUSTOM_VALUES_COLLECTION_FIELDS,
|
|
107
148
|
TEMPLATE_TYPE,
|
|
108
149
|
TOKEN_NAME,
|
|
150
|
+
|
|
109
151
|
};
|
package/backend/consts.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {saveJobsDataToCMS,
|
|
1
|
+
const {saveJobsDataToCMS,saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS,createCollections,aggregateJobs,referenceJobs,syncJobsFast} = require('./data')
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
const QUERY_MAX_LIMIT = 1000;
|
|
@@ -6,7 +6,7 @@ const QUERY_MAX_LIMIT = 1000;
|
|
|
6
6
|
const TASKS_NAMES = {
|
|
7
7
|
SYNC_JOBS: 'syncJobsFromSRAPIToCMS',
|
|
8
8
|
INSERT_JOBS_TO_CMS: 'insertJobsToCMS',
|
|
9
|
-
|
|
9
|
+
INSERT_JOBS_DESCRIPTIONS_LOCATION_APPLY_URL_REFERENCES_TO_CMS: 'insertJobsDescriptionsLocationApplyUrlReferencesToCMS',
|
|
10
10
|
AGGREGATE_JOBS_BY_FIELD_TO_CMS: 'aggregateJobsByFieldToCMS',
|
|
11
11
|
REFERENCE_JOBS: 'referenceJobs',
|
|
12
12
|
CREATE_COLLECTIONS: 'createCollections',
|
|
@@ -21,7 +21,7 @@ const TASKS = {
|
|
|
21
21
|
childTasks: [
|
|
22
22
|
{ name: TASKS_NAMES.CREATE_COLLECTIONS},
|
|
23
23
|
{ name: TASKS_NAMES.INSERT_JOBS_TO_CMS },
|
|
24
|
-
{ name: TASKS_NAMES.
|
|
24
|
+
{ name: TASKS_NAMES.INSERT_JOBS_DESCRIPTIONS_LOCATION_APPLY_URL_REFERENCES_TO_CMS },
|
|
25
25
|
{ name: TASKS_NAMES.AGGREGATE_JOBS_BY_FIELD_TO_CMS },
|
|
26
26
|
{name: TASKS_NAMES.REFERENCE_JOBS},
|
|
27
27
|
],
|
|
@@ -42,10 +42,10 @@ const TASKS = {
|
|
|
42
42
|
shouldSkipCheck:()=>false,
|
|
43
43
|
estimatedDurationSec:20
|
|
44
44
|
},
|
|
45
|
-
[TASKS_NAMES.
|
|
46
|
-
name: TASKS_NAMES.
|
|
45
|
+
[TASKS_NAMES.INSERT_JOBS_DESCRIPTIONS_LOCATION_APPLY_URL_REFERENCES_TO_CMS]: {
|
|
46
|
+
name: TASKS_NAMES.INSERT_JOBS_DESCRIPTIONS_LOCATION_APPLY_URL_REFERENCES_TO_CMS,
|
|
47
47
|
getIdentifier:()=> "SHOULD_NEVER_SKIP",
|
|
48
|
-
process:
|
|
48
|
+
process:saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS,
|
|
49
49
|
shouldSkipCheck:()=>false,
|
|
50
50
|
estimatedDurationSec:20
|
|
51
51
|
},
|
|
@@ -72,17 +72,71 @@ const TASKS = {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
75
|
const TASK_TYPE = {
|
|
79
76
|
SCHEDULED: 'scheduled',
|
|
80
77
|
EVENT: 'event',
|
|
81
78
|
};
|
|
82
79
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
const supportTeamsPageIds={
|
|
81
|
+
PEOPLE_REPEATER: "#peopleRepeater",
|
|
82
|
+
PEOPLE_BUTTON: "#peopleButton",
|
|
83
|
+
PEOPLE_TITLE: "#peopleTitle",
|
|
84
|
+
RECENT_JOBS_REPEATER: "#recentJobsRepeater",
|
|
85
|
+
RECENT_JOBS_TITLE: "#recentJobsTitle",
|
|
86
|
+
RECENT_JOBS_BUTTON: "#recentJobsButton",
|
|
87
|
+
RECENT_JOBS_SECTION: "#recentJobsSection",
|
|
88
|
+
VIDEO_SECTION: "#videoSection",
|
|
89
|
+
VIDEO_TITLE: "#videoTitle",
|
|
90
|
+
VIDEO_PLAYER: "#videoPlayer",
|
|
91
|
+
|
|
92
|
+
RECENTLEY_ADDED_JOBS_ITEM: "#recentleyAddedJobsItem",
|
|
93
|
+
JOB_LOCATION: "#jobLocation",
|
|
94
|
+
JOB_TITLE: "#jobTitle",
|
|
95
|
+
TEAM_SUPPORT_DYNAMIC_DATASET: "#dynamicDataset",
|
|
96
|
+
valueToValueIdMap: {
|
|
97
|
+
"Human Resouces":"PeopleSupport",
|
|
98
|
+
"Merchandise - Buying":"Merchandise",
|
|
99
|
+
"Technology, Data and Digital":"InformationServices",
|
|
100
|
+
"Merchandise - Planning":"Merchandise",
|
|
101
|
+
"Digital":"ecommerceandDigital",// this field doesnt exists in the database
|
|
102
|
+
"Marketing and Market Media":"Marketing",
|
|
103
|
+
"Finance, Property and Legal":"Finance",// this field doesnt exists in the database
|
|
104
|
+
"Services":"ServicesInstallation",
|
|
105
|
+
"Merchandise - Design and Sourcing":"Merchandise",
|
|
106
|
+
"Store Operations":"Operations",// this field doesnt exists in the database
|
|
107
|
+
"Data":"InsightsandDataScience",// this field doesnt exists in the database
|
|
108
|
+
"Property":"Property",// this field doesnt exists in the database,
|
|
109
|
+
"Legal":"Legal",// this field doesnt exists in the database,
|
|
110
|
+
"Supply Chain and Logistics":"Logistics",
|
|
111
|
+
"Contact Centres":"CustomerEngagementCentres",// this field doesnt exists in the database
|
|
112
|
+
"Commercial":"CommercialSales",// this field doesnt exists in the database
|
|
113
|
+
},
|
|
114
|
+
excludeValues: new Set([
|
|
115
|
+
"Noel Leeming Commercial",
|
|
116
|
+
"Noel Leeming Services",
|
|
117
|
+
"Sustainability"
|
|
118
|
+
])
|
|
119
|
+
}
|
|
120
|
+
const LINKS={
|
|
121
|
+
myApplication:'https://www.smartrecruiters.com/app/employee-portal/68246e5512d84f4c00a19e62/job-applications',
|
|
122
|
+
myReferrals:'https://www.smartrecruiters.com/app/referrals/',
|
|
123
|
+
login:'https://www.smartrecruiters.com/web-sso/saml/${companyId}/login',
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
const supportTeamsPageSections={
|
|
128
|
+
RECENT_JOBS: "recentJobs",
|
|
129
|
+
PEOPLE: "people",
|
|
130
|
+
VIDEO: "video",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
module.exports = {
|
|
135
|
+
TASKS_NAMES,
|
|
136
|
+
TASK_TYPE,
|
|
137
|
+
TASKS,
|
|
138
|
+
QUERY_MAX_LIMIT,
|
|
139
|
+
supportTeamsPageIds,
|
|
140
|
+
LINKS,
|
|
141
|
+
supportTeamsPageSections,
|
|
88
142
|
};
|
package/backend/data.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
const { items: wixData } = require('@wix/data');
|
|
2
2
|
const { fetchPositionsFromSRAPI, fetchJobDescription } = require('./fetchPositionsFromSRAPI');
|
|
3
3
|
const { createCollectionIfMissing } = require('@hisense-staging/velo-npm/backend');
|
|
4
|
-
const { COLLECTIONS, COLLECTIONS_FIELDS,JOBS_COLLECTION_FIELDS,TEMPLATE_TYPE,TOKEN_NAME } = require('./collectionConsts');
|
|
4
|
+
const { COLLECTIONS, COLLECTIONS_FIELDS,JOBS_COLLECTION_FIELDS,TEMPLATE_TYPE,TOKEN_NAME,CUSTOM_VALUES_COLLECTION_FIELDS } = require('./collectionConsts');
|
|
5
5
|
const { chunkedBulkOperation, countJobsPerGivenField, fillCityLocationAndLocationAddress ,prepareToSaveArray,normalizeString} = require('./utils');
|
|
6
6
|
const { getAllPositions } = require('./queries');
|
|
7
|
-
const { retrieveSecretVal, getTokenFromCMS } = require('./secretsData');
|
|
7
|
+
const { retrieveSecretVal, getTokenFromCMS ,getApiKeys} = require('./secretsData');
|
|
8
|
+
|
|
9
|
+
let customValuesToJobs = {}
|
|
10
|
+
let locationToJobs = {}
|
|
11
|
+
let siteconfig;
|
|
12
|
+
const EXCLUDED_CUSTOM_FIELDS = new Set(["Department","Country"]);
|
|
8
13
|
|
|
9
14
|
function getBrand(customField) {
|
|
10
15
|
return customField.find(field => field.fieldLabel === 'Brands')?.valueLabel;
|
|
11
16
|
}
|
|
12
17
|
|
|
18
|
+
async function getSiteConfig() {
|
|
19
|
+
const queryresult = await wixData.query(COLLECTIONS.SITE_CONFIGS).find();
|
|
20
|
+
siteconfig = queryresult.items[0];
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
function validatePosition(position) {
|
|
14
24
|
if (!position.id) {
|
|
15
25
|
throw new Error('Position id is required');
|
|
@@ -29,22 +39,22 @@ function validatePosition(position) {
|
|
|
29
39
|
async function filterBasedOnBrand(positions) {
|
|
30
40
|
try{
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
} catch (error) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const desiredBrand = await getTokenFromCMS(TOKEN_NAME.DESIRED_BRAND);
|
|
43
|
+
validateSingleDesiredBrand(desiredBrand);
|
|
44
|
+
console.log("filtering positions based on brand: ", desiredBrand);\
|
|
45
|
+
return positions.content.filter(position => {
|
|
46
|
+
const brand = getBrand(position.customField);
|
|
47
|
+
if (!brand) return false;
|
|
48
|
+
return brand === desiredBrand;
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if(error.message==="[getTokenFromCMS], No desiredBrand found")
|
|
52
|
+
{
|
|
53
|
+
console.log("no desiredBrand found, fetching all positions")
|
|
54
|
+
return positions.content;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
45
57
|
}
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
function validateSingleDesiredBrand(desiredBrand) {
|
|
@@ -53,12 +63,60 @@ function validateSingleDesiredBrand(desiredBrand) {
|
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
|
|
66
|
+
function getLocation(position,basicJob) {
|
|
67
|
+
locationToJobs[basicJob.cityText] ? locationToJobs[basicJob.cityText].push(position.id) : locationToJobs[basicJob.cityText]=[position.id]
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getVisibility(position,customFieldsValues) {
|
|
72
|
+
if (!customFieldsValues["Visibility"]) {
|
|
73
|
+
customFieldsValues["Visibility"] = {};
|
|
74
|
+
}
|
|
75
|
+
let visibility;
|
|
76
|
+
position.visibility.toLowerCase()==="public"? visibility="external" : visibility="internal";
|
|
77
|
+
customFieldsValues["Visibility"][visibility] = visibility;
|
|
78
|
+
customValuesToJobs[visibility] ? customValuesToJobs[visibility].add(position.id) : customValuesToJobs[visibility]=new Set([position.id])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getEmploymentType(position,customFieldsValues) {
|
|
82
|
+
if (!customFieldsValues["employmentType"]) {
|
|
83
|
+
customFieldsValues["employmentType"] = {};
|
|
84
|
+
}
|
|
85
|
+
customFieldsValues["employmentType"][position.typeOfEmployment.id] = position.typeOfEmployment.label;
|
|
86
|
+
customValuesToJobs[position.typeOfEmployment.id] ? customValuesToJobs[position.typeOfEmployment.id].add(position.id) : customValuesToJobs[position.typeOfEmployment.id]=new Set([position.id])
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getCustomFieldsAndValuesFromPosition(position,customFieldsLabels,customFieldsValues) {
|
|
90
|
+
const customFieldsArray = Array.isArray(position?.customField) ? position.customField : [];
|
|
91
|
+
for (const field of customFieldsArray) {
|
|
92
|
+
if(EXCLUDED_CUSTOM_FIELDS.has(field.fieldLabel)) continue; //country and department are not custom fields, they are already in the job object
|
|
93
|
+
const fieldId=normalizeString(field.fieldId)
|
|
94
|
+
const fieldLabel = field.fieldLabel;
|
|
95
|
+
const valueId=normalizeString(field.valueId)
|
|
96
|
+
const valueLabel = field.valueLabel
|
|
97
|
+
customFieldsLabels[fieldId] = fieldLabel
|
|
98
|
+
// Build nested dictionary: fieldId -> { valueId: valueLabel }
|
|
99
|
+
if (!customFieldsValues[fieldId]) {
|
|
100
|
+
customFieldsValues[fieldId] = {};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
customFieldsValues[fieldId][valueId] = valueLabel;
|
|
104
|
+
customValuesToJobs[valueId] ? customValuesToJobs[valueId].add(position.id) : customValuesToJobs[valueId]=new Set([position.id])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
56
107
|
async function saveJobsDataToCMS() {
|
|
57
108
|
const positions = await fetchPositionsFromSRAPI();
|
|
58
109
|
const sourcePositions = await filterBasedOnBrand(positions);
|
|
110
|
+
const customFieldsLabels = {}
|
|
111
|
+
const customFieldsValues = {}
|
|
59
112
|
|
|
113
|
+
const {companyId,templateType} = await getApiKeys();
|
|
114
|
+
if(siteconfig===undefined) {
|
|
115
|
+
await getSiteConfig();
|
|
116
|
+
}
|
|
60
117
|
// bulk insert to jobs collection without descriptions first
|
|
61
118
|
const jobsData = sourcePositions.map(position => {
|
|
119
|
+
|
|
62
120
|
const basicJob = {
|
|
63
121
|
_id: position.id,
|
|
64
122
|
title: position.name || '',
|
|
@@ -79,12 +137,26 @@ async function saveJobsDataToCMS() {
|
|
|
79
137
|
country: position.location?.country || '',
|
|
80
138
|
remote: position.location?.remote || false,
|
|
81
139
|
language: position.language?.label || '',
|
|
82
|
-
brand: getBrand(position.customField),
|
|
140
|
+
brand: siteconfig.disableMultiBrand==="false" ? getBrand(position.customField) : '',
|
|
83
141
|
jobDescription: null, // Will be filled later
|
|
142
|
+
employmentType: position.typeOfEmployment.label,
|
|
143
|
+
releasedDate: position.releasedDate,
|
|
144
|
+
refId: position.refNumber
|
|
84
145
|
};
|
|
146
|
+
|
|
147
|
+
getCustomFieldsAndValuesFromPosition(position,customFieldsLabels,customFieldsValues);
|
|
148
|
+
getEmploymentType(position,customFieldsValues);
|
|
149
|
+
getLocation(position,basicJob);
|
|
150
|
+
if(templateType===TEMPLATE_TYPE.INTERNAL){
|
|
151
|
+
getVisibility(position,customFieldsValues);
|
|
152
|
+
}
|
|
85
153
|
return basicJob;
|
|
86
154
|
});
|
|
87
155
|
|
|
156
|
+
if (siteconfig.customFields==="true") {
|
|
157
|
+
await populateCustomFieldsCollection(customFieldsLabels,templateType);
|
|
158
|
+
await populateCustomValuesCollection(customFieldsValues);
|
|
159
|
+
}
|
|
88
160
|
// Sort jobs by title (ascending, case-insensitive, numeric-aware)
|
|
89
161
|
jobsData.sort((a, b) => {
|
|
90
162
|
const titleA = a.title || '';
|
|
@@ -119,15 +191,60 @@ async function saveJobsDataToCMS() {
|
|
|
119
191
|
}
|
|
120
192
|
},
|
|
121
193
|
});
|
|
122
|
-
|
|
123
194
|
console.log(`✓ All chunks processed. Total jobs saved: ${totalSaved}/${jobsData.length}`);
|
|
124
195
|
}
|
|
125
196
|
|
|
126
|
-
async function
|
|
197
|
+
async function insertJobsReference(valueId) {
|
|
198
|
+
await wixData.insertReference(COLLECTIONS.CUSTOM_VALUES, CUSTOM_VALUES_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES,valueId, Array.from(customValuesToJobs[valueId]));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function populateCustomFieldsCollection(customFields,templateType) {
|
|
202
|
+
let fieldstoinsert=[]
|
|
203
|
+
customFields["employmentType"] = "Employment Type";
|
|
204
|
+
if(templateType===TEMPLATE_TYPE.INTERNAL){
|
|
205
|
+
customFields["Visibility"] = "Visibility";
|
|
206
|
+
}
|
|
207
|
+
for(const ID of Object.keys(customFields)){
|
|
208
|
+
fieldstoinsert.push({
|
|
209
|
+
title: customFields[ID],
|
|
210
|
+
_id: ID,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
await wixData.bulkSave(COLLECTIONS.CUSTOM_FIELDS, fieldstoinsert);
|
|
214
|
+
}
|
|
215
|
+
async function populateCustomValuesCollection(customFieldsValues) {
|
|
216
|
+
let valuesToinsert=[]
|
|
217
|
+
for (const fieldId of Object.keys(customFieldsValues)) {
|
|
218
|
+
const valuesMap = customFieldsValues[fieldId] || {};
|
|
219
|
+
for (const valueId of Object.keys(valuesMap)) {
|
|
220
|
+
valuesToinsert.push({
|
|
221
|
+
_id: valueId,
|
|
222
|
+
title: valuesMap[valueId],
|
|
223
|
+
customField: fieldId,
|
|
224
|
+
count:customValuesToJobs[valueId].size,
|
|
225
|
+
jobIds:Array.from(customValuesToJobs[valueId]),
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
await wixData.bulkSave(COLLECTIONS.CUSTOM_VALUES, valuesToinsert);
|
|
231
|
+
}
|
|
232
|
+
async function saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS() {
|
|
127
233
|
console.log('🚀 Starting job descriptions update process for ALL jobs');
|
|
128
234
|
|
|
129
235
|
try {
|
|
130
236
|
let jobsWithNoDescriptions = await getJobsWithNoDescriptions();
|
|
237
|
+
if (siteconfig.customFields==="true") {
|
|
238
|
+
let customValues=await getAllCustomValues();
|
|
239
|
+
console.log("inserting jobs references to custom values collection");
|
|
240
|
+
console.log("customValues: ",customValues)
|
|
241
|
+
console.log("customValues.items: ",customValues.items)
|
|
242
|
+
for (const value of customValues.items) {
|
|
243
|
+
await insertJobsReference(value._id);
|
|
244
|
+
}
|
|
245
|
+
console.log("inserted jobs references to custom values collection successfully");
|
|
246
|
+
}
|
|
247
|
+
|
|
131
248
|
let totalUpdated = 0;
|
|
132
249
|
let totalFailed = 0;
|
|
133
250
|
let totalProcessed = 0;
|
|
@@ -156,7 +273,7 @@ async function saveJobsDescriptionsAndLocationApplyUrlToCMS() {
|
|
|
156
273
|
const jobLocation = fetchJobLocation(jobDetails);
|
|
157
274
|
const {applyLink , referFriendLink} = fetchApplyAndReferFriendLink(jobDetails);
|
|
158
275
|
|
|
159
|
-
|
|
276
|
+
|
|
160
277
|
const updatedJob = {
|
|
161
278
|
...job,
|
|
162
279
|
locationAddress: jobLocation,
|
|
@@ -220,7 +337,7 @@ async function aggregateJobsByFieldToCMS({ field, collection }) {
|
|
|
220
337
|
console.log(`counting jobs per ${field}.`);
|
|
221
338
|
let results = await getAllPositions();
|
|
222
339
|
const { jobsPerField, cityLocations,citylocationAddress } = iterateOverAllJobs(results, field);
|
|
223
|
-
const toSave = prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress);
|
|
340
|
+
const toSave = prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress,locationToJobs);
|
|
224
341
|
if (toSave.length === 0) {
|
|
225
342
|
console.log('No jobs found.');
|
|
226
343
|
return { success: true, message: 'No jobs to save.' };
|
|
@@ -236,7 +353,10 @@ async function aggregateJobsByFieldToCMS({ field, collection }) {
|
|
|
236
353
|
return { success: false, error: err.message };
|
|
237
354
|
}
|
|
238
355
|
}
|
|
239
|
-
|
|
356
|
+
async function getAllCustomValues() {
|
|
357
|
+
let customValuesQuery = await wixData.query(COLLECTIONS.CUSTOM_VALUES).limit(1000).find();
|
|
358
|
+
return customValuesQuery;
|
|
359
|
+
}
|
|
240
360
|
async function getJobsWithNoDescriptions() {
|
|
241
361
|
let jobswithoutdescriptionsQuery = await wixData
|
|
242
362
|
.query(COLLECTIONS.JOBS)
|
|
@@ -280,6 +400,7 @@ async function referenceJobsToField({ referenceField, sourceCollection, jobField
|
|
|
280
400
|
return rest;
|
|
281
401
|
});
|
|
282
402
|
|
|
403
|
+
|
|
283
404
|
// Bulk update in chunks of 1000
|
|
284
405
|
const chunkSize = 1000;
|
|
285
406
|
await chunkedBulkOperation({
|
|
@@ -325,11 +446,13 @@ function fetchJobLocation(jobDetails) {
|
|
|
325
446
|
async function createCollections() {
|
|
326
447
|
console.log("Creating collections");
|
|
327
448
|
await Promise.all(
|
|
328
|
-
[createCollectionIfMissing(COLLECTIONS.JOBS,
|
|
449
|
+
[createCollectionIfMissing(COLLECTIONS.JOBS, COLLECTIONS_FIELDS.JOBS,{ insert: 'ADMIN', update: 'ADMIN', remove: 'ADMIN', read: 'ANYONE' }),
|
|
329
450
|
createCollectionIfMissing(COLLECTIONS.CITIES, COLLECTIONS_FIELDS.CITIES),
|
|
330
451
|
createCollectionIfMissing(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT, COLLECTIONS_FIELDS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
331
452
|
createCollectionIfMissing(COLLECTIONS.SECRET_MANAGER_MIRROR, COLLECTIONS_FIELDS.SECRET_MANAGER_MIRROR),
|
|
332
|
-
createCollectionIfMissing(COLLECTIONS.BRANDS, COLLECTIONS_FIELDS.BRANDS)
|
|
453
|
+
createCollectionIfMissing(COLLECTIONS.BRANDS, COLLECTIONS_FIELDS.BRANDS),
|
|
454
|
+
createCollectionIfMissing(COLLECTIONS.CUSTOM_VALUES, COLLECTIONS_FIELDS.CUSTOM_VALUES),
|
|
455
|
+
createCollectionIfMissing(COLLECTIONS.CUSTOM_FIELDS, COLLECTIONS_FIELDS.CUSTOM_FIELDS)
|
|
333
456
|
]);
|
|
334
457
|
console.log("finished creating Collections");
|
|
335
458
|
}
|
|
@@ -346,9 +469,15 @@ async function aggregateJobs() {
|
|
|
346
469
|
|
|
347
470
|
async function referenceJobs() {
|
|
348
471
|
console.log("Reference jobs");
|
|
472
|
+
if(siteconfig===undefined) {
|
|
473
|
+
await getSiteConfig();
|
|
474
|
+
}
|
|
349
475
|
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.DEPARTMENT_REF, sourceCollection: COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT, jobField: JOBS_COLLECTION_FIELDS.DEPARTMENT });
|
|
350
476
|
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.CITY, sourceCollection: COLLECTIONS.CITIES, jobField: JOBS_COLLECTION_FIELDS.CITY_TEXT });
|
|
351
|
-
|
|
477
|
+
if(siteconfig.disableMultiBrand==="false"){
|
|
478
|
+
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.BRAND_REF, sourceCollection: COLLECTIONS.BRANDS, jobField: JOBS_COLLECTION_FIELDS.BRAND });
|
|
479
|
+
}
|
|
480
|
+
|
|
352
481
|
console.log("finished referencing jobs");
|
|
353
482
|
}
|
|
354
483
|
|
|
@@ -357,24 +486,30 @@ async function syncJobsFast() {
|
|
|
357
486
|
await createCollections();
|
|
358
487
|
await clearCollections();
|
|
359
488
|
await fillSecretManagerMirror();
|
|
489
|
+
|
|
360
490
|
console.log("saving jobs data to CMS");
|
|
361
491
|
await saveJobsDataToCMS();
|
|
362
492
|
console.log("saved jobs data to CMS successfully");
|
|
493
|
+
|
|
363
494
|
console.log("saving jobs descriptions and location apply url to CMS");
|
|
364
|
-
await
|
|
495
|
+
await saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS();
|
|
496
|
+
|
|
365
497
|
console.log("saved jobs descriptions and location apply url to CMS successfully");
|
|
366
498
|
await aggregateJobs();
|
|
367
499
|
await referenceJobs();
|
|
368
500
|
console.log("syncing jobs fast finished successfully");
|
|
369
501
|
}
|
|
370
502
|
|
|
503
|
+
|
|
371
504
|
async function clearCollections() {
|
|
372
505
|
console.log("clearing collections");
|
|
373
506
|
await Promise.all([
|
|
374
507
|
wixData.truncate(COLLECTIONS.CITIES),
|
|
375
508
|
wixData.truncate(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
376
509
|
wixData.truncate(COLLECTIONS.JOBS),
|
|
377
|
-
wixData.truncate(COLLECTIONS.BRANDS)
|
|
510
|
+
wixData.truncate(COLLECTIONS.BRANDS),
|
|
511
|
+
wixData.truncate(COLLECTIONS.CUSTOM_VALUES),
|
|
512
|
+
wixData.truncate(COLLECTIONS.CUSTOM_FIELDS),
|
|
378
513
|
]);
|
|
379
514
|
console.log("cleared collections successfully");
|
|
380
515
|
}
|
|
@@ -423,7 +558,7 @@ module.exports = {
|
|
|
423
558
|
aggregateJobs,
|
|
424
559
|
createCollections,
|
|
425
560
|
saveJobsDataToCMS,
|
|
426
|
-
|
|
561
|
+
saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS,
|
|
427
562
|
aggregateJobsByFieldToCMS,
|
|
428
563
|
referenceJobsToField,
|
|
429
564
|
fillSecretManagerMirror,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const { fetch } = require('wix-fetch');
|
|
2
2
|
const { TEMPLATE_TYPE,TOKEN_NAME } = require('./collectionConsts');
|
|
3
3
|
const { getTokenFromCMS,getApiKeys } = require('./secretsData');
|
|
4
|
+
|
|
4
5
|
async function makeSmartRecruitersRequest(path,templateType) {
|
|
5
|
-
|
|
6
|
+
const baseUrl = 'https://api.smartrecruiters.com';
|
|
6
7
|
const fullUrl = `${baseUrl}${path}`;
|
|
7
8
|
|
|
8
9
|
try {
|
package/backend/index.js
CHANGED
package/backend/queries.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { COLLECTIONS } = require('./collectionConsts');
|
|
1
|
+
const { COLLECTIONS,JOBS_COLLECTION_FIELDS } = require('./collectionConsts');
|
|
2
2
|
const { items: wixData } = require('@wix/data');
|
|
3
3
|
|
|
4
4
|
|
|
@@ -18,7 +18,11 @@ async function getPositionsByField(field, value) {
|
|
|
18
18
|
.then(result => result.items);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
async function getPositionWithMultiRefField(jobId)
|
|
22
|
+
{
|
|
23
|
+
return wixData
|
|
24
|
+
.queryReferenced(COLLECTIONS.JOBS,jobId,JOBS_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES)
|
|
25
|
+
.then(result => result.items);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { getAllPositions, getPositionsByField, getPositionWithMultiRefField };
|