abmp-npm 1.10.21 → 1.10.22

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.
@@ -3,7 +3,33 @@ const { auth } = require('@wix/essentials');
3
3
 
4
4
  const elevatedGetContact = auth.elevate(contacts.getContact);
5
5
  const elevatedUpdateContact = auth.elevate(contacts.updateContact);
6
+ const elevatedCreateContact = auth.elevate(contacts.createContact);
6
7
 
8
+ /**
9
+ * Create a contact in Wix CRM
10
+ * @param {Object} contactData - Contact data
11
+ * @param {boolean} allowDuplicates - Allow duplicates if contact with same email already exists, will be true only when handling existing members, after that should be removed
12
+ * @returns {Promise<Object>} - Contact data
13
+ */
14
+ async function createContact(contactData, allowDuplicates = false) {
15
+ if (!contactData || !(contactData.contactFormEmail || contactData.email)) {
16
+ throw new Error('Contact data is required');
17
+ }
18
+ const phones =
19
+ Array.isArray(contactData.phones) && contactData.phones.length > 0 ? contactData.phones : [];
20
+ const contactInfo = {
21
+ name: {
22
+ first: contactData.firstName,
23
+ last: contactData.lastName,
24
+ },
25
+ emails: [
26
+ { items: [{ email: contactData.contactFormEmail || contactData.email, primary: true }] },
27
+ ],
28
+ phones: [{ items: phones.map(phone => ({ phone })) }],
29
+ };
30
+ const createContactResponse = await elevatedCreateContact(contactInfo, { allowDuplicates });
31
+ return createContactResponse.contact._id;
32
+ }
7
33
  /**
8
34
  * Generic contact update helper function
9
35
  * @param {string} contactId - The contact ID in Wix CRM
@@ -55,27 +81,33 @@ async function updateContactEmail(contactId, newEmail) {
55
81
  }
56
82
 
57
83
  /**
58
- * Updates contact names in Wix CRM
59
- * @param {string} contactId - The contact ID in Wix CRM
60
- * @param {string} firstName - The new first name
61
- * @param {string} lastName - The new last name
84
+ * Updates contact names in Wix CRM for both contact and member
85
+ * @param {Object} params - Parameters object
86
+ * @param {string} params.wixContactId - The contact ID in Wix CRM
87
+ * @param {string} params.wixMemberId - The member ID in Wix CRM
88
+ * @param {string} params.firstName - The new first name
89
+ * @param {string} params.lastName - The new last name
62
90
  */
63
- async function updateContactNames(contactId, firstName, lastName) {
91
+ async function updateMemberAndContactNames({ wixContactId, wixMemberId, firstName, lastName }) {
92
+ //TODO: rethink if we should keep all info just in contact, meaning no need to update the member
64
93
  if (!firstName && !lastName) {
65
94
  throw new Error('At least one name field is required');
66
95
  }
67
96
 
68
- return await updateContactInfo(
69
- contactId,
70
- currentInfo => ({
71
- ...currentInfo,
72
- name: {
73
- first: firstName || currentInfo?.name?.first || '',
74
- last: lastName || currentInfo?.name?.last || '',
75
- },
76
- }),
77
- 'update contact names'
78
- );
97
+ const createNameUpdate = currentInfo => ({
98
+ ...currentInfo,
99
+ name: {
100
+ first: firstName || currentInfo?.name?.first || '',
101
+ last: lastName || currentInfo?.name?.last || '',
102
+ },
103
+ });
104
+
105
+ const updatePromises = [
106
+ wixContactId && updateContactInfo(wixContactId, createNameUpdate, 'update contact names'),
107
+ wixMemberId && updateContactInfo(wixMemberId, createNameUpdate, 'update member names'),
108
+ ].filter(Boolean);
109
+
110
+ return await Promise.all(updatePromises);
79
111
  }
80
112
 
81
113
  /**
@@ -97,18 +129,18 @@ const updateIfChanged = (existingValues, newValues, updater, argsBuilder) => {
97
129
  * @param {Object} existingMemberData - Existing member data
98
130
  */
99
131
  const updateMemberContactInfo = async (data, existingMemberData) => {
100
- const { contactId } = existingMemberData;
132
+ const { wixContactId, wixMemberId } = existingMemberData;
101
133
 
102
134
  const updateConfig = [
103
135
  {
104
136
  fields: ['contactFormEmail'],
105
137
  updater: updateContactEmail,
106
- args: ([email]) => [contactId, email],
138
+ args: ([email]) => [wixContactId, email],
107
139
  },
108
140
  {
109
141
  fields: ['firstName', 'lastName'],
110
- updater: updateContactNames,
111
- args: ([firstName, lastName]) => [contactId, firstName, lastName],
142
+ updater: updateMemberAndContactNames,
143
+ args: ([firstName, lastName]) => [{ firstName, lastName, wixContactId, wixMemberId }],
112
144
  },
113
145
  ];
114
146
 
@@ -125,4 +157,5 @@ const updateMemberContactInfo = async (data, existingMemberData) => {
125
157
 
126
158
  module.exports = {
127
159
  updateMemberContactInfo,
160
+ createContact,
128
161
  };
@@ -168,7 +168,7 @@ const bulkProcessAndSaveMemberData = async ({
168
168
  const toChangeWixMembersEmails = [];
169
169
  const toSaveMembersData = uniqueUrlsMembersData.map(member => {
170
170
  const { isLoginEmailChanged, isNewToDb: _isNewToDb, ...restMemberData } = member;
171
- if (member.contactId && isLoginEmailChanged) {
171
+ if (member.wixMemberId && isLoginEmailChanged) {
172
172
  toChangeWixMembersEmails.push(member);
173
173
  }
174
174
  return restMemberData; //we don't want to store the isLoginEmailChanged in the database, it's just a flag to know if we need to change the login email in Members area
@@ -9,10 +9,9 @@ const { bulkProcessAndSaveMemberData } = require('./bulk-process-methods');
9
9
  const { SITES_WITH_INTERESTS_TO_MIGRATE } = require('./consts');
10
10
  const { isUpdatedMember, isSiteAssociatedMember } = require('./utils');
11
11
 
12
- async function syncMembersDataPerAction(taskData) {
13
- const { action, backupDate } = taskData;
12
+ async function syncMembersDataPerAction(action) {
14
13
  try {
15
- const firstPageResponse = await fetchPACMembers({ page: 1, action, backupDate });
14
+ const firstPageResponse = await fetchPACMembers(1, action);
16
15
 
17
16
  if (
18
17
  !firstPageResponse ||
@@ -49,7 +48,6 @@ async function syncMembersDataPerAction(taskData) {
49
48
  data: {
50
49
  pageNumber,
51
50
  action,
52
- ...(backupDate ? { backupDate } : {}),
53
51
  },
54
52
  type: 'scheduled',
55
53
  }));
@@ -76,11 +74,11 @@ async function syncMembersDataPerAction(taskData) {
76
74
  * @returns {Promise<Object>} - Page synchronization result
77
75
  */
78
76
  async function synchronizeSinglePage(taskObject) {
79
- const { pageNumber, action, backupDate } = taskObject.data;
77
+ const { pageNumber, action } = taskObject.data;
80
78
  try {
81
79
  const [siteAssociation, memberDataResponse] = await Promise.all([
82
80
  getSiteConfigs(CONFIG_KEYS.SITE_ASSOCIATION),
83
- fetchPACMembers({ page: pageNumber, action, backupDate }),
81
+ fetchPACMembers(pageNumber, action),
84
82
  ]);
85
83
  const addInterests = SITES_WITH_INTERESTS_TO_MIGRATE.includes(siteAssociation);
86
84
  if (
@@ -16,7 +16,7 @@ const contactSubmission = async (data, memberDataId) => {
16
16
  console.log('Member contact form is not enabled for user, skipping contact submission!');
17
17
  return;
18
18
  }
19
- let memberContactId = memberData.contactId;
19
+ let memberContactId = memberData.wixContactId;
20
20
  if (!memberContactId) {
21
21
  /**
22
22
  * Create a member contact here since some members may have never logged in
@@ -27,7 +27,7 @@ const contactSubmission = async (data, memberDataId) => {
27
27
  */
28
28
  console.info('Member contact id not found for user, creating new contact!');
29
29
  const member = await createContactAndMemberIfNew(memberData);
30
- memberContactId = member.contactId;
30
+ memberContactId = member.wixContactId;
31
31
  }
32
32
  console.log('memberContactId', memberContactId);
33
33
  const emailTriggered = await triggerAutomation(automationEmailTriggerId, {
@@ -40,7 +40,7 @@ const contactSubmission = async (data, memberDataId) => {
40
40
  data = {
41
41
  ...data,
42
42
  phone: Number(data.phone),
43
- memberContactId: memberContactId,
43
+ memberContactId,
44
44
  memberEmail: memberData.contactFormEmail,
45
45
  };
46
46
  await wixData.insert(COLLECTIONS.CONTACT_US_SUBMISSIONS, data);
package/backend/jobs.js CHANGED
@@ -13,18 +13,12 @@ async function runScheduledTasks() {
13
13
  }
14
14
  }
15
15
 
16
- /**
17
- * Schedule a daily pull task for the given backup date
18
- * @param {string} backupDate - Optional. The date of the backup to pull in format YYYY-MM-DD
19
- * @returns {Promise<void>}
20
- */
21
- async function scheduleDailyPullTask(backupDate = null) {
16
+ async function scheduleDailyPullTask() {
22
17
  try {
23
18
  console.log('scheduleDailyPullTask started!');
24
- console.log(`backupDate: ${backupDate}`);
25
19
  return await taskManager().schedule({
26
20
  name: TASKS_NAMES.ScheduleDailyMembersDataSync,
27
- data: backupDate ? { backupDate } : {}, // keeping it like this so it would be easier to understand which task was backed up which is not while looking into CMS.
21
+ data: {},
28
22
  type: 'scheduled',
29
23
  });
30
24
  } catch (error) {
@@ -1,4 +1,4 @@
1
- const { getMemberByEmail, getQAUsers } = require('../members-data-methods');
1
+ const { prepareMemberForQALogin, getQAUsers } = require('../members-data-methods');
2
2
  const { getSecret } = require('../utils');
3
3
 
4
4
  const validateQAUser = async userEmail => {
@@ -20,27 +20,23 @@ const validateQAUser = async userEmail => {
20
20
  */
21
21
  const loginQAMember = async ({ userEmail, secret }, generateSessionToken) => {
22
22
  try {
23
- const userValidation = await validateQAUser(userEmail);
23
+ const [userValidation, qaSecret] = await Promise.all([
24
+ validateQAUser(userEmail),
25
+ getSecret('ABMP_QA_SECRET'),
26
+ ]);
24
27
  if (userValidation.error) {
25
28
  return { success: false, error: userValidation.error };
26
29
  }
27
-
28
- const qaSecret = await getSecret('ABMP_QA_SECRET');
29
30
  if (secret !== qaSecret) {
30
31
  return { success: false, error: 'Invalid secret' };
31
32
  }
32
33
 
33
- const token = await generateSessionToken(userValidation.email, qaSecret);
34
-
35
- const result = await getMemberCMSId(userEmail);
36
- if (!result.success) {
37
- return { success: false, error: result.error };
38
- }
39
-
34
+ const memberData = await prepareMemberForQALogin(userValidation.email);
35
+ const token = await generateSessionToken(memberData.email, qaSecret);
40
36
  return {
41
37
  success: true,
42
38
  token,
43
- memberCMSId: result.memberCMSId,
39
+ memberCMSId: memberData._id,
44
40
  };
45
41
  } catch (error) {
46
42
  console.error('QA login error:', error);
@@ -48,25 +44,6 @@ const loginQAMember = async ({ userEmail, secret }, generateSessionToken) => {
48
44
  }
49
45
  };
50
46
 
51
- async function getMemberCMSId(userEmail) {
52
- try {
53
- const userValidation = await validateQAUser(userEmail);
54
- if (userValidation.error) {
55
- return { success: false, error: userValidation.error };
56
- }
57
-
58
- const member = await getMemberByEmail(userEmail);
59
-
60
- if (!member) {
61
- return { success: false, error: `No Member found in DB matching email: ${userEmail}` };
62
- }
63
- return { success: true, memberCMSId: member._id };
64
- } catch (error) {
65
- console.error('Error getting member CMS ID:', error);
66
- return { success: false, error: 'Failed to retrieve member data' };
67
- }
68
- }
69
-
70
47
  module.exports = {
71
48
  loginQAMember,
72
49
  };
@@ -5,7 +5,7 @@ const { decode } = require('jwt-js-decode');
5
5
  const { CONFIG_KEYS, SSO_TOKEN_AUTH_API_URL } = require('../consts');
6
6
  const { MEMBER_ACTIONS } = require('../daily-pull/consts');
7
7
  const { getCurrentMember } = require('../members-area-methods');
8
- const { getMemberByContactId, getSiteMemberId } = require('../members-data-methods');
8
+ const { getMemberByContactId, prepareMemberForSSOLogin } = require('../members-data-methods');
9
9
  const {
10
10
  formatDateToMonthYear,
11
11
  getAddressDisplayOptions,
@@ -133,12 +133,12 @@ const authenticateSSOToken = async ({ token }, generateSessionToken) => {
133
133
  if (isValidToken) {
134
134
  const jwt = decode(responseToken);
135
135
  const payload = jwt.payload;
136
- const membersData = await getSiteMemberId(payload);
137
- console.log('membersDataCollectionId', membersData._id);
138
- const sessionToken = await generateSessionToken(membersData.email);
136
+ const memberData = await prepareMemberForSSOLogin(payload);
137
+ console.log('memberDataCollectionId', memberData._id);
138
+ const sessionToken = await generateSessionToken(memberData.email);
139
139
  const authObj = {
140
140
  type: 'success',
141
- memberId: membersData._id,
141
+ memberId: memberData._id,
142
142
  sessionToken,
143
143
  };
144
144
  return authObj;
@@ -2,10 +2,11 @@ const { auth } = require('@wix/essentials');
2
2
  const { members, authentication } = require('@wix/members');
3
3
  const elevatedCreateMember = auth.elevate(members.createMember);
4
4
 
5
- function prepareContactData(partner) {
5
+ function prepareMemberData(partner) {
6
6
  const phones = Array.isArray(partner.phones) ? partner.phones : []; //some users don't have phones
7
7
  const options = {
8
8
  member: {
9
+ //Keeping contact creation in member data for future purposes, in case we need to use it later
9
10
  contact: {
10
11
  ...partner,
11
12
  phones,
@@ -22,9 +23,8 @@ async function createMemberFunction(member) {
22
23
  }
23
24
  const createSiteMember = async memberDetails => {
24
25
  try {
25
- const options = prepareContactData(memberDetails);
26
- const contactId = await createMemberFunction(options);
27
- return contactId;
26
+ const options = prepareMemberData(memberDetails);
27
+ return await createMemberFunction(options);
28
28
  } catch (error) {
29
29
  console.error(`Error in createSiteMember ${error.message}`);
30
30
  throw error;
@@ -37,22 +37,25 @@ const getCurrentMember = async () => {
37
37
  };
38
38
 
39
39
  /**
40
- * Updates Wix member login email if the member has a contactId (registered Wix member)
41
- * @param {Object} member - Member object with contactId and email
40
+ * Updates Wix member login email if the member has a wixMemberId (registered Wix member)
41
+ * @param {Object} member - Member object with wixMemberId and email
42
42
  * @param {Object} result - Result object to track Wix member updates
43
43
  */
44
44
  async function updateWixMemberLoginEmail(member, result = {}) {
45
- if (!member.contactId) {
46
- console.log(`Member ${member.memberId} has no contactId - skipping Wix login email update`);
45
+ if (!member.wixMemberId) {
46
+ console.log(`Member ${member.memberId} has no wixMemberId - skipping Wix login email update`);
47
47
  return;
48
48
  }
49
49
 
50
50
  try {
51
51
  console.log(
52
- `Updating Wix login email for member ${member.memberId} (contactId: ${member.contactId})`
52
+ `Updating Wix login email for member ${member.memberId} (wixMemberId: ${member.wixMemberId})`
53
53
  );
54
54
 
55
- const updatedWixMember = await authentication.changeLoginEmail(member.contactId, member.email);
55
+ const updatedWixMember = await authentication.changeLoginEmail(
56
+ member.wixMemberId,
57
+ member.email
58
+ );
56
59
 
57
60
  console.log(
58
61
  `✅ Successfully updated Wix login email for member ${member.memberId}: ${updatedWixMember.loginEmail}`
@@ -75,7 +78,7 @@ async function updateWixMemberLoginEmail(member, result = {}) {
75
78
  }
76
79
  result.wixMemberErrors.push({
77
80
  memberId: member.memberId,
78
- contactId: member.contactId,
81
+ wixMemberId: member.wixMemberId,
79
82
  email: member.email,
80
83
  error: error.message,
81
84
  });
@@ -1,8 +1,7 @@
1
1
  const { COLLECTIONS } = require('../public/consts');
2
- const { isWixHostedImage } = require('../public/Utils/sharedUtils');
3
2
 
4
3
  const { MEMBERSHIPS_TYPES } = require('./consts');
5
- const { updateMemberContactInfo } = require('./contacts-methods');
4
+ const { updateMemberContactInfo, createContact } = require('./contacts-methods');
6
5
  const { MEMBER_ACTIONS } = require('./daily-pull/consts');
7
6
  const { wixData } = require('./elevated-modules');
8
7
  const { createSiteMember, getCurrentMember } = require('./members-area-methods');
@@ -43,10 +42,14 @@ async function createContactAndMemberIfNew(memberData) {
43
42
  phones: memberData.phones,
44
43
  contactFormEmail: memberData.contactFormEmail || memberData.email,
45
44
  };
46
- const contactId = await createSiteMember(toCreateMemberData);
45
+ const [wixMemberId, wixContactId] = await Promise.all([
46
+ createSiteMember(toCreateMemberData),
47
+ createContact(toCreateMemberData),
48
+ ]);
47
49
  let memberDataWithContactId = {
48
50
  ...memberData,
49
- contactId,
51
+ wixMemberId,
52
+ wixContactId,
50
53
  };
51
54
  const updatedResult = await updateMember(memberDataWithContactId);
52
55
  memberDataWithContactId = {
@@ -94,10 +97,16 @@ async function findMemberById(memberId) {
94
97
  const queryResult = await wixData
95
98
  .query(COLLECTIONS.MEMBERS_DATA)
96
99
  .eq('memberId', memberId)
100
+ .limit(2)
97
101
  .find();
98
-
99
- return queryResult.items.length > 0 ? queryResult.items[0] : null;
102
+ if (queryResult.items.length > 1) {
103
+ throw new Error(
104
+ `Multiple members found with memberId ${memberId} members _ids are : [${queryResult.items.map(member => member._id).join(', ')}]`
105
+ );
106
+ }
107
+ return queryResult.items.length === 1 ? queryResult.items[0] : null;
100
108
  } catch (error) {
109
+ console.error('Error finding member by ID:', error);
101
110
  throw new Error(`Failed to retrieve member data: ${error.message}`);
102
111
  }
103
112
  }
@@ -319,9 +328,9 @@ async function getAllMembersWithExternalImages() {
319
328
 
320
329
  const allItems = await queryAllItems(membersQuery);
321
330
 
322
- // Filter for external images (not 'wix hosted images')
331
+ // Filter for external images (not starting with 'wix:')
323
332
  const membersWithExternalImages = allItems.filter(
324
- member => member.profileImage && !isWixHostedImage(member.profileImage)
333
+ member => member.profileImage && !member.profileImage.startsWith('wix:')
325
334
  );
326
335
 
327
336
  return membersWithExternalImages;
@@ -442,38 +451,53 @@ const getQAUsers = async () => {
442
451
  throw new Error(`Failed to get QA users: ${error.message}`);
443
452
  }
444
453
  };
445
- async function getSiteMemberId(data) {
454
+ /**
455
+ * Ensures member has a contact - creates one if missing
456
+ * @param {Object} memberData - Member data from DB
457
+ * @returns {Promise<Object>} - Member data with contactId
458
+ */
459
+ async function ensureMemberHasContact(memberData) {
460
+ if (!memberData) {
461
+ throw new Error('Member data is required');
462
+ }
463
+ if (!memberData.contactId) {
464
+ const memberDataWithContactId = await createContactAndMemberIfNew(memberData);
465
+ return memberDataWithContactId;
466
+ }
467
+ return memberData;
468
+ }
469
+ async function prepareMemberForSSOLogin(data) {
446
470
  try {
447
471
  console.log('data', data);
448
472
  const memberId = data?.pac?.cst_recno;
449
473
  if (!memberId) {
450
- const errorMessage = `Member ID is missing in passed data ${JSON.stringify(data)}`;
451
- console.error(errorMessage);
452
- throw new Error(errorMessage);
474
+ throw new Error(`Member ID is missing in passed data ${JSON.stringify(data)}`);
453
475
  }
454
- const queryMemberResult = await wixData
455
- .query(COLLECTIONS.MEMBERS_DATA)
456
- .eq('memberId', Number(memberId))
457
- .find()
458
- .then(res => res.items);
459
- if (!queryMemberResult.length || queryMemberResult.length > 1) {
460
- throw new Error(
461
- `Invalid Members count found in DB for email ${data.email} members count is : [${
462
- queryMemberResult.length
463
- }] membersIds are : [${queryMemberResult.map(member => member.memberId).join(', ')}]`
464
- );
476
+ const memberData = await findMemberById(Number(memberId));
477
+ if (!memberData) {
478
+ throw new Error(`Member data not found for memberId ${memberId}`);
465
479
  }
466
- let memberData = queryMemberResult[0];
467
480
  console.log('memberData', memberData);
468
- const isNewUser = !memberData.contactId;
469
- if (isNewUser) {
470
- const memberDataWithContactId = await createContactAndMemberIfNew(memberData);
471
- console.log('memberDataWithContactId', memberDataWithContactId);
472
- memberData = memberDataWithContactId;
481
+ return await ensureMemberHasContact(memberData);
482
+ } catch (error) {
483
+ console.error('Error in prepareMemberForSSOLogin', error.message);
484
+ throw error;
485
+ }
486
+ }
487
+ async function prepareMemberForQALogin(email) {
488
+ try {
489
+ console.log('qa email:', email);
490
+ if (!email) {
491
+ throw new Error(`Email is missing in passed data ${email}`);
492
+ }
493
+ const memberData = await getMemberByEmail(email);
494
+ if (!memberData) {
495
+ throw new Error(`Member data not found for email ${email}`);
473
496
  }
474
- return memberData;
497
+ console.log('memberData', memberData);
498
+ return await ensureMemberHasContact(memberData);
475
499
  } catch (error) {
476
- console.error('Error in getSiteMemberId', error.message);
500
+ console.error('Error in prepareMemberForQALogin', error.message);
477
501
  throw error;
478
502
  }
479
503
  }
@@ -540,7 +564,8 @@ module.exports = {
540
564
  getMembersByIds,
541
565
  getMemberByEmail,
542
566
  getQAUsers,
543
- getSiteMemberId,
567
+ prepareMemberForSSOLogin,
568
+ prepareMemberForQALogin,
544
569
  checkUrlUniqueness,
545
570
  trackButtonClick,
546
571
  };
@@ -1,4 +1,4 @@
1
- const { 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 () => {
@@ -8,22 +8,8 @@ const getHeaders = async () => {
8
8
  };
9
9
  return headers;
10
10
  };
11
- /**
12
- *
13
- * @param {*} params
14
- * @param {number} params.page - The page number to fetch
15
- * @param {string} params.action - The action to fetch
16
- * @param {string} [params.backupDate] - Optional. The backup date to fetch in format YYYY-MM-DD, use only to fetch from backup endpoint not from PAC endpoint.
17
- * @returns {Promise<Object>} - The response from the API
18
- */
19
- const fetchPACMembers = async ({ page, action, backupDate }) => {
20
- const baseUrl = backupDate ? BACKUP_API_URL : PAC_API_URL;
21
- const queryParams = { page, actionFilter: action };
22
- if (backupDate) {
23
- queryParams.date = backupDate;
24
- }
25
- const url = `${baseUrl}/Members?${new URLSearchParams(queryParams).toString()}`;
26
- console.log(`Fetching PAC members from: ${url}`);
11
+ const fetchPACMembers = async (pageNum, actionFilter) => {
12
+ const url = `${PAC_API_URL}/Members?page=${pageNum}&actionFilter=${actionFilter}`;
27
13
  const headers = await getHeaders();
28
14
  const fetchOptions = {
29
15
  method: 'get',
@@ -32,14 +18,14 @@ const fetchPACMembers = async ({ page, action, backupDate }) => {
32
18
  const response = await fetch(url, fetchOptions);
33
19
  const responseType = response.headers.get('content-type');
34
20
  if (!responseType.includes('application/json')) {
35
- const errorMessage = `[fetchPACMembers] got invalid responseType: ${responseType} for page ${page} and actionFilter ${action}`;
21
+ const errorMessage = `[fetchPACMembers] got invalid responseType: ${responseType} for page ${pageNum} and actionFilter ${actionFilter}`;
36
22
  console.error(errorMessage);
37
23
  throw new Error(errorMessage);
38
24
  }
39
25
  if (response.ok) {
40
26
  return response.json();
41
27
  } else {
42
- const errorMessage = `[fetchPACMembers] failed with status ${response.status} for page ${page} and actionFilter ${action}`;
28
+ const errorMessage = `[fetchPACMembers] failed with status ${response.status} for page ${pageNum} and actionFilter ${actionFilter}`;
43
29
  console.error(errorMessage);
44
30
  throw new Error(errorMessage);
45
31
  }
@@ -1,5 +1,4 @@
1
1
  const { PAGES_PATHS } = require('../../public/consts');
2
- const { isWixHostedImage } = require('../../public/Utils/sharedUtils');
3
2
  //const { fetchAllItemsInParallel } = require('../cms-data-methods'); unused at host site
4
3
  const { CONFIG_KEYS } = require('../consts');
5
4
  const { getSiteConfigs } = require('../utils');
@@ -28,11 +27,7 @@ const createRoutersHandlers = wixRouterMethods => {
28
27
  const defaultProfileImage = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_IMAGE];
29
28
  const profileData = await getMemberProfileData(slug, siteAssociation);
30
29
  if (profileData && profileData.showWixUrl) {
31
- const profileImage =
32
- profileData.profileImage?.trim() && isWixHostedImage(profileData.profileImage)
33
- ? profileData.profileImage
34
- : defaultProfileImage;
35
- const ogImage = profileImage || profileData.logoImage || siteLogoUrl;
30
+ const ogImage = profileData.profileImage || profileData.logoImage || siteLogoUrl;
36
31
  const seoTitle = generateSEOTitle({
37
32
  fullName: profileData.fullName,
38
33
  areasOfPractices: profileData.areasOfPractices,
@@ -43,7 +43,7 @@ const TASKS = {
43
43
  },
44
44
  [TASKS_NAMES.ScheduleMembersDataPerAction]: {
45
45
  name: TASKS_NAMES.ScheduleMembersDataPerAction,
46
- getIdentifier: task => task.data,
46
+ getIdentifier: task => task.data.action,
47
47
  process: syncMembersDataPerAction,
48
48
  shouldSkipCheck: () => false,
49
49
  estimatedDurationSec: 6,
@@ -1,36 +1,29 @@
1
1
  const crypto = require('crypto');
2
2
 
3
- const { auth } = require('@wix/essentials');
4
3
  const { files } = require('@wix/media');
5
4
  const aws4 = require('aws4');
6
5
  const axios = require('axios');
7
6
 
8
- const elevatedGenerateFileUploadUrl = auth.elevate(files.generateFileUploadUrl);
9
-
10
7
  const { PAGES_PATHS } = require('../../public/consts');
11
- const { isWixHostedImage } = require('../../public/Utils/sharedUtils');
12
8
  const { findMemberByWixDataId, updateMember } = require('../members-data-methods');
13
9
  const { getSecret, getSiteBaseUrl, encodeXml, formatDateOnly } = require('../utils');
10
+
14
11
  async function getServerlessAuth() {
15
12
  const serverlessAuth = await getSecret('serverless_auth');
16
13
  return serverlessAuth;
17
14
  }
18
15
 
19
16
  function isValidImageUrl(url) {
20
- console.log('url', url);
21
- console.log('typeof url', typeof url);
22
17
  if (!url || typeof url !== 'string') return false;
23
18
 
24
19
  // Check for valid URL format
25
20
  let parsedUrl;
26
21
  try {
27
22
  parsedUrl = new URL(url);
28
- console.log('parsedUrl', parsedUrl);
29
23
  } catch {
30
24
  return false;
31
25
  }
32
- console.log('parsedUrl', parsedUrl);
33
- console.log('parsedUrl.protocol', parsedUrl.protocol);
26
+
34
27
  // Only allow HTTP and HTTPS protocols (reject blob:, data:, file:, etc.)
35
28
  const validProtocols = ['http:', 'https:'];
36
29
  if (!validProtocols.includes(parsedUrl.protocol)) {
@@ -40,10 +33,10 @@ function isValidImageUrl(url) {
40
33
  // Extract file extension from URL (handle query parameters)
41
34
  const urlPath = url.split('?')[0].toLowerCase();
42
35
  const validExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];
43
- console.log('urlPath', urlPath);
36
+
44
37
  // Check if URL ends with valid extension
45
38
  const hasValidExtension = validExtensions.some(ext => urlPath.endsWith(ext));
46
- console.log('hasValidExtension', hasValidExtension);
39
+
47
40
  // Reject obviously invalid extensions
48
41
  const invalidExtensions = [
49
42
  '.pdf',
@@ -58,7 +51,7 @@ function isValidImageUrl(url) {
58
51
  '_gif',
59
52
  ];
60
53
  const hasInvalidExtension = invalidExtensions.some(ext => urlPath.includes(ext));
61
- console.log('hasInvalidExtension', hasInvalidExtension);
54
+
62
55
  return hasValidExtension && !hasInvalidExtension;
63
56
  }
64
57
 
@@ -145,23 +138,20 @@ async function updateMemberRichContent(memberId) {
145
138
  async function updateMemberProfileImage(memberId) {
146
139
  try {
147
140
  const member = await findMemberByWixDataId(memberId);
148
- const trimmedProfileImage = member.profileImage?.trim();
141
+
149
142
  // Check if member has an external profile image URL
150
- if (!trimmedProfileImage || isWixHostedImage(trimmedProfileImage)) {
143
+ if (!member.profileImage || member.profileImage.startsWith('wix:')) {
151
144
  console.log(`Member ${memberId} already has Wix-hosted image or no image`);
152
145
  return { success: true, message: 'No update needed' };
153
146
  }
154
147
 
155
148
  // Validate image URL format before attempting download
156
- if (!isValidImageUrl(trimmedProfileImage)) {
157
- console.log(`Member ${memberId} has invalid image URL format: ${trimmedProfileImage}`);
149
+ if (!isValidImageUrl(member.profileImage)) {
150
+ console.log(`Member ${memberId} has invalid image URL format: ${member.profileImage}`);
158
151
  return { success: true, message: 'Invalid image URL format - skipped' };
159
152
  }
160
153
 
161
- // Encode URL to handle spaces and special characters in the path
162
- const encodedImageUrl = encodeURI(trimmedProfileImage);
163
-
164
- const response = await axios.get(encodedImageUrl, {
154
+ const response = await axios.get(member.profileImage, {
165
155
  responseType: 'arraybuffer',
166
156
  headers: {
167
157
  'User-Agent':
@@ -218,7 +208,7 @@ async function updateMemberProfileImage(memberId) {
218
208
 
219
209
  const sanitizedFileName = `profile-${memberId}-${Date.now()}.${extension}`.replace(/\./g, '_');
220
210
  const uploadUrl = (
221
- await elevatedGenerateFileUploadUrl(contentType, {
211
+ await files.generateFileUploadUrl(contentType, {
222
212
  fileName: sanitizedFileName,
223
213
  filePath: 'member-profiles',
224
214
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.10.21",
3
+ "version": "1.10.22",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "check-cycles": "madge --circular .",
@@ -50,7 +50,7 @@
50
50
  "csv-parser": "^3.0.0",
51
51
  "ngeohash": "^0.6.3",
52
52
  "phone": "^3.1.67",
53
- "psdev-task-manager": "1.1.10",
53
+ "psdev-task-manager": "1.1.7",
54
54
  "psdev-utils": "1.1.1"
55
55
  }
56
56
  }
package/pages/Home.js CHANGED
@@ -9,7 +9,6 @@ const {
9
9
  getMainAddress,
10
10
  formatPracticeAreasForDisplay,
11
11
  checkAddressIsVisible,
12
- isWixHostedImage,
13
12
  } = require('../public/Utils/sharedUtils.js');
14
13
 
15
14
  let filter = JSON.parse(JSON.stringify(DEFAULT_FILTER));
@@ -188,7 +187,7 @@ const homePageOnReady = async ({
188
187
  : [];
189
188
 
190
189
  // 2) Profile image
191
- if (itemData.profileImage?.trim() && isWixHostedImage(itemData.profileImage)) {
190
+ if (itemData.profileImage) {
192
191
  $item('#profileImage').src = itemData.profileImage;
193
192
  }
194
193
 
@@ -211,16 +210,9 @@ const homePageOnReady = async ({
211
210
  // 5) Location text
212
211
  const mainAddress = getMainAddress(itemData.addressDisplayOption, addresses);
213
212
  $item('#location').text = mainAddress || '';
214
-
215
- // 6) Miles away
216
- const isNearbyEnabled = _$w('#nearBy').checked;
217
213
  const miles = itemData.distance ?? 0;
218
-
219
- if (isNearbyEnabled && miles) {
220
- $item('#differenceInMiles').text = miles.toFixed(1);
221
- $item('#milesAwayText').text = 'miles away';
222
- } else {
223
- $item('#differenceInMiles').text = '';
214
+ $item('#differenceInMiles').text = miles ? miles.toFixed(1) : '';
215
+ if (!miles) {
224
216
  $item('#milesAwayText').text = '';
225
217
  }
226
218
 
package/pages/Profile.js CHANGED
@@ -2,11 +2,7 @@ const { location: wixLocation } = require('@wix/site-location');
2
2
  const { window: wixWindow } = require('@wix/site-window');
3
3
 
4
4
  const { LIGHTBOX_NAMES } = require('../public/consts');
5
- const {
6
- generateId,
7
- formatPracticeAreasForDisplay,
8
- isWixHostedImage,
9
- } = require('../public/Utils/sharedUtils');
5
+ const { generateId, formatPracticeAreasForDisplay } = require('../public/Utils/sharedUtils');
10
6
 
11
7
  const TESTIMONIALS_PER_PAGE_CONFIG = {
12
8
  DESKTOP: 4,
@@ -121,7 +117,7 @@ async function profileOnReady({ $w: _$w }) {
121
117
  _$w('#logoImage').delete();
122
118
  }
123
119
 
124
- if (profileData.profileImage && isWixHostedImage(profileData.profileImage)) {
120
+ if (profileData.profileImage) {
125
121
  _$w('#profileImage').src = profileData.profileImage;
126
122
  } else {
127
123
  _$w('#profileImage').src = profileData.defaultProfileImage;
@@ -9,7 +9,7 @@ const {
9
9
  LIGHTBOX_NAMES,
10
10
  } = require('../public/consts');
11
11
  const { handleOnCustomValidation, isNotValidUrl } = require('../public/Utils/personalDetailsUtils');
12
- const { generateId, isWixHostedImage } = require('../public/Utils/sharedUtils');
12
+ const { generateId } = require('../public/Utils/sharedUtils');
13
13
 
14
14
  const MAX_PHONES_COUNT = 10;
15
15
  const MAX_ADDRESSES_COUNT = 10;
@@ -793,14 +793,8 @@ async function personalDetailsOnReady({
793
793
  : null
794
794
  : itemMemberObj[key];
795
795
 
796
- if (imageValue && imageValue?.trim()) {
797
- // Only set profile image if it's Wix-hosted; other images will always be wix url
798
- const isProfileImage = imageSelector === '#profileImage';
799
- const shouldSetImage = !isProfileImage || isWixHostedImage(imageValue);
800
-
801
- if (shouldSetImage) {
802
- _$w(imageSelector).src = imageValue;
803
- }
796
+ if (imageValue) {
797
+ _$w(imageSelector).src = imageValue;
804
798
  _$w(nameSelector).text = formatFileName(extractFileName(imageValue));
805
799
  _$w(containerSelector).expand();
806
800
  uploadedImages[key === 'bannerImages' ? 'bannerImage' : key] = imageValue;
@@ -1686,13 +1680,7 @@ async function personalDetailsOnReady({
1686
1680
  option.isMain = false;
1687
1681
  });
1688
1682
 
1689
- let selectedOption = itemMemberObj.addressDisplayOption.find(opt => opt.key === selectedId);
1690
-
1691
- // If the option doesn't exist, create it
1692
- if (!selectedOption) {
1693
- selectedOption = { key: selectedId, isMain: false };
1694
- itemMemberObj.addressDisplayOption.push(selectedOption);
1695
- }
1683
+ const selectedOption = itemMemberObj.addressDisplayOption.find(opt => opt.key === selectedId);
1696
1684
 
1697
1685
  selectedOption.isMain = true;
1698
1686
  }
@@ -158,13 +158,6 @@ function generateId() {
158
158
  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
159
159
  }
160
160
 
161
- function isWixHostedImage(imageUrl) {
162
- return (
163
- imageUrl?.trim() &&
164
- (imageUrl?.startsWith('wix:') || imageUrl?.startsWith('https://static.wixstatic.com'))
165
- );
166
- }
167
-
168
161
  module.exports = {
169
162
  checkAddressIsVisible,
170
163
  formatPracticeAreasForDisplay,
@@ -176,5 +169,4 @@ module.exports = {
176
169
  toRadians,
177
170
  generateId,
178
171
  formatAddress,
179
- isWixHostedImage,
180
172
  };