strapi-plugin-magic-mail 2.0.1 → 2.0.3
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/README.md +6 -5
- package/dist/server/index.js +602 -665
- package/dist/server/index.mjs +602 -665
- package/package.json +1 -1
- package/server/src/bootstrap.js +16 -16
- package/server/src/config/features.js +7 -7
- package/server/src/controllers/accounts.js +15 -6
- package/server/src/controllers/analytics.js +56 -42
- package/server/src/controllers/license.js +9 -7
- package/server/src/controllers/oauth.js +9 -9
- package/server/src/controllers/routing-rules.js +18 -11
- package/server/src/controllers/test.js +111 -193
- package/server/src/services/account-manager.js +73 -21
- package/server/src/services/analytics.js +88 -72
- package/server/src/services/email-designer.js +131 -284
- package/server/src/services/email-router.js +69 -43
- package/server/src/services/license-guard.js +24 -24
- package/server/src/services/oauth.js +11 -11
- package/server/src/services/service.js +1 -1
- package/server/src/utils/encryption.js +1 -1
package/package.json
CHANGED
package/server/src/bootstrap.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
module.exports = async ({ strapi }) => {
|
|
10
|
-
strapi.log.info('
|
|
10
|
+
strapi.log.info('[BOOTSTRAP] [magic-mail] Starting...');
|
|
11
11
|
|
|
12
12
|
try {
|
|
13
13
|
// Initialize License Guard
|
|
@@ -19,7 +19,7 @@ module.exports = async ({ strapi }) => {
|
|
|
19
19
|
|
|
20
20
|
if (!licenseStatus.valid && licenseStatus.demo) {
|
|
21
21
|
strapi.log.error('╔════════════════════════════════════════════════════════════════╗');
|
|
22
|
-
strapi.log.error('║
|
|
22
|
+
strapi.log.error('║ [ERROR] MAGICMAIL - NO VALID LICENSE ║');
|
|
23
23
|
strapi.log.error('║ ║');
|
|
24
24
|
strapi.log.error('║ This plugin requires a valid license to operate. ║');
|
|
25
25
|
strapi.log.error('║ Please activate your license via Admin UI: ║');
|
|
@@ -28,7 +28,7 @@ module.exports = async ({ strapi }) => {
|
|
|
28
28
|
strapi.log.error('║ Click "Generate Free License" to get started! ║');
|
|
29
29
|
strapi.log.error('╚════════════════════════════════════════════════════════════════╝');
|
|
30
30
|
} else if (licenseStatus.gracePeriod) {
|
|
31
|
-
strapi.log.warn('
|
|
31
|
+
strapi.log.warn('[WARNING] Running on grace period (license server unreachable)');
|
|
32
32
|
}
|
|
33
33
|
// No additional log here, as initialize() already outputs the license box
|
|
34
34
|
}, 2000);
|
|
@@ -49,7 +49,7 @@ module.exports = async ({ strapi }) => {
|
|
|
49
49
|
|
|
50
50
|
// Override the send method
|
|
51
51
|
originalEmailService.send = async (emailData) => {
|
|
52
|
-
strapi.log.info('[magic-mail]
|
|
52
|
+
strapi.log.info('[magic-mail] [EMAIL] Intercepted from native Strapi service');
|
|
53
53
|
strapi.log.debug('[magic-mail] Email data:', {
|
|
54
54
|
to: emailData.to,
|
|
55
55
|
subject: emailData.subject,
|
|
@@ -67,10 +67,10 @@ module.exports = async ({ strapi }) => {
|
|
|
67
67
|
// Route through MagicMail
|
|
68
68
|
const result = await emailRouter.send(emailData);
|
|
69
69
|
|
|
70
|
-
strapi.log.info('[magic-mail]
|
|
70
|
+
strapi.log.info('[magic-mail] [SUCCESS] Email routed successfully through MagicMail');
|
|
71
71
|
return result;
|
|
72
72
|
} catch (magicMailError) {
|
|
73
|
-
strapi.log.warn('[magic-mail]
|
|
73
|
+
strapi.log.warn('[magic-mail] [WARNING] MagicMail routing failed, falling back to original service');
|
|
74
74
|
strapi.log.error('[magic-mail] Error:', magicMailError.message);
|
|
75
75
|
|
|
76
76
|
// Fallback to original Strapi email service
|
|
@@ -78,11 +78,11 @@ module.exports = async ({ strapi }) => {
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
strapi.log.info('[magic-mail]
|
|
82
|
-
strapi.log.info('[magic-mail]
|
|
81
|
+
strapi.log.info('[magic-mail] [SUCCESS] Native email service overridden!');
|
|
82
|
+
strapi.log.info('[magic-mail] [INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail');
|
|
83
83
|
} else {
|
|
84
|
-
strapi.log.warn('[magic-mail]
|
|
85
|
-
strapi.log.warn('[magic-mail]
|
|
84
|
+
strapi.log.warn('[magic-mail] [WARNING] Native email service not found - MagicMail will work standalone');
|
|
85
|
+
strapi.log.warn('[magic-mail] [INFO] Make sure @strapi/plugin-email is installed');
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// ============================================================
|
|
@@ -98,7 +98,7 @@ module.exports = async ({ strapi }) => {
|
|
|
98
98
|
}
|
|
99
99
|
const accountMgr = strapi.plugin('magic-mail').service('account-manager');
|
|
100
100
|
await accountMgr.resetCounters('hourly');
|
|
101
|
-
strapi.log.info('[magic-mail]
|
|
101
|
+
strapi.log.info('[magic-mail] [RESET] Hourly counters reset');
|
|
102
102
|
} catch (err) {
|
|
103
103
|
console.error('[magic-mail] Hourly reset error:', err.message);
|
|
104
104
|
}
|
|
@@ -121,7 +121,7 @@ module.exports = async ({ strapi }) => {
|
|
|
121
121
|
}
|
|
122
122
|
const accountMgr = strapi.plugin('magic-mail').service('account-manager');
|
|
123
123
|
await accountMgr.resetCounters('daily');
|
|
124
|
-
strapi.log.info('[magic-mail]
|
|
124
|
+
strapi.log.info('[magic-mail] [RESET] Daily counters reset');
|
|
125
125
|
|
|
126
126
|
// Then set daily interval
|
|
127
127
|
const dailyResetInterval = setInterval(async () => {
|
|
@@ -132,7 +132,7 @@ module.exports = async ({ strapi }) => {
|
|
|
132
132
|
}
|
|
133
133
|
const accountMgr = strapi.plugin('magic-mail').service('account-manager');
|
|
134
134
|
await accountMgr.resetCounters('daily');
|
|
135
|
-
strapi.log.info('[magic-mail]
|
|
135
|
+
strapi.log.info('[magic-mail] [RESET] Daily counters reset');
|
|
136
136
|
} catch (err) {
|
|
137
137
|
console.error('[magic-mail] Daily reset error:', err.message);
|
|
138
138
|
}
|
|
@@ -145,9 +145,9 @@ module.exports = async ({ strapi }) => {
|
|
|
145
145
|
}
|
|
146
146
|
}, msUntilMidnight);
|
|
147
147
|
|
|
148
|
-
strapi.log.info('[magic-mail]
|
|
149
|
-
strapi.log.info('[magic-mail]
|
|
148
|
+
strapi.log.info('[magic-mail] [SUCCESS] Counter reset schedules initialized');
|
|
149
|
+
strapi.log.info('[magic-mail] [SUCCESS] Bootstrap complete');
|
|
150
150
|
} catch (err) {
|
|
151
|
-
strapi.log.error('[magic-mail]
|
|
151
|
+
strapi.log.error('[magic-mail] [ERROR] Bootstrap error:', err);
|
|
152
152
|
}
|
|
153
153
|
};
|
|
@@ -118,7 +118,7 @@ module.exports = {
|
|
|
118
118
|
* Check if a feature is available for given license tier
|
|
119
119
|
*/
|
|
120
120
|
hasFeature(licenseData, featureName) {
|
|
121
|
-
/** console.log(`[features.js]
|
|
121
|
+
/** console.log(`[features.js] [CHECK] hasFeature called with:`, {
|
|
122
122
|
featureName,
|
|
123
123
|
hasLicenseData: !!licenseData,
|
|
124
124
|
licenseDataKeys: licenseData ? Object.keys(licenseData) : [],
|
|
@@ -131,7 +131,7 @@ module.exports = {
|
|
|
131
131
|
});
|
|
132
132
|
*/
|
|
133
133
|
if (!licenseData) {
|
|
134
|
-
console.log(`[features.js]
|
|
134
|
+
console.log(`[features.js] [WARNING] No license data → using FREE tier`);
|
|
135
135
|
// Demo mode - only free features
|
|
136
136
|
return this.free.features.includes(featureName);
|
|
137
137
|
}
|
|
@@ -167,7 +167,7 @@ module.exports = {
|
|
|
167
167
|
isPremium = true;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
/* console.log(`[features.js]
|
|
170
|
+
/* console.log(`[features.js] [CHECK] Tier detection:`, {
|
|
171
171
|
isEnterprise,
|
|
172
172
|
isAdvanced,
|
|
173
173
|
isPremium,
|
|
@@ -182,20 +182,20 @@ module.exports = {
|
|
|
182
182
|
*/
|
|
183
183
|
// Check tiers in order: enterprise > advanced > premium > free
|
|
184
184
|
if (isEnterprise && this.enterprise.features.includes(featureName)) {
|
|
185
|
-
console.log(`[features.js]
|
|
185
|
+
console.log(`[features.js] [SUCCESS] ENTERPRISE tier has feature "${featureName}"`);
|
|
186
186
|
return true;
|
|
187
187
|
}
|
|
188
188
|
if (isAdvanced && this.advanced.features.includes(featureName)) {
|
|
189
|
-
console.log(`[features.js]
|
|
189
|
+
console.log(`[features.js] [SUCCESS] ADVANCED tier has feature "${featureName}"`);
|
|
190
190
|
return true;
|
|
191
191
|
}
|
|
192
192
|
if (isPremium && this.premium.features.includes(featureName)) {
|
|
193
|
-
console.log(`[features.js]
|
|
193
|
+
console.log(`[features.js] [SUCCESS] PREMIUM tier has feature "${featureName}"`);
|
|
194
194
|
return true;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
const inFree = this.free.features.includes(featureName);
|
|
198
|
-
console.log(`[features.js] ${inFree ? '
|
|
198
|
+
console.log(`[features.js] ${inFree ? '[SUCCESS]' : '[ERROR]'} FREE tier check for "${featureName}": ${inFree}`);
|
|
199
199
|
return inFree;
|
|
200
200
|
},
|
|
201
201
|
|
|
@@ -39,8 +39,8 @@ module.exports = {
|
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
// Check account limit
|
|
43
|
-
const currentAccounts = await strapi.
|
|
42
|
+
// Check account limit using Document Service count()
|
|
43
|
+
const currentAccounts = await strapi.documents('plugin::magic-mail.email-account').count();
|
|
44
44
|
const maxAccounts = await licenseGuard.getMaxAccounts();
|
|
45
45
|
|
|
46
46
|
if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
|
|
@@ -135,9 +135,9 @@ module.exports = {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
strapi.log.info('[magic-mail] 🧪 Testing Strapi Email Service integration...');
|
|
138
|
-
strapi.log.info('[magic-mail]
|
|
138
|
+
strapi.log.info('[magic-mail] [EMAIL] Calling strapi.plugin("email").service("email").send()');
|
|
139
139
|
if (accountName) {
|
|
140
|
-
strapi.log.info(`[magic-mail]
|
|
140
|
+
strapi.log.info(`[magic-mail] [FORCE] Forcing specific account: ${accountName}`);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// Call native Strapi email service - should be intercepted by MagicMail!
|
|
@@ -166,6 +166,15 @@ module.exports = {
|
|
|
166
166
|
<li>Statistics tracking</li>
|
|
167
167
|
</ul>
|
|
168
168
|
</div>
|
|
169
|
+
<div style="background: #DCFCE7; border: 1px solid #22C55E; border-radius: 8px; padding: 15px; margin: 20px 0;">
|
|
170
|
+
<h3 style="margin-top: 0; color: #15803D;">Security Features Active</h3>
|
|
171
|
+
<ul style="margin: 10px 0; padding-left: 20px;">
|
|
172
|
+
<li>TLS/SSL Encryption enforced</li>
|
|
173
|
+
<li>Email content validated</li>
|
|
174
|
+
<li>Proper headers included</li>
|
|
175
|
+
<li>Message-ID generated</li>
|
|
176
|
+
</ul>
|
|
177
|
+
</div>
|
|
169
178
|
<p style="color: #6B7280; font-size: 14px; margin-top: 30px;">
|
|
170
179
|
Sent at: ${new Date().toLocaleString()}<br>
|
|
171
180
|
Via: MagicMail Email Router
|
|
@@ -176,7 +185,7 @@ module.exports = {
|
|
|
176
185
|
accountName: accountName || null, // Force specific account if provided
|
|
177
186
|
});
|
|
178
187
|
|
|
179
|
-
strapi.log.info('[magic-mail]
|
|
188
|
+
strapi.log.info('[magic-mail] [SUCCESS] Strapi Email Service test completed');
|
|
180
189
|
|
|
181
190
|
ctx.body = {
|
|
182
191
|
success: true,
|
|
@@ -189,7 +198,7 @@ module.exports = {
|
|
|
189
198
|
},
|
|
190
199
|
};
|
|
191
200
|
} catch (err) {
|
|
192
|
-
strapi.log.error('[magic-mail]
|
|
201
|
+
strapi.log.error('[magic-mail] [ERROR] Strapi Email Service test failed:', err);
|
|
193
202
|
ctx.body = {
|
|
194
203
|
success: false,
|
|
195
204
|
message: 'Failed to send test email',
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Analytics Controller
|
|
3
3
|
* Handles tracking endpoints and analytics API
|
|
4
|
+
* [SUCCESS] Migrated to strapi.documents() API (Strapi v5 Best Practice)
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
'use strict';
|
|
7
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
|
+
|
|
8
13
|
module.exports = ({ strapi }) => ({
|
|
9
14
|
/**
|
|
10
15
|
* Tracking pixel endpoint
|
|
@@ -61,7 +66,8 @@ module.exports = ({ strapi }) => ({
|
|
|
61
66
|
async getStats(ctx) {
|
|
62
67
|
try {
|
|
63
68
|
const filters = {
|
|
64
|
-
|
|
69
|
+
// userId is documentId (string) in Strapi v5, NOT parseInt!
|
|
70
|
+
userId: ctx.query.userId || null,
|
|
65
71
|
templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
|
|
66
72
|
accountId: ctx.query.accountId ? parseInt(ctx.query.accountId) : null,
|
|
67
73
|
dateFrom: ctx.query.dateFrom || null,
|
|
@@ -89,7 +95,8 @@ module.exports = ({ strapi }) => ({
|
|
|
89
95
|
async getEmailLogs(ctx) {
|
|
90
96
|
try {
|
|
91
97
|
const filters = {
|
|
92
|
-
|
|
98
|
+
// userId is documentId (string) in Strapi v5, NOT parseInt!
|
|
99
|
+
userId: ctx.query.userId || null,
|
|
93
100
|
templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
|
|
94
101
|
search: ctx.query.search || null,
|
|
95
102
|
};
|
|
@@ -145,15 +152,17 @@ module.exports = ({ strapi }) => ({
|
|
|
145
152
|
/**
|
|
146
153
|
* Get user email activity
|
|
147
154
|
* GET /magic-mail/analytics/users/:userId
|
|
155
|
+
* Note: userId is documentId (string) in Strapi v5
|
|
148
156
|
*/
|
|
149
157
|
async getUserActivity(ctx) {
|
|
150
158
|
try {
|
|
151
159
|
const { userId } = ctx.params;
|
|
152
160
|
|
|
161
|
+
// userId is documentId (string) in Strapi v5, NOT parseInt!
|
|
153
162
|
const activity = await strapi
|
|
154
163
|
.plugin('magic-mail')
|
|
155
164
|
.service('analytics')
|
|
156
|
-
.getUserActivity(
|
|
165
|
+
.getUserActivity(userId);
|
|
157
166
|
|
|
158
167
|
return ctx.send({
|
|
159
168
|
success: true,
|
|
@@ -170,18 +179,18 @@ module.exports = ({ strapi }) => ({
|
|
|
170
179
|
*/
|
|
171
180
|
async debug(ctx) {
|
|
172
181
|
try {
|
|
173
|
-
strapi.log.info('[magic-mail]
|
|
182
|
+
strapi.log.info('[magic-mail] [CHECK] Running Analytics Debug...');
|
|
174
183
|
|
|
175
|
-
// Get email logs
|
|
176
|
-
const emailLogs = await strapi.
|
|
184
|
+
// Get email logs using Document Service
|
|
185
|
+
const emailLogs = await strapi.documents(EMAIL_LOG_UID).findMany({
|
|
177
186
|
limit: 10,
|
|
178
|
-
|
|
187
|
+
sort: [{ sentAt: 'desc' }],
|
|
179
188
|
});
|
|
180
189
|
|
|
181
|
-
// Get email events
|
|
182
|
-
const emailEvents = await strapi.
|
|
190
|
+
// Get email events using Document Service
|
|
191
|
+
const emailEvents = await strapi.documents(EMAIL_EVENT_UID).findMany({
|
|
183
192
|
limit: 20,
|
|
184
|
-
|
|
193
|
+
sort: [{ timestamp: 'desc' }],
|
|
185
194
|
populate: ['emailLog'],
|
|
186
195
|
});
|
|
187
196
|
|
|
@@ -189,8 +198,8 @@ module.exports = ({ strapi }) => ({
|
|
|
189
198
|
const analyticsService = strapi.plugin('magic-mail').service('analytics');
|
|
190
199
|
const stats = await analyticsService.getStats();
|
|
191
200
|
|
|
192
|
-
// Get active accounts
|
|
193
|
-
const accounts = await strapi.
|
|
201
|
+
// Get active accounts using Document Service
|
|
202
|
+
const accounts = await strapi.documents(EMAIL_ACCOUNT_UID).findMany({
|
|
194
203
|
filters: { isActive: true },
|
|
195
204
|
fields: ['id', 'name', 'provider', 'fromEmail', 'emailsSentToday', 'totalEmailsSent'],
|
|
196
205
|
});
|
|
@@ -260,26 +269,28 @@ module.exports = ({ strapi }) => ({
|
|
|
260
269
|
try {
|
|
261
270
|
const { emailId } = ctx.params;
|
|
262
271
|
|
|
263
|
-
// Find email log
|
|
264
|
-
const emailLog = await strapi.
|
|
265
|
-
|
|
272
|
+
// Find email log using Document Service
|
|
273
|
+
const emailLog = await strapi.documents(EMAIL_LOG_UID).findFirst({
|
|
274
|
+
filters: { emailId },
|
|
266
275
|
});
|
|
267
276
|
|
|
268
277
|
if (!emailLog) {
|
|
269
278
|
return ctx.notFound('Email log not found');
|
|
270
279
|
}
|
|
271
280
|
|
|
272
|
-
// Delete associated events
|
|
273
|
-
await strapi.
|
|
274
|
-
|
|
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 } },
|
|
275
284
|
});
|
|
276
285
|
|
|
286
|
+
for (const event of events) {
|
|
287
|
+
await strapi.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
|
|
288
|
+
}
|
|
289
|
+
|
|
277
290
|
// Delete email log
|
|
278
|
-
await strapi.
|
|
279
|
-
where: { id: emailLog.id },
|
|
280
|
-
});
|
|
291
|
+
await strapi.documents(EMAIL_LOG_UID).delete({ documentId: emailLog.documentId });
|
|
281
292
|
|
|
282
|
-
strapi.log.info(`[magic-mail]
|
|
293
|
+
strapi.log.info(`[magic-mail] [DELETE] Deleted email log: ${emailId}`);
|
|
283
294
|
|
|
284
295
|
return ctx.send({
|
|
285
296
|
success: true,
|
|
@@ -300,20 +311,19 @@ module.exports = ({ strapi }) => ({
|
|
|
300
311
|
// Optional: Add query params for filtered deletion
|
|
301
312
|
const { olderThan } = ctx.query; // e.g., ?olderThan=2024-01-01
|
|
302
313
|
|
|
303
|
-
const
|
|
314
|
+
const filters = {};
|
|
304
315
|
if (olderThan) {
|
|
305
|
-
|
|
316
|
+
filters.sentAt = { $lt: new Date(olderThan) };
|
|
306
317
|
}
|
|
307
318
|
|
|
308
|
-
// Get all email logs to delete
|
|
309
|
-
const emailLogs = await strapi.
|
|
310
|
-
|
|
311
|
-
|
|
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,
|
|
312
324
|
});
|
|
313
325
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (emailLogIds.length === 0) {
|
|
326
|
+
if (emailLogs.length === 0) {
|
|
317
327
|
return ctx.send({
|
|
318
328
|
success: true,
|
|
319
329
|
message: 'No email logs to delete',
|
|
@@ -321,22 +331,27 @@ module.exports = ({ strapi }) => ({
|
|
|
321
331
|
});
|
|
322
332
|
}
|
|
323
333
|
|
|
324
|
-
// Delete all associated events
|
|
325
|
-
|
|
326
|
-
|
|
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 } },
|
|
327
339
|
});
|
|
328
340
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
}
|
|
333
348
|
|
|
334
|
-
strapi.log.info(`[magic-mail]
|
|
349
|
+
strapi.log.info(`[magic-mail] [DELETE] Cleared ${emailLogs.length} email logs`);
|
|
335
350
|
|
|
336
351
|
return ctx.send({
|
|
337
352
|
success: true,
|
|
338
|
-
message: `Successfully deleted ${
|
|
339
|
-
deletedCount:
|
|
353
|
+
message: `Successfully deleted ${emailLogs.length} email log(s)`,
|
|
354
|
+
deletedCount: emailLogs.length,
|
|
340
355
|
});
|
|
341
356
|
} catch (error) {
|
|
342
357
|
strapi.log.error('[magic-mail] Error clearing email logs:', error);
|
|
@@ -344,4 +359,3 @@ module.exports = ({ strapi }) => ({
|
|
|
344
359
|
}
|
|
345
360
|
},
|
|
346
361
|
});
|
|
347
|
-
|
|
@@ -132,7 +132,7 @@ module.exports = ({ strapi }) => ({
|
|
|
132
132
|
const verification = await licenseGuard.verifyLicense(trimmedKey);
|
|
133
133
|
|
|
134
134
|
if (!verification.valid) {
|
|
135
|
-
strapi.log.warn(`[magic-mail]
|
|
135
|
+
strapi.log.warn(`[magic-mail] [WARNING] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
|
|
136
136
|
return ctx.badRequest('Invalid or expired license key');
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -145,7 +145,7 @@ module.exports = ({ strapi }) => ({
|
|
|
145
145
|
|
|
146
146
|
// Verify email matches
|
|
147
147
|
if (license.email.toLowerCase() !== trimmedEmail) {
|
|
148
|
-
strapi.log.warn(`[magic-mail]
|
|
148
|
+
strapi.log.warn(`[magic-mail] [WARNING] Email mismatch for license key`);
|
|
149
149
|
return ctx.badRequest('Email address does not match this license key');
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -162,7 +162,7 @@ module.exports = ({ strapi }) => ({
|
|
|
162
162
|
data: verification.data,
|
|
163
163
|
};
|
|
164
164
|
|
|
165
|
-
strapi.log.info(`[magic-mail]
|
|
165
|
+
strapi.log.info(`[magic-mail] [SUCCESS] License validated and stored`);
|
|
166
166
|
|
|
167
167
|
return ctx.send({
|
|
168
168
|
success: true,
|
|
@@ -214,10 +214,12 @@ module.exports = ({ strapi }) => ({
|
|
|
214
214
|
const maxRules = await licenseGuard.getMaxRoutingRules();
|
|
215
215
|
const maxTemplates = await licenseGuard.getMaxEmailTemplates();
|
|
216
216
|
|
|
217
|
-
// Get current counts
|
|
218
|
-
const currentAccounts = await
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
// Get current counts using Document Service count()
|
|
218
|
+
const [currentAccounts, currentRules, currentTemplates] = await Promise.all([
|
|
219
|
+
strapi.documents('plugin::magic-mail.email-account').count(),
|
|
220
|
+
strapi.documents('plugin::magic-mail.routing-rule').count(),
|
|
221
|
+
strapi.documents('plugin::magic-mail.email-template').count(),
|
|
222
|
+
]);
|
|
221
223
|
|
|
222
224
|
// Get tier info - check both formats
|
|
223
225
|
let tier = 'free';
|
|
@@ -56,7 +56,7 @@ module.exports = {
|
|
|
56
56
|
</style>
|
|
57
57
|
</head>
|
|
58
58
|
<body>
|
|
59
|
-
<div class="error"
|
|
59
|
+
<div class="error">[ERROR] OAuth Authorization Failed</div>
|
|
60
60
|
<p>Error: ${error}</p>
|
|
61
61
|
<p>You can close this window and try again.</p>
|
|
62
62
|
<script>
|
|
@@ -93,7 +93,7 @@ module.exports = {
|
|
|
93
93
|
</style>
|
|
94
94
|
</head>
|
|
95
95
|
<body>
|
|
96
|
-
<div class="success"
|
|
96
|
+
<div class="success">[SUCCESS]</div>
|
|
97
97
|
<div class="message">Gmail OAuth Authorized!</div>
|
|
98
98
|
<div class="note">Closing window...</div>
|
|
99
99
|
<script>
|
|
@@ -177,7 +177,7 @@ module.exports = {
|
|
|
177
177
|
</style>
|
|
178
178
|
</head>
|
|
179
179
|
<body>
|
|
180
|
-
<div class="error"
|
|
180
|
+
<div class="error">[ERROR] OAuth Authorization Failed</div>
|
|
181
181
|
<p>Error: ${error}</p>
|
|
182
182
|
<p>You can close this window and try again.</p>
|
|
183
183
|
<script>
|
|
@@ -214,7 +214,7 @@ module.exports = {
|
|
|
214
214
|
</style>
|
|
215
215
|
</head>
|
|
216
216
|
<body>
|
|
217
|
-
<div class="success"
|
|
217
|
+
<div class="success">[SUCCESS]</div>
|
|
218
218
|
<div class="message">Microsoft OAuth Authorized!</div>
|
|
219
219
|
<div class="note">Closing window...</div>
|
|
220
220
|
<script>
|
|
@@ -293,7 +293,7 @@ module.exports = {
|
|
|
293
293
|
</style>
|
|
294
294
|
</head>
|
|
295
295
|
<body>
|
|
296
|
-
<div class="error"
|
|
296
|
+
<div class="error">[ERROR] OAuth Authorization Failed</div>
|
|
297
297
|
<p>Error: ${error}</p>
|
|
298
298
|
<p>You can close this window and try again.</p>
|
|
299
299
|
<script>
|
|
@@ -330,7 +330,7 @@ module.exports = {
|
|
|
330
330
|
</style>
|
|
331
331
|
</head>
|
|
332
332
|
<body>
|
|
333
|
-
<div class="success"
|
|
333
|
+
<div class="success">[SUCCESS]</div>
|
|
334
334
|
<div class="message">Yahoo Mail OAuth Authorized!</div>
|
|
335
335
|
<div class="note">Closing window...</div>
|
|
336
336
|
<script>
|
|
@@ -388,8 +388,8 @@ module.exports = {
|
|
|
388
388
|
return;
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
// Check account limit
|
|
392
|
-
const currentAccounts = await strapi.
|
|
391
|
+
// Check account limit using Document Service count()
|
|
392
|
+
const currentAccounts = await strapi.documents('plugin::magic-mail.email-account').count();
|
|
393
393
|
const maxAccounts = await licenseGuard.getMaxAccounts();
|
|
394
394
|
|
|
395
395
|
if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
|
|
@@ -457,7 +457,7 @@ module.exports = {
|
|
|
457
457
|
accountDetails.config // contains clientId and clientSecret
|
|
458
458
|
);
|
|
459
459
|
|
|
460
|
-
strapi.log.info('[magic-mail]
|
|
460
|
+
strapi.log.info('[magic-mail] [SUCCESS] OAuth account created successfully');
|
|
461
461
|
|
|
462
462
|
ctx.body = {
|
|
463
463
|
success: true,
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Routing Rules Controller
|
|
5
5
|
* Manages email routing rules CRUD operations
|
|
6
|
+
* [SUCCESS] Migrated to strapi.documents() API (Strapi v5 Best Practice)
|
|
6
7
|
*/
|
|
7
8
|
|
|
9
|
+
const ROUTING_RULE_UID = 'plugin::magic-mail.routing-rule';
|
|
10
|
+
|
|
8
11
|
module.exports = {
|
|
9
12
|
/**
|
|
10
13
|
* Get all routing rules
|
|
11
14
|
*/
|
|
12
15
|
async getAll(ctx) {
|
|
13
16
|
try {
|
|
14
|
-
const rules = await strapi.
|
|
15
|
-
sort: { priority: 'desc' },
|
|
17
|
+
const rules = await strapi.documents(ROUTING_RULE_UID).findMany({
|
|
18
|
+
sort: [{ priority: 'desc' }],
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
ctx.body = {
|
|
@@ -31,7 +34,9 @@ module.exports = {
|
|
|
31
34
|
async getOne(ctx) {
|
|
32
35
|
try {
|
|
33
36
|
const { ruleId } = ctx.params;
|
|
34
|
-
const rule = await strapi.
|
|
37
|
+
const rule = await strapi.documents(ROUTING_RULE_UID).findOne({
|
|
38
|
+
documentId: ruleId,
|
|
39
|
+
});
|
|
35
40
|
|
|
36
41
|
if (!rule) {
|
|
37
42
|
ctx.throw(404, 'Routing rule not found');
|
|
@@ -53,8 +58,8 @@ module.exports = {
|
|
|
53
58
|
try {
|
|
54
59
|
const licenseGuard = strapi.plugin('magic-mail').service('license-guard');
|
|
55
60
|
|
|
56
|
-
// Check routing rule limit
|
|
57
|
-
const currentRules = await strapi.
|
|
61
|
+
// Check routing rule limit using Document Service count()
|
|
62
|
+
const currentRules = await strapi.documents(ROUTING_RULE_UID).count();
|
|
58
63
|
const maxRules = await licenseGuard.getMaxRoutingRules();
|
|
59
64
|
|
|
60
65
|
if (maxRules !== -1 && currentRules >= maxRules) {
|
|
@@ -62,7 +67,7 @@ module.exports = {
|
|
|
62
67
|
return;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
const rule = await strapi.
|
|
70
|
+
const rule = await strapi.documents(ROUTING_RULE_UID).create({
|
|
66
71
|
data: ctx.request.body,
|
|
67
72
|
});
|
|
68
73
|
|
|
@@ -71,7 +76,7 @@ module.exports = {
|
|
|
71
76
|
message: 'Routing rule created successfully',
|
|
72
77
|
};
|
|
73
78
|
|
|
74
|
-
strapi.log.info(`[magic-mail]
|
|
79
|
+
strapi.log.info(`[magic-mail] [SUCCESS] Routing rule created: ${rule.name}`);
|
|
75
80
|
} catch (err) {
|
|
76
81
|
strapi.log.error('[magic-mail] Error creating routing rule:', err);
|
|
77
82
|
ctx.throw(err.status || 500, err.message || 'Error creating routing rule');
|
|
@@ -84,7 +89,8 @@ module.exports = {
|
|
|
84
89
|
async update(ctx) {
|
|
85
90
|
try {
|
|
86
91
|
const { ruleId } = ctx.params;
|
|
87
|
-
const rule = await strapi.
|
|
92
|
+
const rule = await strapi.documents(ROUTING_RULE_UID).update({
|
|
93
|
+
documentId: ruleId,
|
|
88
94
|
data: ctx.request.body,
|
|
89
95
|
});
|
|
90
96
|
|
|
@@ -93,7 +99,7 @@ module.exports = {
|
|
|
93
99
|
message: 'Routing rule updated successfully',
|
|
94
100
|
};
|
|
95
101
|
|
|
96
|
-
strapi.log.info(`[magic-mail]
|
|
102
|
+
strapi.log.info(`[magic-mail] [SUCCESS] Routing rule updated: ${rule.name}`);
|
|
97
103
|
} catch (err) {
|
|
98
104
|
strapi.log.error('[magic-mail] Error updating routing rule:', err);
|
|
99
105
|
ctx.throw(500, err.message || 'Error updating routing rule');
|
|
@@ -106,7 +112,9 @@ module.exports = {
|
|
|
106
112
|
async delete(ctx) {
|
|
107
113
|
try {
|
|
108
114
|
const { ruleId } = ctx.params;
|
|
109
|
-
await strapi.
|
|
115
|
+
await strapi.documents(ROUTING_RULE_UID).delete({
|
|
116
|
+
documentId: ruleId,
|
|
117
|
+
});
|
|
110
118
|
|
|
111
119
|
ctx.body = {
|
|
112
120
|
message: 'Routing rule deleted successfully',
|
|
@@ -119,4 +127,3 @@ module.exports = {
|
|
|
119
127
|
}
|
|
120
128
|
},
|
|
121
129
|
};
|
|
122
|
-
|