abmp-npm 1.8.43 → 1.8.45
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/CONTACT_EMAIL_UPDATE_DEBUG.md +313 -0
- package/DEBUG_QUICKSTART.md +133 -0
- package/backend/cms-data-methods.js +8 -0
- package/backend/consts.js +22 -7
- package/backend/contacts-methods-DEBUG.js +237 -0
- package/backend/contacts-methods-TEST.js +271 -0
- package/backend/contacts-methods.js +6 -1
- package/backend/daily-pull/consts.js +0 -3
- package/backend/daily-pull/process-member-methods.js +1 -1
- package/backend/daily-pull/sync-to-cms-methods.js +10 -6
- package/backend/daily-pull/utils.js +3 -3
- package/backend/data-hooks.js +29 -0
- package/backend/elevated-modules.js +2 -0
- package/backend/http-functions/httpFunctions.js +86 -0
- package/backend/http-functions/index.js +3 -0
- package/backend/http-functions/interests.js +37 -0
- package/backend/index.js +6 -1
- package/backend/jobs.js +15 -3
- package/backend/login/index.js +7 -0
- package/backend/login/login-methods-factory.js +24 -0
- package/backend/login/qa-login-methods.js +72 -0
- package/backend/login/sso-methods.js +158 -0
- package/backend/members-data-methods.js +271 -94
- package/backend/pac-api-methods.js +3 -4
- package/backend/routers/index.js +3 -0
- package/backend/routers/methods.js +177 -0
- package/backend/routers/utils.js +118 -0
- package/backend/search-filters-methods.js +3 -0
- package/backend/tasks/consts.js +19 -0
- package/backend/tasks/index.js +6 -0
- package/backend/tasks/migration-methods.js +26 -0
- package/backend/tasks/tasks-configs.js +124 -0
- package/backend/tasks/tasks-helpers-methods.js +419 -0
- package/backend/tasks/tasks-process-methods.js +545 -0
- package/backend/test-methods.js +118 -0
- package/backend/utils.js +85 -41
- package/package.json +13 -2
- package/pages/LoadingPage.js +20 -0
- package/pages/Profile.js +2 -2
- package/pages/QAPage.js +39 -0
- package/pages/SaveAlerts.js +13 -0
- package/pages/SelectBannerImages.js +46 -0
- package/pages/deleteConfirm.js +19 -0
- package/pages/index.js +5 -0
- package/pages/personalDetails.js +12 -8
- package/public/consts.js +6 -23
- package/public/sso-auth-methods.js +43 -0
- package/backend/routers-methods.js +0 -186
- package/backend/routers-utils.js +0 -158
- package/backend/tasks.js +0 -37
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
const { COLLECTIONS } = require('../public/consts');
|
|
2
2
|
|
|
3
|
+
const { MEMBERSHIPS_TYPES } = require('./consts');
|
|
3
4
|
const { updateMemberContactInfo } = require('./contacts-methods');
|
|
4
|
-
const { MEMBER_ACTIONS } = require('./daily-pull');
|
|
5
|
+
const { MEMBER_ACTIONS } = require('./daily-pull/consts');
|
|
5
6
|
const { wixData } = require('./elevated-modules');
|
|
6
|
-
const { createSiteMember
|
|
7
|
+
const { createSiteMember } = require('./members-area-methods');
|
|
7
8
|
const {
|
|
8
|
-
|
|
9
|
+
chunkArray,
|
|
9
10
|
normalizeUrlForComparison,
|
|
10
11
|
queryAllItems,
|
|
11
|
-
formatDateToMonthYear,
|
|
12
|
-
getAddressDisplayOptions,
|
|
13
|
-
isStudent,
|
|
14
12
|
generateGeoHash,
|
|
15
13
|
} = require('./utils');
|
|
16
14
|
|
|
@@ -48,7 +46,7 @@ async function createContactAndMemberIfNew(memberData) {
|
|
|
48
46
|
...memberData,
|
|
49
47
|
contactId,
|
|
50
48
|
};
|
|
51
|
-
const updatedResult = await
|
|
49
|
+
const updatedResult = await updateMember(memberDataWithContactId);
|
|
52
50
|
memberDataWithContactId = {
|
|
53
51
|
...memberDataWithContactId,
|
|
54
52
|
...updatedResult,
|
|
@@ -60,79 +58,6 @@ async function createContactAndMemberIfNew(memberData) {
|
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
/**
|
|
64
|
-
* Validates member token and retrieves member data
|
|
65
|
-
* @param {string} memberIdInput - The member ID to validate
|
|
66
|
-
* @returns {Promise<{memberData: Object|null, isValid: boolean}>} Validation result with member data
|
|
67
|
-
*/
|
|
68
|
-
async function validateMemberToken(memberIdInput) {
|
|
69
|
-
const invalidTokenResponse = { memberData: null, isValid: false };
|
|
70
|
-
|
|
71
|
-
if (!memberIdInput) {
|
|
72
|
-
return invalidTokenResponse;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const member = await getCurrentMember();
|
|
77
|
-
if (!member || !member._id) {
|
|
78
|
-
console.log(
|
|
79
|
-
'member not found from members.getCurrentMember() for memberIdInput',
|
|
80
|
-
memberIdInput
|
|
81
|
-
);
|
|
82
|
-
return invalidTokenResponse;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Query member data using elevated permissions (suppressAuth equivalent)
|
|
86
|
-
const { items } = await wixData
|
|
87
|
-
.query(COLLECTIONS.MEMBERS_DATA)
|
|
88
|
-
.eq('contactId', member._id)
|
|
89
|
-
.find();
|
|
90
|
-
|
|
91
|
-
console.log('items', items[0]);
|
|
92
|
-
console.log('member._id', member._id);
|
|
93
|
-
|
|
94
|
-
if (!items[0]?._id) {
|
|
95
|
-
const errorMessage = `No record found in DB for logged in Member [Corrupted Data - Duplicate Members? ] - There is no match in DB for currentMember: ${JSON.stringify(
|
|
96
|
-
{ memberIdInput, currentMemberId: member._id }
|
|
97
|
-
)}`;
|
|
98
|
-
console.error(errorMessage);
|
|
99
|
-
throw new Error('CORRUPTED_MEMBER_DATA');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
console.log(`Id found in DB for memberIdInput :${memberIdInput} is ${items[0]?._id}`);
|
|
103
|
-
|
|
104
|
-
const memberData = items[0];
|
|
105
|
-
|
|
106
|
-
// Format membership dates
|
|
107
|
-
memberData.memberships = memberData.memberships.map(membership => ({
|
|
108
|
-
...membership,
|
|
109
|
-
membersince: formatDateToMonthYear(membership.membersince),
|
|
110
|
-
}));
|
|
111
|
-
|
|
112
|
-
const savedMemberId = memberData?._id;
|
|
113
|
-
const isValid = savedMemberId === memberIdInput;
|
|
114
|
-
|
|
115
|
-
if (!savedMemberId || !isValid) {
|
|
116
|
-
return invalidTokenResponse;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Check if member is dropped
|
|
120
|
-
if (memberData.action === MEMBER_ACTIONS.DROP) {
|
|
121
|
-
return invalidTokenResponse;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Add computed properties
|
|
125
|
-
memberData.addressDisplayOption = getAddressDisplayOptions(memberData);
|
|
126
|
-
console.log('memberData', memberData);
|
|
127
|
-
memberData.isStudent = isStudent(memberData);
|
|
128
|
-
|
|
129
|
-
return { memberData, isValid };
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Error in validateMemberToken:', error);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
61
|
/** Performs bulk save operation for member data
|
|
137
62
|
* @param { Array } memberDataList - Array of member data objects to save
|
|
138
63
|
* @returns { Promise < Object >} - Bulk save operation result
|
|
@@ -144,7 +69,7 @@ async function bulkSaveMembers(memberDataList) {
|
|
|
144
69
|
|
|
145
70
|
try {
|
|
146
71
|
// bulkSave all with batches of 1000 items as this is the Velo limit for bulkSave
|
|
147
|
-
const batches =
|
|
72
|
+
const batches = chunkArray(memberDataList, 1000);
|
|
148
73
|
return await Promise.all(
|
|
149
74
|
batches.map(batch => wixData.bulkSave(COLLECTIONS.MEMBERS_DATA, batch))
|
|
150
75
|
);
|
|
@@ -183,7 +108,7 @@ async function findMemberById(memberId) {
|
|
|
183
108
|
* @param {boolean} options.excludeDropped - Whether to exclude dropped members (default: true)
|
|
184
109
|
* @param {boolean} options.excludeSearchedMember - Whether to exclude a specific member (default: false)
|
|
185
110
|
* @param {string|number} [options.memberId] - Member ID to exclude when excludeSearchedMember is true (optional)
|
|
186
|
-
* @param {boolean} [options.
|
|
111
|
+
* @param {boolean} [options.normalizeSlugForComparison=false] - Whether to normalize the slug for comparison (default: false)
|
|
187
112
|
* @returns {Promise<Object|null>} - Member data or null if not found
|
|
188
113
|
*/
|
|
189
114
|
async function getMemberBySlug({
|
|
@@ -191,7 +116,7 @@ async function getMemberBySlug({
|
|
|
191
116
|
excludeDropped = true,
|
|
192
117
|
excludeSearchedMember = false,
|
|
193
118
|
memberId = null,
|
|
194
|
-
|
|
119
|
+
normalizeSlugForComparison = false,
|
|
195
120
|
}) {
|
|
196
121
|
if (!slug) return null;
|
|
197
122
|
|
|
@@ -205,17 +130,12 @@ async function getMemberBySlug({
|
|
|
205
130
|
if (excludeSearchedMember && memberId) {
|
|
206
131
|
query = query.ne('memberId', memberId);
|
|
207
132
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
query = query.limit(1000);
|
|
211
|
-
membersList = await queryAllItems(query);
|
|
212
|
-
} else {
|
|
213
|
-
membersList = await query.find().then(res => res.items);
|
|
214
|
-
}
|
|
133
|
+
query = query.limit(1000);
|
|
134
|
+
const membersList = await queryAllItems(query);
|
|
215
135
|
let matchingMembers = membersList.filter(
|
|
216
136
|
item => item.url && item.url.toLowerCase() === slug.toLowerCase()
|
|
217
137
|
);
|
|
218
|
-
if (
|
|
138
|
+
if (normalizeSlugForComparison) {
|
|
219
139
|
matchingMembers = membersList
|
|
220
140
|
.filter(
|
|
221
141
|
//remove trailing "-1", "-2", etc.
|
|
@@ -227,7 +147,7 @@ async function getMemberBySlug({
|
|
|
227
147
|
const queryResultMsg = `Multiple members found with same slug ${slug} membersIds are : [${matchingMembers
|
|
228
148
|
.map(member => member.memberId)
|
|
229
149
|
.join(', ')}]`;
|
|
230
|
-
if (!
|
|
150
|
+
if (!normalizeSlugForComparison) {
|
|
231
151
|
throw new Error(queryResultMsg);
|
|
232
152
|
} else {
|
|
233
153
|
console.log(queryResultMsg);
|
|
@@ -240,6 +160,59 @@ async function getMemberBySlug({
|
|
|
240
160
|
}
|
|
241
161
|
}
|
|
242
162
|
|
|
163
|
+
async function getMemberByContactId(contactId) {
|
|
164
|
+
if (!contactId) {
|
|
165
|
+
throw new Error('Contact ID is required');
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const members = await wixData
|
|
169
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
170
|
+
.eq('contactId', contactId)
|
|
171
|
+
.limit(2)
|
|
172
|
+
.find()
|
|
173
|
+
.then(res => res.items);
|
|
174
|
+
if (members.length > 1) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`[getMemberByContactId] Multiple members found with contactId ${contactId} membersIds are : [${members.map(member => member.memberId).join(', ')}]`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return members[0] || null;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`[getMemberByContactId] Failed to retrieve member by contactId ${contactId} data: ${error.message}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Gets all members with aboutyoustatus as null
|
|
188
|
+
* @returns {Promise<import('wix-data').WixDataQueryResult>} - WixDataQueryResult of member data
|
|
189
|
+
*/
|
|
190
|
+
const getAllEmptyAboutYouMembers = async () => {
|
|
191
|
+
try {
|
|
192
|
+
const membersQuery = wixData
|
|
193
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
194
|
+
.isEmpty('aboutYourSelf')
|
|
195
|
+
.isNotEmpty('aboutYouHtml');
|
|
196
|
+
return await queryAllItems(membersQuery);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error('Error getting empty about you members:', error);
|
|
199
|
+
throw new Error(`Failed to get empty about you members: ${error.message}`);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* updates member data
|
|
205
|
+
* @param {Object} memberToUpdate - The member data to update
|
|
206
|
+
* @returns {Promise<Object|null>} - Member data or null if not found
|
|
207
|
+
*/
|
|
208
|
+
async function updateMember(memberToUpdate) {
|
|
209
|
+
try {
|
|
210
|
+
const updatedMember = await wixData.update(COLLECTIONS.MEMBERS_DATA, memberToUpdate);
|
|
211
|
+
return updatedMember;
|
|
212
|
+
} catch (error) {
|
|
213
|
+
throw new Error(`Failed to update member data: ${error.message}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
243
216
|
/**
|
|
244
217
|
* Saves member registration data
|
|
245
218
|
* @param {Object} data - Member data to save
|
|
@@ -271,7 +244,7 @@ async function saveRegistrationData(data, id) {
|
|
|
271
244
|
|
|
272
245
|
await updateMemberContactInfo(data, existingMemberData);
|
|
273
246
|
|
|
274
|
-
const saveData = await
|
|
247
|
+
const saveData = await updateMember(data);
|
|
275
248
|
return {
|
|
276
249
|
type: 'success',
|
|
277
250
|
saveData,
|
|
@@ -318,12 +291,216 @@ async function urlExists(url, excludeMemberId) {
|
|
|
318
291
|
}
|
|
319
292
|
}
|
|
320
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Checks URL uniqueness for a member
|
|
296
|
+
* @param {string} url - The URL to check
|
|
297
|
+
* @param {string} memberId - The member ID to exclude from the check
|
|
298
|
+
* @returns {Promise<Object>} Result object with isUnique boolean
|
|
299
|
+
*/
|
|
300
|
+
async function checkUrlUniqueness(url, memberId) {
|
|
301
|
+
if (!url || !memberId) {
|
|
302
|
+
throw new Error('Missing required parameters: url and memberId are required');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const trimmedUrl = url.trim();
|
|
307
|
+
const exists = await urlExists(trimmedUrl, memberId);
|
|
308
|
+
|
|
309
|
+
return { isUnique: !exists };
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.error('Error checking URL uniqueness:', error);
|
|
312
|
+
throw new Error(`Failed to check URL uniqueness: ${error.message}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get all members with external profile images
|
|
317
|
+
* @returns {Promise<Array>} - Array of member IDs
|
|
318
|
+
*/
|
|
319
|
+
async function getAllMembersWithExternalImages() {
|
|
320
|
+
try {
|
|
321
|
+
const membersQuery = await wixData
|
|
322
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
323
|
+
.isNotEmpty('profileImage')
|
|
324
|
+
.ne('profileImage', null);
|
|
325
|
+
|
|
326
|
+
const allItems = await queryAllItems(membersQuery);
|
|
327
|
+
|
|
328
|
+
// Filter for external images (not starting with 'wix:')
|
|
329
|
+
const membersWithExternalImages = allItems.filter(
|
|
330
|
+
member => member.profileImage && !member.profileImage.startsWith('wix:')
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
return membersWithExternalImages;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.error('Error getting members with external images:', error);
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function getMembersWithWixUrl() {
|
|
341
|
+
const membersQuery = wixData
|
|
342
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
343
|
+
.eq('isVisible', true)
|
|
344
|
+
.eq('showWixUrl', true)
|
|
345
|
+
.ne('action', MEMBER_ACTIONS.DROP)
|
|
346
|
+
.ne('memberships.membertype', MEMBERSHIPS_TYPES.PAC_STAFF)
|
|
347
|
+
.isNotEmpty('url')
|
|
348
|
+
.limit(1000);
|
|
349
|
+
let currentResults = await membersQuery.find();
|
|
350
|
+
let i = 0;
|
|
351
|
+
const allItems = currentResults.items;
|
|
352
|
+
while (currentResults.hasNext()) {
|
|
353
|
+
if (i % 50 === 0) console.log(`page ${i}`);
|
|
354
|
+
currentResults = await currentResults.next();
|
|
355
|
+
allItems.push(...currentResults.items);
|
|
356
|
+
i++;
|
|
357
|
+
}
|
|
358
|
+
console.log('i is ', i);
|
|
359
|
+
const filtered = allItems.filter(item => typeof item.url === 'string' && !item.url.includes('/'));
|
|
360
|
+
console.log('filtered is ', filtered.length);
|
|
361
|
+
return filtered;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Gets all members who need contactFormEmail migration (missing contactFormEmail field)
|
|
366
|
+
* @returns {Promise<Array>} - Array of member data
|
|
367
|
+
*/
|
|
368
|
+
const getAllMembersWithoutContactFormEmail = async () => {
|
|
369
|
+
try {
|
|
370
|
+
const membersQuery = wixData
|
|
371
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
372
|
+
.isEmpty('contactFormEmail')
|
|
373
|
+
.isNotEmpty('email')
|
|
374
|
+
.limit(1000);
|
|
375
|
+
|
|
376
|
+
const allItems = await queryAllItems(membersQuery);
|
|
377
|
+
return allItems;
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.error('Error getting members without contactFormEmail:', error);
|
|
380
|
+
throw new Error(`Failed to get members without contactFormEmail: ${error.message}`);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/* Gets all updated login emails from the updated emails database
|
|
385
|
+
* @returns {Promise<Array>} - Array of updated email data
|
|
386
|
+
*/
|
|
387
|
+
const getAllUpdatedLoginEmails = async () => {
|
|
388
|
+
try {
|
|
389
|
+
const updatedEmailsQuery = await wixData
|
|
390
|
+
.query(COLLECTIONS.UPDATED_LOGIN_EMAILS)
|
|
391
|
+
.isNotEmpty('memberId')
|
|
392
|
+
.isNotEmpty('loginEmail')
|
|
393
|
+
.limit(1000);
|
|
394
|
+
return await queryAllItems(updatedEmailsQuery);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.error('Error getting updated login emails:', error);
|
|
397
|
+
throw new Error(`Failed to get updated login emails: ${error.message}`);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Gets members by their member IDs for email sync
|
|
402
|
+
* @param {Array} memberIds - Array of member IDs to fetch
|
|
403
|
+
* @returns {Promise<Array>} - Array of member data
|
|
404
|
+
*/
|
|
405
|
+
const getMembersByIds = async memberIds => {
|
|
406
|
+
try {
|
|
407
|
+
const membersQuery = wixData
|
|
408
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
409
|
+
.hasSome('memberId', memberIds)
|
|
410
|
+
.limit(1000);
|
|
411
|
+
|
|
412
|
+
return await queryAllItems(membersQuery);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
console.error('Error getting members by IDs:', error);
|
|
415
|
+
throw new Error(`Failed to get members by IDs: ${error.message}`);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const getMemberByEmail = async email => {
|
|
420
|
+
try {
|
|
421
|
+
const members = await wixData
|
|
422
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
423
|
+
.eq('email', email)
|
|
424
|
+
.limit(2)
|
|
425
|
+
.find()
|
|
426
|
+
.then(res => res.items);
|
|
427
|
+
if (members.length > 1) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
`[getMemberByEmail] Multiple members found with email ${email} membersIds are : [${members.map(member => member.memberId).join(', ')}]`
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
return members[0] || null;
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.error('Error getting member by email:', error);
|
|
435
|
+
throw new Error(`Failed to get member by email: ${error.message}`);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const getQAUsers = async () => {
|
|
440
|
+
try {
|
|
441
|
+
return await wixData
|
|
442
|
+
.query(COLLECTIONS.QA_USERS)
|
|
443
|
+
.include('member')
|
|
444
|
+
.find()
|
|
445
|
+
.then(res => res.items.map(item => item.member));
|
|
446
|
+
} catch (error) {
|
|
447
|
+
console.error('Error getting QA users:', error);
|
|
448
|
+
throw new Error(`Failed to get QA users: ${error.message}`);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
async function getSiteMemberId(data) {
|
|
452
|
+
try {
|
|
453
|
+
console.log('data', data);
|
|
454
|
+
const memberId = data?.pac?.cst_recno;
|
|
455
|
+
if (!memberId) {
|
|
456
|
+
const errorMessage = `Member ID is missing in passed data ${JSON.stringify(data)}`;
|
|
457
|
+
console.error(errorMessage);
|
|
458
|
+
throw new Error(errorMessage);
|
|
459
|
+
}
|
|
460
|
+
const queryMemberResult = await wixData
|
|
461
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
462
|
+
.eq('memberId', Number(memberId))
|
|
463
|
+
.find()
|
|
464
|
+
.then(res => res.items);
|
|
465
|
+
if (!queryMemberResult.length || queryMemberResult.length > 1) {
|
|
466
|
+
throw new Error(
|
|
467
|
+
`Invalid Members count found in DB for email ${data.email} members count is : [${
|
|
468
|
+
queryMemberResult.length
|
|
469
|
+
}] membersIds are : [${queryMemberResult.map(member => member.memberId).join(', ')}]`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
let memberData = queryMemberResult[0];
|
|
473
|
+
console.log('memberData', memberData);
|
|
474
|
+
const isNewUser = !memberData.contactId;
|
|
475
|
+
if (isNewUser) {
|
|
476
|
+
const memberDataWithContactId = await createContactAndMemberIfNew(memberData);
|
|
477
|
+
console.log('memberDataWithContactId', memberDataWithContactId);
|
|
478
|
+
memberData = memberDataWithContactId;
|
|
479
|
+
}
|
|
480
|
+
return memberData;
|
|
481
|
+
} catch (error) {
|
|
482
|
+
console.error('Error in getSiteMemberId', error.message);
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
321
487
|
module.exports = {
|
|
322
488
|
findMemberByWixDataId,
|
|
323
489
|
createContactAndMemberIfNew,
|
|
324
|
-
validateMemberToken,
|
|
325
490
|
saveRegistrationData,
|
|
326
491
|
bulkSaveMembers,
|
|
327
492
|
findMemberById,
|
|
328
493
|
getMemberBySlug,
|
|
494
|
+
getMemberByContactId,
|
|
495
|
+
getAllEmptyAboutYouMembers,
|
|
496
|
+
updateMember,
|
|
497
|
+
getAllMembersWithExternalImages,
|
|
498
|
+
getMembersWithWixUrl,
|
|
499
|
+
getAllMembersWithoutContactFormEmail,
|
|
500
|
+
getAllUpdatedLoginEmails,
|
|
501
|
+
getMembersByIds,
|
|
502
|
+
getMemberByEmail,
|
|
503
|
+
getQAUsers,
|
|
504
|
+
getSiteMemberId,
|
|
505
|
+
checkUrlUniqueness,
|
|
329
506
|
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
const { PAC_API_URL } = require('./daily-pull/consts');
|
|
1
|
+
const { PAC_API_URL } = require('./consts');
|
|
2
|
+
const { getSecret } = require('./utils');
|
|
4
3
|
|
|
5
4
|
const getHeaders = async () => {
|
|
6
|
-
const AUTH_TOKEN = await
|
|
5
|
+
const AUTH_TOKEN = await getSecret('members-data-api-key');
|
|
7
6
|
const headers = {
|
|
8
7
|
Authorization: `Bearer ${AUTH_TOKEN}`,
|
|
9
8
|
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const { PAGES_PATHS } = require('../../public/consts');
|
|
2
|
+
//const { fetchAllItemsInParallel } = require('../cms-data-methods'); unused at host site
|
|
3
|
+
const { CONFIG_KEYS } = require('../consts');
|
|
4
|
+
const { getSiteConfigs } = require('../utils');
|
|
5
|
+
|
|
6
|
+
const { generateSEOTitle, stripHtmlTags, getMemberProfileData } = require('./utils');
|
|
7
|
+
|
|
8
|
+
const createRoutersHandlers = wixRouterMethods => {
|
|
9
|
+
const {
|
|
10
|
+
redirect,
|
|
11
|
+
ok,
|
|
12
|
+
notFound,
|
|
13
|
+
sendStatus,
|
|
14
|
+
WixRouterSitemapEntry: _WixRouterSitemapEntry,
|
|
15
|
+
} = wixRouterMethods; // These dependencies needs to be injected as they do not have an SDK equivalent for now
|
|
16
|
+
|
|
17
|
+
async function profileRouter(request) {
|
|
18
|
+
const slug = request.path[0];
|
|
19
|
+
if (!slug) {
|
|
20
|
+
return redirect(request.baseUrl);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const siteConfigs = await getSiteConfigs();
|
|
24
|
+
const siteAssociation = siteConfigs[CONFIG_KEYS.SITE_ASSOCIATION];
|
|
25
|
+
const defaultSEODescription = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_SEO_DESCRIPTION];
|
|
26
|
+
const siteLogoUrl = siteConfigs[CONFIG_KEYS.SITE_LOGO_URL];
|
|
27
|
+
const defaultProfileImage = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_IMAGE];
|
|
28
|
+
const profileData = await getMemberProfileData(slug, siteAssociation);
|
|
29
|
+
if (profileData && profileData.showWixUrl) {
|
|
30
|
+
const ogImage = profileData.profileImage || profileData.logoImage || siteLogoUrl;
|
|
31
|
+
const seoTitle = generateSEOTitle({
|
|
32
|
+
fullName: profileData.fullName,
|
|
33
|
+
areasOfPractices: profileData.areasOfPractices,
|
|
34
|
+
siteAssociation,
|
|
35
|
+
});
|
|
36
|
+
// Use stripped HTML from aboutService rich text content
|
|
37
|
+
let description = stripHtmlTags(profileData.aboutService) || defaultSEODescription;
|
|
38
|
+
|
|
39
|
+
// Limit description to 160 characters for optimal SEO
|
|
40
|
+
if (description.length > 160) {
|
|
41
|
+
description = description.substring(0, 157) + '...';
|
|
42
|
+
}
|
|
43
|
+
const profileUrl = `${request.baseUrl}/${PAGES_PATHS.PROFILE}/${profileData.url}`;
|
|
44
|
+
const isPrivateMember = profileData.isPrivateMember;
|
|
45
|
+
const seoData = {
|
|
46
|
+
title: seoTitle,
|
|
47
|
+
description: description,
|
|
48
|
+
noIndex: isPrivateMember,
|
|
49
|
+
metaTags: [
|
|
50
|
+
{
|
|
51
|
+
name: 'description',
|
|
52
|
+
content: description,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'keywords',
|
|
56
|
+
content:
|
|
57
|
+
`${profileData.fullName}, ${profileData.areasOfPractices ? profileData.areasOfPractices.slice(0, 3).join(', ') : ''}, ${siteAssociation}, ${profileData.city || ''}, ${profileData.state || ''}`
|
|
58
|
+
.replace(/,\s*,/g, ',')
|
|
59
|
+
.replace(/^,|,$/g, ''),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'author',
|
|
63
|
+
content: profileData.fullName,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'robots',
|
|
67
|
+
content: isPrivateMember ? 'noindex, nofollow' : 'index, follow',
|
|
68
|
+
},
|
|
69
|
+
// Open Graph tags
|
|
70
|
+
{
|
|
71
|
+
property: 'og:type',
|
|
72
|
+
content: 'profile',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
property: 'og:title',
|
|
76
|
+
content: seoTitle,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
property: 'og:description',
|
|
80
|
+
content: description,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
property: 'og:image',
|
|
84
|
+
content: ogImage,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
property: 'og:url',
|
|
88
|
+
content: profileUrl,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
property: 'og:site_name',
|
|
92
|
+
content: `${siteAssociation} Members`,
|
|
93
|
+
},
|
|
94
|
+
// Twitter Card tags
|
|
95
|
+
{
|
|
96
|
+
name: 'twitter:card',
|
|
97
|
+
content: 'summary_large_image',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'twitter:title',
|
|
101
|
+
content: seoTitle,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'twitter:description',
|
|
105
|
+
content: description,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'twitter:image',
|
|
109
|
+
content: ogImage,
|
|
110
|
+
},
|
|
111
|
+
// Additional SEO tags
|
|
112
|
+
{
|
|
113
|
+
name: 'geo.region',
|
|
114
|
+
content: profileData.state || '',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'geo.placename',
|
|
118
|
+
content: profileData.city || '',
|
|
119
|
+
},
|
|
120
|
+
].filter(tag => tag.content && tag.content.trim() !== ''), // Remove empty tags
|
|
121
|
+
};
|
|
122
|
+
return ok('profile', { ...profileData, defaultProfileImage }, seoData);
|
|
123
|
+
}
|
|
124
|
+
return notFound();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(error);
|
|
127
|
+
return sendStatus('500', 'Internal Server Error');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function profileSiteMap(_sitemapRequest) {
|
|
131
|
+
return [];
|
|
132
|
+
// Commented out - currently disabled in host site
|
|
133
|
+
// try {
|
|
134
|
+
// const membersQuery = wixData
|
|
135
|
+
// .query(COLLECTIONS.MEMBERS_DATA)
|
|
136
|
+
// .eq('showWixUrl', true)
|
|
137
|
+
// .isNotEmpty('url')
|
|
138
|
+
// .ne('action', 'drop')
|
|
139
|
+
// .fields('url', 'fullName');
|
|
140
|
+
|
|
141
|
+
// const allMembers = await fetchAllItemsInParallel(membersQuery);
|
|
142
|
+
|
|
143
|
+
// const batchSize = 1000;
|
|
144
|
+
// const sitemapEntries = [];
|
|
145
|
+
// const totalItems = allMembers.items.length;
|
|
146
|
+
|
|
147
|
+
// for (let i = 0; i < totalItems; i += batchSize) {
|
|
148
|
+
// const batch = allMembers.items.slice(i, i + batchSize);
|
|
149
|
+
// const batchEntries = batch.map(member => {
|
|
150
|
+
// const entry = new WixRouterSitemapEntry(member.fullName);
|
|
151
|
+
// entry.pageName = 'profile';
|
|
152
|
+
// entry.url = `${PAGES_PATHS.PROFILE}/${member.url}`;
|
|
153
|
+
// entry.title = member.fullName;
|
|
154
|
+
// entry.changeFrequency = 'monthly';
|
|
155
|
+
// entry.priority = 1.0;
|
|
156
|
+
// return entry;
|
|
157
|
+
// });
|
|
158
|
+
// sitemapEntries.push(...batchEntries);
|
|
159
|
+
// }
|
|
160
|
+
|
|
161
|
+
// return sitemapEntries;
|
|
162
|
+
// } catch (error) {
|
|
163
|
+
// console.error('Error generating profile sitemap:', error);
|
|
164
|
+
// return [];
|
|
165
|
+
// }
|
|
166
|
+
}
|
|
167
|
+
//Add other routers here
|
|
168
|
+
return {
|
|
169
|
+
profileRouter,
|
|
170
|
+
profileSiteMap,
|
|
171
|
+
//Add other routers here
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
module.exports = {
|
|
176
|
+
createRoutersHandlers,
|
|
177
|
+
};
|