strapi-plugin-magic-mail 2.0.2 → 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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.2",
2
+ "version": "2.0.3",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "strapi-plugin",
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  module.exports = async ({ strapi }) => {
10
- strapi.log.info('🚀 [magic-mail] Bootstrap starting...');
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('║ MAGICMAIL - NO VALID LICENSE ║');
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('⚠️ Running on grace period (license server unreachable)');
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] 📧 Email intercepted from native Strapi service');
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] Email routed successfully through MagicMail');
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] ⚠️ MagicMail routing failed, falling back to original service');
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] Native email service overridden!');
82
- strapi.log.info('[magic-mail] 💡 All strapi.plugins.email.services.email.send() calls will route through MagicMail');
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] ⚠️ Native email service not found - MagicMail will work standalone');
85
- strapi.log.warn('[magic-mail] 💡 Make sure @strapi/plugin-email is installed');
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] Hourly counters reset');
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] Daily counters reset');
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] Daily counters reset');
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] Counter reset schedules initialized');
149
- strapi.log.info('[magic-mail] Bootstrap complete');
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] Bootstrap error:', err);
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] 🔍 hasFeature called with:`, {
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] ⚠️ No license data → using FREE tier`);
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] 🔍 Tier detection:`, {
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] ENTERPRISE tier has feature "${featureName}"`);
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] ADVANCED tier has feature "${featureName}"`);
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] PREMIUM tier has feature "${featureName}"`);
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 ? '' : ''} FREE tier check for "${featureName}": ${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.entityService.count('plugin::magic-mail.email-account');
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] 📧 Calling strapi.plugin("email").service("email").send()');
138
+ strapi.log.info('[magic-mail] [EMAIL] Calling strapi.plugin("email").service("email").send()');
139
139
  if (accountName) {
140
- strapi.log.info(`[magic-mail] 🎯 Forcing specific account: ${accountName}`);
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] Strapi Email Service test completed');
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] Strapi Email Service test failed:', err);
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
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
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
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
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(parseInt(userId));
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] 🔍 Running Analytics Debug...');
182
+ strapi.log.info('[magic-mail] [CHECK] Running Analytics Debug...');
174
183
 
175
- // Get email logs
176
- const emailLogs = await strapi.db.query('plugin::magic-mail.email-log').findMany({
184
+ // Get email logs using Document Service
185
+ const emailLogs = await strapi.documents(EMAIL_LOG_UID).findMany({
177
186
  limit: 10,
178
- orderBy: { sentAt: 'DESC' },
187
+ sort: [{ sentAt: 'desc' }],
179
188
  });
180
189
 
181
- // Get email events
182
- const emailEvents = await strapi.db.query('plugin::magic-mail.email-event').findMany({
190
+ // Get email events using Document Service
191
+ const emailEvents = await strapi.documents(EMAIL_EVENT_UID).findMany({
183
192
  limit: 20,
184
- orderBy: { timestamp: 'DESC' },
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.entityService.findMany('plugin::magic-mail.email-account', {
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.db.query('plugin::magic-mail.email-log').findOne({
265
- where: { emailId },
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 first
273
- await strapi.db.query('plugin::magic-mail.email-event').deleteMany({
274
- where: { emailLog: emailLog.id },
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.db.query('plugin::magic-mail.email-log').delete({
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] 🗑️ Deleted email log: ${emailId}`);
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 where = {};
314
+ const filters = {};
304
315
  if (olderThan) {
305
- where.sentAt = { $lt: new Date(olderThan) };
316
+ filters.sentAt = { $lt: new Date(olderThan) };
306
317
  }
307
318
 
308
- // Get all email logs to delete
309
- const emailLogs = await strapi.db.query('plugin::magic-mail.email-log').findMany({
310
- where,
311
- select: ['id'],
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
- const emailLogIds = emailLogs.map(log => log.id);
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
- await strapi.db.query('plugin::magic-mail.email-event').deleteMany({
326
- where: { emailLog: { $in: emailLogIds } },
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
- // Delete all email logs
330
- await strapi.db.query('plugin::magic-mail.email-log').deleteMany({
331
- where: { id: { $in: emailLogIds } },
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] 🗑️ Cleared ${emailLogIds.length} email logs`);
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 ${emailLogIds.length} email log(s)`,
339
- deletedCount: emailLogIds.length,
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] ⚠️ Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
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] ⚠️ Email mismatch for license key`);
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] License validated and stored`);
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 strapi.entityService.count('plugin::magic-mail.email-account');
219
- const currentRules = await strapi.entityService.count('plugin::magic-mail.routing-rule');
220
- const currentTemplates = await strapi.entityService.count('plugin::magic-mail.email-template');
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">❌ OAuth Authorization Failed</div>
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">✅</div>
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">❌ OAuth Authorization Failed</div>
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">✅</div>
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">❌ OAuth Authorization Failed</div>
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">✅</div>
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.entityService.count('plugin::magic-mail.email-account');
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] OAuth account created successfully');
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.entityService.findMany('plugin::magic-mail.routing-rule', {
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.entityService.findOne('plugin::magic-mail.routing-rule', ruleId);
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.entityService.count('plugin::magic-mail.routing-rule');
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.entityService.create('plugin::magic-mail.routing-rule', {
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] Routing rule created: ${rule.name}`);
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.entityService.update('plugin::magic-mail.routing-rule', ruleId, {
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] Routing rule updated: ${rule.name}`);
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.entityService.delete('plugin::magic-mail.routing-rule', ruleId);
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
-