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.
- package/backend/contacts-methods.js +53 -20
- package/backend/daily-pull/bulk-process-methods.js +1 -1
- package/backend/daily-pull/sync-to-cms-methods.js +4 -6
- package/backend/forms-methods.js +3 -3
- package/backend/jobs.js +2 -8
- package/backend/login/qa-login-methods.js +8 -31
- package/backend/login/sso-methods.js +5 -5
- package/backend/members-area-methods.js +14 -11
- package/backend/members-data-methods.js +57 -32
- package/backend/pac-api-methods.js +5 -19
- package/backend/routers/methods.js +1 -6
- package/backend/tasks/tasks-configs.js +1 -1
- package/backend/tasks/tasks-helpers-methods.js +11 -21
- package/package.json +2 -2
- package/pages/Home.js +3 -11
- package/pages/Profile.js +2 -6
- package/pages/personalDetails.js +4 -16
- package/public/Utils/sharedUtils.js +0 -8
|
@@ -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 {
|
|
60
|
-
* @param {string}
|
|
61
|
-
* @param {string}
|
|
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
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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 {
|
|
132
|
+
const { wixContactId, wixMemberId } = existingMemberData;
|
|
101
133
|
|
|
102
134
|
const updateConfig = [
|
|
103
135
|
{
|
|
104
136
|
fields: ['contactFormEmail'],
|
|
105
137
|
updater: updateContactEmail,
|
|
106
|
-
args: ([email]) => [
|
|
138
|
+
args: ([email]) => [wixContactId, email],
|
|
107
139
|
},
|
|
108
140
|
{
|
|
109
141
|
fields: ['firstName', 'lastName'],
|
|
110
|
-
updater:
|
|
111
|
-
args: ([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.
|
|
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(
|
|
13
|
-
const { action, backupDate } = taskData;
|
|
12
|
+
async function syncMembersDataPerAction(action) {
|
|
14
13
|
try {
|
|
15
|
-
const firstPageResponse = await fetchPACMembers(
|
|
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
|
|
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(
|
|
81
|
+
fetchPACMembers(pageNumber, action),
|
|
84
82
|
]);
|
|
85
83
|
const addInterests = SITES_WITH_INTERESTS_TO_MIGRATE.includes(siteAssociation);
|
|
86
84
|
if (
|
package/backend/forms-methods.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
|
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:
|
|
21
|
+
data: {},
|
|
28
22
|
type: 'scheduled',
|
|
29
23
|
});
|
|
30
24
|
} catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
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
|
|
137
|
-
console.log('
|
|
138
|
-
const sessionToken = await generateSessionToken(
|
|
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:
|
|
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
|
|
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 =
|
|
26
|
-
|
|
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
|
|
41
|
-
* @param {Object} member - Member object with
|
|
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.
|
|
46
|
-
console.log(`Member ${member.memberId} has no
|
|
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} (
|
|
52
|
+
`Updating Wix login email for member ${member.memberId} (wixMemberId: ${member.wixMemberId})`
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
-
const updatedWixMember = await authentication.changeLoginEmail(
|
|
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
|
-
|
|
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
|
|
45
|
+
const [wixMemberId, wixContactId] = await Promise.all([
|
|
46
|
+
createSiteMember(toCreateMemberData),
|
|
47
|
+
createContact(toCreateMemberData),
|
|
48
|
+
]);
|
|
47
49
|
let memberDataWithContactId = {
|
|
48
50
|
...memberData,
|
|
49
|
-
|
|
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
|
-
|
|
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
|
|
331
|
+
// Filter for external images (not starting with 'wix:')
|
|
323
332
|
const membersWithExternalImages = allItems.filter(
|
|
324
|
-
member => 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
|
-
|
|
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
|
-
|
|
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
|
|
455
|
-
|
|
456
|
-
|
|
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
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
497
|
+
console.log('memberData', memberData);
|
|
498
|
+
return await ensureMemberHasContact(memberData);
|
|
475
499
|
} catch (error) {
|
|
476
|
-
console.error('Error in
|
|
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
|
-
|
|
567
|
+
prepareMemberForSSOLogin,
|
|
568
|
+
prepareMemberForQALogin,
|
|
544
569
|
checkUrlUniqueness,
|
|
545
570
|
trackButtonClick,
|
|
546
571
|
};
|
|
@@ -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 () => {
|
|
@@ -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 ${
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
|
|
36
|
+
|
|
44
37
|
// Check if URL ends with valid extension
|
|
45
38
|
const hasValidExtension = validExtensions.some(ext => urlPath.endsWith(ext));
|
|
46
|
-
|
|
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
|
-
|
|
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
|
-
|
|
141
|
+
|
|
149
142
|
// Check if member has an external profile image URL
|
|
150
|
-
if (!
|
|
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(
|
|
157
|
-
console.log(`Member ${memberId} has invalid image URL format: ${
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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 (
|
|
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
|
|
120
|
+
if (profileData.profileImage) {
|
|
125
121
|
_$w('#profileImage').src = profileData.profileImage;
|
|
126
122
|
} else {
|
|
127
123
|
_$w('#profileImage').src = profileData.defaultProfileImage;
|
package/pages/personalDetails.js
CHANGED
|
@@ -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
|
|
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
|
|
797
|
-
|
|
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
|
-
|
|
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
|
};
|