abmp-npm 10.3.9 → 10.3.10
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/__tests__/daily-pull-execution-check.test.js +124 -0
- package/backend/daily-pull/schedule-methods.js +41 -0
- package/backend/jobs.js +31 -18
- package/backend/tasks/consts.js +2 -0
- package/backend/tasks/daily-pull-check-methods.js +38 -18
- package/backend/tasks/hide-addresses-methods.js +159 -0
- package/backend/tasks/tasks-configs.js +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
jest.mock('../elevated-modules', () => ({
|
|
2
|
+
wixData: { query: jest.fn() },
|
|
3
|
+
}));
|
|
4
|
+
jest.mock('psdev-task-manager', () => ({ taskManager: jest.fn() }));
|
|
5
|
+
|
|
6
|
+
const { taskManager } = require('psdev-task-manager');
|
|
7
|
+
|
|
8
|
+
const { buildDailyPullTasks } = require('../daily-pull/schedule-methods');
|
|
9
|
+
const { wixData } = require('../elevated-modules');
|
|
10
|
+
const { TASKS_NAMES } = require('../tasks/consts');
|
|
11
|
+
const { dailyPullExecutionCheck } = require('../tasks/daily-pull-check-methods');
|
|
12
|
+
|
|
13
|
+
const makeQueryResult = items => ({ items, hasNext: () => false });
|
|
14
|
+
|
|
15
|
+
const mockTasksQuery = items => {
|
|
16
|
+
const query = {
|
|
17
|
+
hasSome: jest.fn().mockReturnThis(),
|
|
18
|
+
ge: jest.fn().mockReturnThis(),
|
|
19
|
+
find: jest.fn().mockResolvedValue(makeQueryResult(items)),
|
|
20
|
+
};
|
|
21
|
+
wixData.query.mockReturnValue(query);
|
|
22
|
+
return query;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('buildDailyPullTasks', () => {
|
|
26
|
+
test('schedules one ScheduleMembersDataPerAction task per action, excluding none by default', () => {
|
|
27
|
+
const tasks = buildDailyPullTasks();
|
|
28
|
+
|
|
29
|
+
expect(tasks.map(task => task.data.action).sort()).toEqual(['drop', 'new', 'update']);
|
|
30
|
+
tasks.forEach(task => {
|
|
31
|
+
expect(task.name).toBe(TASKS_NAMES.ScheduleMembersDataPerAction);
|
|
32
|
+
expect(task.type).toBe('scheduled');
|
|
33
|
+
expect(task.data).toEqual({ action: task.data.action });
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('includes the none action and flag when includeNone is set', () => {
|
|
38
|
+
const tasks = buildDailyPullTasks({ includeNone: true });
|
|
39
|
+
|
|
40
|
+
expect(tasks.map(task => task.data.action).sort()).toEqual(['drop', 'new', 'none', 'update']);
|
|
41
|
+
tasks.forEach(task => expect(task.data.includeNone).toBe(true));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('propagates isTestEnvironment and backupDate to every task', () => {
|
|
45
|
+
const tasks = buildDailyPullTasks({ isTestEnvironment: true, backupDate: '2026-06-01' });
|
|
46
|
+
|
|
47
|
+
tasks.forEach(task => {
|
|
48
|
+
expect(task.data.isTestEnvironment).toBe(true);
|
|
49
|
+
expect(task.data.backupDate).toBe('2026-06-01');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('dailyPullExecutionCheck', () => {
|
|
55
|
+
let scheduleInBulk;
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
wixData.query.mockReset();
|
|
59
|
+
scheduleInBulk = jest.fn().mockResolvedValue(undefined);
|
|
60
|
+
taskManager.mockReturnValue({ scheduleInBulk });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('counts the per-action tasks the cron creates as evidence the pull ran', async () => {
|
|
64
|
+
const query = mockTasksQuery([{ name: TASKS_NAMES.ScheduleMembersDataPerAction }]);
|
|
65
|
+
|
|
66
|
+
const result = await dailyPullExecutionCheck({});
|
|
67
|
+
|
|
68
|
+
expect(query.hasSome).toHaveBeenCalledWith('name', [
|
|
69
|
+
TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
70
|
+
TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
71
|
+
]);
|
|
72
|
+
expect(result.success).toBe(true);
|
|
73
|
+
expect(result.fallbackScheduled).toBeUndefined();
|
|
74
|
+
expect(scheduleInBulk).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('schedules the per-action fallback with environment flags when no pull is found', async () => {
|
|
78
|
+
mockTasksQuery([]);
|
|
79
|
+
|
|
80
|
+
const result = await dailyPullExecutionCheck({ isTestEnvironment: true, includeNone: true });
|
|
81
|
+
|
|
82
|
+
expect(result.success).toBe(false);
|
|
83
|
+
expect(result.fallbackScheduled).toBe(true);
|
|
84
|
+
expect(scheduleInBulk).toHaveBeenCalledTimes(1);
|
|
85
|
+
const scheduledTasks = scheduleInBulk.mock.calls[0][0];
|
|
86
|
+
expect(scheduledTasks.map(task => task.data.action).sort()).toEqual([
|
|
87
|
+
'drop',
|
|
88
|
+
'new',
|
|
89
|
+
'none',
|
|
90
|
+
'update',
|
|
91
|
+
]);
|
|
92
|
+
scheduledTasks.forEach(task => {
|
|
93
|
+
expect(task.name).toBe(TASKS_NAMES.ScheduleMembersDataPerAction);
|
|
94
|
+
expect(task.data.isTestEnvironment).toBe(true);
|
|
95
|
+
expect(task.data.includeNone).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('fallback defaults to production flags when no task data is provided', async () => {
|
|
100
|
+
mockTasksQuery([]);
|
|
101
|
+
|
|
102
|
+
await dailyPullExecutionCheck(undefined);
|
|
103
|
+
|
|
104
|
+
const scheduledTasks = scheduleInBulk.mock.calls[0][0];
|
|
105
|
+
expect(scheduledTasks.map(task => task.data.action).sort()).toEqual(['drop', 'new', 'update']);
|
|
106
|
+
scheduledTasks.forEach(task => {
|
|
107
|
+
expect(task.data.isTestEnvironment).toBeUndefined();
|
|
108
|
+
expect(task.data.includeNone).toBeUndefined();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('uses the provided lookback window', async () => {
|
|
113
|
+
const query = mockTasksQuery([{ name: TASKS_NAMES.ScheduleDailyMembersDataSync }]);
|
|
114
|
+
const before = Date.now();
|
|
115
|
+
|
|
116
|
+
const result = await dailyPullExecutionCheck({ hoursBack: 12 });
|
|
117
|
+
|
|
118
|
+
const sinceDate = query.ge.mock.calls[0][1];
|
|
119
|
+
expect(query.ge).toHaveBeenCalledWith('_createdDate', expect.any(Date));
|
|
120
|
+
const expectedSince = before - 12 * 60 * 60 * 1000;
|
|
121
|
+
expect(Math.abs(sinceDate.getTime() - expectedSince)).toBeLessThan(5000);
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { taskManager } = require('psdev-task-manager');
|
|
2
|
+
|
|
3
|
+
const { TASKS_NAMES } = require('../tasks/consts');
|
|
4
|
+
|
|
5
|
+
const { MEMBER_ACTIONS } = require('./consts');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builds the per-action daily pull tasks. Single source of truth for what a
|
|
9
|
+
* "daily pull" schedules, shared by the cron job and the execution-check
|
|
10
|
+
* fallback so both produce identical tasks (same names, same environment flags).
|
|
11
|
+
* @param {Object} [options]
|
|
12
|
+
* @param {string} [options.backupDate] - Optional backup date (YYYY-MM-DD) to pull from the backup endpoint
|
|
13
|
+
* @param {boolean} [options.isTestEnvironment=false] - Whether to pull from the test PAC API
|
|
14
|
+
* @param {boolean} [options.includeNone=false] - Whether to also sync the NONE action
|
|
15
|
+
* @returns {Array<Object>} - Task definitions for taskManager().scheduleInBulk
|
|
16
|
+
*/
|
|
17
|
+
const buildDailyPullTasks = ({ backupDate, isTestEnvironment, includeNone } = {}) => {
|
|
18
|
+
const actionsToSync = includeNone
|
|
19
|
+
? Object.values(MEMBER_ACTIONS)
|
|
20
|
+
: Object.values(MEMBER_ACTIONS).filter(action => action !== MEMBER_ACTIONS.NONE);
|
|
21
|
+
return actionsToSync.map(action => ({
|
|
22
|
+
name: TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
23
|
+
data: {
|
|
24
|
+
action,
|
|
25
|
+
...(backupDate ? { backupDate } : {}),
|
|
26
|
+
...(isTestEnvironment ? { isTestEnvironment } : {}),
|
|
27
|
+
...(includeNone ? { includeNone } : {}),
|
|
28
|
+
},
|
|
29
|
+
type: 'scheduled',
|
|
30
|
+
}));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Schedules the daily pull (one ScheduleMembersDataPerAction task per action).
|
|
35
|
+
* @param {Object} [options] - Same options as buildDailyPullTasks
|
|
36
|
+
* @returns {Promise<any>}
|
|
37
|
+
*/
|
|
38
|
+
const scheduleDailyPullTasks = options =>
|
|
39
|
+
taskManager().scheduleInBulk(buildDailyPullTasks(options));
|
|
40
|
+
|
|
41
|
+
module.exports = { buildDailyPullTasks, scheduleDailyPullTasks };
|
package/backend/jobs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { taskManager } = require('psdev-task-manager');
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { scheduleDailyPullTasks } = require('./daily-pull/schedule-methods');
|
|
4
4
|
const { TASKS_NAMES } = require('./tasks/consts');
|
|
5
5
|
const { dailyPullExecutionCheck } = require('./tasks/daily-pull-check-methods');
|
|
6
6
|
const { TASKS } = require('./tasks/tasks-configs');
|
|
@@ -34,21 +34,7 @@ async function scheduleDailyPullTask(options = null) {
|
|
|
34
34
|
console.log(`isTestEnvironment: ${isTestEnvironment}`);
|
|
35
35
|
console.log(`includeNone: ${includeNone}`);
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
? Object.values(MEMBER_ACTIONS)
|
|
39
|
-
: Object.values(MEMBER_ACTIONS).filter(action => action !== MEMBER_ACTIONS.NONE);
|
|
40
|
-
const toScheduleTasks = actionsToSync.map(action => ({
|
|
41
|
-
name: TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
42
|
-
data: {
|
|
43
|
-
action,
|
|
44
|
-
...(backupDate ? { backupDate } : {}),
|
|
45
|
-
...(isTestEnvironment ? { isTestEnvironment } : {}),
|
|
46
|
-
...(includeNone ? { includeNone } : {}),
|
|
47
|
-
},
|
|
48
|
-
type: 'scheduled',
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
return await taskManager().scheduleInBulk(toScheduleTasks);
|
|
37
|
+
return await scheduleDailyPullTasks({ backupDate, isTestEnvironment, includeNone });
|
|
52
38
|
} catch (error) {
|
|
53
39
|
console.error(`Failed to scheduleDailyPullTask: ${error.message}`);
|
|
54
40
|
throw new Error(`Failed to scheduleDailyPullTask: ${error.message}`);
|
|
@@ -111,10 +97,36 @@ async function scheduleNormalizeMemberEmailsTask() {
|
|
|
111
97
|
}
|
|
112
98
|
}
|
|
113
99
|
|
|
114
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Schedules hiding ALL addresses for ALL members that have any address (sets each address's
|
|
102
|
+
* addressStatus to DONT_SHOW). Manually triggered one-off maintenance task.
|
|
103
|
+
*/
|
|
104
|
+
async function scheduleHideAllMemberAddressesTask() {
|
|
105
|
+
try {
|
|
106
|
+
console.log('scheduleHideAllMemberAddresses started!');
|
|
107
|
+
return await taskManager().schedule({
|
|
108
|
+
name: TASKS_NAMES.scheduleHideAllMemberAddresses,
|
|
109
|
+
data: {},
|
|
110
|
+
type: 'scheduled',
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`Failed to scheduleHideAllMemberAddresses: ${error.message}`);
|
|
114
|
+
throw new Error(`Failed to scheduleHideAllMemberAddresses: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Runs the daily pull execution check (watchdog).
|
|
120
|
+
* @param {Object} [options]
|
|
121
|
+
* @param {number} [options.hoursBack=4] - Lookback window in hours
|
|
122
|
+
* @param {boolean} [options.isTestEnvironment=false] - Pull from the test PAC API if the fallback fires
|
|
123
|
+
* @param {boolean} [options.includeNone=false] - Include the NONE action if the fallback fires
|
|
124
|
+
* @returns {Promise<Object>} - Check result
|
|
125
|
+
*/
|
|
126
|
+
async function runDailyPullExecutionCheck(options = {}) {
|
|
115
127
|
try {
|
|
116
128
|
console.log('runDailyPullExecutionCheck started!');
|
|
117
|
-
return await dailyPullExecutionCheck({});
|
|
129
|
+
return await dailyPullExecutionCheck(options || {});
|
|
118
130
|
} catch (error) {
|
|
119
131
|
console.error(`Failed to runDailyPullExecutionCheck: ${error.message}`);
|
|
120
132
|
throw new Error(`Failed to runDailyPullExecutionCheck: ${error.message}`);
|
|
@@ -141,5 +153,6 @@ module.exports = {
|
|
|
141
153
|
scheduleFixPrimaryAddressForMembersTask,
|
|
142
154
|
scheduleFixUrlsWithSpacesTask,
|
|
143
155
|
scheduleNormalizeMemberEmailsTask,
|
|
156
|
+
scheduleHideAllMemberAddressesTask,
|
|
144
157
|
runDailyPullExecutionCheck,
|
|
145
158
|
};
|
package/backend/tasks/consts.js
CHANGED
|
@@ -22,6 +22,8 @@ const TASKS_NAMES = {
|
|
|
22
22
|
fixPrimaryAddressChunk: 'fixPrimaryAddressChunk',
|
|
23
23
|
scheduleFixUrlsWithSpaces: 'scheduleFixUrlsWithSpaces',
|
|
24
24
|
fixUrlsWithSpacesChunk: 'fixUrlsWithSpacesChunk',
|
|
25
|
+
scheduleHideAllMemberAddresses: 'scheduleHideAllMemberAddresses',
|
|
26
|
+
hideMemberAddressesChunk: 'hideMemberAddressesChunk',
|
|
25
27
|
scheduleNormalizeMemberEmails: 'scheduleNormalizeMemberEmails',
|
|
26
28
|
normalizeMemberEmailsChunk: 'normalizeMemberEmailsChunk',
|
|
27
29
|
dailyPullExecutionCheck: 'dailyPullExecutionCheck',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const { taskManager } = require('psdev-task-manager');
|
|
2
1
|
const { COLLECTIONS } = require('psdev-task-manager/public/consts');
|
|
3
2
|
|
|
3
|
+
const { scheduleDailyPullTasks } = require('../daily-pull/schedule-methods');
|
|
4
4
|
const { wixData } = require('../elevated-modules');
|
|
5
5
|
const { queryAllItems } = require('../utils');
|
|
6
6
|
|
|
@@ -8,43 +8,63 @@ const { TASKS_NAMES } = require('./consts');
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_HOURS_BACK = 4;
|
|
10
10
|
|
|
11
|
+
// The cron path (scheduleDailyPullTask) creates ScheduleMembersDataPerAction tasks
|
|
12
|
+
// directly; ScheduleDailyMembersDataSync only exists when the pull is triggered via
|
|
13
|
+
// the root task. Either one in the window is evidence the daily pull was scheduled.
|
|
14
|
+
const DAILY_PULL_TASK_NAMES = [
|
|
15
|
+
TASKS_NAMES.ScheduleMembersDataPerAction,
|
|
16
|
+
TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
17
|
+
];
|
|
18
|
+
|
|
11
19
|
/**
|
|
12
|
-
* Detects whether the daily pull was scheduled
|
|
13
|
-
* If no
|
|
20
|
+
* Detects whether the daily pull was scheduled in the lookback window.
|
|
21
|
+
* If no daily pull task exists, re-schedules the same per-action tasks the cron
|
|
22
|
+
* would have created, propagating the environment flags from the task data so a
|
|
23
|
+
* test site's fallback pulls from the test PAC API.
|
|
24
|
+
* @param {Object} [taskData]
|
|
25
|
+
* @param {number} [taskData.hoursBack=4] - Lookback window in hours
|
|
26
|
+
* @param {boolean} [taskData.isTestEnvironment=false] - Pull from the test PAC API on fallback
|
|
27
|
+
* @param {boolean} [taskData.includeNone=false] - Include the NONE action on fallback
|
|
28
|
+
* @returns {Promise<Object>} - Check result
|
|
14
29
|
*/
|
|
15
30
|
async function dailyPullExecutionCheck(taskData) {
|
|
16
31
|
const hoursBack =
|
|
17
32
|
taskData?.hoursBack && Number.isFinite(taskData.hoursBack)
|
|
18
33
|
? taskData.hoursBack
|
|
19
34
|
: DEFAULT_HOURS_BACK;
|
|
35
|
+
const isTestEnvironment = Boolean(taskData?.isTestEnvironment);
|
|
36
|
+
const includeNone = Boolean(taskData?.includeNone);
|
|
20
37
|
const sinceDate = new Date(Date.now() - hoursBack * 60 * 60 * 1000);
|
|
21
38
|
|
|
22
|
-
console.log('dailyPullExecutionCheck started', {
|
|
39
|
+
console.log('dailyPullExecutionCheck started', {
|
|
40
|
+
hoursBack,
|
|
41
|
+
sinceDate,
|
|
42
|
+
isTestEnvironment,
|
|
43
|
+
includeNone,
|
|
44
|
+
});
|
|
23
45
|
|
|
24
|
-
const
|
|
46
|
+
const dailyPullTasksQuery = wixData
|
|
25
47
|
.query(COLLECTIONS.TASKS)
|
|
26
|
-
.
|
|
48
|
+
.hasSome('name', DAILY_PULL_TASK_NAMES)
|
|
27
49
|
.ge('_createdDate', sinceDate);
|
|
28
50
|
|
|
29
|
-
const
|
|
30
|
-
const
|
|
51
|
+
const dailyPullTasks = await queryAllItems(dailyPullTasksQuery);
|
|
52
|
+
const dailyPullScheduled = dailyPullTasks.length > 0;
|
|
31
53
|
|
|
32
54
|
const result = {
|
|
33
|
-
success:
|
|
55
|
+
success: dailyPullScheduled,
|
|
34
56
|
sinceDate: sinceDate.toISOString(),
|
|
35
|
-
|
|
36
|
-
|
|
57
|
+
checkedTaskNames: DAILY_PULL_TASK_NAMES,
|
|
58
|
+
dailyPullTasksFound: dailyPullTasks.length,
|
|
37
59
|
};
|
|
38
60
|
|
|
39
|
-
if (!
|
|
40
|
-
console.log('
|
|
61
|
+
if (!dailyPullScheduled) {
|
|
62
|
+
console.log('No daily pull tasks found in window; re-scheduling per-action pull tasks', {
|
|
41
63
|
hoursBack,
|
|
64
|
+
isTestEnvironment,
|
|
65
|
+
includeNone,
|
|
42
66
|
});
|
|
43
|
-
await
|
|
44
|
-
name: TASKS_NAMES.ScheduleDailyMembersDataSync,
|
|
45
|
-
data: {},
|
|
46
|
-
type: 'scheduled',
|
|
47
|
-
});
|
|
67
|
+
await scheduleDailyPullTasks({ isTestEnvironment, includeNone });
|
|
48
68
|
result.fallbackScheduled = true;
|
|
49
69
|
}
|
|
50
70
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const { taskManager } = require('psdev-task-manager');
|
|
2
|
+
|
|
3
|
+
const { COLLECTIONS, ADDRESS_STATUS_TYPES } = require('../../public/consts');
|
|
4
|
+
const { wixData } = require('../elevated-modules');
|
|
5
|
+
const { bulkSaveMembers, getMembersByIds } = require('../members-data-methods');
|
|
6
|
+
const { chunkArray, queryAllItems } = require('../utils');
|
|
7
|
+
|
|
8
|
+
const { TASKS_NAMES } = require('./consts');
|
|
9
|
+
|
|
10
|
+
const CHUNK_SIZE = 1000;
|
|
11
|
+
|
|
12
|
+
const getMemberAddresses = member => (Array.isArray(member.addresses) ? member.addresses : []);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Whether a member has at least one address that is not already hidden.
|
|
16
|
+
* @param {Object} member
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
const hasVisibleAddress = member =>
|
|
20
|
+
getMemberAddresses(member).some(
|
|
21
|
+
address => address && address.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Sets every address on a member to DONT_SHOW (other address fields are preserved).
|
|
26
|
+
* @param {Object} member
|
|
27
|
+
* @returns {Array} the member's addresses with addressStatus set to DONT_SHOW
|
|
28
|
+
*/
|
|
29
|
+
const hideMemberAddresses = member =>
|
|
30
|
+
getMemberAddresses(member).map(address => ({
|
|
31
|
+
...address,
|
|
32
|
+
addressStatus: ADDRESS_STATUS_TYPES.DONT_SHOW,
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Schedules tasks to hide ALL addresses for ALL members that have any address.
|
|
37
|
+
* Manually triggered (not cron-wired). Sets each address's addressStatus to DONT_SHOW.
|
|
38
|
+
*/
|
|
39
|
+
async function scheduleHideAllMemberAddresses() {
|
|
40
|
+
console.log('=== Scheduling Hide All Member Addresses Tasks ===');
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const membersQuery = await wixData
|
|
44
|
+
.query(COLLECTIONS.MEMBERS_DATA)
|
|
45
|
+
.isNotEmpty('addresses')
|
|
46
|
+
.limit(1000);
|
|
47
|
+
const members = await queryAllItems(membersQuery);
|
|
48
|
+
console.log(`Fetched ${members.length} members with addresses`);
|
|
49
|
+
|
|
50
|
+
// Only members that still have at least one visible address need updating.
|
|
51
|
+
const memberIds = [
|
|
52
|
+
...new Set(
|
|
53
|
+
members
|
|
54
|
+
.filter(hasVisibleAddress)
|
|
55
|
+
.map(member => Number(member.memberId))
|
|
56
|
+
.filter(memberId => Number.isFinite(memberId) && memberId > 0)
|
|
57
|
+
),
|
|
58
|
+
];
|
|
59
|
+
console.log(`Members with at least one visible address: ${memberIds.length}`);
|
|
60
|
+
|
|
61
|
+
if (memberIds.length === 0) {
|
|
62
|
+
console.log('No members need their addresses hidden');
|
|
63
|
+
return {
|
|
64
|
+
success: true,
|
|
65
|
+
message: 'No members need their addresses hidden',
|
|
66
|
+
totalMembers: 0,
|
|
67
|
+
tasksScheduled: 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const chunks = chunkArray(memberIds, CHUNK_SIZE);
|
|
72
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
73
|
+
const chunk = chunks[i];
|
|
74
|
+
await taskManager().schedule({
|
|
75
|
+
name: TASKS_NAMES.hideMemberAddressesChunk,
|
|
76
|
+
data: {
|
|
77
|
+
memberIds: chunk,
|
|
78
|
+
chunkIndex: i,
|
|
79
|
+
totalChunks: chunks.length,
|
|
80
|
+
},
|
|
81
|
+
type: 'scheduled',
|
|
82
|
+
});
|
|
83
|
+
console.log(`Scheduled task ${i + 1}/${chunks.length} (${chunk.length} members)`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const result = {
|
|
87
|
+
success: true,
|
|
88
|
+
message: `Scheduled ${chunks.length} tasks for ${memberIds.length} members`,
|
|
89
|
+
totalMembers: memberIds.length,
|
|
90
|
+
tasksScheduled: chunks.length,
|
|
91
|
+
};
|
|
92
|
+
console.log('=== Scheduling Complete ===');
|
|
93
|
+
console.log(JSON.stringify(result, null, 2));
|
|
94
|
+
return result;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Error scheduling hide-all-addresses:', error);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Processes a chunk of members and sets every address to DONT_SHOW.
|
|
103
|
+
* @param {Object} data
|
|
104
|
+
* @param {Array<number|string>} data.memberIds
|
|
105
|
+
* @param {number} data.chunkIndex
|
|
106
|
+
* @param {number} data.totalChunks
|
|
107
|
+
*/
|
|
108
|
+
async function hideMemberAddressesChunk(data) {
|
|
109
|
+
const { memberIds, chunkIndex, totalChunks } = data;
|
|
110
|
+
console.log(
|
|
111
|
+
`Processing hide-addresses chunk ${chunkIndex + 1}/${totalChunks} (${memberIds.length} members)`
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const result = { successful: 0, failed: 0, skipped: 0, errors: [], failedIds: [] };
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const members = await getMembersByIds(memberIds);
|
|
118
|
+
console.log(`Loaded ${members.length} members for this chunk`);
|
|
119
|
+
|
|
120
|
+
const membersToUpdate = [];
|
|
121
|
+
members.forEach(member => {
|
|
122
|
+
// Skip members that have no address or are already fully hidden.
|
|
123
|
+
if (!hasVisibleAddress(member)) {
|
|
124
|
+
result.skipped++;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
membersToUpdate.push({
|
|
128
|
+
...member,
|
|
129
|
+
addresses: hideMemberAddresses(member),
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (membersToUpdate.length === 0) {
|
|
134
|
+
console.log('No members need updating in this batch');
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
await bulkSaveMembers(membersToUpdate);
|
|
140
|
+
result.successful += membersToUpdate.length;
|
|
141
|
+
console.log(`✅ Successfully hid addresses for ${membersToUpdate.length} members`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('❌ Error bulk saving members:', error);
|
|
144
|
+
result.failed += membersToUpdate.length;
|
|
145
|
+
result.failedIds.push(...membersToUpdate.map(member => member.memberId));
|
|
146
|
+
result.errors.push({ error: error.message, memberCount: membersToUpdate.length });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return result;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(`Error processing hide-addresses chunk ${chunkIndex}:`, error);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
scheduleHideAllMemberAddresses,
|
|
158
|
+
hideMemberAddressesChunk,
|
|
159
|
+
};
|
|
@@ -14,6 +14,10 @@ const {
|
|
|
14
14
|
scheduleNormalizeMemberEmails,
|
|
15
15
|
normalizeMemberEmailsChunk,
|
|
16
16
|
} = require('./email-normalize-methods');
|
|
17
|
+
const {
|
|
18
|
+
scheduleHideAllMemberAddresses,
|
|
19
|
+
hideMemberAddressesChunk,
|
|
20
|
+
} = require('./hide-addresses-methods');
|
|
17
21
|
const {
|
|
18
22
|
scheduleTaskForEmptyAboutYouMembers,
|
|
19
23
|
convertAboutYouHtmlToRichContent,
|
|
@@ -207,6 +211,20 @@ const TASKS = {
|
|
|
207
211
|
shouldSkipCheck: () => false,
|
|
208
212
|
estimatedDurationSec: 80,
|
|
209
213
|
},
|
|
214
|
+
[TASKS_NAMES.scheduleHideAllMemberAddresses]: {
|
|
215
|
+
name: TASKS_NAMES.scheduleHideAllMemberAddresses,
|
|
216
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
217
|
+
process: scheduleHideAllMemberAddresses,
|
|
218
|
+
shouldSkipCheck: () => false,
|
|
219
|
+
estimatedDurationSec: 80,
|
|
220
|
+
},
|
|
221
|
+
[TASKS_NAMES.hideMemberAddressesChunk]: {
|
|
222
|
+
name: TASKS_NAMES.hideMemberAddressesChunk,
|
|
223
|
+
getIdentifier: task => task.data,
|
|
224
|
+
process: hideMemberAddressesChunk,
|
|
225
|
+
shouldSkipCheck: () => false,
|
|
226
|
+
estimatedDurationSec: 80,
|
|
227
|
+
},
|
|
210
228
|
[TASKS_NAMES.scheduleNormalizeMemberEmails]: {
|
|
211
229
|
name: TASKS_NAMES.scheduleNormalizeMemberEmails,
|
|
212
230
|
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|