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.
@@ -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,6 @@
1
+ module.exports = {
2
+ ...require('./tasks-configs'),
3
+ ...require('./consts'),
4
+ ...require('./tasks-process-methods'),
5
+ ...require('./migration-methods'),
6
+ };
@@ -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 };