abmp-npm 1.1.80 → 1.1.82
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/backend/consts.js +0 -2
- package/backend/daily-pull/bulk-process-methods.js +114 -3
- package/backend/daily-pull/index.js +1 -0
- package/backend/daily-pull/process-member-methods.js +1 -1
- package/backend/daily-pull/utils.js +20 -0
- package/backend/members-data-methods.js +1 -1
- package/backend/pac-api-methods.js +2 -2
- package/package.json +1 -1
package/backend/consts.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const PAC_API_URL = 'https://members.abmp.com/eweb/api/Wix';
|
|
2
|
-
const BACKUP_API_URL = 'https://psdevteamenterpris.wixstudio.com/abmp-backup/_functions';
|
|
3
2
|
const SSO_TOKEN_AUTH_API_URL = 'https://members.professionalassistcorp.com/';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -41,5 +40,4 @@ module.exports = {
|
|
|
41
40
|
COMPILED_FILTERS_FIELDS,
|
|
42
41
|
MEMBERSHIPS_TYPES,
|
|
43
42
|
SSO_TOKEN_AUTH_API_URL,
|
|
44
|
-
BACKUP_API_URL,
|
|
45
43
|
};
|
|
@@ -1,7 +1,115 @@
|
|
|
1
|
-
const { bulkSaveMembers } = require('../members-data-methods');
|
|
1
|
+
const { bulkSaveMembers, getMemberBySlug } = require('../members-data-methods');
|
|
2
2
|
|
|
3
3
|
const { generateUpdatedMemberData } = require('./process-member-methods');
|
|
4
|
-
const { changeWixMembersEmails } = require('./utils');
|
|
4
|
+
const { changeWixMembersEmails, extractUrlCounter, incrementUrlCounter } = require('./utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ensures unique URLs within a batch of members by deduplicating URLs
|
|
8
|
+
* Groups members by their base URL (normalized) and assigns unique counters
|
|
9
|
+
* Also checks database to handle cross-page conflicts
|
|
10
|
+
* @param {Array} memberDataList - Array of processed member data
|
|
11
|
+
* @returns {Promise<Array>} - Array of members with unique URLs assigned
|
|
12
|
+
*/
|
|
13
|
+
async function ensureUniqueUrlsInBatch(memberDataList) {
|
|
14
|
+
if (!Array.isArray(memberDataList) || memberDataList.length === 0) {
|
|
15
|
+
return memberDataList;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Group members by their normalized base URL
|
|
19
|
+
const urlGroups = new Map();
|
|
20
|
+
|
|
21
|
+
memberDataList.forEach(member => {
|
|
22
|
+
if (!member || !member.url) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const baseUrl = member.url;
|
|
27
|
+
if (!urlGroups.has(baseUrl)) {
|
|
28
|
+
urlGroups.set(baseUrl, []);
|
|
29
|
+
}
|
|
30
|
+
urlGroups.get(baseUrl).push(member);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// For each group, check database and assign unique URLs sequentially
|
|
34
|
+
for (const [baseUrl, members] of urlGroups.entries()) {
|
|
35
|
+
if (members.length <= 1) {
|
|
36
|
+
// Single member - still check DB to ensure it doesn't conflict with other pages
|
|
37
|
+
const member = members[0];
|
|
38
|
+
if (member) {
|
|
39
|
+
const dbMember = await getMemberBySlug({
|
|
40
|
+
slug: baseUrl,
|
|
41
|
+
excludeDropped: false,
|
|
42
|
+
normalizeSlugForComparison: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (dbMember && dbMember.url) {
|
|
46
|
+
// Conflict found in DB, need to add counter
|
|
47
|
+
member.url = incrementUrlCounter(dbMember.url, baseUrl);
|
|
48
|
+
console.log(
|
|
49
|
+
`Found DB conflict for single member with base URL "${baseUrl}", assigned: ${member.url}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Sort members to ensure consistent ordering (by memberId for determinism)
|
|
57
|
+
members.sort((a, b) => {
|
|
58
|
+
if (a.memberId && b.memberId) {
|
|
59
|
+
return String(a.memberId).localeCompare(String(b.memberId));
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Check database for existing members with this base URL to find highest counter
|
|
65
|
+
const dbMember = await getMemberBySlug({
|
|
66
|
+
slug: baseUrl,
|
|
67
|
+
excludeDropped: false,
|
|
68
|
+
normalizeSlugForComparison: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const dbMaxCounter = extractUrlCounter(dbMember?.url);
|
|
72
|
+
|
|
73
|
+
// Find the highest existing counter among all members in this batch group
|
|
74
|
+
let batchMaxCounter = -1;
|
|
75
|
+
members.forEach(member => {
|
|
76
|
+
const originalUrl = member.url;
|
|
77
|
+
const urlParts = originalUrl.split('-');
|
|
78
|
+
const lastSegment = urlParts[urlParts.length - 1];
|
|
79
|
+
const isNumeric = /^\d+$/.test(lastSegment);
|
|
80
|
+
if (isNumeric) {
|
|
81
|
+
const counter = parseInt(lastSegment, 10);
|
|
82
|
+
if (counter > batchMaxCounter) {
|
|
83
|
+
batchMaxCounter = counter;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Start index from the maximum of DB counter and batch counter + 1
|
|
89
|
+
const maxCounter = Math.max(dbMaxCounter, batchMaxCounter);
|
|
90
|
+
const startIndex = maxCounter + 1;
|
|
91
|
+
|
|
92
|
+
// Assign unique URLs: start from the appropriate index
|
|
93
|
+
members.forEach((member, index) => {
|
|
94
|
+
const assignedIndex = startIndex + index;
|
|
95
|
+
if (assignedIndex === 0) {
|
|
96
|
+
// Index 0 means no counter, use baseUrl
|
|
97
|
+
member.url = baseUrl;
|
|
98
|
+
} else {
|
|
99
|
+
// Index > 0 means add counter
|
|
100
|
+
member.url = `${baseUrl}-${assignedIndex}`;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
console.log(
|
|
105
|
+
`Deduplicated ${members.length} members with base URL "${baseUrl}" (DB max: ${dbMaxCounter}, batch max: ${batchMaxCounter}, start: ${startIndex}): ${members
|
|
106
|
+
.map(m => m.url)
|
|
107
|
+
.join(', ')}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return memberDataList;
|
|
112
|
+
}
|
|
5
113
|
|
|
6
114
|
/**
|
|
7
115
|
* Processes and saves multiple member records in bulk
|
|
@@ -37,6 +145,9 @@ const bulkProcessAndSaveMemberData = async ({
|
|
|
37
145
|
data => data !== null && data !== undefined
|
|
38
146
|
);
|
|
39
147
|
|
|
148
|
+
// Ensure unique URLs within the batch to prevent duplicates (also checks DB for cross-page conflicts)
|
|
149
|
+
await ensureUniqueUrlsInBatch(validMemberData);
|
|
150
|
+
|
|
40
151
|
if (validMemberData.length === 0) {
|
|
41
152
|
return {
|
|
42
153
|
totalProcessed: memberDataList.length,
|
|
@@ -73,4 +184,4 @@ const bulkProcessAndSaveMemberData = async ({
|
|
|
73
184
|
}
|
|
74
185
|
};
|
|
75
186
|
|
|
76
|
-
module.exports = { bulkProcessAndSaveMemberData };
|
|
187
|
+
module.exports = { bulkProcessAndSaveMemberData, ensureUniqueUrlsInBatch };
|
|
@@ -39,7 +39,7 @@ const ensureUniqueUrl = async ({ url, memberId, fullName }) => {
|
|
|
39
39
|
|
|
40
40
|
const existingMember = await getMemberBySlug({
|
|
41
41
|
slug: uniqueUrl,
|
|
42
|
-
excludeDropped:
|
|
42
|
+
excludeDropped: false,
|
|
43
43
|
excludeSearchedMember: true,
|
|
44
44
|
memberId,
|
|
45
45
|
normalizeSlugForComparison: true,
|
|
@@ -15,6 +15,24 @@ const changeWixMembersEmails = async toChangeWixMembersEmails => {
|
|
|
15
15
|
);
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
const extractUrlCounter = url => {
|
|
19
|
+
if (!url) return -1;
|
|
20
|
+
const lastSegment = url.split('-').pop() || '0';
|
|
21
|
+
const isNumeric = /^\d+$/.test(lastSegment);
|
|
22
|
+
return isNumeric ? parseInt(lastSegment, 10) : -1;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const incrementUrlCounter = (existingUrl, baseUrl) => {
|
|
26
|
+
if (existingUrl && existingUrl === baseUrl) {
|
|
27
|
+
console.log(
|
|
28
|
+
`Found member with same url ${existingUrl} for baseUrl ${baseUrl}, increasing counter by 1`
|
|
29
|
+
);
|
|
30
|
+
const lastSegment = existingUrl.split('-').pop() || '0';
|
|
31
|
+
const isNumeric = /^\d+$/.test(lastSegment);
|
|
32
|
+
const lastCounter = isNumeric ? parseInt(lastSegment, 10) : 0;
|
|
33
|
+
return `${baseUrl}-${lastCounter + 1}`;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
18
36
|
/**
|
|
19
37
|
* Validates core member data requirements
|
|
20
38
|
* @param {Object} inputMemberData - Raw member data from API to validate
|
|
@@ -75,4 +93,6 @@ module.exports = {
|
|
|
75
93
|
validateCoreMemberData,
|
|
76
94
|
containsNonEnglish,
|
|
77
95
|
createFullName,
|
|
96
|
+
extractUrlCounter,
|
|
97
|
+
incrementUrlCounter,
|
|
78
98
|
};
|
|
@@ -273,7 +273,7 @@ async function urlExists(url, excludeMemberId) {
|
|
|
273
273
|
let query = wixData
|
|
274
274
|
.query(COLLECTIONS.MEMBERS_DATA)
|
|
275
275
|
.contains('url', url)
|
|
276
|
-
.ne('action', MEMBER_ACTIONS.DROP);
|
|
276
|
+
.ne('action', MEMBER_ACTIONS.DROP); //TODO: change it to wix search
|
|
277
277
|
|
|
278
278
|
if (excludeMemberId) {
|
|
279
279
|
query = query.ne('memberId', excludeMemberId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { PAC_API_URL
|
|
1
|
+
const { PAC_API_URL } = require('./consts');
|
|
2
2
|
const { getSecret } = require('./utils');
|
|
3
3
|
|
|
4
4
|
const getHeaders = async () => {
|
|
@@ -9,7 +9,7 @@ const getHeaders = async () => {
|
|
|
9
9
|
return headers;
|
|
10
10
|
};
|
|
11
11
|
const fetchPACMembers = async (pageNum, actionFilter) => {
|
|
12
|
-
const url = `${
|
|
12
|
+
const url = `${PAC_API_URL}/Members?page=${pageNum}&actionFilter=${actionFilter}`;
|
|
13
13
|
const headers = await getHeaders();
|
|
14
14
|
const fetchOptions = {
|
|
15
15
|
method: 'get',
|