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.
- package/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/cli/cli.js +1534 -0
- package/dist/manager/functions/core/actions/api/admin/backup.js +338 -0
- package/dist/manager/functions/core/actions/api/admin/create-post.js +388 -0
- package/dist/manager/functions/core/actions/api/admin/cron.js +37 -0
- package/dist/manager/functions/core/actions/api/admin/database-read.js +35 -0
- package/dist/manager/functions/core/actions/api/admin/database-write.js +39 -0
- package/dist/manager/functions/core/actions/api/admin/edit-post.js +158 -0
- package/dist/manager/functions/core/actions/api/admin/firestore-query.js +165 -0
- package/dist/manager/functions/core/actions/api/admin/firestore-read.js +38 -0
- package/dist/manager/functions/core/actions/api/admin/firestore-write.js +54 -0
- package/dist/manager/functions/core/actions/api/admin/get-stats.js +269 -0
- package/dist/manager/functions/core/actions/api/admin/payment-processor.js +57 -0
- package/dist/manager/functions/core/actions/api/admin/run-hook.js +95 -0
- package/dist/manager/functions/core/actions/api/admin/send-notification.js +197 -0
- package/dist/manager/functions/core/actions/api/admin/sync-users.js +125 -0
- package/dist/manager/functions/core/actions/api/admin/templates/post.html +16 -0
- package/dist/manager/functions/core/actions/api/firebase/get-providers.js +102 -0
- package/dist/manager/functions/core/actions/api/general/emails/general:download-app-link.js +21 -0
- package/dist/manager/functions/core/actions/api/general/fetch-post.js +99 -0
- package/dist/manager/functions/core/actions/api/general/generate-uuid.js +41 -0
- package/dist/manager/functions/core/actions/api/general/send-email.js +112 -0
- package/dist/manager/functions/core/actions/api/handler/create-post.js +146 -0
- package/dist/manager/functions/core/actions/api/special/setup-electron-manager-client.js +103 -0
- package/dist/manager/functions/core/actions/api/template.js +33 -0
- package/dist/manager/functions/core/actions/api/test/authenticate.js +22 -0
- package/dist/manager/functions/core/actions/api/test/create-test-accounts.js +27 -0
- package/dist/manager/functions/core/actions/api/test/lab.js +55 -0
- package/dist/manager/functions/core/actions/api/test/redirect.js +26 -0
- package/dist/manager/functions/core/actions/api/test/webhook.js +30 -0
- package/dist/manager/functions/core/actions/api/user/create-custom-token.js +32 -0
- package/dist/manager/functions/core/actions/api/user/delete.js +68 -0
- package/dist/manager/functions/core/actions/api/user/get-active-sessions.js +45 -0
- package/dist/manager/functions/core/actions/api/user/get-subscription-info.js +49 -0
- package/dist/manager/functions/core/actions/api/user/oauth2/discord.js +114 -0
- package/dist/manager/functions/core/actions/api/user/oauth2/google.js +99 -0
- package/dist/manager/functions/core/actions/api/user/oauth2.js +476 -0
- package/dist/manager/functions/core/actions/api/user/regenerate-api-keys.js +54 -0
- package/dist/manager/functions/core/actions/api/user/resolve.js +32 -0
- package/dist/manager/functions/core/actions/api/user/sign-out-all-sessions.js +118 -0
- package/dist/manager/functions/core/actions/api/user/sign-up copy.js +544 -0
- package/dist/manager/functions/core/actions/api/user/sign-up.js +99 -0
- package/dist/manager/functions/core/actions/api/user/submit-feedback.js +96 -0
- package/dist/manager/functions/core/actions/api/user/validate-settings.js +86 -0
- package/dist/manager/functions/core/actions/api.js +354 -0
- package/dist/manager/functions/core/actions/create-post-handler.js +184 -0
- package/dist/manager/functions/core/actions/generate-uuid.js +62 -0
- package/dist/manager/functions/core/actions/sign-up-handler.js +205 -0
- package/dist/manager/functions/core/admin/create-post.js +206 -0
- package/dist/manager/functions/core/admin/firestore-write.js +72 -0
- package/dist/manager/functions/core/admin/get-stats.js +218 -0
- package/dist/manager/functions/core/admin/query.js +198 -0
- package/dist/manager/functions/core/admin/send-notification.js +206 -0
- package/dist/manager/functions/core/cron/daily/ghostii-auto-publisher.js +377 -0
- package/dist/manager/functions/core/cron/daily/reset-usage.js +197 -0
- package/dist/manager/functions/core/cron/daily.js +114 -0
- package/dist/manager/functions/core/events/auth/before-create.js +124 -0
- package/dist/manager/functions/core/events/auth/before-signin.js +62 -0
- package/dist/manager/functions/core/events/auth/on-create copy.js +121 -0
- package/dist/manager/functions/core/events/auth/on-create.js +564 -0
- package/dist/manager/functions/core/events/auth/on-delete.js +72 -0
- package/dist/manager/functions/core/events/firestore/on-subscription.js +107 -0
- package/dist/manager/functions/test/authenticate.js +38 -0
- package/dist/manager/functions/test/create-test-accounts.js +144 -0
- package/dist/manager/functions/test/webhook.js +37 -0
- package/dist/manager/functions/wrappers/mailchimp/addToList.js +25 -0
- package/dist/manager/helpers/analytics copy.js +217 -0
- package/dist/manager/helpers/analytics.js +467 -0
- package/dist/manager/helpers/api-manager.js +324 -0
- package/dist/manager/helpers/assistant.js +1043 -0
- package/dist/manager/helpers/metadata.js +32 -0
- package/dist/manager/helpers/middleware.js +154 -0
- package/dist/manager/helpers/roles.js +69 -0
- package/dist/manager/helpers/settings.js +158 -0
- package/dist/manager/helpers/subscription-resolver-new.js +828 -0
- package/dist/manager/helpers/subscription-resolver.js +842 -0
- package/dist/manager/helpers/usage.js +381 -0
- package/dist/manager/helpers/user.js +198 -0
- package/dist/manager/helpers/utilities.js +292 -0
- package/dist/manager/index.js +1076 -0
- package/dist/manager/libraries/openai.js +460 -0
- package/dist/manager/routes/restart/index.js +52 -0
- package/dist/manager/routes/test/index.js +43 -0
- package/dist/manager/schemas/restart.js +13 -0
- package/dist/manager/schemas/test.js +13 -0
- package/dist/require.js +3 -0
- 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;
|