strapi-plugin-magic-mail 2.2.4 → 2.2.6

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 (71) hide show
  1. package/README.md +0 -2
  2. package/dist/server/index.js +1 -1
  3. package/dist/server/index.mjs +1 -1
  4. package/package.json +1 -3
  5. package/admin/jsconfig.json +0 -10
  6. package/admin/src/components/AddAccountModal.jsx +0 -1943
  7. package/admin/src/components/Initializer.jsx +0 -14
  8. package/admin/src/components/LicenseGuard.jsx +0 -475
  9. package/admin/src/components/PluginIcon.jsx +0 -5
  10. package/admin/src/hooks/useAuthRefresh.js +0 -44
  11. package/admin/src/hooks/useLicense.js +0 -158
  12. package/admin/src/index.js +0 -87
  13. package/admin/src/pages/Analytics.jsx +0 -762
  14. package/admin/src/pages/App.jsx +0 -111
  15. package/admin/src/pages/EmailDesigner/EditorPage.jsx +0 -1424
  16. package/admin/src/pages/EmailDesigner/TemplateList.jsx +0 -1807
  17. package/admin/src/pages/HomePage.jsx +0 -1170
  18. package/admin/src/pages/LicensePage.jsx +0 -430
  19. package/admin/src/pages/RoutingRules.jsx +0 -1141
  20. package/admin/src/pages/Settings.jsx +0 -603
  21. package/admin/src/pluginId.js +0 -3
  22. package/admin/src/translations/de.json +0 -71
  23. package/admin/src/translations/en.json +0 -70
  24. package/admin/src/translations/es.json +0 -71
  25. package/admin/src/translations/fr.json +0 -71
  26. package/admin/src/translations/pt.json +0 -71
  27. package/admin/src/utils/fetchWithRetry.js +0 -123
  28. package/admin/src/utils/getTranslation.js +0 -5
  29. package/admin/src/utils/theme.js +0 -85
  30. package/server/jsconfig.json +0 -10
  31. package/server/src/bootstrap.js +0 -157
  32. package/server/src/config/features.js +0 -260
  33. package/server/src/config/index.js +0 -9
  34. package/server/src/content-types/email-account/schema.json +0 -93
  35. package/server/src/content-types/email-event/index.js +0 -8
  36. package/server/src/content-types/email-event/schema.json +0 -57
  37. package/server/src/content-types/email-link/index.js +0 -8
  38. package/server/src/content-types/email-link/schema.json +0 -49
  39. package/server/src/content-types/email-log/index.js +0 -8
  40. package/server/src/content-types/email-log/schema.json +0 -106
  41. package/server/src/content-types/email-template/schema.json +0 -74
  42. package/server/src/content-types/email-template-version/schema.json +0 -60
  43. package/server/src/content-types/index.js +0 -33
  44. package/server/src/content-types/routing-rule/schema.json +0 -59
  45. package/server/src/controllers/accounts.js +0 -229
  46. package/server/src/controllers/analytics.js +0 -361
  47. package/server/src/controllers/controller.js +0 -26
  48. package/server/src/controllers/email-designer.js +0 -474
  49. package/server/src/controllers/index.js +0 -21
  50. package/server/src/controllers/license.js +0 -269
  51. package/server/src/controllers/oauth.js +0 -474
  52. package/server/src/controllers/routing-rules.js +0 -129
  53. package/server/src/controllers/test.js +0 -301
  54. package/server/src/destroy.js +0 -27
  55. package/server/src/index.js +0 -25
  56. package/server/src/middlewares/index.js +0 -3
  57. package/server/src/policies/index.js +0 -3
  58. package/server/src/register.js +0 -5
  59. package/server/src/routes/admin.js +0 -469
  60. package/server/src/routes/content-api.js +0 -37
  61. package/server/src/routes/index.js +0 -9
  62. package/server/src/services/account-manager.js +0 -329
  63. package/server/src/services/analytics.js +0 -512
  64. package/server/src/services/email-designer.js +0 -717
  65. package/server/src/services/email-router.js +0 -1446
  66. package/server/src/services/index.js +0 -17
  67. package/server/src/services/license-guard.js +0 -423
  68. package/server/src/services/oauth.js +0 -515
  69. package/server/src/services/service.js +0 -7
  70. package/server/src/utils/encryption.js +0 -81
  71. package/server/src/utils/logger.js +0 -84
@@ -1,361 +0,0 @@
1
- /**
2
- * Analytics Controller
3
- * Handles tracking endpoints and analytics API
4
- * [SUCCESS] Migrated to strapi.documents() API (Strapi v5 Best Practice)
5
- */
6
-
7
- 'use strict';
8
-
9
- const EMAIL_LOG_UID = 'plugin::magic-mail.email-log';
10
- const EMAIL_EVENT_UID = 'plugin::magic-mail.email-event';
11
- const EMAIL_ACCOUNT_UID = 'plugin::magic-mail.email-account';
12
-
13
- module.exports = ({ strapi }) => ({
14
- /**
15
- * Tracking pixel endpoint
16
- * GET /magic-mail/track/open/:emailId/:recipientHash
17
- */
18
- async trackOpen(ctx) {
19
- const { emailId, recipientHash } = ctx.params;
20
-
21
- // Record the open event
22
- await strapi.plugin('magic-mail').service('analytics').recordOpen(emailId, recipientHash, ctx.request);
23
-
24
- // Return 1x1 transparent GIF
25
- const pixel = Buffer.from(
26
- 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
27
- 'base64'
28
- );
29
-
30
- ctx.type = 'image/gif';
31
- ctx.body = pixel;
32
- },
33
-
34
- /**
35
- * Click tracking endpoint
36
- * GET /magic-mail/track/click/:emailId/:linkHash/:recipientHash
37
- */
38
- async trackClick(ctx) {
39
- const { emailId, linkHash, recipientHash } = ctx.params;
40
- let { url } = ctx.query;
41
-
42
- // Try to get URL from database if not in query string
43
- if (!url) {
44
- const analyticsService = strapi.plugin('magic-mail').service('analytics');
45
- url = await analyticsService.getOriginalUrlFromHash(emailId, linkHash);
46
- }
47
-
48
- if (!url) {
49
- return ctx.badRequest('Missing target URL');
50
- }
51
-
52
- // Record the click event
53
- await strapi
54
- .plugin('magic-mail')
55
- .service('analytics')
56
- .recordClick(emailId, linkHash, recipientHash, url, ctx.request);
57
-
58
- // Redirect to the original URL
59
- ctx.redirect(url);
60
- },
61
-
62
- /**
63
- * Get analytics statistics
64
- * GET /magic-mail/analytics/stats
65
- */
66
- async getStats(ctx) {
67
- try {
68
- const filters = {
69
- // userId is documentId (string) in Strapi v5, NOT parseInt!
70
- userId: ctx.query.userId || null,
71
- templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
72
- accountId: ctx.query.accountId ? parseInt(ctx.query.accountId) : null,
73
- dateFrom: ctx.query.dateFrom || null,
74
- dateTo: ctx.query.dateTo || null,
75
- };
76
-
77
- // Remove null values
78
- Object.keys(filters).forEach(key => filters[key] === null && delete filters[key]);
79
-
80
- const stats = await strapi.plugin('magic-mail').service('analytics').getStats(filters);
81
-
82
- return ctx.send({
83
- success: true,
84
- data: stats,
85
- });
86
- } catch (error) {
87
- ctx.throw(500, error);
88
- }
89
- },
90
-
91
- /**
92
- * Get email logs
93
- * GET /magic-mail/analytics/emails
94
- */
95
- async getEmailLogs(ctx) {
96
- try {
97
- const filters = {
98
- // userId is documentId (string) in Strapi v5, NOT parseInt!
99
- userId: ctx.query.userId || null,
100
- templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
101
- search: ctx.query.search || null,
102
- };
103
-
104
- const pagination = {
105
- page: ctx.query.page ? parseInt(ctx.query.page) : 1,
106
- pageSize: ctx.query.pageSize ? parseInt(ctx.query.pageSize) : 25,
107
- };
108
-
109
- // Remove null values
110
- Object.keys(filters).forEach(key => filters[key] === null && delete filters[key]);
111
-
112
- const result = await strapi
113
- .plugin('magic-mail')
114
- .service('analytics')
115
- .getEmailLogs(filters, pagination);
116
-
117
- return ctx.send({
118
- success: true,
119
- ...result,
120
- });
121
- } catch (error) {
122
- ctx.throw(500, error);
123
- }
124
- },
125
-
126
- /**
127
- * Get email log details
128
- * GET /magic-mail/analytics/emails/:emailId
129
- */
130
- async getEmailDetails(ctx) {
131
- try {
132
- const { emailId } = ctx.params;
133
-
134
- const emailLog = await strapi
135
- .plugin('magic-mail')
136
- .service('analytics')
137
- .getEmailLogDetails(emailId);
138
-
139
- if (!emailLog) {
140
- return ctx.notFound('Email log not found');
141
- }
142
-
143
- return ctx.send({
144
- success: true,
145
- data: emailLog,
146
- });
147
- } catch (error) {
148
- ctx.throw(500, error);
149
- }
150
- },
151
-
152
- /**
153
- * Get user email activity
154
- * GET /magic-mail/analytics/users/:userId
155
- * Note: userId is documentId (string) in Strapi v5
156
- */
157
- async getUserActivity(ctx) {
158
- try {
159
- const { userId } = ctx.params;
160
-
161
- // userId is documentId (string) in Strapi v5, NOT parseInt!
162
- const activity = await strapi
163
- .plugin('magic-mail')
164
- .service('analytics')
165
- .getUserActivity(userId);
166
-
167
- return ctx.send({
168
- success: true,
169
- data: activity,
170
- });
171
- } catch (error) {
172
- ctx.throw(500, error);
173
- }
174
- },
175
-
176
- /**
177
- * Debug Analytics - Check database state
178
- * GET /magic-mail/analytics/debug
179
- */
180
- async debug(ctx) {
181
- try {
182
- strapi.log.info('[magic-mail] [CHECK] Running Analytics Debug...');
183
-
184
- // Get email logs using Document Service
185
- const emailLogs = await strapi.documents(EMAIL_LOG_UID).findMany({
186
- limit: 10,
187
- sort: [{ sentAt: 'desc' }],
188
- });
189
-
190
- // Get email events using Document Service
191
- const emailEvents = await strapi.documents(EMAIL_EVENT_UID).findMany({
192
- limit: 20,
193
- sort: [{ timestamp: 'desc' }],
194
- populate: ['emailLog'],
195
- });
196
-
197
- // Get stats
198
- const analyticsService = strapi.plugin('magic-mail').service('analytics');
199
- const stats = await analyticsService.getStats();
200
-
201
- // Get active accounts using Document Service
202
- const accounts = await strapi.documents(EMAIL_ACCOUNT_UID).findMany({
203
- filters: { isActive: true },
204
- fields: ['id', 'name', 'provider', 'fromEmail', 'emailsSentToday', 'totalEmailsSent'],
205
- });
206
-
207
- // Generate sample tracking URLs
208
- let sampleTrackingUrls = null;
209
- if (emailLogs.length > 0) {
210
- const testLog = emailLogs[0];
211
- const testHash = analyticsService.generateRecipientHash(testLog.emailId, testLog.recipient);
212
-
213
- const baseUrl = strapi.config.get('server.url') || 'http://localhost:1337';
214
- sampleTrackingUrls = {
215
- trackingPixel: `${baseUrl}/api/magic-mail/track/open/${testLog.emailId}/${testHash}`,
216
- clickTracking: `${baseUrl}/api/magic-mail/track/click/${testLog.emailId}/test/${testHash}?url=https://example.com`,
217
- emailId: testLog.emailId,
218
- recipient: testLog.recipient,
219
- };
220
- }
221
-
222
- return ctx.send({
223
- success: true,
224
- debug: {
225
- timestamp: new Date().toISOString(),
226
- stats,
227
- emailLogsCount: emailLogs.length,
228
- emailEventsCount: emailEvents.length,
229
- activeAccountsCount: accounts.length,
230
- recentEmailLogs: emailLogs.map(log => ({
231
- emailId: log.emailId,
232
- recipient: log.recipient,
233
- subject: log.subject,
234
- sentAt: log.sentAt,
235
- openCount: log.openCount,
236
- clickCount: log.clickCount,
237
- firstOpenedAt: log.firstOpenedAt,
238
- accountName: log.accountName,
239
- templateName: log.templateName,
240
- })),
241
- recentEvents: emailEvents.map(event => ({
242
- type: event.type,
243
- timestamp: event.timestamp,
244
- emailId: event.emailLog?.emailId,
245
- ipAddress: event.ipAddress,
246
- linkUrl: event.linkUrl,
247
- })),
248
- accounts,
249
- sampleTrackingUrls,
250
- notes: [
251
- 'If emailLogsCount is 0: Emails are not being tracked (check if enableTracking=true)',
252
- 'If openCount is 0: Tracking pixel not being loaded (check email HTML source)',
253
- 'Test tracking URLs should be publicly accessible without authentication',
254
- 'Check Strapi console logs for tracking events when opening emails',
255
- ],
256
- },
257
- });
258
- } catch (error) {
259
- strapi.log.error('[magic-mail] Debug error:', error);
260
- ctx.throw(500, error);
261
- }
262
- },
263
-
264
- /**
265
- * Delete single email log
266
- * DELETE /magic-mail/analytics/emails/:emailId
267
- */
268
- async deleteEmailLog(ctx) {
269
- try {
270
- const { emailId } = ctx.params;
271
-
272
- // Find email log using Document Service
273
- const emailLog = await strapi.documents(EMAIL_LOG_UID).findFirst({
274
- filters: { emailId },
275
- });
276
-
277
- if (!emailLog) {
278
- return ctx.notFound('Email log not found');
279
- }
280
-
281
- // Delete associated events - filter relation with documentId object (Strapi v5)
282
- const events = await strapi.documents(EMAIL_EVENT_UID).findMany({
283
- filters: { emailLog: { documentId: emailLog.documentId } },
284
- });
285
-
286
- for (const event of events) {
287
- await strapi.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
288
- }
289
-
290
- // Delete email log
291
- await strapi.documents(EMAIL_LOG_UID).delete({ documentId: emailLog.documentId });
292
-
293
- strapi.log.info(`[magic-mail] [DELETE] Deleted email log: ${emailId}`);
294
-
295
- return ctx.send({
296
- success: true,
297
- message: 'Email log deleted successfully',
298
- });
299
- } catch (error) {
300
- strapi.log.error('[magic-mail] Error deleting email log:', error);
301
- ctx.throw(500, error);
302
- }
303
- },
304
-
305
- /**
306
- * Clear all email logs
307
- * DELETE /magic-mail/analytics/emails
308
- */
309
- async clearAllEmailLogs(ctx) {
310
- try {
311
- // Optional: Add query params for filtered deletion
312
- const { olderThan } = ctx.query; // e.g., ?olderThan=2024-01-01
313
-
314
- const filters = {};
315
- if (olderThan) {
316
- filters.sentAt = { $lt: new Date(olderThan) };
317
- }
318
-
319
- // Get all email logs to delete using Document Service
320
- const emailLogs = await strapi.documents(EMAIL_LOG_UID).findMany({
321
- filters,
322
- fields: ['id', 'documentId'],
323
- limit: 100000,
324
- });
325
-
326
- if (emailLogs.length === 0) {
327
- return ctx.send({
328
- success: true,
329
- message: 'No email logs to delete',
330
- deletedCount: 0,
331
- });
332
- }
333
-
334
- // Delete all associated events and logs
335
- for (const log of emailLogs) {
336
- // Delete events for this log - filter relation with documentId object (Strapi v5)
337
- const events = await strapi.documents(EMAIL_EVENT_UID).findMany({
338
- filters: { emailLog: { documentId: log.documentId } },
339
- });
340
-
341
- for (const event of events) {
342
- await strapi.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
343
- }
344
-
345
- // Delete the log itself
346
- await strapi.documents(EMAIL_LOG_UID).delete({ documentId: log.documentId });
347
- }
348
-
349
- strapi.log.info(`[magic-mail] [DELETE] Cleared ${emailLogs.length} email logs`);
350
-
351
- return ctx.send({
352
- success: true,
353
- message: `Successfully deleted ${emailLogs.length} email log(s)`,
354
- deletedCount: emailLogs.length,
355
- });
356
- } catch (error) {
357
- strapi.log.error('[magic-mail] Error clearing email logs:', error);
358
- ctx.throw(500, error);
359
- }
360
- },
361
- });
@@ -1,26 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Main Controller
5
- * Handles email sending requests
6
- */
7
-
8
- module.exports = {
9
- /**
10
- * Send email via MagicMail router
11
- */
12
- async send(ctx) {
13
- try {
14
- const emailRouter = strapi.plugin('magic-mail').service('email-router');
15
- const result = await emailRouter.send(ctx.request.body);
16
-
17
- ctx.body = {
18
- success: true,
19
- ...result,
20
- };
21
- } catch (err) {
22
- strapi.log.error('[magic-mail] Error sending email:', err);
23
- ctx.throw(500, err.message || 'Failed to send email');
24
- }
25
- },
26
- };