abmp-npm 1.1.80 → 1.1.81

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 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: true,
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: _PAC_API_URL, BACKUP_API_URL } = require('./consts');
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 = `${BACKUP_API_URL}/Members?page=${pageNum}&actionFilter=${actionFilter}`;
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',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.1.80",
3
+ "version": "1.1.81",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "check-cycles": "madge --circular .",