backend-manager 3.2.169 → 3.2.171

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.
Files changed (88) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/dist/cli/cli.js +1534 -0
  4. package/dist/manager/functions/core/actions/api/admin/backup.js +338 -0
  5. package/dist/manager/functions/core/actions/api/admin/create-post.js +388 -0
  6. package/dist/manager/functions/core/actions/api/admin/cron.js +37 -0
  7. package/dist/manager/functions/core/actions/api/admin/database-read.js +35 -0
  8. package/dist/manager/functions/core/actions/api/admin/database-write.js +39 -0
  9. package/dist/manager/functions/core/actions/api/admin/edit-post.js +158 -0
  10. package/dist/manager/functions/core/actions/api/admin/firestore-query.js +165 -0
  11. package/dist/manager/functions/core/actions/api/admin/firestore-read.js +38 -0
  12. package/dist/manager/functions/core/actions/api/admin/firestore-write.js +54 -0
  13. package/dist/manager/functions/core/actions/api/admin/get-stats.js +269 -0
  14. package/dist/manager/functions/core/actions/api/admin/payment-processor.js +57 -0
  15. package/dist/manager/functions/core/actions/api/admin/run-hook.js +95 -0
  16. package/dist/manager/functions/core/actions/api/admin/send-notification.js +197 -0
  17. package/dist/manager/functions/core/actions/api/admin/sync-users.js +125 -0
  18. package/dist/manager/functions/core/actions/api/admin/templates/post.html +16 -0
  19. package/dist/manager/functions/core/actions/api/firebase/get-providers.js +102 -0
  20. package/dist/manager/functions/core/actions/api/general/emails/general:download-app-link.js +21 -0
  21. package/dist/manager/functions/core/actions/api/general/fetch-post.js +99 -0
  22. package/dist/manager/functions/core/actions/api/general/generate-uuid.js +41 -0
  23. package/dist/manager/functions/core/actions/api/general/send-email.js +112 -0
  24. package/dist/manager/functions/core/actions/api/handler/create-post.js +146 -0
  25. package/dist/manager/functions/core/actions/api/special/setup-electron-manager-client.js +103 -0
  26. package/dist/manager/functions/core/actions/api/template.js +33 -0
  27. package/dist/manager/functions/core/actions/api/test/authenticate.js +22 -0
  28. package/dist/manager/functions/core/actions/api/test/create-test-accounts.js +27 -0
  29. package/dist/manager/functions/core/actions/api/test/lab.js +55 -0
  30. package/dist/manager/functions/core/actions/api/test/redirect.js +26 -0
  31. package/dist/manager/functions/core/actions/api/test/webhook.js +30 -0
  32. package/dist/manager/functions/core/actions/api/user/create-custom-token.js +32 -0
  33. package/dist/manager/functions/core/actions/api/user/delete.js +68 -0
  34. package/dist/manager/functions/core/actions/api/user/get-active-sessions.js +45 -0
  35. package/dist/manager/functions/core/actions/api/user/get-subscription-info.js +49 -0
  36. package/dist/manager/functions/core/actions/api/user/oauth2/discord.js +114 -0
  37. package/dist/manager/functions/core/actions/api/user/oauth2/google.js +99 -0
  38. package/dist/manager/functions/core/actions/api/user/oauth2.js +476 -0
  39. package/dist/manager/functions/core/actions/api/user/regenerate-api-keys.js +54 -0
  40. package/dist/manager/functions/core/actions/api/user/resolve.js +32 -0
  41. package/dist/manager/functions/core/actions/api/user/sign-out-all-sessions.js +118 -0
  42. package/dist/manager/functions/core/actions/api/user/sign-up copy.js +544 -0
  43. package/dist/manager/functions/core/actions/api/user/sign-up.js +99 -0
  44. package/dist/manager/functions/core/actions/api/user/submit-feedback.js +96 -0
  45. package/dist/manager/functions/core/actions/api/user/validate-settings.js +86 -0
  46. package/dist/manager/functions/core/actions/api.js +354 -0
  47. package/dist/manager/functions/core/actions/create-post-handler.js +184 -0
  48. package/dist/manager/functions/core/actions/generate-uuid.js +62 -0
  49. package/dist/manager/functions/core/actions/sign-up-handler.js +205 -0
  50. package/dist/manager/functions/core/admin/create-post.js +206 -0
  51. package/dist/manager/functions/core/admin/firestore-write.js +72 -0
  52. package/dist/manager/functions/core/admin/get-stats.js +218 -0
  53. package/dist/manager/functions/core/admin/query.js +198 -0
  54. package/dist/manager/functions/core/admin/send-notification.js +206 -0
  55. package/dist/manager/functions/core/cron/daily/ghostii-auto-publisher.js +377 -0
  56. package/dist/manager/functions/core/cron/daily/reset-usage.js +197 -0
  57. package/dist/manager/functions/core/cron/daily.js +114 -0
  58. package/dist/manager/functions/core/events/auth/before-create.js +124 -0
  59. package/dist/manager/functions/core/events/auth/before-signin.js +62 -0
  60. package/dist/manager/functions/core/events/auth/on-create copy.js +121 -0
  61. package/dist/manager/functions/core/events/auth/on-create.js +564 -0
  62. package/dist/manager/functions/core/events/auth/on-delete.js +72 -0
  63. package/dist/manager/functions/core/events/firestore/on-subscription.js +107 -0
  64. package/dist/manager/functions/test/authenticate.js +38 -0
  65. package/dist/manager/functions/test/create-test-accounts.js +144 -0
  66. package/dist/manager/functions/test/webhook.js +37 -0
  67. package/dist/manager/functions/wrappers/mailchimp/addToList.js +25 -0
  68. package/dist/manager/helpers/analytics copy.js +217 -0
  69. package/dist/manager/helpers/analytics.js +467 -0
  70. package/dist/manager/helpers/api-manager.js +324 -0
  71. package/dist/manager/helpers/assistant.js +1043 -0
  72. package/dist/manager/helpers/metadata.js +32 -0
  73. package/dist/manager/helpers/middleware.js +154 -0
  74. package/dist/manager/helpers/roles.js +69 -0
  75. package/dist/manager/helpers/settings.js +158 -0
  76. package/dist/manager/helpers/subscription-resolver-new.js +828 -0
  77. package/dist/manager/helpers/subscription-resolver.js +842 -0
  78. package/dist/manager/helpers/usage.js +381 -0
  79. package/dist/manager/helpers/user.js +198 -0
  80. package/dist/manager/helpers/utilities.js +292 -0
  81. package/dist/manager/index.js +1076 -0
  82. package/dist/manager/libraries/openai.js +460 -0
  83. package/dist/manager/routes/restart/index.js +52 -0
  84. package/dist/manager/routes/test/index.js +43 -0
  85. package/dist/manager/schemas/restart.js +13 -0
  86. package/dist/manager/schemas/test.js +13 -0
  87. package/dist/require.js +3 -0
  88. package/package.json +19 -9
@@ -0,0 +1,377 @@
1
+ // Libraries
2
+ const fetch = require('wonderful-fetch');
3
+ const powertools = require('node-powertools');
4
+ const moment = require('moment');
5
+ const JSON5 = require('json5');
6
+
7
+ // const PROMPT = `
8
+ // Company: {app.name}: {app.brand.description}
9
+ // Date: {date}
10
+ // Instructions: {prompt}
11
+
12
+ // Use the following information to find a topic related to our company:
13
+ // {suggestion}
14
+ // `
15
+ const PROMPT = `
16
+ Company: {app.name}: {app.brand.description}
17
+ Date: {date}
18
+ Instructions: {prompt}
19
+
20
+ Use the following information to find a topic for our company blog (it can be about our company OR any topic that would be relevant to our website and business BUT not about a competitor):
21
+ {suggestion}
22
+ `
23
+
24
+ const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36';
25
+
26
+ function Module() {
27
+
28
+ }
29
+
30
+ Module.prototype.main = function (assistant, context) {
31
+ const self = this;
32
+
33
+ // Shortcuts
34
+ const Manager = assistant.Manager;
35
+ const libraries = Manager.libraries;
36
+
37
+ return new Promise(async function(resolve, reject) {
38
+ // Log
39
+ assistant.log(`Starting...`);
40
+
41
+ // Set post ID
42
+ self.postId = moment().unix();
43
+
44
+ // Get app content
45
+ self.appObject = await self.getAppData(Manager.config.app.id).catch((e) => e);
46
+ if (self.appObject instanceof Error) {
47
+ return reject(self.appObject);
48
+ }
49
+
50
+ // Log
51
+ assistant.log(`App object`, self.appObject);
52
+
53
+ // Get settings
54
+ let settingsArray = powertools.arrayify(Manager.config.ghostii);
55
+
56
+ // Loop through each item
57
+ for (const settings of settingsArray) {
58
+ const appId = settings.app || self.appObject.id;
59
+
60
+ // Fix settings
61
+ settings.articles = settings.articles || 0;
62
+ settings.sources = randomize(settings.sources || []);
63
+ settings.links = randomize(settings.links || []);
64
+ settings.prompt = settings.prompt || '';
65
+ settings.chance = settings.chance || 1.0;
66
+ settings.author = settings.author || 'alex';
67
+ settings.app = await self.getAppData(appId).catch((e) => e);
68
+
69
+ // Check for errors
70
+ if (settings.app instanceof Error) {
71
+ assistant.error(`Error fetching app data`, settings.app);
72
+
73
+ continue;
74
+ }
75
+
76
+ // Log
77
+ assistant.log(`Settings (app=${appId})`, settings);
78
+
79
+ // Quit if articles are disabled
80
+ if (!settings.articles || !settings.sources.length) {
81
+ assistant.log(`Quitting because articles are disabled`);
82
+
83
+ continue;
84
+ }
85
+
86
+ // Quit if the chance is not met
87
+ const chance = Math.random();
88
+ if (chance > settings.chance) {
89
+ assistant.log(`Quitting because the chance is not met (${chance} <= ${settings.chance})`);
90
+ }
91
+
92
+ // Harvest articles
93
+ const result = await self.harvest(settings).catch((e) => e);
94
+ if (result instanceof Error) {
95
+ return reject(result);
96
+ }
97
+
98
+ // Log
99
+ assistant.log(`Finished!`, result);
100
+ }
101
+
102
+ // Resolve
103
+ return resolve();
104
+ });
105
+ }
106
+
107
+ Module.prototype.harvest = function (settings) {
108
+ const self = this;
109
+
110
+ // Shortcuts
111
+ const Manager = self.Manager;
112
+ const libraries = self.libraries;
113
+ const assistant = self.assistant;
114
+ const context = self.context;
115
+
116
+ return new Promise(async function(resolve, reject) {
117
+ const date = moment().format('MMMM YYYY');
118
+
119
+ // Log
120
+ assistant.log(`harvest(): Starting ${settings.app.id}...`);
121
+
122
+ // Process the number of sources in the settings
123
+ for (let index = 0; index < settings.articles; index++) {
124
+ const source = powertools.random(settings.sources);
125
+ const isURL = self.isURL(source);
126
+ let suggestion = null;
127
+
128
+ // Log
129
+ assistant.log(`harvest(): Processing ${index + 1}/${settings.articles} sources isURL=${isURL}`, source);
130
+
131
+ // Get suggestion
132
+ if (source === '$app') {
133
+ suggestion = 'Write an article about any topic that would be relevant to our website and business (it does not have to be about our company, but it can be)';
134
+ } else if (isURL) {
135
+ suggestion = await self.getURLContent(source).catch((e) => e);
136
+ } else {
137
+ suggestion = source;
138
+ }
139
+
140
+ // Check for errors
141
+ if (suggestion instanceof Error) {
142
+ assistant.error(`harvest(): Error fetching ${source} suggestion`, suggestion);
143
+
144
+ break;
145
+ }
146
+
147
+ // Set suggestion
148
+ const final = powertools.template(PROMPT, {
149
+ ...settings,
150
+ prompt: settings.prompt,
151
+ date: date,
152
+ suggestion: suggestion,
153
+ });
154
+
155
+ // Log
156
+ assistant.log('harvest(): Get final content', final);
157
+
158
+ // Request to Ghostii
159
+ const article = await self.requestGhostii(settings, final).catch((e) => e);
160
+ if (article instanceof Error) {
161
+ assistant.error(`harvest(): Error requesting Ghostii`, article);
162
+
163
+ break;
164
+ }
165
+
166
+ // Log
167
+ assistant.log(`harvest(): Article`, article);
168
+
169
+ // Upload post to blog
170
+ const uploadedPost = await self.uploadPost(settings, article).catch((e) => e);
171
+ if (uploadedPost instanceof Error) {
172
+ assistant.error(`harvest(): Error uploading post to blog`, uploadedPost);
173
+
174
+ break;
175
+ }
176
+
177
+ // Log
178
+ assistant.log(`harvest(): Uploaded post`, uploadedPost);
179
+ }
180
+
181
+ // Log
182
+ return resolve();
183
+ });
184
+ }
185
+
186
+ Module.prototype.getAppData = function (id) {
187
+ const self = this;
188
+
189
+ // Shortcuts
190
+ const Manager = self.Manager;
191
+ const libraries = self.libraries;
192
+ const assistant = self.assistant;
193
+ const context = self.context;
194
+
195
+ return new Promise(async function(resolve, reject) {
196
+ // Fetch app details
197
+ fetch('https://us-central1-itw-creative-works.cloudfunctions.net/getApp', {
198
+ method: 'post',
199
+ timeout: 30000,
200
+ tries: 3,
201
+ response: 'json',
202
+ body: {
203
+ id: id,
204
+ },
205
+ })
206
+ .then((r) => resolve(r))
207
+ .catch((e) => reject(e));
208
+ });
209
+ }
210
+
211
+ Module.prototype.getURLContent = function (url) {
212
+ const self = this;
213
+
214
+ // Shortcuts
215
+ const Manager = self.Manager;
216
+ const libraries = self.libraries;
217
+ const assistant = self.assistant;
218
+ const context = self.context;
219
+
220
+ return new Promise(async function(resolve, reject) {
221
+ // Fetch URL
222
+ fetch(url, {
223
+ timeout: 30000,
224
+ tries: 3,
225
+ response: 'raw',
226
+ headers: {
227
+ 'User-Agent': USER_AGENT,
228
+ }
229
+ })
230
+ .then(async (r) => {
231
+ const contentType = res.headers.get('content-type');
232
+ const text = await res.text();
233
+
234
+ return resolve(extractBodyContent(text, contentType, url));
235
+ })
236
+ .catch((e) => reject(e));
237
+ });
238
+ }
239
+
240
+ Module.prototype.isURL = function (url) {
241
+ const self = this;
242
+
243
+ // Shortcuts
244
+ const Manager = self.Manager;
245
+ const libraries = self.libraries;
246
+ const assistant = self.assistant;
247
+ const context = self.context;
248
+
249
+ try {
250
+ return !!new URL(url);
251
+ } catch (e) {
252
+ return false;
253
+ }
254
+ }
255
+
256
+ // Request to Ghostii
257
+ Module.prototype.requestGhostii = function (settings, content) {
258
+ const self = this;
259
+
260
+ // Shortcuts
261
+ const Manager = self.Manager;
262
+ const libraries = self.libraries;
263
+ const assistant = self.assistant;
264
+ const context = self.context;
265
+
266
+ return new Promise(async function(resolve, reject) {
267
+ // Fetch URL
268
+ fetch('https://api.ghostii.ai/write/article', {
269
+ method: 'post',
270
+ timeout: 90000,
271
+ tries: 1,
272
+ response: 'json',
273
+ body: {
274
+ backendManagerKey: Manager.config.backend_manager.key,
275
+ keywords: [''],
276
+ description: content,
277
+ insertLinks: true,
278
+ headerImageUrl: 'unsplash',
279
+ url: settings.app.url,
280
+ sectionQuantity: powertools.random(3, 6, {mode: 'gaussian'}),
281
+ feedUrl: `${settings.app.url}/feeds/posts.json`,
282
+ links: settings.links,
283
+ },
284
+ })
285
+ .then((r) => resolve(r))
286
+ .catch((e) => reject(e));
287
+ });
288
+ }
289
+
290
+ Module.prototype.uploadPost = function (settings, article) {
291
+ const self = this;
292
+
293
+ // Shortcuts
294
+ const Manager = self.Manager;
295
+ const libraries = self.libraries;
296
+ const assistant = self.assistant;
297
+ const context = self.context;
298
+
299
+ return new Promise(async function(resolve, reject) {
300
+ // if (assistant.isDevelopment()) {
301
+ // assistant.log('uploadPost(): Skipping because we are in development mode');
302
+
303
+ // return resolve();
304
+ // }
305
+
306
+ // Fetch URL
307
+ fetch(`${settings.app.server}/bm_api`, {
308
+ method: 'post',
309
+ timeout: 90000,
310
+ tries: 1,
311
+ response: 'json',
312
+ body: {
313
+ backendManagerKey: Manager.config.backend_manager.key,
314
+ command: 'admin:create-post',
315
+ payload: {
316
+ title: article.title,
317
+ url: article.title, // This is formatted on the bm_api endpoint
318
+ excerpt: article.description,
319
+ headerImageURL: article.headerImageUrl,
320
+ body: article.body,
321
+ id: self.postId++,
322
+ author: settings.author,
323
+ categories: article.categories,
324
+ tags: article.keywords,
325
+ path: 'ghostii',
326
+ githubUser: settings.app.github.user,
327
+ githubRepo: settings.app.github.repo,
328
+ },
329
+ },
330
+ })
331
+ .then((r) => resolve(r))
332
+ .catch((e) => reject(e));
333
+ });
334
+ }
335
+
336
+ const extractBodyContent = (text, contentType, url) => {
337
+ const parsed = tryParse(text);
338
+
339
+ // Try JSON
340
+ if (parsed) {
341
+ // If it's from rss.app, extract the content
342
+ if (parsed.items) {
343
+ return parsed.items.map((i) => `${i.title}: ${i.content_text}`).join('\n');
344
+ }
345
+
346
+ // If we cant recognize the JSON, return the original text
347
+ return text;
348
+ }
349
+
350
+ // Extract the content within the body tag
351
+ const bodyMatch = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
352
+ if (!bodyMatch) return '';
353
+
354
+ let bodyContent = bodyMatch[1];
355
+
356
+ // Remove script and meta tags
357
+ bodyContent = bodyContent.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
358
+ bodyContent = bodyContent.replace(/<meta[^>]*>/gi, '');
359
+
360
+ // Remove remaining HTML tags
361
+ return bodyContent.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
362
+ };
363
+
364
+ function tryParse(json) {
365
+ try {
366
+ return JSON5.parse(json);
367
+ } catch (e) {
368
+ return null;
369
+ }
370
+ };
371
+
372
+ // Randomize array
373
+ function randomize(array) {
374
+ return array.sort(() => Math.random() - 0.5);
375
+ }
376
+
377
+ module.exports = Module;
@@ -0,0 +1,197 @@
1
+ // Libraries
2
+ const fetch = require('wonderful-fetch');
3
+
4
+ function Module() {
5
+
6
+ }
7
+
8
+ Module.prototype.main = function (assistant, context) {
9
+ const self = this;
10
+
11
+ // Shortcuts
12
+ const Manager = assistant.Manager;
13
+ const libraries = Manager.libraries;
14
+
15
+ return new Promise(async function(resolve, reject) {
16
+ self.storage = Manager.storage({name: 'usage', temporary: true, clear: false, log: false});
17
+
18
+ assistant.log(`Starting...`);
19
+
20
+ // Clear local
21
+ await self.clearLocal();
22
+
23
+ // Clear firestore
24
+ await self.clearFirestore();
25
+
26
+ return resolve();
27
+ });
28
+ }
29
+
30
+ Module.prototype.clearLocal = function() {
31
+ const self = this;
32
+
33
+ // Shortcuts
34
+ const Manager = self.Manager;
35
+ const libraries = self.libraries;
36
+ const assistant = self.assistant;
37
+ const context = self.context;
38
+
39
+ return new Promise(async function(resolve, reject) {
40
+ // Log status
41
+ assistant.log(`[local]: Starting...`);
42
+
43
+ // Set variables
44
+ const now = new Date();
45
+
46
+ // Log storage
47
+ assistant.log(`[local]: storage(apps)`, self.storage.get('apps', {}).value());
48
+ assistant.log(`[local]: storage(users)`, self.storage.get('users', {}).value());
49
+
50
+ // Clear storage
51
+ self.storage.setState({}).write();
52
+
53
+ // Log status
54
+ assistant.log(`[local]: Completed!`);
55
+
56
+ return resolve();
57
+ });
58
+ }
59
+
60
+ Module.prototype.clearFirestore = function() {
61
+ const self = this;
62
+ const Manager = self.Manager;
63
+ const libraries = self.libraries;
64
+ const assistant = self.assistant;
65
+ const context = self.context;
66
+
67
+ const { admin } = libraries;
68
+
69
+ return new Promise(async function(resolve, reject) {
70
+ // Log status
71
+ assistant.log(`[firestore]: Starting...`);
72
+
73
+ // Clear storage
74
+ const metrics = await fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/getApp`, {
75
+ method: 'post',
76
+ response: 'json',
77
+ body: {
78
+ id: Manager.config.app.id,
79
+ }
80
+ })
81
+ .then(response => {
82
+ response.products = response.products || {};
83
+
84
+ for (let product of Object.values(response.products)) {
85
+ product = product || {};
86
+ product.planId = product.planId || '';
87
+
88
+ if (product.planId.includes('basic')) {
89
+ return product.limits;
90
+ }
91
+ }
92
+
93
+ return new Error('No basic product found');
94
+ })
95
+ .catch(e => e);
96
+
97
+ // Log status
98
+ assistant.log(`[firestore]: Resetting metrics`, metrics);
99
+
100
+ if (metrics instanceof Error) {
101
+ return reject(assistant.errorify(`Failed to check providers: ${metrics}`, {code: 500}));
102
+ }
103
+
104
+ // Reset all metrics with for loop of metrics
105
+ // TODO: OPTIMIZATION: Put all of the changes into a single batch
106
+ for (const metric of Object.keys(metrics)) {
107
+ assistant.log(`[firestore]: Resetting ${metric} for all users`);
108
+
109
+ await Manager.Utilities().iterateCollection((batch, index) => {
110
+ return new Promise(async (resolve, reject) => {
111
+ for (const doc of batch.docs) {
112
+ const data = doc.data();
113
+
114
+ // Normalize the metric
115
+ data.usage = data.usage || {};
116
+ data.usage[metric] = data.usage[metric] || {};
117
+ data.usage[metric].period = data.usage[metric].period || 0;
118
+ data.usage[metric].total = data.usage[metric].total || 0;
119
+ data.usage[metric].last = data.usage[metric].last || {};
120
+
121
+ // Yeet if its 0
122
+ if (data.usage[metric].period <= 0) {
123
+ continue;
124
+ }
125
+
126
+ // Reset the metric
127
+ const original = data.usage[metric].period;
128
+ data.usage[metric].period = 0;
129
+
130
+ // Update the doc
131
+ await doc.ref.update({usage: data.usage})
132
+ .then(r => {
133
+ assistant.log(`[firestore]: Reset ${metric} for ${doc.id} (${original} -> 0)`);
134
+ })
135
+ .catch(e => {
136
+ assistant.errorify(`Error resetting ${metric} for ${doc.id}: ${e}`, {code: 500, log: true});
137
+ })
138
+ }
139
+
140
+ // Complete
141
+ return resolve();
142
+ });
143
+ }, {
144
+ collection: 'users',
145
+ where: [
146
+ {field: `usage.${metric}.period`, operator: '>', value: 0},
147
+ ],
148
+ batchSize: 5000,
149
+ log: true,
150
+ })
151
+ .then((r) => {
152
+ assistant.log(`[firestore]: Reset ${metric} for all users complete!`);
153
+ })
154
+ .catch(e => {
155
+ assistant.errorify(`Error resetting ${metric} for all users: ${e}`, {code: 500, log: true});
156
+ })
157
+ }
158
+
159
+ // Clear temporary/usage in firestore by deleting the doc
160
+ admin.firestore().collection('temporary').listDocuments()
161
+ .then((snap) => {
162
+ const chunks = [];
163
+ for (let i = 0; i < snap.length; i += 500) {
164
+ chunks.push(snap.slice(i, i + 500))
165
+ }
166
+
167
+ // Delete in chunks
168
+ for (const chunk of chunks) {
169
+ // Get a new write batch
170
+ const batch = admin.firestore().batch()
171
+
172
+ chunk.map((doc) => {
173
+ assistant.log('Deleting', doc.id);
174
+
175
+ batch.delete(doc);
176
+ });
177
+
178
+ batch.commit()
179
+ .catch((e) => {
180
+ assistant.error('Error committing batch', e);
181
+ });
182
+ }
183
+ })
184
+ // await libraries.admin.firestore().doc(`temporary/usage`).delete()
185
+ // .then(r => {
186
+ // assistant.log(`[firestore]: Deleted temporary/usage`);
187
+ // })
188
+ // .catch(e => {
189
+ // assistant.errorify(`Error deleting temporary/usage: ${e}`, {code: 500, log: true});
190
+ // })
191
+
192
+ return resolve();
193
+ });
194
+ }
195
+
196
+
197
+ module.exports = Module;
@@ -0,0 +1,114 @@
1
+ const fetch = require('wonderful-fetch');
2
+ const jetpack = require('fs-jetpack');
3
+
4
+ function Module() {
5
+
6
+ }
7
+
8
+ Module.prototype.init = function (Manager, data) {
9
+ const self = this;
10
+
11
+ // Shortcuts
12
+ self.Manager = Manager;
13
+ self.libraries = Manager.libraries;
14
+ self.assistant = Manager.Assistant();
15
+
16
+ self.context = data.context;
17
+
18
+ return self;
19
+ }
20
+
21
+ Module.prototype.main = function() {
22
+ const self = this;
23
+
24
+ // Shortcuts
25
+ const Manager = self.Manager;
26
+ const libraries = self.libraries;
27
+ const assistant = self.assistant;
28
+ const context = self.context;
29
+
30
+ return new Promise(async function(resolve, reject) {
31
+ // Set log prefix
32
+ assistant.setLogPrefix('cron/daily()');
33
+
34
+ // Log
35
+ assistant.log(`Starting...`);
36
+
37
+ // Setup error
38
+ let error;
39
+
40
+ // Load BEM jobs
41
+ await loadAndExecuteJobs(`${__dirname}/daily`, Manager, context).catch((e) => error = e);
42
+
43
+ // Load custom jobs
44
+ await loadAndExecuteJobs(`${Manager.cwd}/hooks/cron/daily`, Manager, context).catch((e) => error = e);
45
+
46
+ // If there was an error, reject
47
+ if (error) {
48
+ return reject(error);
49
+ }
50
+
51
+ // Return
52
+ return resolve();
53
+ });
54
+ }
55
+
56
+ function loadAndExecuteJobs(jobsPath, Manager, context) {
57
+ const assistant = Manager.assistant;
58
+
59
+ return new Promise(async function(resolve, reject) {
60
+ const jobs = jetpack.list(jobsPath) || [];
61
+ let caught;
62
+
63
+ // Log
64
+ assistant.log(`Located ${jobs.length} jobs @ ${jobsPath}...`);
65
+
66
+ for (let i = 0; i < jobs.length; i++) {
67
+ // Create new assistant for each job
68
+ const assistant = Manager.Assistant();
69
+
70
+ // Load job
71
+ const job = jobs[i];
72
+ const jobName = job.replace('.js', '');
73
+
74
+ // Set log prefix
75
+ assistant.setLogPrefix(`cron/daily/${jobName}()`);
76
+
77
+ // Log
78
+ assistant.log(`Starting...`);
79
+
80
+ // Load job
81
+ const Job = require(`${jobsPath}/${job}`);
82
+ const jobInstance = new Job();
83
+
84
+ // Setup
85
+ jobInstance.Manager = Manager;
86
+ jobInstance.assistant = assistant;
87
+ jobInstance.context = context;
88
+ jobInstance.libraries = Manager.libraries;
89
+
90
+ // Execute job
91
+ await jobInstance.main(assistant, context)
92
+ .then(res => {
93
+ assistant.log(`Completed!`);
94
+ })
95
+ .catch(e => {
96
+ assistant.errorify(`Error executing: ${e}`, {
97
+ code: 500,
98
+ sentry: true
99
+ });
100
+ caught = e;
101
+ })
102
+ }
103
+
104
+ // If there was an error, reject
105
+ if (caught) {
106
+ return reject(caught);
107
+ }
108
+
109
+ // Return
110
+ return resolve();
111
+ });
112
+ }
113
+
114
+ module.exports = Module;