sr-npm 1.0.21 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/update-sites.yml +27 -0
- package/backend/careersMultiBoxesPageIds.js +61 -0
- package/backend/collectionConsts.js +60 -5
- package/backend/consts.js +68 -14
- package/backend/data.js +201 -34
- package/backend/index.js +2 -0
- package/backend/queries.js +9 -5
- package/backend/secretsData.js +6 -14
- package/backend/utils.js +11 -16
- 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 +521 -0
- package/pages/careersPage.js +162 -83
- 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 +107 -2
- package/pages/supportTeamsPage.js +92 -0
- package/public/selectors.js +43 -0
- package/public/utils.js +12 -2
- 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
package/backend/data.js
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
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');
|
|
5
|
-
const { chunkedBulkOperation, countJobsPerGivenField, fillCityLocationAndLocationAddress ,prepareToSaveArray,
|
|
4
|
+
const { COLLECTIONS, COLLECTIONS_FIELDS,JOBS_COLLECTION_FIELDS,TEMPLATE_TYPE,TOKEN_NAME,CUSTOM_VALUES_COLLECTION_FIELDS } = require('./collectionConsts');
|
|
5
|
+
const { chunkedBulkOperation, countJobsPerGivenField, fillCityLocationAndLocationAddress ,prepareToSaveArray,normalizeString} = require('./utils');
|
|
6
6
|
const { getAllPositions } = require('./queries');
|
|
7
|
-
const {
|
|
7
|
+
const { retrieveSecretVal, getTokenFromCMS ,getApiKeys} = require('./secretsData');
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
let customValuesToJobs = {}
|
|
12
|
+
let locationToJobs = {}
|
|
13
|
+
let siteconfig;
|
|
14
|
+
const EXCLUDED_CUSTOM_FIELDS = new Set(["Department","Country"]);
|
|
15
|
+
|
|
16
|
+
function getBrand(customField) {
|
|
17
|
+
return customField.find(field => field.fieldLabel === 'Brands')?.valueLabel;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function getSiteConfig() {
|
|
21
|
+
const queryresult = await wixData.query(COLLECTIONS.SITE_CONFIGS).find();
|
|
22
|
+
siteconfig = queryresult.items[0];
|
|
23
|
+
}
|
|
9
24
|
function validatePosition(position) {
|
|
10
25
|
if (!position.id) {
|
|
11
26
|
throw new Error('Position id is required');
|
|
@@ -22,15 +37,91 @@ function validatePosition(position) {
|
|
|
22
37
|
|
|
23
38
|
}
|
|
24
39
|
|
|
40
|
+
async function filterBasedOnBrand(positions) {
|
|
41
|
+
try{
|
|
42
|
+
|
|
43
|
+
const desiredBrand = await getTokenFromCMS(TOKEN_NAME.DESIRED_BRAND);
|
|
44
|
+
validateSingleDesiredBrand(desiredBrand);
|
|
45
|
+
console.log("filtering positions based on brand: ", desiredBrand);
|
|
46
|
+
return positions.content.filter(position => {
|
|
47
|
+
const brand = getBrand(position.customField);
|
|
48
|
+
if (!brand) return false;
|
|
49
|
+
return brand === desiredBrand;
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if(error.message==="[getTokenFromCMS], No desiredBrand found")
|
|
53
|
+
{
|
|
54
|
+
console.log("no desiredBrand found, fetching all positions")
|
|
55
|
+
return positions.content;
|
|
56
|
+
}
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function validateSingleDesiredBrand(desiredBrand) {
|
|
62
|
+
if(typeof desiredBrand !== 'string' || desiredBrand.includes("[") || desiredBrand.includes("]") || desiredBrand.includes(",")){
|
|
63
|
+
throw new Error("Desired brand must be a single brand");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getLocation(position,basicJob) {
|
|
67
|
+
|
|
68
|
+
locationToJobs[basicJob.cityText] ? locationToJobs[basicJob.cityText].push(position.id) : locationToJobs[basicJob.cityText]=[position.id]
|
|
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
|
+
customFieldsValues[fieldId][valueId] = valueLabel;
|
|
103
|
+
|
|
104
|
+
customValuesToJobs[valueId] ? customValuesToJobs[valueId].add(position.id) : customValuesToJobs[valueId]=new Set([position.id])
|
|
105
|
+
}
|
|
106
|
+
}
|
|
25
107
|
async function saveJobsDataToCMS() {
|
|
26
108
|
const positions = await fetchPositionsFromSRAPI();
|
|
109
|
+
const sourcePositions = await filterBasedOnBrand(positions);
|
|
110
|
+
const customFieldsLabels = {}
|
|
111
|
+
const customFieldsValues = {}
|
|
112
|
+
|
|
113
|
+
const {companyId,templateType} = await getApiKeys();
|
|
114
|
+
if(siteconfig===undefined) {
|
|
115
|
+
await getSiteConfig();
|
|
116
|
+
}
|
|
27
117
|
// bulk insert to jobs collection without descriptions first
|
|
28
|
-
const jobsData =
|
|
118
|
+
const jobsData = sourcePositions.map(position => {
|
|
119
|
+
|
|
29
120
|
const basicJob = {
|
|
30
121
|
_id: position.id,
|
|
31
122
|
title: position.name || '',
|
|
32
123
|
department: position.department?.label || 'Other',
|
|
33
|
-
cityText:
|
|
124
|
+
cityText: normalizeString(position.location?.city),
|
|
34
125
|
location: position.location && Object.keys(position.location).length > 0
|
|
35
126
|
? position.location
|
|
36
127
|
: {
|
|
@@ -46,11 +137,25 @@ async function saveJobsDataToCMS() {
|
|
|
46
137
|
country: position.location?.country || '',
|
|
47
138
|
remote: position.location?.remote || false,
|
|
48
139
|
language: position.language?.label || '',
|
|
140
|
+
brand: siteconfig.disableMultiBrand==="false" ? getBrand(position.customField) : '',
|
|
49
141
|
jobDescription: null, // Will be filled later
|
|
142
|
+
employmentType: position.typeOfEmployment.label,
|
|
143
|
+
releasedDate: position.releasedDate
|
|
50
144
|
};
|
|
145
|
+
|
|
146
|
+
getCustomFieldsAndValuesFromPosition(position,customFieldsLabels,customFieldsValues);
|
|
147
|
+
getEmploymentType(position,customFieldsValues);
|
|
148
|
+
getLocation(position,basicJob);
|
|
149
|
+
if(templateType===TEMPLATE_TYPE.INTERNAL){
|
|
150
|
+
getVisibility(position,customFieldsValues);
|
|
151
|
+
}
|
|
51
152
|
return basicJob;
|
|
52
153
|
});
|
|
53
154
|
|
|
155
|
+
if (siteconfig.customFields==="true") {
|
|
156
|
+
await populateCustomFieldsCollection(customFieldsLabels,templateType);
|
|
157
|
+
await populateCustomValuesCollection(customFieldsValues);
|
|
158
|
+
}
|
|
54
159
|
// Sort jobs by title (ascending, case-insensitive, numeric-aware)
|
|
55
160
|
jobsData.sort((a, b) => {
|
|
56
161
|
const titleA = a.title || '';
|
|
@@ -85,15 +190,60 @@ async function saveJobsDataToCMS() {
|
|
|
85
190
|
}
|
|
86
191
|
},
|
|
87
192
|
});
|
|
88
|
-
|
|
89
193
|
console.log(`✓ All chunks processed. Total jobs saved: ${totalSaved}/${jobsData.length}`);
|
|
90
194
|
}
|
|
91
195
|
|
|
92
|
-
async function
|
|
196
|
+
async function insertJobsReference(valueId) {
|
|
197
|
+
await wixData.insertReference(COLLECTIONS.CUSTOM_VALUES, CUSTOM_VALUES_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES,valueId, Array.from(customValuesToJobs[valueId]));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function populateCustomFieldsCollection(customFields,templateType) {
|
|
201
|
+
let fieldstoinsert=[]
|
|
202
|
+
customFields["employmentType"] = "Employment Type";
|
|
203
|
+
if(templateType===TEMPLATE_TYPE.INTERNAL){
|
|
204
|
+
customFields["Visibility"] = "Visibility";
|
|
205
|
+
}
|
|
206
|
+
for(const ID of Object.keys(customFields)){
|
|
207
|
+
fieldstoinsert.push({
|
|
208
|
+
title: customFields[ID],
|
|
209
|
+
_id: ID,
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
await wixData.bulkSave(COLLECTIONS.CUSTOM_FIELDS, fieldstoinsert);
|
|
213
|
+
}
|
|
214
|
+
async function populateCustomValuesCollection(customFieldsValues) {
|
|
215
|
+
let valuesToinsert=[]
|
|
216
|
+
for (const fieldId of Object.keys(customFieldsValues)) {
|
|
217
|
+
const valuesMap = customFieldsValues[fieldId] || {};
|
|
218
|
+
for (const valueId of Object.keys(valuesMap)) {
|
|
219
|
+
valuesToinsert.push({
|
|
220
|
+
_id: valueId,
|
|
221
|
+
title: valuesMap[valueId],
|
|
222
|
+
customField: fieldId,
|
|
223
|
+
count:customValuesToJobs[valueId].size,
|
|
224
|
+
jobIds:Array.from(customValuesToJobs[valueId]),
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
await wixData.bulkSave(COLLECTIONS.CUSTOM_VALUES, valuesToinsert);
|
|
230
|
+
}
|
|
231
|
+
async function saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS() {
|
|
93
232
|
console.log('🚀 Starting job descriptions update process for ALL jobs');
|
|
94
233
|
|
|
95
234
|
try {
|
|
96
235
|
let jobsWithNoDescriptions = await getJobsWithNoDescriptions();
|
|
236
|
+
if (siteconfig.customFields==="true") {
|
|
237
|
+
let customValues=await getAllCustomValues();
|
|
238
|
+
console.log("inserting jobs references to custom values collection");
|
|
239
|
+
console.log("customValues: ",customValues)
|
|
240
|
+
console.log("customValues.items: ",customValues.items)
|
|
241
|
+
for (const value of customValues.items) {
|
|
242
|
+
await insertJobsReference(value._id);
|
|
243
|
+
}
|
|
244
|
+
console.log("inserted jobs references to custom values collection successfully");
|
|
245
|
+
}
|
|
246
|
+
|
|
97
247
|
let totalUpdated = 0;
|
|
98
248
|
let totalFailed = 0;
|
|
99
249
|
let totalProcessed = 0;
|
|
@@ -122,7 +272,7 @@ async function saveJobsDescriptionsAndLocationApplyUrlToCMS() {
|
|
|
122
272
|
const jobLocation = fetchJobLocation(jobDetails);
|
|
123
273
|
const {applyLink , referFriendLink} = fetchApplyAndReferFriendLink(jobDetails);
|
|
124
274
|
|
|
125
|
-
|
|
275
|
+
|
|
126
276
|
const updatedJob = {
|
|
127
277
|
...job,
|
|
128
278
|
locationAddress: jobLocation,
|
|
@@ -186,7 +336,7 @@ async function aggregateJobsByFieldToCMS({ field, collection }) {
|
|
|
186
336
|
console.log(`counting jobs per ${field}.`);
|
|
187
337
|
let results = await getAllPositions();
|
|
188
338
|
const { jobsPerField, cityLocations,citylocationAddress } = iterateOverAllJobs(results, field);
|
|
189
|
-
const toSave = prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress);
|
|
339
|
+
const toSave = prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress,locationToJobs);
|
|
190
340
|
if (toSave.length === 0) {
|
|
191
341
|
console.log('No jobs found.');
|
|
192
342
|
return { success: true, message: 'No jobs to save.' };
|
|
@@ -202,7 +352,10 @@ async function aggregateJobsByFieldToCMS({ field, collection }) {
|
|
|
202
352
|
return { success: false, error: err.message };
|
|
203
353
|
}
|
|
204
354
|
}
|
|
205
|
-
|
|
355
|
+
async function getAllCustomValues() {
|
|
356
|
+
let customValuesQuery = await wixData.query(COLLECTIONS.CUSTOM_VALUES).limit(1000).find();
|
|
357
|
+
return customValuesQuery;
|
|
358
|
+
}
|
|
206
359
|
async function getJobsWithNoDescriptions() {
|
|
207
360
|
let jobswithoutdescriptionsQuery = await wixData
|
|
208
361
|
.query(COLLECTIONS.JOBS)
|
|
@@ -246,6 +399,7 @@ async function referenceJobsToField({ referenceField, sourceCollection, jobField
|
|
|
246
399
|
return rest;
|
|
247
400
|
});
|
|
248
401
|
|
|
402
|
+
|
|
249
403
|
// Bulk update in chunks of 1000
|
|
250
404
|
const chunkSize = 1000;
|
|
251
405
|
await chunkedBulkOperation({
|
|
@@ -291,10 +445,13 @@ function fetchJobLocation(jobDetails) {
|
|
|
291
445
|
async function createCollections() {
|
|
292
446
|
console.log("Creating collections");
|
|
293
447
|
await Promise.all(
|
|
294
|
-
[createCollectionIfMissing(COLLECTIONS.JOBS,
|
|
448
|
+
[createCollectionIfMissing(COLLECTIONS.JOBS, COLLECTIONS_FIELDS.JOBS,{ insert: 'ADMIN', update: 'ADMIN', remove: 'ADMIN', read: 'ANYONE' }),
|
|
295
449
|
createCollectionIfMissing(COLLECTIONS.CITIES, COLLECTIONS_FIELDS.CITIES),
|
|
296
450
|
createCollectionIfMissing(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT, COLLECTIONS_FIELDS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
297
|
-
createCollectionIfMissing(COLLECTIONS.SECRET_MANAGER_MIRROR, COLLECTIONS_FIELDS.SECRET_MANAGER_MIRROR)
|
|
451
|
+
createCollectionIfMissing(COLLECTIONS.SECRET_MANAGER_MIRROR, COLLECTIONS_FIELDS.SECRET_MANAGER_MIRROR),
|
|
452
|
+
createCollectionIfMissing(COLLECTIONS.BRANDS, COLLECTIONS_FIELDS.BRANDS),
|
|
453
|
+
createCollectionIfMissing(COLLECTIONS.CUSTOM_VALUES, COLLECTIONS_FIELDS.CUSTOM_VALUES),
|
|
454
|
+
createCollectionIfMissing(COLLECTIONS.CUSTOM_FIELDS, COLLECTIONS_FIELDS.CUSTOM_FIELDS)
|
|
298
455
|
]);
|
|
299
456
|
console.log("finished creating Collections");
|
|
300
457
|
}
|
|
@@ -303,15 +460,23 @@ async function aggregateJobs() {
|
|
|
303
460
|
console.log("Aggregating jobs");
|
|
304
461
|
await Promise.all([
|
|
305
462
|
aggregateJobsByFieldToCMS({ field: JOBS_COLLECTION_FIELDS.DEPARTMENT, collection: COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT }),
|
|
306
|
-
aggregateJobsByFieldToCMS({ field: JOBS_COLLECTION_FIELDS.CITY_TEXT, collection: COLLECTIONS.CITIES })
|
|
463
|
+
aggregateJobsByFieldToCMS({ field: JOBS_COLLECTION_FIELDS.CITY_TEXT, collection: COLLECTIONS.CITIES }),
|
|
464
|
+
aggregateJobsByFieldToCMS({ field: JOBS_COLLECTION_FIELDS.BRAND, collection: COLLECTIONS.BRANDS })
|
|
307
465
|
]);
|
|
308
466
|
console.log("finished aggregating jobs");
|
|
309
467
|
}
|
|
310
468
|
|
|
311
469
|
async function referenceJobs() {
|
|
312
470
|
console.log("Reference jobs");
|
|
471
|
+
if(siteconfig===undefined) {
|
|
472
|
+
await getSiteConfig();
|
|
473
|
+
}
|
|
313
474
|
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.DEPARTMENT_REF, sourceCollection: COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT, jobField: JOBS_COLLECTION_FIELDS.DEPARTMENT });
|
|
314
475
|
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.CITY, sourceCollection: COLLECTIONS.CITIES, jobField: JOBS_COLLECTION_FIELDS.CITY_TEXT });
|
|
476
|
+
if(siteconfig.disableMultiBrand==="false"){
|
|
477
|
+
await referenceJobsToField({ referenceField: JOBS_COLLECTION_FIELDS.BRAND_REF, sourceCollection: COLLECTIONS.BRANDS, jobField: JOBS_COLLECTION_FIELDS.BRAND });
|
|
478
|
+
}
|
|
479
|
+
|
|
315
480
|
console.log("finished referencing jobs");
|
|
316
481
|
}
|
|
317
482
|
|
|
@@ -324,19 +489,23 @@ async function syncJobsFast() {
|
|
|
324
489
|
await saveJobsDataToCMS();
|
|
325
490
|
console.log("saved jobs data to CMS successfully");
|
|
326
491
|
console.log("saving jobs descriptions and location apply url to CMS");
|
|
327
|
-
await
|
|
492
|
+
await saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS();
|
|
328
493
|
console.log("saved jobs descriptions and location apply url to CMS successfully");
|
|
329
494
|
await aggregateJobs();
|
|
330
495
|
await referenceJobs();
|
|
331
496
|
console.log("syncing jobs fast finished successfully");
|
|
332
497
|
}
|
|
333
498
|
|
|
499
|
+
|
|
334
500
|
async function clearCollections() {
|
|
335
501
|
console.log("clearing collections");
|
|
336
502
|
await Promise.all([
|
|
337
503
|
wixData.truncate(COLLECTIONS.CITIES),
|
|
338
504
|
wixData.truncate(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
339
|
-
wixData.truncate(COLLECTIONS.JOBS)
|
|
505
|
+
wixData.truncate(COLLECTIONS.JOBS),
|
|
506
|
+
wixData.truncate(COLLECTIONS.BRANDS),
|
|
507
|
+
wixData.truncate(COLLECTIONS.CUSTOM_VALUES),
|
|
508
|
+
wixData.truncate(COLLECTIONS.CUSTOM_FIELDS),
|
|
340
509
|
]);
|
|
341
510
|
console.log("cleared collections successfully");
|
|
342
511
|
}
|
|
@@ -358,27 +527,25 @@ async function markTemplateAsInternal() {
|
|
|
358
527
|
}
|
|
359
528
|
|
|
360
529
|
async function fillSecretManagerMirror() {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
console.log("companyId inserted into the SecretManagerMirror collection");
|
|
369
|
-
try{
|
|
370
|
-
const token = await getSmartToken();
|
|
371
|
-
await wixData.insert(COLLECTIONS.SECRET_MANAGER_MIRROR, {
|
|
372
|
-
tokenName: TOKEN_NAME.SMART_TOKEN,
|
|
373
|
-
tokenValue: token.value
|
|
374
|
-
});
|
|
375
|
-
console.log("x-smarttoken inserted into the SecretManagerMirror collection");
|
|
376
|
-
} catch (error) {
|
|
377
|
-
console.warn("Error with inserting x-smarttoken into the SecretManagerMirror collection:", error);
|
|
530
|
+
for(const tokenName of Object.values(TOKEN_NAME)){
|
|
531
|
+
try{
|
|
532
|
+
await insertSecretValToCMS(tokenName);
|
|
533
|
+
console.log("inserted ", tokenName, "into the SecretManagerMirror collection successfully");
|
|
534
|
+
} catch (error) {
|
|
535
|
+
console.warn("Error with inserting ", tokenName, "into the SecretManagerMirror collection:", error);
|
|
536
|
+
}
|
|
378
537
|
}
|
|
379
538
|
}
|
|
380
539
|
|
|
381
|
-
|
|
540
|
+
async function insertSecretValToCMS(tokenName) {
|
|
541
|
+
const token = await retrieveSecretVal(tokenName);
|
|
542
|
+
console.log("token is: ", token);
|
|
543
|
+
await wixData.save(COLLECTIONS.SECRET_MANAGER_MIRROR, {
|
|
544
|
+
tokenName: tokenName,
|
|
545
|
+
value: token.value,
|
|
546
|
+
_id: normalizeString(tokenName)
|
|
547
|
+
});
|
|
548
|
+
}
|
|
382
549
|
|
|
383
550
|
|
|
384
551
|
module.exports = {
|
|
@@ -387,7 +554,7 @@ module.exports = {
|
|
|
387
554
|
aggregateJobs,
|
|
388
555
|
createCollections,
|
|
389
556
|
saveJobsDataToCMS,
|
|
390
|
-
|
|
557
|
+
saveJobsDescriptionsAndLocationApplyUrlReferencesToCMS,
|
|
391
558
|
aggregateJobsByFieldToCMS,
|
|
392
559
|
referenceJobsToField,
|
|
393
560
|
fillSecretManagerMirror,
|
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 };
|
package/backend/secretsData.js
CHANGED
|
@@ -4,14 +4,7 @@ const { items: wixData } = require('@wix/data');
|
|
|
4
4
|
const { COLLECTIONS,TOKEN_NAME } = require('./collectionConsts');
|
|
5
5
|
|
|
6
6
|
const getSecretValue = auth.elevate(secrets.getSecretValue);
|
|
7
|
-
|
|
8
|
-
function getSmartToken() {
|
|
9
|
-
return retrieveSecretVal(TOKEN_NAME.SMART_TOKEN)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getCompanyId() {
|
|
13
|
-
return retrieveSecretVal(TOKEN_NAME.COMPANY_ID_SM)
|
|
14
|
-
}
|
|
7
|
+
const elevatedQuery = auth.elevate(wixData.query);
|
|
15
8
|
|
|
16
9
|
async function retrieveSecretVal(tokenName)
|
|
17
10
|
{
|
|
@@ -27,15 +20,15 @@ function getSmartToken() {
|
|
|
27
20
|
}
|
|
28
21
|
|
|
29
22
|
async function getTokenFromCMS(tokenName) {
|
|
30
|
-
const result = await
|
|
23
|
+
const result = await elevatedQuery(COLLECTIONS.SECRET_MANAGER_MIRROR).eq('tokenName',tokenName).find();
|
|
31
24
|
if (result.items.length > 0) {
|
|
32
|
-
return result.items[0].
|
|
25
|
+
return result.items[0].value;
|
|
33
26
|
} else {
|
|
34
27
|
throw new Error(`[getTokenFromCMS], No ${tokenName} found`);
|
|
35
28
|
}
|
|
36
29
|
}
|
|
37
30
|
async function getTemplateTypeFromCMS() {
|
|
38
|
-
const result = await
|
|
31
|
+
const result = await elevatedQuery(COLLECTIONS.TEMPLATE_TYPE).limit(1).find();
|
|
39
32
|
if (result.items.length > 0) {
|
|
40
33
|
return result.items[0].templateType;
|
|
41
34
|
} else {
|
|
@@ -50,8 +43,7 @@ function getSmartToken() {
|
|
|
50
43
|
}
|
|
51
44
|
|
|
52
45
|
module.exports = {
|
|
53
|
-
getCompanyId,
|
|
54
|
-
getSmartToken,
|
|
55
46
|
getTokenFromCMS,
|
|
56
|
-
getApiKeys
|
|
47
|
+
getApiKeys,
|
|
48
|
+
retrieveSecretVal
|
|
57
49
|
};
|
package/backend/utils.js
CHANGED
|
@@ -30,12 +30,12 @@ function fillCityLocationAndLocationAddress(jobs, cityLocations,citylocationAddr
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress) {
|
|
33
|
+
function prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress,customValuesToJobs=null) {
|
|
34
34
|
if (field === 'cityText') {
|
|
35
35
|
return Object.entries(jobsPerField).map(([value, amount]) => {
|
|
36
36
|
const loc = cityLocations[value] || {};
|
|
37
37
|
const locAddress = citylocationAddress[value] || {};
|
|
38
|
-
value =
|
|
38
|
+
value = normalizeString(value);
|
|
39
39
|
return {
|
|
40
40
|
title: value,
|
|
41
41
|
_id: value.replace(/\s+/g, ''),
|
|
@@ -43,34 +43,29 @@ function prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddre
|
|
|
43
43
|
locationAddress: locAddress,
|
|
44
44
|
country: loc.country,
|
|
45
45
|
city: loc.city,
|
|
46
|
+
jobIds: customValuesToJobs[value],
|
|
46
47
|
};
|
|
47
48
|
});
|
|
48
49
|
} else {
|
|
49
50
|
return Object.entries(jobsPerField).map(([value, amount]) => ({
|
|
50
51
|
title: value,
|
|
51
|
-
_id:
|
|
52
|
+
_id: normalizeString(value).replace(/&/g, 'and'),
|
|
52
53
|
count: amount,
|
|
53
54
|
}));
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
function
|
|
58
|
-
if (!
|
|
58
|
+
function normalizeString(str) {
|
|
59
|
+
if (!str) return str;
|
|
59
60
|
// Remove accents/diacritics, trim whitespace
|
|
60
|
-
return
|
|
61
|
+
return str
|
|
61
62
|
.normalize('NFD')
|
|
62
63
|
.replace(/\p{Diacritic}/gu, '')
|
|
64
|
+
.replace(/[^A-Za-z0-9-]/g, '')
|
|
63
65
|
.trim();
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
if (!input) return '';
|
|
68
|
-
const withoutDiacritics = String(input)
|
|
69
|
-
.normalize('NFD')
|
|
70
|
-
.replace(/\p{Diacritic}/gu, '');
|
|
71
|
-
const withAnd = withoutDiacritics.replace(/&/g, 'and');
|
|
72
|
-
return withAnd.replace(/[^A-Za-z0-9-]/g, '');
|
|
73
|
-
}
|
|
68
|
+
|
|
74
69
|
|
|
75
70
|
module.exports = {
|
|
76
71
|
chunkedBulkOperation,
|
|
@@ -78,6 +73,6 @@ module.exports = {
|
|
|
78
73
|
countJobsPerGivenField,
|
|
79
74
|
fillCityLocationAndLocationAddress,
|
|
80
75
|
prepareToSaveArray,
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
normalizeString,
|
|
77
|
+
|
|
83
78
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import js from "@eslint/js";
|
|
3
|
+
import { defineConfig } from "eslint/config";
|
|
4
|
+
|
|
5
|
+
export default defineConfig([
|
|
6
|
+
// Core recommended rules (includes no-undef, no-unused-vars, etc.)
|
|
7
|
+
js.configs.recommended,
|
|
8
|
+
|
|
9
|
+
// Node backend files
|
|
10
|
+
{
|
|
11
|
+
files: ["backend/**/*.js"],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
sourceType: "commonjs",
|
|
14
|
+
globals: { ...globals.node },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
// Browser/frontend files
|
|
19
|
+
{
|
|
20
|
+
files: ["pages/**/*.js", "public/**/*.js"],
|
|
21
|
+
languageOptions: {
|
|
22
|
+
sourceType: "commonjs",
|
|
23
|
+
globals: { ...globals.browser },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sr-npm",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,9 +25,14 @@
|
|
|
25
25
|
"@wix/site-window": "^1.0.0",
|
|
26
26
|
"axios": "^1.11.0",
|
|
27
27
|
"jest": "^30.0.5",
|
|
28
|
+
"psdev-utils": "1.7.3",
|
|
28
29
|
"tests-utils": "^1.0.7"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"
|
|
32
|
+
"@eslint/js": "^9.39.0",
|
|
33
|
+
"eslint": "^9.38.0",
|
|
34
|
+
"globals": "^16.4.0",
|
|
35
|
+
"prettier": "^3.6.2",
|
|
36
|
+
"rewire": "^9.0.1"
|
|
32
37
|
}
|
|
33
38
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
const { location } = require("@wix/site-location");
|
|
3
|
+
async function boardPeoplePageOnReady(_$w,) {
|
|
4
|
+
|
|
5
|
+
await bindBoardPeopleRepeaters(_$w);
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function bindBoardPeopleRepeaters(_$w) {
|
|
11
|
+
|
|
12
|
+
_$w('#directorsRepeaterItem').onClick((event) => {
|
|
13
|
+
const $item = _$w.at(event.context);
|
|
14
|
+
const clickedItemData = $item('#dynamicDataset').getCurrentItem();
|
|
15
|
+
location.to(`/${clickedItemData['link-board-people-title_fld']}`);
|
|
16
|
+
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
_$w('#executivesRepeaterItem').onClick((event) => {
|
|
20
|
+
const $item = _$w.at(event.context);
|
|
21
|
+
const clickedItemData = $item('#dataset1').getCurrentItem();
|
|
22
|
+
location.to(`/${clickedItemData['link-board-people-title_fld']}`);
|
|
23
|
+
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
module.exports = {
|
|
27
|
+
boardPeoplePageOnReady,
|
|
28
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
const { location } = require("@wix/site-location");
|
|
3
|
+
async function brandPageOnReady(_$w,brand) {
|
|
4
|
+
const decodedBrand = decodeURIComponent(brand);
|
|
5
|
+
_$w('#seeJobsButton').onClick(() => {
|
|
6
|
+
location.to(`/search?brand=${decodedBrand}`);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
brandPageOnReady,
|
|
12
|
+
};
|