abmp-npm 2.0.76 → 2.0.78
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/package.json +8 -1
- package/pages/Home.js +27 -55
- package/pages/index.js +0 -1
- package/public/Utils/personalDetailsUtils.js +5 -1
- package/public/Utils/sharedUtils.js +32 -0
- package/public/consts.js +0 -1
- package/.claude/worktrees/fix-save-button-disable/.husky/pre-commit +0 -19
- package/.claude/worktrees/fix-save-button-disable/.prettierignore +0 -7
- package/.claude/worktrees/fix-save-button-disable/.prettierrc.json +0 -16
- package/.claude/worktrees/fix-save-button-disable/README.md +0 -1
- package/.claude/worktrees/fix-save-button-disable/backend/README-member-contact-flows.md +0 -136
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/daily-pull-execution-check.test.js +0 -124
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/login-email-sync.test.js +0 -49
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/backend/__tests__/url-uniqueness.test.js +0 -194
- package/.claude/worktrees/fix-save-button-disable/backend/automations-methods.js +0 -13
- package/.claude/worktrees/fix-save-button-disable/backend/cms-data-methods.js +0 -251
- package/.claude/worktrees/fix-save-button-disable/backend/consts.js +0 -58
- package/.claude/worktrees/fix-save-button-disable/backend/contacts-methods.js +0 -67
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/bulk-process-methods.js +0 -222
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/consts.js +0 -39
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/process-member-methods.js +0 -213
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/schedule-methods.js +0 -41
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/sync-to-cms-methods.js +0 -161
- package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/utils.js +0 -151
- package/.claude/worktrees/fix-save-button-disable/backend/data-hooks.js +0 -29
- package/.claude/worktrees/fix-save-button-disable/backend/dev-only-methods.js +0 -58
- package/.claude/worktrees/fix-save-button-disable/backend/elevated-modules.js +0 -18
- package/.claude/worktrees/fix-save-button-disable/backend/forms-methods.js +0 -52
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/httpFunctions.js +0 -86
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/index.js +0 -3
- package/.claude/worktrees/fix-save-button-disable/backend/http-functions/interests.js +0 -35
- package/.claude/worktrees/fix-save-button-disable/backend/index.js +0 -19
- package/.claude/worktrees/fix-save-button-disable/backend/jobs.js +0 -158
- package/.claude/worktrees/fix-save-button-disable/backend/login/generate-member-session-token.js +0 -27
- package/.claude/worktrees/fix-save-button-disable/backend/login/index.js +0 -8
- package/.claude/worktrees/fix-save-button-disable/backend/login/qa-login-methods.js +0 -54
- package/.claude/worktrees/fix-save-button-disable/backend/login/sso-methods.js +0 -159
- package/.claude/worktrees/fix-save-button-disable/backend/member-contact-orchestration.js +0 -111
- package/.claude/worktrees/fix-save-button-disable/backend/members-area-methods.js +0 -88
- package/.claude/worktrees/fix-save-button-disable/backend/members-data-methods.js +0 -789
- package/.claude/worktrees/fix-save-button-disable/backend/pac-api-methods.js +0 -54
- package/.claude/worktrees/fix-save-button-disable/backend/routers/index.js +0 -3
- package/.claude/worktrees/fix-save-button-disable/backend/routers/methods.js +0 -191
- package/.claude/worktrees/fix-save-button-disable/backend/routers/utils.js +0 -128
- package/.claude/worktrees/fix-save-button-disable/backend/search-filters-methods.js +0 -124
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-primary-methods.js +0 -256
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-visibility-methods.js +0 -160
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/consts.js +0 -34
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/daily-pull-check-methods.js +0 -78
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/email-normalize-methods.js +0 -134
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/index.js +0 -10
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/migration-methods.js +0 -46
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-configs.js +0 -251
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-helpers-methods.js +0 -433
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-process-methods.js +0 -606
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-migration-methods.js +0 -378
- package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-space-fix-methods.js +0 -174
- package/.claude/worktrees/fix-save-button-disable/backend/utils.js +0 -277
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-ids.js +0 -159
- package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-urls.js +0 -201
- package/.claude/worktrees/fix-save-button-disable/eslint.config.js +0 -120
- package/.claude/worktrees/fix-save-button-disable/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/package-lock.json +0 -12160
- package/.claude/worktrees/fix-save-button-disable/package.json +0 -60
- package/.claude/worktrees/fix-save-button-disable/pages/ContactUs.js +0 -129
- package/.claude/worktrees/fix-save-button-disable/pages/Home.js +0 -779
- package/.claude/worktrees/fix-save-button-disable/pages/LearnMore.js +0 -27
- package/.claude/worktrees/fix-save-button-disable/pages/LoadingPage.js +0 -29
- package/.claude/worktrees/fix-save-button-disable/pages/Profile.js +0 -354
- package/.claude/worktrees/fix-save-button-disable/pages/QAPage.js +0 -39
- package/.claude/worktrees/fix-save-button-disable/pages/SaveAlerts.js +0 -13
- package/.claude/worktrees/fix-save-button-disable/pages/SelectBannerImages.js +0 -46
- package/.claude/worktrees/fix-save-button-disable/pages/deleteConfirm.js +0 -19
- package/.claude/worktrees/fix-save-button-disable/pages/index.js +0 -12
- package/.claude/worktrees/fix-save-button-disable/pages/personalDetails.js +0 -2486
- package/.claude/worktrees/fix-save-button-disable/public/Utils/homePage.js +0 -798
- package/.claude/worktrees/fix-save-button-disable/public/Utils/personalDetailsUtils.js +0 -25
- package/.claude/worktrees/fix-save-button-disable/public/Utils/sharedUtils.js +0 -235
- package/.claude/worktrees/fix-save-button-disable/public/consts.js +0 -113
- package/.claude/worktrees/fix-save-button-disable/public/index.js +0 -5
- package/.claude/worktrees/fix-save-button-disable/public/messages.js +0 -16
- package/.claude/worktrees/fix-save-button-disable/public/sso-auth-methods.js +0 -43
- package/.husky/pre-commit +0 -19
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -16
- package/backend/__tests__/daily-pull-execution-check.test.js +0 -124
- package/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
- package/backend/__tests__/login-email-sync.test.js +0 -49
- package/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
- package/backend/__tests__/url-uniqueness.test.js +0 -194
- package/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
- package/dev-only-scripts/find-duplicate-ids.js +0 -159
- package/dev-only-scripts/find-duplicate-urls.js +0 -201
- package/eslint.config.js +0 -120
- package/pages/contactForLocation.js +0 -28
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
const { taskManager } = require('psdev-task-manager');
|
|
2
|
-
|
|
3
|
-
const { CONFIG_KEYS } = require('../consts');
|
|
4
|
-
const { fetchPACMembers } = require('../pac-api-methods');
|
|
5
|
-
const { TASKS_NAMES } = require('../tasks/consts');
|
|
6
|
-
const { getSiteConfigs } = require('../utils');
|
|
7
|
-
|
|
8
|
-
const { bulkProcessAndSaveMemberData } = require('./bulk-process-methods');
|
|
9
|
-
const { MEMBER_ACTIONS } = require('./consts');
|
|
10
|
-
const { isUpdatedMember, isSiteAssociatedMember } = require('./utils');
|
|
11
|
-
|
|
12
|
-
const filterLicensesByAssociation = (member, siteAssociation) => {
|
|
13
|
-
if (!member?.licenses || !Array.isArray(member.licenses)) {
|
|
14
|
-
return member;
|
|
15
|
-
}
|
|
16
|
-
const filteredLicenses = member.licenses.filter(license => {
|
|
17
|
-
if (!license || !license.association) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
return license.association === siteAssociation;
|
|
21
|
-
});
|
|
22
|
-
return {
|
|
23
|
-
...member,
|
|
24
|
-
licenses: filteredLicenses,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
async function syncMembersDataPerAction(taskData) {
|
|
29
|
-
const { action, backupDate, isTestEnvironment, includeNone } = taskData;
|
|
30
|
-
try {
|
|
31
|
-
const firstPageResponse = await fetchPACMembers({
|
|
32
|
-
page: 1,
|
|
33
|
-
action,
|
|
34
|
-
backupDate,
|
|
35
|
-
isTestEnvironment,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
!firstPageResponse ||
|
|
40
|
-
!firstPageResponse.results ||
|
|
41
|
-
firstPageResponse.results.length === 0
|
|
42
|
-
) {
|
|
43
|
-
return {
|
|
44
|
-
success: true,
|
|
45
|
-
totalPagesProcessed: 0,
|
|
46
|
-
lastPageProcessed: 0,
|
|
47
|
-
completedAt: new Date().toISOString(),
|
|
48
|
-
message: 'No data found',
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Calculate total pages from API response
|
|
53
|
-
const totalResults = firstPageResponse.total_results || 0;
|
|
54
|
-
const perPage = firstPageResponse.results.length;
|
|
55
|
-
const totalPages = firstPageResponse.total_pages || 0;
|
|
56
|
-
|
|
57
|
-
// Cap at 1000 pages as safety measure
|
|
58
|
-
const pagesToProcess = Math.min(totalPages, 1000);
|
|
59
|
-
|
|
60
|
-
console.log(
|
|
61
|
-
`Scheduling ${pagesToProcess} pages for processing (${totalResults} total records, ${perPage} per page)`
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
// Schedule tasks for all pages at once
|
|
65
|
-
const toScheduleTasks = Array.from(
|
|
66
|
-
{ length: pagesToProcess },
|
|
67
|
-
(_, i) => i + 1 // API expects page number to start from 1
|
|
68
|
-
).map(pageNumber => ({
|
|
69
|
-
name: TASKS_NAMES.SyncMembers,
|
|
70
|
-
data: {
|
|
71
|
-
pageNumber,
|
|
72
|
-
action,
|
|
73
|
-
...(backupDate ? { backupDate } : {}),
|
|
74
|
-
...(isTestEnvironment ? { isTestEnvironment } : {}),
|
|
75
|
-
...(includeNone ? { includeNone } : {}),
|
|
76
|
-
},
|
|
77
|
-
type: 'scheduled',
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
// Wait for all scheduling to complete
|
|
81
|
-
await taskManager().scheduleInBulk(toScheduleTasks);
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
success: true,
|
|
85
|
-
totalPagesProcessed: pagesToProcess,
|
|
86
|
-
lastPageProcessed: pagesToProcess,
|
|
87
|
-
totalRecords: totalResults,
|
|
88
|
-
recordsPerPage: perPage,
|
|
89
|
-
completedAt: new Date().toISOString(),
|
|
90
|
-
};
|
|
91
|
-
} catch (error) {
|
|
92
|
-
throw new Error(`Synchronization failed: ${error.message}`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Synchronizes a single page of member data
|
|
98
|
-
* @param {Object} taskObject - Task object containing page data
|
|
99
|
-
* @returns {Promise<Object>} - Page synchronization result
|
|
100
|
-
*/
|
|
101
|
-
async function synchronizeSinglePage(taskObject) {
|
|
102
|
-
const { pageNumber, action, backupDate, isTestEnvironment, includeNone } = taskObject.data;
|
|
103
|
-
try {
|
|
104
|
-
const [siteAssociation, memberDataResponse] = await Promise.all([
|
|
105
|
-
getSiteConfigs(CONFIG_KEYS.SITE_ASSOCIATION),
|
|
106
|
-
fetchPACMembers({
|
|
107
|
-
page: pageNumber,
|
|
108
|
-
action,
|
|
109
|
-
backupDate,
|
|
110
|
-
isTestEnvironment,
|
|
111
|
-
}),
|
|
112
|
-
]);
|
|
113
|
-
if (
|
|
114
|
-
!memberDataResponse ||
|
|
115
|
-
!memberDataResponse.results ||
|
|
116
|
-
memberDataResponse.results.length === 0
|
|
117
|
-
) {
|
|
118
|
-
throw new Error(`No data found for page ${pageNumber}`);
|
|
119
|
-
}
|
|
120
|
-
const toSyncMembers = memberDataResponse.results.filter(member => {
|
|
121
|
-
if (!isSiteAssociatedMember(member, siteAssociation)) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
if (action === MEMBER_ACTIONS.NONE && includeNone) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
return isUpdatedMember(member);
|
|
128
|
-
});
|
|
129
|
-
const toSyncMembersWithFilteredLicenses = toSyncMembers.map(member =>
|
|
130
|
-
filterLicensesByAssociation(member, siteAssociation)
|
|
131
|
-
);
|
|
132
|
-
if (toSyncMembers.length === 0) {
|
|
133
|
-
return {
|
|
134
|
-
success: true,
|
|
135
|
-
pageNumber,
|
|
136
|
-
totalPageSize: memberDataResponse.results.length,
|
|
137
|
-
filteredPageSize: toSyncMembers.length,
|
|
138
|
-
message: `No to be updated, or members of association: '${siteAssociation}' found`,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const result = await bulkProcessAndSaveMemberData({
|
|
142
|
-
memberDataList: toSyncMembersWithFilteredLicenses,
|
|
143
|
-
currentPageNumber: pageNumber,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
success: true,
|
|
148
|
-
pageNumber,
|
|
149
|
-
totalPageSize: memberDataResponse.results.length,
|
|
150
|
-
filteredPageSize: toSyncMembers.length,
|
|
151
|
-
...result,
|
|
152
|
-
};
|
|
153
|
-
} catch (error) {
|
|
154
|
-
throw new Error(`Page ${pageNumber} synchronization failed: ${error.message}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
module.exports = {
|
|
159
|
-
syncMembersDataPerAction,
|
|
160
|
-
synchronizeSinglePage,
|
|
161
|
-
};
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
const { LOGIN_EMAIL_SYNC_STATUS } = require('../consts');
|
|
2
|
-
const { updateWixMemberLoginEmail } = require('../members-area-methods');
|
|
3
|
-
const { extractUrlCounter } = require('../utils');
|
|
4
|
-
|
|
5
|
-
const { MEMBER_ACTIONS } = require('./consts');
|
|
6
|
-
|
|
7
|
-
const isUpdatedMember = member => member.action !== MEMBER_ACTIONS.NONE;
|
|
8
|
-
const isSiteAssociatedMember = (member, siteAssociation) =>
|
|
9
|
-
member.memberships.some(membership => membership.association === siteAssociation);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Attempts to change Wix login emails for the given members and returns one structured
|
|
13
|
-
* outcome per member (see updateWixMemberLoginEmail). Never throws for an individual member.
|
|
14
|
-
* @param {Array} toChangeWixMembersEmails
|
|
15
|
-
* @returns {Promise<Array>} outcomes
|
|
16
|
-
*/
|
|
17
|
-
const changeWixMembersEmails = async toChangeWixMembersEmails => {
|
|
18
|
-
console.log(
|
|
19
|
-
`[loginEmailSync] changing login emails for ${toChangeWixMembersEmails.length} members with ids: [${toChangeWixMembersEmails.map(member => member.memberId).join(', ')}]`
|
|
20
|
-
);
|
|
21
|
-
const outcomes = await Promise.all(
|
|
22
|
-
toChangeWixMembersEmails.map(member => updateWixMemberLoginEmail(member))
|
|
23
|
-
);
|
|
24
|
-
const summary = outcomes.reduce((acc, outcome) => {
|
|
25
|
-
acc[outcome.status] = (acc[outcome.status] || 0) + 1;
|
|
26
|
-
return acc;
|
|
27
|
-
}, {});
|
|
28
|
-
console.log(`[loginEmailSync] results summary: ${JSON.stringify(summary)}`);
|
|
29
|
-
return outcomes;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Summarizes login-email sync outcomes for manual handling via the task result.
|
|
34
|
-
* Pure function so it can be unit-tested without Wix.
|
|
35
|
-
* @param {Array} outcomes - from updateWixMemberLoginEmail / changeWixMembersEmails
|
|
36
|
-
* @returns {{ failedMemberIds: Set, failures: Array }} set of failed memberIds (whose CMS login
|
|
37
|
-
* email must be left unchanged) and the failure records to surface in the task result
|
|
38
|
-
*/
|
|
39
|
-
const summarizeLoginEmailOutcomes = (outcomes = []) => {
|
|
40
|
-
const failedMemberIds = new Set();
|
|
41
|
-
const failures = [];
|
|
42
|
-
outcomes.forEach(outcome => {
|
|
43
|
-
if (outcome.status === LOGIN_EMAIL_SYNC_STATUS.FAILED) {
|
|
44
|
-
failedMemberIds.add(outcome.memberId);
|
|
45
|
-
failures.push({
|
|
46
|
-
memberId: outcome.memberId,
|
|
47
|
-
wixMemberId: outcome.wixMemberId,
|
|
48
|
-
desiredEmail: outcome.desiredEmail,
|
|
49
|
-
error: outcome.error || 'unknown error',
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
return { failedMemberIds, failures };
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const extractBaseUrl = url => {
|
|
57
|
-
if (!url) return url;
|
|
58
|
-
const lastCounter = extractUrlCounter(url);
|
|
59
|
-
if (lastCounter > 0) {
|
|
60
|
-
// Remove the numeric counter to get the base URL
|
|
61
|
-
return url.split('-').slice(0, -1).join('-');
|
|
62
|
-
}
|
|
63
|
-
// No counter found, return the URL as-is
|
|
64
|
-
return url;
|
|
65
|
-
};
|
|
66
|
-
const incrementUrlCounter = (existingUrl, baseUrl) => {
|
|
67
|
-
if (!existingUrl || !baseUrl) {
|
|
68
|
-
return baseUrl;
|
|
69
|
-
}
|
|
70
|
-
// Normalize for comparison (case-insensitive)
|
|
71
|
-
const normalizedExisting = existingUrl.toLowerCase();
|
|
72
|
-
const normalizedBase = baseUrl.toLowerCase();
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
normalizedExisting === normalizedBase ||
|
|
76
|
-
normalizedExisting.startsWith(`${normalizedBase}-`)
|
|
77
|
-
) {
|
|
78
|
-
console.log(
|
|
79
|
-
`Found member with same url ${existingUrl} for baseUrl ${baseUrl}, increasing counter by 1`
|
|
80
|
-
);
|
|
81
|
-
const lastCounter = Math.max(0, extractUrlCounter(existingUrl));
|
|
82
|
-
return `${baseUrl}-${lastCounter + 1}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// No conflict, return baseUrl with counter 1 to be safe
|
|
86
|
-
return `${baseUrl}-1`;
|
|
87
|
-
};
|
|
88
|
-
/**
|
|
89
|
-
* Validates core member data requirements
|
|
90
|
-
* @param {Object} inputMemberData - Raw member data from API to validate
|
|
91
|
-
* @returns {boolean} - True if all required fields are valid, false otherwise
|
|
92
|
-
*/
|
|
93
|
-
const validateCoreMemberData = inputMemberData => {
|
|
94
|
-
// Check memberid
|
|
95
|
-
if (!inputMemberData?.memberid) {
|
|
96
|
-
console.warn('validateCoreMemberData: Missing required field - memberid is mandatory');
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Check email
|
|
101
|
-
if (
|
|
102
|
-
!inputMemberData?.email ||
|
|
103
|
-
typeof inputMemberData.email !== 'string' ||
|
|
104
|
-
!inputMemberData.email.trim()
|
|
105
|
-
) {
|
|
106
|
-
console.warn(
|
|
107
|
-
'validateCoreMemberData: Missing required field - email (valid string) is mandatory'
|
|
108
|
-
);
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Check memberships
|
|
113
|
-
if (
|
|
114
|
-
!inputMemberData?.memberships ||
|
|
115
|
-
!Array.isArray(inputMemberData.memberships) ||
|
|
116
|
-
inputMemberData.memberships.length === 0
|
|
117
|
-
) {
|
|
118
|
-
console.warn(
|
|
119
|
-
'validateCoreMemberData: Missing required field - memberships (non-empty array) is mandatory'
|
|
120
|
-
);
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return true;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const containsNonEnglish = str => /[^a-zA-Z0-9-]/.test(str); // if it contains any non-english characters or invalid URL chars, test1 is allowed, hyphens are allowed
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Creates a full name from first and last name components
|
|
131
|
-
* @param {string} firstName - First name
|
|
132
|
-
* @param {string} lastName - Last name
|
|
133
|
-
* @returns {string} - Combined full name
|
|
134
|
-
*/
|
|
135
|
-
const createFullName = (firstName, lastName) => {
|
|
136
|
-
const trimmedFirst = firstName?.trim() || '';
|
|
137
|
-
const trimmedLast = lastName?.trim() || '';
|
|
138
|
-
return `${trimmedFirst} ${trimmedLast}`.trim();
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
module.exports = {
|
|
142
|
-
isUpdatedMember,
|
|
143
|
-
isSiteAssociatedMember,
|
|
144
|
-
changeWixMembersEmails,
|
|
145
|
-
summarizeLoginEmailOutcomes,
|
|
146
|
-
validateCoreMemberData,
|
|
147
|
-
containsNonEnglish,
|
|
148
|
-
createFullName,
|
|
149
|
-
incrementUrlCounter,
|
|
150
|
-
extractBaseUrl,
|
|
151
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const { taskManager, TASK_TYPE } = require('psdev-task-manager');
|
|
2
|
-
|
|
3
|
-
const { COMPILED_FILTERS_FIELDS } = require('./consts');
|
|
4
|
-
const { TASKS_NAMES } = require('./tasks/consts');
|
|
5
|
-
|
|
6
|
-
const scheduleCompileFiltersTask = field =>
|
|
7
|
-
taskManager().schedule({
|
|
8
|
-
name: TASKS_NAMES.CompileFiltersOptions,
|
|
9
|
-
data: { field },
|
|
10
|
-
type: TASK_TYPE.SCHEDULED,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
function scheduleCompileInterestsTask() {
|
|
14
|
-
return scheduleCompileFiltersTask(COMPILED_FILTERS_FIELDS.COMPILED_AREAS_OF_PRACTICES);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function scheduleCompileStatesTask() {
|
|
18
|
-
return scheduleCompileFiltersTask(COMPILED_FILTERS_FIELDS.COMPILED_STATE_LIST);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function scheduleCompileCitiesTask() {
|
|
22
|
-
return scheduleCompileFiltersTask(COMPILED_FILTERS_FIELDS.COMPILED_STATE_CITY_MAP);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = {
|
|
26
|
-
scheduleCompileInterestsTask,
|
|
27
|
-
scheduleCompileStatesTask,
|
|
28
|
-
scheduleCompileCitiesTask,
|
|
29
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
const { COLLECTIONS } = require('../public/consts');
|
|
2
|
-
|
|
3
|
-
const { ensureUniqueUrlsInBatch } = require('./daily-pull/bulk-process-methods');
|
|
4
|
-
const { ensureUniqueUrl } = require('./daily-pull/process-member-methods');
|
|
5
|
-
const { wixData } = require('./elevated-modules');
|
|
6
|
-
const { bulkSaveMembers } = require('./members-data-methods');
|
|
7
|
-
const { queryAllItems } = require('./utils');
|
|
8
|
-
|
|
9
|
-
async function deduplicateURls(collectionName, duplicateUrlsList) {
|
|
10
|
-
const query = await wixData.query(collectionName).hasSome('url', duplicateUrlsList).limit(1000);
|
|
11
|
-
const membersWithSameUrl = await queryAllItems(query);
|
|
12
|
-
|
|
13
|
-
console.log({ membersWithSameUrl });
|
|
14
|
-
const membersWithUniqueUrls = await ensureUniqueUrlsInBatch(membersWithSameUrl);
|
|
15
|
-
console.log({ membersWithUniqueUrls });
|
|
16
|
-
const deduplicatedUrls = membersWithUniqueUrls.map(m => m.url);
|
|
17
|
-
console.log({ deduplicatedUrls });
|
|
18
|
-
return await bulkSaveMembers(membersWithUniqueUrls, collectionName);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function copyContactIdToWixMemberId() {
|
|
22
|
-
const query = wixData.query(COLLECTIONS.MEMBERS_DATA).isNotEmpty('contactId');
|
|
23
|
-
const members = await queryAllItems(query);
|
|
24
|
-
const updatedMembers = members.map(member => ({
|
|
25
|
-
...member,
|
|
26
|
-
wixMemberId: member.contactId,
|
|
27
|
-
}));
|
|
28
|
-
return await bulkSaveMembers(updatedMembers, COLLECTIONS.MEMBERS_DATA);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function createMissingUrls() {
|
|
32
|
-
const query = wixData.query(COLLECTIONS.MEMBERS_DATA).isEmpty('url');
|
|
33
|
-
const members = await queryAllItems(query);
|
|
34
|
-
console.log(
|
|
35
|
-
'membersWithoutUrls info',
|
|
36
|
-
JSON.stringify({
|
|
37
|
-
count: members.length,
|
|
38
|
-
membersIds: members.map(m => m.memberId),
|
|
39
|
-
})
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
const membersWithGeneratedUrlsPromises = members.map(async member => ({
|
|
43
|
-
...member,
|
|
44
|
-
url: await ensureUniqueUrl({
|
|
45
|
-
url: member.url,
|
|
46
|
-
memberId: member.memberId,
|
|
47
|
-
fullName: member.fullName,
|
|
48
|
-
}),
|
|
49
|
-
}));
|
|
50
|
-
const membersWithGeneratedUrls = await Promise.all(membersWithGeneratedUrlsPromises);
|
|
51
|
-
//recheck urls in same batch to avoid duplicates
|
|
52
|
-
const uniqueUrlsUpdatedMembers = await ensureUniqueUrlsInBatch(membersWithGeneratedUrls);
|
|
53
|
-
const urls = uniqueUrlsUpdatedMembers.map(m => m.url).filter(Boolean);
|
|
54
|
-
console.log('unique urls', [...new Set(urls)]);
|
|
55
|
-
return await bulkSaveMembers(uniqueUrlsUpdatedMembers, COLLECTIONS.MEMBERS_DATA);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = { deduplicateURls, copyContactIdToWixMemberId, createMissingUrls };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const { items } = require('@wix/data');
|
|
2
|
-
const { auth } = require('@wix/essentials');
|
|
3
|
-
|
|
4
|
-
// @wix/data does not support suppressAuth currently, so we need to elevate it
|
|
5
|
-
const wixData = {
|
|
6
|
-
insert: auth.elevate(items.insert),
|
|
7
|
-
update: auth.elevate(items.update),
|
|
8
|
-
bulkInsert: auth.elevate(items.bulkInsert),
|
|
9
|
-
query: auth.elevate(items.query),
|
|
10
|
-
save: auth.elevate(items.save),
|
|
11
|
-
remove: auth.elevate(items.remove),
|
|
12
|
-
get: auth.elevate(items.get),
|
|
13
|
-
truncate: auth.elevate(items.truncate),
|
|
14
|
-
bulkSave: auth.elevate(items.bulkSave),
|
|
15
|
-
search: auth.elevate(items.search),
|
|
16
|
-
//TODO: add other methods here as needed
|
|
17
|
-
};
|
|
18
|
-
module.exports = { wixData };
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
const { COLLECTIONS } = require('../public/consts');
|
|
2
|
-
|
|
3
|
-
const { triggerAutomation } = require('./automations-methods');
|
|
4
|
-
const { CONFIG_KEYS } = require('./consts');
|
|
5
|
-
const { wixData } = require('./elevated-modules');
|
|
6
|
-
const { findMemberByWixDataId, createContactAndMemberIfNew } = require('./members-data-methods');
|
|
7
|
-
const { getSiteConfigs } = require('./utils');
|
|
8
|
-
|
|
9
|
-
const contactSubmission = async (data, memberDataId) => {
|
|
10
|
-
const { firstName, lastName, email, phone, message } = data;
|
|
11
|
-
const [memberData, automationEmailTriggerId] = await Promise.all([
|
|
12
|
-
findMemberByWixDataId(memberDataId),
|
|
13
|
-
getSiteConfigs(CONFIG_KEYS.AUTOMATION_EMAIL_TRIGGER_ID),
|
|
14
|
-
]);
|
|
15
|
-
if (!memberData.showContactForm) {
|
|
16
|
-
console.log('Member contact form is not enabled for user, skipping contact submission!');
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
let memberContactId = memberData.wixContactId;
|
|
20
|
-
if (!memberContactId) {
|
|
21
|
-
/**
|
|
22
|
-
* Create a member contact here since some members may have never logged in
|
|
23
|
-
* and therefore don’t have a contact ID. However, these members can still
|
|
24
|
-
* appear in the directory, and site visitors can reach out to them if they’ve
|
|
25
|
-
* enabled their contact form. To handle this, we ensure a contact is created for
|
|
26
|
-
* them during this flow if it doesn’t already exist.
|
|
27
|
-
*/
|
|
28
|
-
console.info('Member contact id not found for user, creating new contact!');
|
|
29
|
-
const member = await createContactAndMemberIfNew(memberData);
|
|
30
|
-
memberContactId = member.wixContactId;
|
|
31
|
-
}
|
|
32
|
-
console.log('memberContactId', memberContactId);
|
|
33
|
-
const emailTriggered = await triggerAutomation(automationEmailTriggerId, {
|
|
34
|
-
contactId: memberContactId,
|
|
35
|
-
name: `${firstName} ${lastName}`,
|
|
36
|
-
email: email,
|
|
37
|
-
phone: phone,
|
|
38
|
-
message: message,
|
|
39
|
-
});
|
|
40
|
-
data = {
|
|
41
|
-
...data,
|
|
42
|
-
phone: Number(data.phone),
|
|
43
|
-
memberContactId,
|
|
44
|
-
memberEmail: memberData.contactFormEmail,
|
|
45
|
-
};
|
|
46
|
-
await wixData.insert(COLLECTIONS.CONTACT_US_SUBMISSIONS, data);
|
|
47
|
-
return emailTriggered;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
module.exports = {
|
|
51
|
-
contactSubmission,
|
|
52
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
const { COLLECTIONS } = require('../../public/consts');
|
|
2
|
-
const { clearCollection } = require('../cms-data-methods');
|
|
3
|
-
const { CONFIG_KEYS } = require('../consts');
|
|
4
|
-
const { getSecret, getSiteConfigs } = require('../utils');
|
|
5
|
-
|
|
6
|
-
const { migrateInterests } = require('./interests');
|
|
7
|
-
|
|
8
|
-
const createHTTPFunctionsHelpers = wixHTTPFunctionsMethods => {
|
|
9
|
-
const { created, serverError, forbidden, ok, badRequest } = wixHTTPFunctionsMethods;
|
|
10
|
-
const responseOptions = {
|
|
11
|
-
headers: {
|
|
12
|
-
'Content-Type': 'application/json',
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const isRequestAuthenticated = async request => {
|
|
17
|
-
const AUTH_TOKEN = await getSecret('migrate-api-key');
|
|
18
|
-
return request.headers.authorization === 'Bearer ' + AUTH_TOKEN;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const withAuth = handler => async request => {
|
|
22
|
-
if (!(await isRequestAuthenticated(request))) {
|
|
23
|
-
return forbidden({
|
|
24
|
-
...responseOptions,
|
|
25
|
-
body: { error: 'Unauthorized' },
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return handler(request);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const migrateInterestsHandler = async _request => {
|
|
32
|
-
try {
|
|
33
|
-
const result = await migrateInterests();
|
|
34
|
-
return created({
|
|
35
|
-
...responseOptions,
|
|
36
|
-
body: {
|
|
37
|
-
result,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error('Error migrating interests:', error);
|
|
42
|
-
return serverError(error);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const clearCollectionHandler = async request => {
|
|
47
|
-
try {
|
|
48
|
-
const collectionName = request.query.collectionName;
|
|
49
|
-
if (!collectionName || !Object.values(COLLECTIONS).includes(collectionName)) {
|
|
50
|
-
return badRequest({
|
|
51
|
-
...responseOptions,
|
|
52
|
-
body: { error: 'Invalid collection name' },
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
const result = await clearCollection(collectionName);
|
|
56
|
-
return ok({
|
|
57
|
-
...responseOptions,
|
|
58
|
-
body: {
|
|
59
|
-
result,
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
} catch (error) {
|
|
63
|
-
return serverError(error);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
const getSiteAssociationHandler = async _request => {
|
|
67
|
-
try {
|
|
68
|
-
const siteAssociation = await getSiteConfigs(CONFIG_KEYS.SITE_ASSOCIATION);
|
|
69
|
-
return ok({
|
|
70
|
-
...responseOptions,
|
|
71
|
-
body: { siteAssociation },
|
|
72
|
-
});
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error('Error getting site association:', error);
|
|
75
|
-
return serverError(error);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
post_migrateInterests: withAuth(migrateInterestsHandler),
|
|
81
|
-
delete_clearCollection: withAuth(clearCollectionHandler),
|
|
82
|
-
get_getSiteAssociation: withAuth(getSiteAssociationHandler),
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
module.exports = { createHTTPFunctionsHelpers };
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const axios = require('axios');
|
|
2
|
-
|
|
3
|
-
const { COLLECTIONS } = require('../../public/consts');
|
|
4
|
-
const { clearCollection } = require('../cms-data-methods');
|
|
5
|
-
const { CONFIG_KEYS } = require('../consts');
|
|
6
|
-
const { wixData } = require('../elevated-modules');
|
|
7
|
-
const { getHeaders } = require('../pac-api-methods');
|
|
8
|
-
const { getSiteConfigs } = require('../utils');
|
|
9
|
-
|
|
10
|
-
const getInterests = async () => {
|
|
11
|
-
const [url, headers] = await Promise.all([
|
|
12
|
-
getSiteConfigs(CONFIG_KEYS.INTERESTS_API_URL),
|
|
13
|
-
getHeaders(),
|
|
14
|
-
]);
|
|
15
|
-
try {
|
|
16
|
-
const response = await axios.get(url, { headers });
|
|
17
|
-
return response.data;
|
|
18
|
-
} catch (e) {
|
|
19
|
-
console.error('Error getting interests:', e);
|
|
20
|
-
throw e;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
async function migrateInterests() {
|
|
25
|
-
const [interests, _] = await Promise.all([
|
|
26
|
-
getInterests(),
|
|
27
|
-
clearCollection(COLLECTIONS.INTERESTS),
|
|
28
|
-
]);
|
|
29
|
-
const interestData = interests.map(val => ({ title: val.interest }));
|
|
30
|
-
return await wixData.bulkInsert(COLLECTIONS.INTERESTS, interestData);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
module.exports = {
|
|
34
|
-
migrateInterests,
|
|
35
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
...require('./forms-methods'),
|
|
3
|
-
...require('./search-filters-methods'),
|
|
4
|
-
...require('./jobs'),
|
|
5
|
-
...require('./consts'), //TODO: remove it once we finish NPM movement
|
|
6
|
-
...require('./utils'), //TODO: remove it once we finish NPM movement
|
|
7
|
-
...require('./daily-pull'), //TODO: remove it once we finish NPM movement
|
|
8
|
-
...require('./pac-api-methods'), //TODO: remove it once we finish NPM movement
|
|
9
|
-
...require('./members-area-methods'), //TODO: remove it once we finish NPM movement
|
|
10
|
-
...require('./members-data-methods'), //TODO: remove it once we finish NPM movement
|
|
11
|
-
...require('./cms-data-methods'), //TODO: remove it once we finish NPM movement
|
|
12
|
-
...require('./routers'),
|
|
13
|
-
...require('./login'),
|
|
14
|
-
...require('./data-hooks'),
|
|
15
|
-
...require('./http-functions'),
|
|
16
|
-
...require('./dev-only-methods'),
|
|
17
|
-
...require('./tasks/migration-methods'),
|
|
18
|
-
...require('./tasks/url-migration-methods'),
|
|
19
|
-
};
|