abmp-npm 1.8.43 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/consts.js +24 -7
- package/backend/daily-pull/consts.js +0 -3
- 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/index.js +3 -1
- package/backend/jobs.js +14 -3
- package/backend/members-data-methods.js +231 -83
- package/backend/pac-api-methods.js +3 -4
- package/backend/search-filters-methods.js +3 -0
- package/backend/sso-methods.js +161 -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/utils.js +47 -28
- package/package.json +13 -2
- package/pages/LoadingPage.js +20 -0
- package/pages/Profile.js +2 -2
- package/pages/Save Alerts.js +14 -0
- package/pages/index.js +1 -0
- package/pages/personalDetails.js +12 -8
- package/public/Utils/sharedUtils.js +0 -1
- package/public/consts.js +8 -23
- package/public/index.js +0 -1
- 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
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const { createHmac } = require('crypto');
|
|
2
|
+
|
|
3
|
+
const { auth } = require('@wix/essentials');
|
|
4
|
+
const { authentication } = require('@wix/identity'); //importing from @wix/identity because @wix/members authentication do not have generateSessionToken method
|
|
5
|
+
const generateSessionToken = auth.elevate(authentication.signOn);
|
|
6
|
+
const { decode } = require('jwt-js-decode');
|
|
7
|
+
|
|
8
|
+
const { CONFIG_KEYS, SSO_TOKEN_AUTH_API_URL, SSO_TOKEN_AUTH_API_KEY } = require('./consts');
|
|
9
|
+
const { MEMBER_ACTIONS } = require('./daily-pull');
|
|
10
|
+
const { getCurrentMember } = require('./members-area-methods');
|
|
11
|
+
const { getMemberByContactId, getSiteMemberId } = require('./members-data-methods');
|
|
12
|
+
const {
|
|
13
|
+
formatDateToMonthYear,
|
|
14
|
+
getAddressDisplayOptions,
|
|
15
|
+
isStudent,
|
|
16
|
+
getSiteConfigs,
|
|
17
|
+
} = require('./utils');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validates member token and retrieves member data
|
|
21
|
+
* @param {string} memberIdInput - The member ID to validate
|
|
22
|
+
* @returns {Promise<{memberData: Object|null, isValid: boolean}>} Validation result with member data
|
|
23
|
+
*/
|
|
24
|
+
async function validateMemberToken(memberIdInput) {
|
|
25
|
+
const invalidTokenResponse = { memberData: null, isValid: false };
|
|
26
|
+
|
|
27
|
+
if (!memberIdInput) {
|
|
28
|
+
return invalidTokenResponse;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const member = await getCurrentMember();
|
|
33
|
+
if (!member || !member._id) {
|
|
34
|
+
console.log(
|
|
35
|
+
'member not found from members.getCurrentMember() for memberIdInput',
|
|
36
|
+
memberIdInput
|
|
37
|
+
);
|
|
38
|
+
return invalidTokenResponse;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const [dbMember, siteConfigs] = await Promise.all([
|
|
42
|
+
getMemberByContactId(member._id),
|
|
43
|
+
getSiteConfigs(),
|
|
44
|
+
]);
|
|
45
|
+
const siteAssociation = siteConfigs[CONFIG_KEYS.SITE_ASSOCIATION];
|
|
46
|
+
const membersExternalPortalUrl = siteConfigs[CONFIG_KEYS.MEMBERS_EXTERNAL_PORTAL_URL];
|
|
47
|
+
console.log('dbMember by contact id is:', dbMember);
|
|
48
|
+
console.log('member._id', member._id);
|
|
49
|
+
|
|
50
|
+
if (!dbMember?._id) {
|
|
51
|
+
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(
|
|
52
|
+
{ memberIdInput, currentMemberId: member._id }
|
|
53
|
+
)}`;
|
|
54
|
+
console.error(errorMessage);
|
|
55
|
+
throw new Error('CORRUPTED_MEMBER_DATA');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(`Id found in DB for memberIdInput :${memberIdInput} is ${dbMember?._id}`);
|
|
59
|
+
|
|
60
|
+
const memberData = dbMember;
|
|
61
|
+
|
|
62
|
+
// Format membership dates
|
|
63
|
+
memberData.memberships = memberData.memberships.map(membership => ({
|
|
64
|
+
...membership,
|
|
65
|
+
membersince: formatDateToMonthYear(membership.membersince),
|
|
66
|
+
isSiteAssociation: membership.association === siteAssociation,
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
const savedMemberId = memberData?._id;
|
|
70
|
+
const isValid = savedMemberId === memberIdInput;
|
|
71
|
+
|
|
72
|
+
if (!savedMemberId || !isValid) {
|
|
73
|
+
return invalidTokenResponse;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check if member is dropped
|
|
77
|
+
if (memberData.action === MEMBER_ACTIONS.DROP) {
|
|
78
|
+
return invalidTokenResponse;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add computed properties
|
|
82
|
+
memberData.addressDisplayOption = getAddressDisplayOptions(memberData);
|
|
83
|
+
console.log('memberData', memberData);
|
|
84
|
+
memberData.isStudent = isStudent(memberData);
|
|
85
|
+
|
|
86
|
+
return { memberData, isValid, membersExternalPortalUrl };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('Error in validateMemberToken:', error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function checkAndFetchSSO(token) {
|
|
93
|
+
const signature = createHmac('sha256', SSO_TOKEN_AUTH_API_KEY).update(token).digest('hex');
|
|
94
|
+
const professionalassistcorpUrl = `${SSO_TOKEN_AUTH_API_URL}/eweb/SSOToken.ashx?token=${token}&Partner=Wix&Signature=${signature}`;
|
|
95
|
+
const options = {
|
|
96
|
+
method: 'get',
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
const httpResponse = await fetch(professionalassistcorpUrl, options);
|
|
100
|
+
console.log('httpResponse status', httpResponse.status);
|
|
101
|
+
if (!httpResponse.ok) {
|
|
102
|
+
throw new Error('Fetch did not succeed with status: ' + httpResponse.status);
|
|
103
|
+
}
|
|
104
|
+
const responseToken = await httpResponse.text();
|
|
105
|
+
return responseToken;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Error in checkAndFetchSSO', error);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function generateSessionTokenFunction(email) {
|
|
113
|
+
return generateSessionToken({ email })
|
|
114
|
+
.then(response => response.sessionToken)
|
|
115
|
+
.catch(error => {
|
|
116
|
+
console.error('Error in generateSessionTokenFunction', error);
|
|
117
|
+
throw error;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const authenticateSSOToken = async token => {
|
|
122
|
+
const responseToken = await checkAndFetchSSO(token);
|
|
123
|
+
const isValidToken = Boolean(
|
|
124
|
+
responseToken && typeof responseToken === 'string' && responseToken?.trim()
|
|
125
|
+
);
|
|
126
|
+
const toLogTokenData = {
|
|
127
|
+
isValidToken,
|
|
128
|
+
tokenData: responseToken
|
|
129
|
+
? {
|
|
130
|
+
length: responseToken.length,
|
|
131
|
+
preview: responseToken.substring(0, 50),
|
|
132
|
+
}
|
|
133
|
+
: 'No token',
|
|
134
|
+
};
|
|
135
|
+
console.log('checkAndFetchSSO responseToken data', JSON.stringify(toLogTokenData, null, 2));
|
|
136
|
+
if (isValidToken) {
|
|
137
|
+
const jwt = decode(responseToken);
|
|
138
|
+
const payload = jwt.payload;
|
|
139
|
+
const membersData = await getSiteMemberId(payload);
|
|
140
|
+
console.log('membersDataCollectionId', membersData._id);
|
|
141
|
+
const sessionToken = await generateSessionTokenFunction(membersData.email);
|
|
142
|
+
const authObj = {
|
|
143
|
+
type: 'success',
|
|
144
|
+
memberId: membersData._id,
|
|
145
|
+
sessionToken,
|
|
146
|
+
};
|
|
147
|
+
return authObj;
|
|
148
|
+
} else {
|
|
149
|
+
console.log('invalid Token responseToken is: ', responseToken);
|
|
150
|
+
return {
|
|
151
|
+
type: 'error',
|
|
152
|
+
memberId: '',
|
|
153
|
+
sessionToken: '',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
module.exports = {
|
|
159
|
+
validateMemberToken,
|
|
160
|
+
authenticateSSOToken,
|
|
161
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const TASKS_NAMES = {
|
|
2
|
+
ScheduleDailyMembersDataSync: 'ScheduleDailyMembersDataSync',
|
|
3
|
+
ScheduleMembersDataPerAction: 'ScheduleMembersDataPerAction',
|
|
4
|
+
SyncMembers: 'SyncMembers',
|
|
5
|
+
scheduleTaskForEmptyAboutYouMembers: 'scheduleTaskForEmptyAboutYouMembers',
|
|
6
|
+
convertHtmlToRichContent: 'convertHtmlToRichContent',
|
|
7
|
+
CompileFiltersOptions: 'CompileFiltersOptions',
|
|
8
|
+
scheduleTaskForExternalProfileImages: 'scheduleTaskForExternalProfileImages',
|
|
9
|
+
convertExternalProfilesToWixImages: 'convertExternalProfilesToWixImages',
|
|
10
|
+
updateSiteMapS3: 'updateSiteMapS3',
|
|
11
|
+
scheduleEmailSync: 'scheduleEmailSync',
|
|
12
|
+
syncMemberLoginEmails: 'syncMemberLoginEmails',
|
|
13
|
+
scheduleContactFormEmailMigration: 'scheduleContactFormEmailMigration',
|
|
14
|
+
migrateContactFormEmails: 'migrateContactFormEmails',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
TASKS_NAMES,
|
|
19
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const { taskManager } = require('psdev-task-manager');
|
|
2
|
+
|
|
3
|
+
const { TASKS_NAMES } = require('./consts');
|
|
4
|
+
|
|
5
|
+
//this will be run only once by the developers during the migration
|
|
6
|
+
function scheduleConvertHtmlToRichContent() {
|
|
7
|
+
return taskManager().schedule({
|
|
8
|
+
name: TASKS_NAMES.scheduleTaskForEmptyAboutYouMembers,
|
|
9
|
+
data: {},
|
|
10
|
+
type: 'scheduled',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// This function is used to migrate external profile images to Wix-hosted images
|
|
15
|
+
function scheduleExternalProfileImageMigration() {
|
|
16
|
+
return taskManager().schedule({
|
|
17
|
+
name: TASKS_NAMES.scheduleTaskForExternalProfileImages,
|
|
18
|
+
data: {},
|
|
19
|
+
type: 'scheduled',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
scheduleConvertHtmlToRichContent,
|
|
25
|
+
scheduleExternalProfileImageMigration,
|
|
26
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const {
|
|
2
|
+
MEMBER_ACTIONS,
|
|
3
|
+
synchronizeSinglePage,
|
|
4
|
+
syncMembersDataPerAction,
|
|
5
|
+
} = require('../daily-pull');
|
|
6
|
+
|
|
7
|
+
const { TASKS_NAMES } = require('./consts');
|
|
8
|
+
const {
|
|
9
|
+
scheduleTaskForEmptyAboutYouMembers,
|
|
10
|
+
convertAboutYouHtmlToRichContent,
|
|
11
|
+
compileFiltersOptions,
|
|
12
|
+
scheduleTaskForExternalProfileImages,
|
|
13
|
+
convertExternalProfilesToWixImages,
|
|
14
|
+
updateSiteMapS3,
|
|
15
|
+
scheduleContactFormEmailMigration,
|
|
16
|
+
migrateContactFormEmails,
|
|
17
|
+
scheduleEmailSync,
|
|
18
|
+
syncMemberLoginEmails,
|
|
19
|
+
} = require('./tasks-process-methods');
|
|
20
|
+
|
|
21
|
+
const getDailyMembersDataSyncChildTasks = () => {
|
|
22
|
+
// we don't want to sync none action as it means this members data hasn't changed and we don't need to sync it
|
|
23
|
+
const MEMBER_ACTIONS_EXCEPT_NONE = Object.values(MEMBER_ACTIONS).filter(
|
|
24
|
+
action => action !== MEMBER_ACTIONS.NONE
|
|
25
|
+
);
|
|
26
|
+
return MEMBER_ACTIONS_EXCEPT_NONE.map(action => ({
|
|
27
|
+
name: TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
28
|
+
data: { action },
|
|
29
|
+
}));
|
|
30
|
+
};
|
|
31
|
+
const TASKS = {
|
|
32
|
+
[TASKS_NAMES.ScheduleDailyMembersDataSync]: {
|
|
33
|
+
name: TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
34
|
+
scheduleChildrenSequentially: false,
|
|
35
|
+
estimatedDurationSec: 60,
|
|
36
|
+
childTasks: getDailyMembersDataSyncChildTasks(),
|
|
37
|
+
},
|
|
38
|
+
[TASKS_NAMES.ScheduleMembersDataPerAction]: {
|
|
39
|
+
name: TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
40
|
+
getIdentifier: task => task.data.action,
|
|
41
|
+
process: syncMembersDataPerAction,
|
|
42
|
+
shouldSkipCheck: () => false,
|
|
43
|
+
estimatedDurationSec: 6,
|
|
44
|
+
},
|
|
45
|
+
[TASKS_NAMES.SyncMembers]: {
|
|
46
|
+
name: TASKS_NAMES.SyncMembers,
|
|
47
|
+
getIdentifier: task => task,
|
|
48
|
+
process: synchronizeSinglePage,
|
|
49
|
+
shouldSkipCheck: () => false,
|
|
50
|
+
estimatedDurationSec: 6,
|
|
51
|
+
},
|
|
52
|
+
[TASKS_NAMES.scheduleTaskForEmptyAboutYouMembers]: {
|
|
53
|
+
name: TASKS_NAMES.scheduleTaskForEmptyAboutYouMembers,
|
|
54
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
55
|
+
process: scheduleTaskForEmptyAboutYouMembers,
|
|
56
|
+
shouldSkipCheck: () => false,
|
|
57
|
+
estimatedDurationSec: 40,
|
|
58
|
+
},
|
|
59
|
+
[TASKS_NAMES.convertHtmlToRichContent]: {
|
|
60
|
+
name: TASKS_NAMES.convertHtmlToRichContent,
|
|
61
|
+
getIdentifier: task => task.data.memberIds,
|
|
62
|
+
process: convertAboutYouHtmlToRichContent,
|
|
63
|
+
shouldSkipCheck: () => false,
|
|
64
|
+
estimatedDurationSec: 45,
|
|
65
|
+
},
|
|
66
|
+
[TASKS_NAMES.CompileFiltersOptions]: {
|
|
67
|
+
name: TASKS_NAMES.CompileFiltersOptions,
|
|
68
|
+
getIdentifier: task => task.data.field,
|
|
69
|
+
process: compileFiltersOptions,
|
|
70
|
+
shouldSkipCheck: () => false,
|
|
71
|
+
estimatedDurationSec: 6,
|
|
72
|
+
},
|
|
73
|
+
[TASKS_NAMES.scheduleTaskForExternalProfileImages]: {
|
|
74
|
+
name: TASKS_NAMES.scheduleTaskForExternalProfileImages,
|
|
75
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
76
|
+
process: scheduleTaskForExternalProfileImages,
|
|
77
|
+
shouldSkipCheck: () => false,
|
|
78
|
+
estimatedDurationSec: 60,
|
|
79
|
+
},
|
|
80
|
+
[TASKS_NAMES.convertExternalProfilesToWixImages]: {
|
|
81
|
+
name: TASKS_NAMES.convertExternalProfilesToWixImages,
|
|
82
|
+
getIdentifier: task => task.data.memberIds,
|
|
83
|
+
process: convertExternalProfilesToWixImages,
|
|
84
|
+
shouldSkipCheck: () => false,
|
|
85
|
+
estimatedDurationSec: 55,
|
|
86
|
+
},
|
|
87
|
+
[TASKS_NAMES.updateSiteMapS3]: {
|
|
88
|
+
name: TASKS_NAMES.updateSiteMapS3,
|
|
89
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
90
|
+
process: updateSiteMapS3,
|
|
91
|
+
shouldSkipCheck: () => false,
|
|
92
|
+
estimatedDurationSec: 70,
|
|
93
|
+
},
|
|
94
|
+
[TASKS_NAMES.scheduleContactFormEmailMigration]: {
|
|
95
|
+
name: TASKS_NAMES.scheduleContactFormEmailMigration,
|
|
96
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
97
|
+
process: scheduleContactFormEmailMigration,
|
|
98
|
+
shouldSkipCheck: () => false,
|
|
99
|
+
estimatedDurationSec: 30,
|
|
100
|
+
},
|
|
101
|
+
[TASKS_NAMES.migrateContactFormEmails]: {
|
|
102
|
+
name: TASKS_NAMES.migrateContactFormEmails,
|
|
103
|
+
getIdentifier: task => task.data,
|
|
104
|
+
process: migrateContactFormEmails,
|
|
105
|
+
shouldSkipCheck: () => false,
|
|
106
|
+
estimatedDurationSec: 40,
|
|
107
|
+
},
|
|
108
|
+
[TASKS_NAMES.scheduleEmailSync]: {
|
|
109
|
+
name: TASKS_NAMES.scheduleEmailSync,
|
|
110
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
111
|
+
process: scheduleEmailSync,
|
|
112
|
+
shouldSkipCheck: () => false,
|
|
113
|
+
estimatedDurationSec: 30,
|
|
114
|
+
},
|
|
115
|
+
[TASKS_NAMES.syncMemberLoginEmails]: {
|
|
116
|
+
name: TASKS_NAMES.syncMemberLoginEmails,
|
|
117
|
+
getIdentifier: task => task.data,
|
|
118
|
+
process: syncMemberLoginEmails,
|
|
119
|
+
shouldSkipCheck: () => false,
|
|
120
|
+
estimatedDurationSec: 45,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
module.exports = { TASKS };
|