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
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
const { files } = require('@wix/media');
|
|
4
|
+
const aws4 = require('aws4');
|
|
5
|
+
const axios = require('axios');
|
|
6
|
+
|
|
7
|
+
const { PAGES_PATHS } = require('../../public/consts');
|
|
8
|
+
const { findMemberByWixDataId, updateMember } = require('../members-data-methods');
|
|
9
|
+
const { getSecret, getSiteBaseUrl, encodeXml, formatDateOnly } = require('../utils');
|
|
10
|
+
|
|
11
|
+
async function getServerlessAuth() {
|
|
12
|
+
const serverlessAuth = await getSecret('serverless_auth');
|
|
13
|
+
return serverlessAuth;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isValidImageUrl(url) {
|
|
17
|
+
if (!url || typeof url !== 'string') return false;
|
|
18
|
+
|
|
19
|
+
// Check for valid URL format
|
|
20
|
+
let parsedUrl;
|
|
21
|
+
try {
|
|
22
|
+
parsedUrl = new URL(url);
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Only allow HTTP and HTTPS protocols (reject blob:, data:, file:, etc.)
|
|
28
|
+
const validProtocols = ['http:', 'https:'];
|
|
29
|
+
if (!validProtocols.includes(parsedUrl.protocol)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Extract file extension from URL (handle query parameters)
|
|
34
|
+
const urlPath = url.split('?')[0].toLowerCase();
|
|
35
|
+
const validExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];
|
|
36
|
+
|
|
37
|
+
// Check if URL ends with valid extension
|
|
38
|
+
const hasValidExtension = validExtensions.some(ext => urlPath.endsWith(ext));
|
|
39
|
+
|
|
40
|
+
// Reject obviously invalid extensions
|
|
41
|
+
const invalidExtensions = [
|
|
42
|
+
'.pdf',
|
|
43
|
+
'.doc',
|
|
44
|
+
'.docx',
|
|
45
|
+
'.txt',
|
|
46
|
+
'.ps',
|
|
47
|
+
'.html',
|
|
48
|
+
'.htm',
|
|
49
|
+
'_jpg',
|
|
50
|
+
'_png',
|
|
51
|
+
'_gif',
|
|
52
|
+
];
|
|
53
|
+
const hasInvalidExtension = invalidExtensions.some(ext => urlPath.includes(ext));
|
|
54
|
+
|
|
55
|
+
return hasValidExtension && !hasInvalidExtension;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isValidContentType(contentType) {
|
|
59
|
+
if (!contentType) return false;
|
|
60
|
+
|
|
61
|
+
const contentTypeLower = contentType.toLowerCase();
|
|
62
|
+
|
|
63
|
+
// Valid image content types
|
|
64
|
+
const validTypes = [
|
|
65
|
+
'image/jpeg',
|
|
66
|
+
'image/jpg',
|
|
67
|
+
'image/png',
|
|
68
|
+
'image/gif',
|
|
69
|
+
'image/webp',
|
|
70
|
+
'image/bmp',
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
// Explicitly reject non-image content types
|
|
74
|
+
const invalidTypes = [
|
|
75
|
+
'application/pdf',
|
|
76
|
+
'application/msword',
|
|
77
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
78
|
+
'text/plain',
|
|
79
|
+
'text/html',
|
|
80
|
+
'text/htm',
|
|
81
|
+
'application/octet-stream',
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
if (invalidTypes.some(type => contentTypeLower.includes(type))) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return validTypes.includes(contentTypeLower);
|
|
89
|
+
}
|
|
90
|
+
async function updateMemberRichContent(memberId) {
|
|
91
|
+
console.log('starting to call http function for member', memberId);
|
|
92
|
+
|
|
93
|
+
const member = await findMemberByWixDataId(memberId);
|
|
94
|
+
const htmlString = member.aboutYouHtml;
|
|
95
|
+
const raw = JSON.stringify({
|
|
96
|
+
content: htmlString,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const requestOptions = {
|
|
100
|
+
method: 'post',
|
|
101
|
+
headers: {
|
|
102
|
+
'Content-Type': 'application/json',
|
|
103
|
+
Cookie: 'XSRF-TOKEN=1753949844|p--a7HsuVjR4',
|
|
104
|
+
Authorization: 'Bearer ' + (await getServerlessAuth()),
|
|
105
|
+
},
|
|
106
|
+
body: raw,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const response = await fetch(
|
|
111
|
+
'https://www.wixapis.com/data-sync/v1/abmp-content-converter',
|
|
112
|
+
requestOptions
|
|
113
|
+
);
|
|
114
|
+
if (response.ok) {
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
const updatedMember = {
|
|
117
|
+
...member,
|
|
118
|
+
aboutYourSelf: data.richContent.richContent,
|
|
119
|
+
aboutYouText: data.plainText.plainText,
|
|
120
|
+
};
|
|
121
|
+
if (data.richContent.status != 'VALID' || data.plainText.status != 'VALID') {
|
|
122
|
+
console.error(`updateMemberRichContent faield for member: ${memberId} `, {
|
|
123
|
+
memberId,
|
|
124
|
+
raw,
|
|
125
|
+
data,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
console.log('updatedMember **********', updatedMember);
|
|
129
|
+
await updateMember(updatedMember);
|
|
130
|
+
console.log('rich content added successfully for member with id: ', memberId);
|
|
131
|
+
} else {
|
|
132
|
+
console.error(`error in fetching data for member ID: ${memberId}, response: ${response}`);
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error('error in fetching data', error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function updateMemberProfileImage(memberId) {
|
|
139
|
+
try {
|
|
140
|
+
const member = await findMemberByWixDataId(memberId);
|
|
141
|
+
|
|
142
|
+
// Check if member has an external profile image URL
|
|
143
|
+
if (!member.profileImage || member.profileImage.startsWith('wix:')) {
|
|
144
|
+
console.log(`Member ${memberId} already has Wix-hosted image or no image`);
|
|
145
|
+
return { success: true, message: 'No update needed' };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Validate image URL format before attempting download
|
|
149
|
+
if (!isValidImageUrl(member.profileImage)) {
|
|
150
|
+
console.log(`Member ${memberId} has invalid image URL format: ${member.profileImage}`);
|
|
151
|
+
return { success: true, message: 'Invalid image URL format - skipped' };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const response = await axios.get(member.profileImage, {
|
|
155
|
+
responseType: 'arraybuffer',
|
|
156
|
+
headers: {
|
|
157
|
+
'User-Agent':
|
|
158
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
|
159
|
+
Accept: 'image/webp,image/apng,image/*,*/*;q=0.8',
|
|
160
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
161
|
+
'Cache-Control': 'no-cache',
|
|
162
|
+
},
|
|
163
|
+
timeout: 10000, // 10 second timeout
|
|
164
|
+
});
|
|
165
|
+
const buffer = Buffer.from(response.data);
|
|
166
|
+
console.log('Downloaded image buffer size:', buffer.length);
|
|
167
|
+
|
|
168
|
+
// Check minimum file size (1KB) to avoid empty/corrupted files
|
|
169
|
+
if (buffer.length < 1024) {
|
|
170
|
+
console.log(`Member ${memberId} has file too small: ${buffer.length} bytes`);
|
|
171
|
+
return {
|
|
172
|
+
success: true,
|
|
173
|
+
message: `File too small (${buffer.length} bytes) - skipped`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const contentType = response.headers['content-type'];
|
|
178
|
+
|
|
179
|
+
// Validate content type after download
|
|
180
|
+
if (!isValidContentType(contentType)) {
|
|
181
|
+
console.log(`Member ${memberId} has invalid content type: ${contentType}`);
|
|
182
|
+
return {
|
|
183
|
+
success: true,
|
|
184
|
+
message: `Invalid content type: ${contentType} - skipped`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Determine file extension from content type
|
|
189
|
+
const extension = contentType.includes('png')
|
|
190
|
+
? 'png'
|
|
191
|
+
: contentType.includes('gif')
|
|
192
|
+
? 'gif'
|
|
193
|
+
: contentType.includes('webp')
|
|
194
|
+
? 'webp'
|
|
195
|
+
: contentType.includes('bmp')
|
|
196
|
+
? 'bmp'
|
|
197
|
+
: 'jpg';
|
|
198
|
+
|
|
199
|
+
// Double-check: ensure we're not trying to upload non-image files
|
|
200
|
+
const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
|
|
201
|
+
if (!allowedExtensions.includes(extension)) {
|
|
202
|
+
console.log(`Member ${memberId} has invalid file extension: ${extension}`);
|
|
203
|
+
return {
|
|
204
|
+
success: true,
|
|
205
|
+
message: `Invalid file extension: ${extension} - skipped`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const sanitizedFileName = `profile-${memberId}-${Date.now()}.${extension}`.replace(/\./g, '_');
|
|
210
|
+
const uploadUrl = (
|
|
211
|
+
await files.generateFileUploadUrl(contentType, {
|
|
212
|
+
fileName: sanitizedFileName,
|
|
213
|
+
filePath: 'member-profiles',
|
|
214
|
+
})
|
|
215
|
+
).uploadUrl;
|
|
216
|
+
const params = { filename: sanitizedFileName };
|
|
217
|
+
const headers = {
|
|
218
|
+
'Content-Type': contentType,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const uploadResponse = await axios.put(uploadUrl, buffer, {
|
|
222
|
+
headers,
|
|
223
|
+
params,
|
|
224
|
+
});
|
|
225
|
+
const fileUrl = uploadResponse.data.file.url;
|
|
226
|
+
const updatedMember = {
|
|
227
|
+
...member,
|
|
228
|
+
profileImage: fileUrl,
|
|
229
|
+
};
|
|
230
|
+
await updateMember(updatedMember);
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
message: 'Profile image updated successfully',
|
|
235
|
+
oldUrl: member.profileImage,
|
|
236
|
+
newUrl: fileUrl,
|
|
237
|
+
};
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error(`Error updating profile image for member ${memberId}:`, error);
|
|
240
|
+
|
|
241
|
+
// Handle specific HTTP errors
|
|
242
|
+
if (error.response) {
|
|
243
|
+
const status = error.response.status;
|
|
244
|
+
if (status === 403) {
|
|
245
|
+
return {
|
|
246
|
+
success: true,
|
|
247
|
+
message: `403 Forbidden - Access denied to image URL - skipped`,
|
|
248
|
+
};
|
|
249
|
+
} else if (status === 404) {
|
|
250
|
+
return {
|
|
251
|
+
success: true,
|
|
252
|
+
message: `404 Not Found - Image URL not found - skipped`,
|
|
253
|
+
};
|
|
254
|
+
} else if (status === 406) {
|
|
255
|
+
return {
|
|
256
|
+
success: true,
|
|
257
|
+
message: `406 Not Acceptable - Server rejected request headers - skipped`,
|
|
258
|
+
};
|
|
259
|
+
} else if (status >= 400 && status < 500) {
|
|
260
|
+
return {
|
|
261
|
+
success: true,
|
|
262
|
+
message: `${status} Client Error - Invalid image URL - skipped`,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
error: error.message || error,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function getAWSTokens() {
|
|
275
|
+
const [AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY] = await Promise.all([
|
|
276
|
+
getSecret('AWS_ACCESS_KEY_ID'),
|
|
277
|
+
getSecret('AWS_SECRET_ACCESS_KEY'),
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
// const AWS_SESSION_TOKEN = await getSecret("AWS_SESSION_TOKEN")
|
|
281
|
+
return {
|
|
282
|
+
AWS_ACCESS_KEY_ID,
|
|
283
|
+
AWS_SECRET_ACCESS_KEY,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function generateSitemapXml(members) {
|
|
288
|
+
const baseUrl = await getSiteBaseUrl();
|
|
289
|
+
const profilePageUrl = `${baseUrl}/${PAGES_PATHS.PROFILE}`;
|
|
290
|
+
const urls = members
|
|
291
|
+
.map(m => {
|
|
292
|
+
const loc = `${profilePageUrl}/${encodeURIComponent(m.url)}`;
|
|
293
|
+
const lastmod =
|
|
294
|
+
m && m._updatedDate
|
|
295
|
+
? `\n <lastmod>${encodeXml(formatDateOnly(m._updatedDate))}</lastmod>`
|
|
296
|
+
: '';
|
|
297
|
+
return ` <url>\n <loc>${encodeXml(loc)}</loc>${lastmod}\n </url>`;
|
|
298
|
+
})
|
|
299
|
+
.join('\n');
|
|
300
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>\n`;
|
|
301
|
+
}
|
|
302
|
+
async function uploadMembersSitemap({ members, tokens, destinationFileName, siteAssociation }) {
|
|
303
|
+
const toLowerCaseSiteAssociation = siteAssociation.toLowerCase().trim();
|
|
304
|
+
const bucketHostname = (bucket, region) => {
|
|
305
|
+
const r = region || process?.env?.AWS_REGION || process?.env?.AWS_DEFAULT_REGION || 'us-east-1';
|
|
306
|
+
return `${bucket}.s3.${r}.amazonaws.com`;
|
|
307
|
+
};
|
|
308
|
+
if (!siteAssociation) {
|
|
309
|
+
throw new Error('Site association is required to determine the AWS S3 bucket name');
|
|
310
|
+
}
|
|
311
|
+
const bucket = `${toLowerCaseSiteAssociation}-sitemap`; // e.g: 'abmp-sitemap' or 'ascp-sitemap'
|
|
312
|
+
const region = 'us-east-1';
|
|
313
|
+
const destination_file_name = destinationFileName;
|
|
314
|
+
|
|
315
|
+
console.log('Sitemap generation started');
|
|
316
|
+
const xml = await generateSitemapXml(members);
|
|
317
|
+
console.log('Sitemap generation completed');
|
|
318
|
+
const body = xml;
|
|
319
|
+
console.log('Body length:', body.length);
|
|
320
|
+
const sha256Hex = crypto.createHash('sha256').update(body).digest('hex');
|
|
321
|
+
console.log('SHA256 hash calculated');
|
|
322
|
+
const host = bucketHostname(bucket, region);
|
|
323
|
+
const method = 'PUT';
|
|
324
|
+
const pathName = `/${encodeURI(destination_file_name).replace(/%2F/g, '/')}`;
|
|
325
|
+
console.log('Path name calculated');
|
|
326
|
+
const headers = {
|
|
327
|
+
'Content-Type': 'application/xml',
|
|
328
|
+
'X-Amz-Content-Sha256': sha256Hex,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const creds = {
|
|
332
|
+
accessKeyId: tokens.AWS_ACCESS_KEY_ID,
|
|
333
|
+
secretAccessKey: tokens.AWS_SECRET_ACCESS_KEY,
|
|
334
|
+
// sessionToken: tokens.AWS_SESSION_TOKEN,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const reqOpts = {
|
|
338
|
+
host,
|
|
339
|
+
path: pathName,
|
|
340
|
+
service: 's3',
|
|
341
|
+
region: region,
|
|
342
|
+
method,
|
|
343
|
+
headers,
|
|
344
|
+
body,
|
|
345
|
+
};
|
|
346
|
+
aws4.sign(reqOpts, creds);
|
|
347
|
+
console.log('Request options signed');
|
|
348
|
+
|
|
349
|
+
const url = `https://${host}${pathName}`;
|
|
350
|
+
console.log('url', url);
|
|
351
|
+
const res = await fetch(url, { method, headers: reqOpts.headers, body });
|
|
352
|
+
if (!res.ok) {
|
|
353
|
+
const respText = await res.text();
|
|
354
|
+
console.log('Response body', respText);
|
|
355
|
+
throw new Error(`S3 PUT failed ${res.status} ${res.statusText}: ${respText}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function stsPost(body, baseAccessKeyId, baseSecretAccessKey) {
|
|
360
|
+
const host = 'sts.amazonaws.com';
|
|
361
|
+
const method = 'POST';
|
|
362
|
+
const path = '/';
|
|
363
|
+
const headers = {
|
|
364
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
365
|
+
'X-Amz-Content-Sha256': 'UNSIGNED-PAYLOAD',
|
|
366
|
+
};
|
|
367
|
+
const reqOpts = {
|
|
368
|
+
host,
|
|
369
|
+
path,
|
|
370
|
+
service: 'sts',
|
|
371
|
+
region: 'us-east-1',
|
|
372
|
+
method,
|
|
373
|
+
headers,
|
|
374
|
+
body,
|
|
375
|
+
};
|
|
376
|
+
const parseXmlVal = (xml, tag) => {
|
|
377
|
+
const m = xml.match(new RegExp(`<${tag}>([^<]+)</${tag}>`));
|
|
378
|
+
return m ? m[1] : '';
|
|
379
|
+
};
|
|
380
|
+
aws4.sign(reqOpts, {
|
|
381
|
+
accessKeyId: baseAccessKeyId,
|
|
382
|
+
secretAccessKey: baseSecretAccessKey,
|
|
383
|
+
});
|
|
384
|
+
const res = await fetch(`https://${host}${path}`, {
|
|
385
|
+
method,
|
|
386
|
+
headers: reqOpts.headers,
|
|
387
|
+
body,
|
|
388
|
+
});
|
|
389
|
+
const text = await res.text();
|
|
390
|
+
if (!res.ok) throw new Error(`STS ${res.status}: ${text}`);
|
|
391
|
+
|
|
392
|
+
const accessKeyId = parseXmlVal(text, 'AccessKeyId');
|
|
393
|
+
const secretAccessKey = parseXmlVal(text, 'SecretAccessKey');
|
|
394
|
+
const sessionToken = parseXmlVal(text, 'SessionToken');
|
|
395
|
+
const expiration = parseXmlVal(text, 'Expiration');
|
|
396
|
+
if (!accessKeyId || !secretAccessKey || !sessionToken || !expiration) {
|
|
397
|
+
throw new Error('Failed parsing STS response');
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
accessKeyId,
|
|
401
|
+
secretAccessKey,
|
|
402
|
+
// sessionToken,
|
|
403
|
+
expiresAt: new Date(expiration).toISOString(),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// GetSessionToken (no role)
|
|
408
|
+
function getNewStsSessionToken(baseAccessKeyId, baseSecretAccessKey, durationSeconds = 3600) {
|
|
409
|
+
const body = `Action=GetSessionToken&Version=2011-06-15&DurationSeconds=${durationSeconds}`;
|
|
410
|
+
return stsPost(body, baseAccessKeyId, baseSecretAccessKey);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
module.exports = {
|
|
414
|
+
updateMemberRichContent,
|
|
415
|
+
updateMemberProfileImage,
|
|
416
|
+
getAWSTokens,
|
|
417
|
+
uploadMembersSitemap,
|
|
418
|
+
getNewStsSessionToken, //Dev only Method
|
|
419
|
+
};
|