sr-npm 1.0.11 → 1.0.13

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.
@@ -1,17 +1,17 @@
1
- import { fetch } from 'wix-fetch';
2
-
1
+ const { fetch } = require('wix-fetch');
2
+ const { items: wixData } = require('@wix/data');
3
+ const { COLLECTIONS } = require('./collectionConsts');
4
+ const secretsData = require('./secretsData');
3
5
  async function makeSmartRecruitersRequest(path) {
4
- // const baseUrl = 'https://api.smartrecruiters.com'; // PROD
5
- const baseUrl = 'https://aoxley54.wixstudio.com/external-template/_functions'; // TEST
6
- const fullUrl = `${baseUrl}${path}`;
7
- //console.log(`Making request to: ${fullUrl}`);
6
+ const baseUrl = 'https://api.smartrecruiters.com';
7
+ const fullUrl = `${baseUrl}${path}`;
8
+
8
9
  try {
9
10
  const response = await fetch(fullUrl, {
10
11
  method: 'GET',
11
12
  headers: {
12
13
  'Accept-Language': 'en',
13
14
  'accept': 'application/json',
14
- 'x-smarttoken': 'DCRA1-1d30ea5fe9be42d9b9ae94ff933ebef5',
15
15
  'Cookie': 'AWSALB=GYltFw3fLKortMxHR5vIOT1CuUROyhWNIX/qL8ZnPl1/8mhOcnIsBKYslzmNJPEzSy/jvNbO+6tXpH8yqcpQJagYt57MhbKlLqTSzoNq1G/w7TjOxPGR3UTdXW0d; AWSALBCORS=GYltFw3fLKortMxHR5vIOT1CuUROyhWNIX/qL8ZnPl1/8mhOcnIsBKYslzmNJPEzSy/jvNbO+6tXpH8yqcpQJagYt57MhbKlLqTSzoNq1G/w7TjOxPGR3UTdXW0d'
16
16
  }
17
17
  });
@@ -28,70 +28,60 @@ async function makeSmartRecruitersRequest(path) {
28
28
  }
29
29
  }
30
30
 
31
- export async function fetchPositionsFromSRAPI() {
31
+ async function fetchPositionsFromSRAPI() {
32
32
  let allPositions = [];
33
33
  let totalFound = 0;
34
- let nextPageId = null; // Start with no page ID for the first request
35
- let pageCount = 0;
34
+ let page = 0;
36
35
  const MAX_PAGES = 30 // Safety limit to prevent infinite loops
37
-
36
+ const companyId = await getCompanyIdFromCMS();
38
37
  console.log('Starting to fetch all positions with pagination...');
38
+ let offset=0;
39
39
 
40
40
  do {
41
41
  try {
42
- pageCount++;
43
-
42
+ page++;
43
+
44
44
  // Build the API path - first request has no page parameter, subsequent use nextPageId
45
- let apiPath = '/jobs?limit=50';
46
- if (nextPageId) {
47
- apiPath += `&nextPageId=${nextPageId}`;
48
- }
45
+ const apiPath = `/v1/companies/${companyId}/postings?offset=${offset}`;
49
46
 
50
- console.log(`Fetching page ${pageCount} with path: ${apiPath}`);
47
+ console.log(`Fetching page ${page} with path: ${apiPath}`);
51
48
  const response = await makeSmartRecruitersRequest(apiPath);
52
49
 
53
50
  // Add positions from this page to our collection
54
51
  if (response.content && Array.isArray(response.content)) {
55
52
  allPositions = allPositions.concat(response.content);
56
- console.log(`Page ${pageCount}: Found ${response.content.length} positions`);
53
+ console.log(`Page ${page}: Found ${response.content.length} positions`);
57
54
  }
58
-
55
+
59
56
  // Update total count from first response
60
- if (pageCount === 1) {
57
+ if (page === 1) {
61
58
  totalFound = response.totalFound || 0;
62
59
  console.log(`Total positions available: ${totalFound}`);
63
60
  }
64
-
65
- // Get the nextPageId for the next iteration
66
- nextPageId = response.nextPageId && response.nextPageId !== "" ? response.nextPageId : null;
67
-
68
- if (nextPageId) {
69
- console.log(`Next page ID: ${nextPageId}`);
70
- } else {
71
- console.log('No more pages to fetch');
72
- }
73
-
61
+
62
+ offset+=100;
63
+
74
64
  } catch (error) {
75
- console.error(`Error fetching page ${pageCount}:`, error);
65
+ console.error(`Error fetching page ${page}:`, error);
76
66
  throw error;
77
67
  }
78
-
68
+
79
69
  // Safety check to prevent infinite loops
80
- if (pageCount >= MAX_PAGES) {
70
+ if (page >= MAX_PAGES) {
81
71
  console.warn(`Reached maximum page limit of ${MAX_PAGES}. Stopping pagination.`);
82
72
  break;
83
73
  }
84
- } while (nextPageId); // Continue while there's a nextPageId
74
+ } while (offset<totalFound); // Continue while there's a nextPageId
85
75
 
86
76
  console.log(`Finished fetching all pages. Total positions collected: ${allPositions.length}`);
87
77
 
88
78
  // Return response in the same format as before, but with all positions
89
- const result = {
79
+ const result = {
90
80
  totalFound: totalFound,
91
81
  offset: 0,
92
82
  limit: allPositions.length,
93
- nextPageId: "", // Always empty since we've fetched everything
94
- content: allPositions
83
+ nextPageId: '', // Always empty since we've fetched everything
84
+ content: allPositions,
95
85
  };
96
86
 
97
87
  const amountOfUniqueJobs = new Set(allPositions.map(job => job.id)).size;
@@ -104,6 +94,23 @@ export async function fetchPositionsFromSRAPI() {
104
94
  return result;
105
95
  }
106
96
 
107
- export async function fetchJobDescription(jobId) {
108
- return await makeSmartRecruitersRequest(`/jobs/${jobId}`);
97
+ async function fetchJobDescription(jobId) {
98
+ const companyId = await getCompanyIdFromCMS();
99
+ return await makeSmartRecruitersRequest(`/v1/companies/${companyId}/postings/${jobId}`);
109
100
  }
101
+
102
+ async function getCompanyIdFromCMS() {
103
+ const result = await wixData.query(COLLECTIONS.COMPANY_ID).limit(1).find();
104
+ if (result.items.length > 0) {
105
+ return result.items[0].companyId;
106
+ } else {
107
+ throw new Error('[getCompanyIdFromCMS], No companyId found');
108
+ }
109
+ }
110
+
111
+
112
+ module.exports = {
113
+ fetchPositionsFromSRAPI,
114
+ fetchJobDescription,
115
+ getCompanyIdFromCMS
116
+ };
package/backend/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
- ...require('./utils'),
3
- ...require('./queries'),
4
- };
5
-
2
+ ...require('./utils'),
3
+ ...require('./queries'),
4
+ ...require('./fetchPositionsFromSRAPI'),
5
+ ...require('./consts'),
6
+ };
@@ -1,23 +1,24 @@
1
- const { COLLECTIONS } = require('./consts');
2
- const { items } = require('@wix/data');
1
+ const { COLLECTIONS } = require('./collectionConsts');
2
+ const { items: wixData } = require('@wix/data');
3
3
 
4
4
 
5
5
  async function getAllPositions() {
6
- const query = items.query(COLLECTIONS.JOBS);
7
- const results = await query.find();
8
- return results.items;
9
-
6
+ return wixData
7
+ .query(COLLECTIONS.JOBS)
8
+ .limit(1000)
9
+ .find()
10
+ .then(result => result.items);
10
11
  }
11
12
 
12
13
  async function getPositionsByField(field, value) {
13
- const query = items.query(COLLECTIONS.JOBS)
14
- .eq(field, value);
15
- const results = await query.find();
16
- return results.items;
14
+ return wixData
15
+ .query(COLLECTIONS.JOBS)
16
+ .eq(field, value)
17
+ .find()
18
+ .then(result => result.items);
17
19
  }
18
20
 
19
-
20
21
  module.exports = {
21
- getAllPositions,
22
- getPositionsByField,
23
- };
22
+ getAllPositions,
23
+ getPositionsByField,
24
+ };
@@ -0,0 +1,14 @@
1
+ const { secrets } = require("@wix/secrets");
2
+ const { auth } = require('@wix/essentials');
3
+
4
+ const getSecretValue = auth.elevate(secrets.getSecretValue);
5
+
6
+ function getCompanyId() {
7
+ return getSecretValue("companyID")
8
+ .then((secret) => {
9
+ return secret;
10
+ })
11
+ }
12
+ module.exports = {
13
+ getCompanyId
14
+ };
package/backend/utils.js CHANGED
@@ -1,6 +1,83 @@
1
1
  async function chunkedBulkOperation({ items, chunkSize, processChunk }) {
2
- for (let i = 0; i < items.length; i += chunkSize) {
3
- const chunk = items.slice(i, i + chunkSize);
4
- await processChunk(chunk, Math.floor(i / chunkSize) + 1);
2
+ for (let i = 0; i < items.length; i += chunkSize) {
3
+ const chunk = items.slice(i, i + chunkSize);
4
+ await processChunk(chunk, Math.floor(i / chunkSize) + 1);
5
+ }
6
+ }
7
+
8
+ async function delay(ms) {
9
+ await new Promise(resolve => setTimeout(resolve, ms));
10
+ }
11
+
12
+ function countJobsPerGivenField(jobs, field,jobsPerField) {
13
+ for (const job of jobs) {
14
+ if (!job[field]) {
15
+ console.warn(`Job ${job._id} missing required field '${field}' - continue`);
16
+ continue;
5
17
  }
6
- }
18
+ else{
19
+ jobsPerField[job[field]] = (jobsPerField[job[field]] || 0) + 1;
20
+ }
21
+ }
22
+ }
23
+
24
+ function fillCityLocationAndLocationAddress(jobs, cityLocations,citylocationAddress) {
25
+ for (const job of jobs) {
26
+ if (!cityLocations[job.cityText] && !citylocationAddress[job.cityText]) {
27
+ cityLocations[job.cityText] = job.location;
28
+ citylocationAddress[job.cityText] = job.locationAddress;
29
+ }
30
+ }
31
+ }
32
+
33
+ function prepareToSaveArray(jobsPerField, cityLocations, field,citylocationAddress) {
34
+ if (field === 'cityText') {
35
+ return Object.entries(jobsPerField).map(([value, amount]) => {
36
+ const loc = cityLocations[value] || {};
37
+ const locAddress = citylocationAddress[value] || {};
38
+ value = normalizeCityName(value);
39
+ return {
40
+ title: value,
41
+ _id: value.replace(/\s+/g, ''),
42
+ count: amount,
43
+ locationAddress: locAddress,
44
+ country: loc.country,
45
+ city: loc.city,
46
+ };
47
+ });
48
+ } else {
49
+ return Object.entries(jobsPerField).map(([value, amount]) => ({
50
+ title: value,
51
+ _id: sanitizeId(value),
52
+ count: amount,
53
+ }));
54
+ }
55
+ }
56
+
57
+ function normalizeCityName(city) {
58
+ if (!city) return city;
59
+ // Remove accents/diacritics, trim whitespace
60
+ return city
61
+ .normalize('NFD')
62
+ .replace(/\p{Diacritic}/gu, '')
63
+ .trim();
64
+ }
65
+
66
+ function sanitizeId(input) {
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
+ }
74
+
75
+ module.exports = {
76
+ chunkedBulkOperation,
77
+ delay,
78
+ countJobsPerGivenField,
79
+ fillCityLocationAndLocationAddress,
80
+ prepareToSaveArray,
81
+ normalizeCityName,
82
+ sanitizeId,
83
+ };
package/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  module.exports = {
2
- ...require('./public'),
3
- ...require('./pages'),
4
- ...require('./backend'),
5
- };
6
-
2
+ ...require('./public'),
3
+ ...require('./pages'),
4
+ ...require('./backend'),
5
+ };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "sr-npm",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "jest"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -17,6 +17,17 @@
17
17
  },
18
18
  "homepage": "https://github.com/psdevteamenterprise/sr-npm#readme",
19
19
  "dependencies": {
20
- "@hisense-staging/velo-npm": "1.7.249"
20
+ "@hisense-staging/velo-npm": "3.0.19",
21
+ "@wix/data": "^1.0.211",
22
+ "@wix/essentials": "^0.1.24",
23
+ "@wix/secrets": "^1.0.53",
24
+ "@wix/site-location": "^1.0.0",
25
+ "@wix/site-window": "^1.0.0",
26
+ "axios": "^1.11.0",
27
+ "jest": "^30.0.5",
28
+ "tests-utils": "^1.0.7"
29
+ },
30
+ "devDependencies": {
31
+ "prettier": "^3.6.2"
21
32
  }
22
33
  }