@yrpri/api 9.0.88 → 9.0.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,230 @@
1
+ import { YpAgentProduct } from "../../agentProduct.js";
2
+ import { YpSubscriptionPlan } from "../../subscriptionPlan.js";
3
+ async function setupAgentProductsConfiguration() {
4
+ const competitionAgentWorkflow = {
5
+ currentStepIndex: 0,
6
+ steps: [
7
+ {
8
+ name: "Competitor Analysis Wide Search",
9
+ shortName: "Wide search",
10
+ description: "Wide search for competitor strategies and market positions.",
11
+ shortDescription: "Wide search for competitor strategies and market positions.",
12
+ agentClassUuid: "a1b2c3d4-e5f6-c7c8-a9c0-c1225354f516",
13
+ type: "agentOps",
14
+ stepBackgroundColor: "#ffdc2f",
15
+ stepTextColor: "#211e1c",
16
+ },
17
+ {
18
+ name: "Competitor Analysis People Review",
19
+ shortName: "Vet top 10 competitors",
20
+ description: "People review to vet top 10 key competitors",
21
+ shortDescription: "People review to vet top 10 key competitors",
22
+ agentClassUuid: "a1b2c3d4-e5f6-c7c8-a9c0-c1225354f516",
23
+ type: "engagmentFromOutputConnector",
24
+ stepBackgroundColor: "#e74c3c",
25
+ stepTextColor: "#ffffff",
26
+ emailCallForAction: "Start Vetting Competitors",
27
+ emailInstructions: "Use up 👍 and down 👎 thumbs to vet competitors. You can choose as many as you want but <b>only top 10 will go forward</b>, to the next round!"
28
+ },
29
+ {
30
+ name: "Competitor Analysis Detailed Search",
31
+ shortName: "Detailed search",
32
+ description: "Detailed search for competitor strategies and market positions.",
33
+ shortDescription: "Detailed search for competitor strategies and market positions.",
34
+ agentClassUuid: "c6e99ac4-e5f6-c7c1-a1c0-c1ab53c4ff16",
35
+ type: "agentOps",
36
+ stepBackgroundColor: "#1e90ff",
37
+ stepTextColor: "#ffffff",
38
+ },
39
+ {
40
+ name: "Competitor Analysis Comment on Key Competitors",
41
+ shortName: "Competitors comments",
42
+ description: "Comment on key competitors before creating report",
43
+ shortDescription: "Comment on key competitors before report",
44
+ agentClassUuid: "c6e99ac4-e5f6-c7c1-a1c0-c1ab53c4ff16",
45
+ type: "engagmentFromOutputConnector",
46
+ stepBackgroundColor: "#2ecc71",
47
+ stepTextColor: "#ffffff",
48
+ emailCallForAction: "Comment On Key Competitors",
49
+ emailInstructions: "View the details for key competitors and add your insights before the final report is created."
50
+ },
51
+ {
52
+ name: "Competitors Report",
53
+ shortName: "Competitor report",
54
+ description: "Report on the state of the market based on the competitors analysis.",
55
+ shortDescription: "Report on the state of the market based on the competitors analysis.",
56
+ agentClassUuid: "1cf3af64-a5f6-a7c1-91c1-51fb13c72f1a",
57
+ type: "agentOps",
58
+ stepBackgroundColor: "#d486da",
59
+ stepTextColor: "#ffffff",
60
+ emailCallForAction: "View the Competitor Report",
61
+ emailInstructions: "View the final report on the state of the market based on the competitors analysis."
62
+ },
63
+ ],
64
+ };
65
+ const competitorAgentFreeTrial = await YpAgentProduct.findByPk(1);
66
+ if (competitorAgentFreeTrial) {
67
+ competitorAgentFreeTrial.set("configuration.workflow", competitionAgentWorkflow);
68
+ competitorAgentFreeTrial.changed("configuration", true);
69
+ await competitorAgentFreeTrial.save();
70
+ }
71
+ else {
72
+ console.log("CompetitorAgentFreeTrial not found");
73
+ }
74
+ const competitorAgentPaid = await YpAgentProduct.findByPk(2);
75
+ if (competitorAgentPaid) {
76
+ competitorAgentPaid.set("configuration.workflow", competitionAgentWorkflow);
77
+ competitorAgentPaid.changed("configuration", true);
78
+ await competitorAgentPaid.save();
79
+ }
80
+ const fundingAgent = await YpAgentProduct.findByPk(6);
81
+ if (fundingAgent) {
82
+ const fundingAgentWorkflow = {
83
+ currentStepIndex: 0,
84
+ steps: [
85
+ {
86
+ name: "Funding Agent Wide Search",
87
+ shortName: "Wide Search",
88
+ description: "Wide search for investors and funding opportunities.",
89
+ shortDescription: "Wide search for investors and funding opportunities.",
90
+ agentClassUuid: "956e7f74-6fc6-4e01-81b4-098c193e6450",
91
+ type: "agentOps",
92
+ stepBackgroundColor: "#ffdc2f",
93
+ stepTextColor: "#211e1c"
94
+ },
95
+ {
96
+ name: "Funding Agent Select Top 20 Investors",
97
+ shortName: "Select top 20 investors",
98
+ description: "Select top 20 investors from the wide search results.",
99
+ shortDescription: "Select top 20 investors from the wide search results.",
100
+ agentClassUuid: "956e7f74-6fc6-4e01-81b4-098c193e6450",
101
+ type: "engagmentFromOutputConnector",
102
+ stepBackgroundColor: "#e74c3c",
103
+ stepTextColor: "#ffffff",
104
+ emailCallForAction: "Vet Investors",
105
+ emailInstructions: "Use up 👍 and down 👎 thumbs to vet investors. You can choose as many as you want but <b>only top 20 will go forward</b>, to the next round!"
106
+ },
107
+ {
108
+ name: "Funding Agent Detailed Search",
109
+ shortName: "Detailed search",
110
+ description: "Detailed search for investors and funding opportunities.",
111
+ shortDescription: "Detailed search for investors and funding opportunities.",
112
+ agentClassUuid: "b36ffca6-7363-44be-bd55-40661210cf24",
113
+ type: "agentOps",
114
+ stepBackgroundColor: "#1e90ff",
115
+ stepTextColor: "#ffffff",
116
+ },
117
+ {
118
+ name: "Comment on Key Investors",
119
+ shortName: "Comment on investors",
120
+ description: "Comment on investors before creating report",
121
+ shortDescription: "Comment on investors before creating report",
122
+ agentClassUuid: "b36ffca6-7363-44be-bd55-40661210cf24",
123
+ type: "engagmentFromOutputConnector",
124
+ stepBackgroundColor: "#2ecc71",
125
+ stepTextColor: "#ffffff",
126
+ emailCallForAction: "Comment On Key Investors",
127
+ emailInstructions: "View the details for key investors and add your insights before the final report is created."
128
+ },
129
+ {
130
+ name: "Funding Agent Report",
131
+ shortName: "Funding report",
132
+ description: "Report on investors and funding opportunities.",
133
+ shortDescription: "Report on investors and funding opportunities.",
134
+ agentClassUuid: "1bbf8f86-0ffc-4356-aaa1-9cea04b78ec4",
135
+ type: "agentOps",
136
+ stepBackgroundColor: "#d486da",
137
+ stepTextColor: "#ffffff",
138
+ emailCallForAction: "View the Funding Report",
139
+ emailInstructions: "View the final report on investors and funding opportunities."
140
+ },
141
+ ],
142
+ };
143
+ fundingAgent.set("configuration.workflow", fundingAgentWorkflow);
144
+ fundingAgent.changed("configuration", true);
145
+ await fundingAgent.save();
146
+ }
147
+ const fundingSubscriptionPlan = await YpSubscriptionPlan.findByPk(6);
148
+ if (fundingSubscriptionPlan) {
149
+ fundingSubscriptionPlan.set("configuration.structuredAnswersOverride", []);
150
+ fundingSubscriptionPlan.set("configuration.requiredStructuredQuestions", [
151
+ {
152
+ uniqueId: "businessDescription",
153
+ type: "textAreaLong",
154
+ description: "Detailed description of the business, this is critical for the agent to understand the business and provide accurate results.",
155
+ value: "",
156
+ maxLength: 7500,
157
+ required: true,
158
+ rows: 5,
159
+ charCounter: true,
160
+ text: "Business Description",
161
+ },
162
+ {
163
+ uniqueId: "investorGeographicFocus",
164
+ type: "textFieldLong",
165
+ description: "Geographic focus of the investors",
166
+ value: "",
167
+ maxLength: 250,
168
+ required: false,
169
+ rows: 1,
170
+ charCounter: true,
171
+ text: "Investor Geographic Focus",
172
+ },
173
+ {
174
+ uniqueId: "investorIndustryFocus",
175
+ type: "textFieldLong",
176
+ description: "Industry focus of the investors",
177
+ value: "",
178
+ maxLength: 250,
179
+ required: false,
180
+ rows: 1,
181
+ charCounter: true,
182
+ text: "Investor Industry Focus",
183
+ }
184
+ ]);
185
+ fundingSubscriptionPlan.changed("configuration", true);
186
+ await fundingSubscriptionPlan.save();
187
+ }
188
+ else {
189
+ console.log("FundingSubscriptionPlan not found");
190
+ }
191
+ // Update subscription plans 2-5 to coming_soon
192
+ for (let planId = 2; planId <= 5; planId++) {
193
+ const subscriptionPlan = await YpSubscriptionPlan.findByPk(planId);
194
+ if (subscriptionPlan) {
195
+ subscriptionPlan.set("configuration.type", "coming_soon");
196
+ if (planId == 2) {
197
+ subscriptionPlan.set("configuration.type", "paid");
198
+ }
199
+ subscriptionPlan.changed("configuration", true);
200
+ await subscriptionPlan.save();
201
+ }
202
+ else {
203
+ console.log(`SubscriptionPlan ${planId} not found`);
204
+ }
205
+ }
206
+ for (let planId = 1; planId <= 2; planId++) {
207
+ const subscriptionPlan = await YpSubscriptionPlan.findByPk(planId);
208
+ if (subscriptionPlan) {
209
+ subscriptionPlan.set("configuration.requiredStructuredQuestions", [
210
+ {
211
+ uniqueId: "businessDescription",
212
+ type: "textAreaLong",
213
+ description: "Detailed description of the business, this is critical for the agent to understand the business and provide accurate results.",
214
+ value: "",
215
+ maxLength: 7500,
216
+ required: true,
217
+ rows: 5,
218
+ charCounter: true,
219
+ text: "Business Description",
220
+ }
221
+ ]);
222
+ subscriptionPlan.changed("configuration", true);
223
+ await subscriptionPlan.save();
224
+ }
225
+ else {
226
+ console.log(`SubscriptionPlan ${planId} not found`);
227
+ }
228
+ }
229
+ }
230
+ setupAgentProductsConfiguration();
@@ -5,60 +5,60 @@ async function setupAgentProductsConfiguration() {
5
5
  currentStepIndex: 0,
6
6
  steps: [
7
7
  {
8
- name: "Competitor Analysis Wide Search",
9
- shortName: "Wide search",
10
- description: "Wide search for competitor strategies and market positions.",
11
- shortDescription: "Wide search for competitor strategies and market positions.",
8
+ name: "Wide search for competitors",
9
+ shortName: "Competitors wide search",
10
+ shortDescription: "A wide search for competitors based on your business description.",
11
+ description: "A wide search for competitors based on your business description. The wide search will result in a list of competitors that you and your team can vet as actual competitors.",
12
12
  agentClassUuid: "a1b2c3d4-e5f6-c7c8-a9c0-c1225354f516",
13
13
  type: "agentOps",
14
14
  stepBackgroundColor: "#ffdc2f",
15
15
  stepTextColor: "#211e1c",
16
16
  },
17
17
  {
18
- name: "Competitor Analysis People Review",
19
- shortName: "Vet top 10 competitors",
20
- description: "People review to vet top 10 key competitors",
21
- shortDescription: "People review to vet top 10 key competitors",
18
+ name: "Vet and vote top 10 competitors",
19
+ shortName: "Vote 10 competitors",
20
+ shortDescription: "Your team reviews and votes on competitors.",
21
+ description: "You and your team can now review the results of the wide search which is a list of potential competitors. Everyone can vote for ten competitors and the competitors with the most votes will move ahead to the next round and become key competitors.",
22
22
  agentClassUuid: "a1b2c3d4-e5f6-c7c8-a9c0-c1225354f516",
23
23
  type: "engagmentFromOutputConnector",
24
24
  stepBackgroundColor: "#e74c3c",
25
25
  stepTextColor: "#ffffff",
26
26
  emailCallForAction: "Start Vetting Competitors",
27
- emailInstructions: "Use up 👍 and down 👎 thumbs to vet competitors. You can choose as many as you want but <b>only top 10 will go forward</b>, to the next round!"
27
+ emailInstructions: "Use up 👍 and down 👎 thumbs to vet competitors. You can choose as many as you want but <b>only top 10 will go forward</b>, to the next round!",
28
28
  },
29
29
  {
30
- name: "Competitor Analysis Detailed Search",
31
- shortName: "Detailed search",
32
- description: "Detailed search for competitor strategies and market positions.",
33
- shortDescription: "Detailed search for competitor strategies and market positions.",
30
+ name: "Detailed search on key competitors",
31
+ shortName: "Key competitors' details",
32
+ shortDescription: "Multi-dimensional search to understand your key competitors.",
33
+ description: "Detailed search for competitors in multiple dimensions that include a company overview, recent news & updates, products & services, event participation, customer acquisitions, partnerships and collaborations, and ethical practices.",
34
34
  agentClassUuid: "c6e99ac4-e5f6-c7c1-a1c0-c1ab53c4ff16",
35
35
  type: "agentOps",
36
36
  stepBackgroundColor: "#1e90ff",
37
37
  stepTextColor: "#ffffff",
38
38
  },
39
39
  {
40
- name: "Competitor Analysis Comment on Key Competitors",
41
- shortName: "Competitors comments",
42
- description: "Comment on key competitors before creating report",
43
- shortDescription: "Comment on key competitors before report",
40
+ name: "Add team insights about key competitors",
41
+ shortName: "Add team insights",
42
+ shortDescription: "Your team can now add their insights about key competitors.",
43
+ description: "You and your team can now review the details about competitors and add insights by commenting on competitors. Your comments will used in the final report.",
44
44
  agentClassUuid: "c6e99ac4-e5f6-c7c1-a1c0-c1ab53c4ff16",
45
45
  type: "engagmentFromOutputConnector",
46
46
  stepBackgroundColor: "#2ecc71",
47
47
  stepTextColor: "#ffffff",
48
48
  emailCallForAction: "Comment On Key Competitors",
49
- emailInstructions: "View the details for key competitors and add your insights before the final report is created."
49
+ emailInstructions: "View the details for key competitors and add your insights before the final report is created.",
50
50
  },
51
51
  {
52
- name: "Competitors Report",
53
- shortName: "Competitor report",
54
- description: "Report on the state of the market based on the competitors analysis.",
55
- shortDescription: "Report on the state of the market based on the competitors analysis.",
52
+ name: "Competitor analysis report",
53
+ shortName: "Competitor Report",
54
+ shortDescription: "Report on the state of your key competitors and recommendations.",
55
+ description: "Report on the state of your key competitors where all the information gathered in earlier steps has been consolidated into chapters for each competitor and concludes with a chapter on action-oriented recommendations.",
56
56
  agentClassUuid: "1cf3af64-a5f6-a7c1-91c1-51fb13c72f1a",
57
57
  type: "agentOps",
58
58
  stepBackgroundColor: "#d486da",
59
59
  stepTextColor: "#ffffff",
60
60
  emailCallForAction: "View the Competitor Report",
61
- emailInstructions: "View the final report on the state of the market based on the competitors analysis."
61
+ emailInstructions: "View the final report on the state of the market based on the competitors analysis.",
62
62
  },
63
63
  ],
64
64
  };
@@ -90,23 +90,23 @@ async function setupAgentProductsConfiguration() {
90
90
  agentClassUuid: "956e7f74-6fc6-4e01-81b4-098c193e6450",
91
91
  type: "agentOps",
92
92
  stepBackgroundColor: "#ffdc2f",
93
- stepTextColor: "#211e1c"
93
+ stepTextColor: "#211e1c",
94
94
  },
95
95
  {
96
- name: "Funding Agent People Prioritization",
97
- shortName: "Vetting investors",
98
- description: "People prioritization of the wide search results.",
99
- shortDescription: "People prioritization of the wide search results.",
96
+ name: "Funding Agent Select Top 20 Investors",
97
+ shortName: "Select top 20 investors",
98
+ description: "Select top 20 investors from the wide search results.",
99
+ shortDescription: "Select top 20 investors from the wide search results.",
100
100
  agentClassUuid: "956e7f74-6fc6-4e01-81b4-098c193e6450",
101
101
  type: "engagmentFromOutputConnector",
102
102
  stepBackgroundColor: "#e74c3c",
103
103
  stepTextColor: "#ffffff",
104
104
  emailCallForAction: "Vet Investors",
105
- emailInstructions: "Use up 👍 and down 👎 thumbs to vet investors. You can choose as many as you want but <b>only top 10 will go forward</b>, to the next round!"
105
+ emailInstructions: "Use up 👍 and down 👎 thumbs to vet investors. You can choose as many as you want but <b>only top 20 will go forward</b>, to the next round!",
106
106
  },
107
107
  {
108
108
  name: "Funding Agent Detailed Search",
109
- shortName: "Detailed Search",
109
+ shortName: "Detailed search",
110
110
  description: "Detailed search for investors and funding opportunities.",
111
111
  shortDescription: "Detailed search for investors and funding opportunities.",
112
112
  agentClassUuid: "b36ffca6-7363-44be-bd55-40661210cf24",
@@ -115,16 +115,16 @@ async function setupAgentProductsConfiguration() {
115
115
  stepTextColor: "#ffffff",
116
116
  },
117
117
  {
118
- name: "Funding Agent Detailed Search People Prioritization",
119
- shortName: "Key investors",
120
- description: "People prioritization of the detailed search results.",
121
- shortDescription: "People prioritization of the detailed search results.",
118
+ name: "Comment on Key Investors",
119
+ shortName: "Comment on investors",
120
+ description: "Comment on investors before creating report",
121
+ shortDescription: "Comment on investors before creating report",
122
122
  agentClassUuid: "b36ffca6-7363-44be-bd55-40661210cf24",
123
123
  type: "engagmentFromOutputConnector",
124
124
  stepBackgroundColor: "#2ecc71",
125
125
  stepTextColor: "#ffffff",
126
126
  emailCallForAction: "Comment On Key Investors",
127
- emailInstructions: "View the details for key investors and add your insights before the final report is created."
127
+ emailInstructions: "View the details for key investors and add your insights before the final report is created.",
128
128
  },
129
129
  {
130
130
  name: "Funding Agent Report",
@@ -136,7 +136,7 @@ async function setupAgentProductsConfiguration() {
136
136
  stepBackgroundColor: "#d486da",
137
137
  stepTextColor: "#ffffff",
138
138
  emailCallForAction: "View the Funding Report",
139
- emailInstructions: "View the final report on investors and funding opportunities."
139
+ emailInstructions: "View the final report on investors and funding opportunities.",
140
140
  },
141
141
  ],
142
142
  };
@@ -180,7 +180,7 @@ async function setupAgentProductsConfiguration() {
180
180
  rows: 1,
181
181
  charCounter: true,
182
182
  text: "Investor Industry Focus",
183
- }
183
+ },
184
184
  ]);
185
185
  fundingSubscriptionPlan.changed("configuration", true);
186
186
  await fundingSubscriptionPlan.save();
@@ -217,7 +217,7 @@ async function setupAgentProductsConfiguration() {
217
217
  rows: 5,
218
218
  charCounter: true,
219
219
  text: "Business Description",
220
- }
220
+ },
221
221
  ]);
222
222
  subscriptionPlan.changed("configuration", true);
223
223
  await subscriptionPlan.save();
@@ -554,7 +554,7 @@ router.get('/*', function botController(req, res, next) {
554
554
  ], error => {
555
555
  if (error) {
556
556
  log.error("Id for nonSpa is not a number", { error });
557
- res.sendStatus(404);
557
+ res.sendStatus(200);
558
558
  }
559
559
  else {
560
560
  if (req.ypCommunity && req.ypCommunity.id != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yrpri/api",
3
- "version": "9.0.88",
3
+ "version": "9.0.90",
4
4
  "license": "MIT",
5
5
  "author": "Robert Bjarnason & Citizens Foundation",
6
6
  "repository": {
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ const models = require('../../models/index.cjs');
3
+ const moment = require('moment');
4
+ const maxNumberFromPath = process.argv[2];
5
+ const maxNumberOfNotificationsToDelete = maxNumberFromPath ? maxNumberFromPath : 1000;
6
+ let numberOfDeletedNotifications = 0;
7
+ let startTime = moment();
8
+ function sleep(ms) {
9
+ return new Promise(resolve => setTimeout(resolve, ms));
10
+ }
11
+ const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
12
+ (async () => {
13
+ let haveNotificationsToDelete = true;
14
+ let userOffset = 0;
15
+ while (haveNotificationsToDelete && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
16
+ try {
17
+ const users = await models.User.unscoped().findAll({
18
+ where: {
19
+ created_at: {
20
+ [models.Sequelize.Op.lte]: moment().add(-3, 'days').toISOString()
21
+ },
22
+ profile_data: {
23
+ isAnonymousUser: {
24
+ [models.Sequelize.Op.is]: true
25
+ }
26
+ }
27
+ },
28
+ attributes: ['id'],
29
+ order: ['id'],
30
+ offset: userOffset,
31
+ limit: 500
32
+ });
33
+ if (users.length > 0) {
34
+ console.log(`${users.length} users offset ${userOffset}`);
35
+ userOffset += 500;
36
+ const userIds = users.map(n => { return n.id; });
37
+ let haveNotificationsLeftToProcess = true;
38
+ let notificationsOffset = 0;
39
+ while (haveNotificationsLeftToProcess && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
40
+ const notifications = await models.AcNotification.unscoped().findAll({
41
+ where: {
42
+ user_id: {
43
+ [models.Sequelize.Op.in]: userIds
44
+ }
45
+ },
46
+ limit: 1000,
47
+ offset: notificationsOffset,
48
+ order: ['user_id'],
49
+ attributes: ['id'],
50
+ });
51
+ console.log(`${notifications.length} notifications offset ${notificationsOffset}`);
52
+ if (notifications.length > 0) {
53
+ notificationsOffset += 1000;
54
+ const notificationIds = notifications.map(n => { return n.id; });
55
+ const chunkedIds = chunk(notificationIds, 100);
56
+ for (let i = 0; i < chunkedIds.length; i++) {
57
+ const destroyInfo = await models.AcNotification.unscoped().destroy({
58
+ where: {
59
+ id: {
60
+ [models.Sequelize.Op.in]: chunkedIds[i]
61
+ }
62
+ }
63
+ });
64
+ numberOfDeletedNotifications += destroyInfo;
65
+ console.log(`${numberOfDeletedNotifications}`);
66
+ await sleep(50);
67
+ if (numberOfDeletedNotifications >= maxNumberOfNotificationsToDelete) {
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ else {
73
+ haveNotificationsLeftToProcess = false;
74
+ console.log("No more notifications left to process from user");
75
+ }
76
+ await sleep(100);
77
+ }
78
+ }
79
+ else {
80
+ haveNotificationsToDelete = false;
81
+ }
82
+ }
83
+ catch (error) {
84
+ console.error(error);
85
+ haveNotificationsToDelete = false;
86
+ }
87
+ }
88
+ console.log(`${numberOfDeletedNotifications} old anon notifications deleted`);
89
+ console.log(`Duration ${moment(moment() - startTime).format("HH:mm:ss.SSS")}`);
90
+ process.exit();
91
+ })();
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ const models = require('../../models/index.cjs');
3
+ const moment = require('moment');
4
+ const maxNumberFromPath = process.argv[2];
5
+ // Default to 1,000,000 if no command line arg given, adjust as you see fit
6
+ const maxNumberOfNotificationsToDelete = maxNumberFromPath ? parseInt(maxNumberFromPath) : 1000000;
7
+ let numberOfDeletedNotifications = 0;
8
+ const startTime = moment();
9
+ function sleep(ms) {
10
+ return new Promise(resolve => setTimeout(resolve, ms));
11
+ }
12
+ function chunk(arr, size) {
13
+ return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size));
14
+ }
15
+ (async () => {
16
+ let haveNotificationsToDelete = true;
17
+ let offset = 0;
18
+ // Calculate the cutoff date for "older than 1 year"
19
+ const cutoffDate = moment().subtract(1, 'year').toISOString();
20
+ while (haveNotificationsToDelete && numberOfDeletedNotifications < maxNumberOfNotificationsToDelete) {
21
+ try {
22
+ // Fetch a batch of notifications older than 1 year
23
+ const notifications = await models.AcNotification.unscoped().findAll({
24
+ where: {
25
+ created_at: {
26
+ [models.Sequelize.Op.lte]: cutoffDate,
27
+ },
28
+ },
29
+ limit: 1000,
30
+ offset: offset,
31
+ order: ['id'],
32
+ attributes: ['id'],
33
+ });
34
+ if (notifications.length > 0) {
35
+ console.log(`${notifications.length} notifications found at offset ${offset}`);
36
+ offset += 1000;
37
+ // Extract IDs and chunk them to avoid huge deletions in one query
38
+ const notificationIds = notifications.map(n => n.id);
39
+ const chunkedIds = chunk(notificationIds, 100);
40
+ // Delete chunk by chunk
41
+ for (const chunkIds of chunkedIds) {
42
+ const destroyInfo = await models.AcNotification.unscoped().destroy({
43
+ where: {
44
+ id: {
45
+ [models.Sequelize.Op.in]: chunkIds,
46
+ },
47
+ },
48
+ });
49
+ numberOfDeletedNotifications += destroyInfo;
50
+ console.log(`Total deleted so far: ${numberOfDeletedNotifications}`);
51
+ await sleep(10); // short pause
52
+ // Stop if we’ve hit our daily (or run) limit
53
+ if (numberOfDeletedNotifications >= maxNumberOfNotificationsToDelete) {
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ else {
59
+ // No more notifications to delete
60
+ haveNotificationsToDelete = false;
61
+ }
62
+ await sleep(25); // short pause between big fetches
63
+ }
64
+ catch (error) {
65
+ console.error(error);
66
+ haveNotificationsToDelete = false;
67
+ }
68
+ }
69
+ console.log(`${numberOfDeletedNotifications} old notifications deleted`);
70
+ console.log(`Duration: ${moment(moment() - startTime).format('HH:mm:ss.SSS')}`);
71
+ process.exit();
72
+ })();
@@ -68,6 +68,10 @@ var generateSitemap = async function (req, res) {
68
68
  })
69
69
  .then(function (communities) {
70
70
  _.forEach(communities, function (community) {
71
+ if (!community) {
72
+ console.error("No community found in sitemap generation");
73
+ return;
74
+ }
71
75
  const path = "/community/" + community.id;
72
76
  if (community.hostname &&
73
77
  wildCardDomainNames.indexOf(domainName) > -1) {
@@ -134,6 +138,10 @@ var generateSitemap = async function (req, res) {
134
138
  })
135
139
  .then(function (groups) {
136
140
  _.forEach(groups, function (group) {
141
+ if (!group) {
142
+ console.error("No group found in sitemap generation");
143
+ return;
144
+ }
137
145
  const path = "/group/" + group.id;
138
146
  if (group.Community.hostname &&
139
147
  wildCardDomainNames.indexOf(domainName) > -1) {
@@ -217,6 +225,10 @@ var generateSitemap = async function (req, res) {
217
225
  })
218
226
  .then(function (posts) {
219
227
  _.forEach(posts, function (post) {
228
+ if (!post) {
229
+ console.error("No post found in sitemap generation");
230
+ return;
231
+ }
220
232
  links.push({ url: "/post/" + post.id });
221
233
  });
222
234
  seriesCallback();