strapi-plugin-magic-mail 2.0.2 → 2.0.4

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 (37) hide show
  1. package/README.md +15 -17
  2. package/admin/src/index.js +26 -25
  3. package/admin/src/pages/Analytics.jsx +19 -19
  4. package/admin/src/pages/EmailDesigner/EditorPage.jsx +33 -33
  5. package/admin/src/pages/EmailDesigner/TemplateList.jsx +36 -36
  6. package/admin/src/pages/HomePage.jsx +25 -88
  7. package/admin/src/pages/LicensePage.jsx +12 -6
  8. package/admin/src/pages/RoutingRules.jsx +21 -21
  9. package/admin/src/pages/Settings.jsx +3 -3
  10. package/admin/src/utils/theme.js +85 -0
  11. package/dist/_chunks/{App-DYNCyt54.mjs → App-BZaHrE0R.mjs} +184 -200
  12. package/dist/_chunks/{App-DF9vAGXX.js → App-Bze8Ixs_.js} +184 -200
  13. package/dist/_chunks/{LicensePage-CJXwPnEe.js → LicensePage-Bg72gy8w.js} +12 -6
  14. package/dist/_chunks/{LicensePage-Bl02myMx.mjs → LicensePage-ndUhjynY.mjs} +12 -6
  15. package/dist/_chunks/{Settings-zuFQ3pnn.js → Settings-BSFLpt0H.js} +3 -7
  16. package/dist/_chunks/{Settings-C_TmKwcz.mjs → Settings-Ca5UE3c1.mjs} +3 -7
  17. package/dist/admin/index.js +41 -24
  18. package/dist/admin/index.mjs +41 -24
  19. package/dist/server/index.js +602 -665
  20. package/dist/server/index.mjs +602 -665
  21. package/package.json +1 -1
  22. package/server/src/bootstrap.js +16 -16
  23. package/server/src/config/features.js +7 -7
  24. package/server/src/controllers/accounts.js +15 -6
  25. package/server/src/controllers/analytics.js +56 -42
  26. package/server/src/controllers/license.js +9 -7
  27. package/server/src/controllers/oauth.js +9 -9
  28. package/server/src/controllers/routing-rules.js +18 -11
  29. package/server/src/controllers/test.js +111 -193
  30. package/server/src/services/account-manager.js +73 -21
  31. package/server/src/services/analytics.js +88 -72
  32. package/server/src/services/email-designer.js +131 -284
  33. package/server/src/services/email-router.js +69 -43
  34. package/server/src/services/license-guard.js +24 -24
  35. package/server/src/services/oauth.js +11 -11
  36. package/server/src/services/service.js +1 -1
  37. package/server/src/utils/encryption.js +1 -1
@@ -31,14 +31,14 @@ function requireBootstrap() {
31
31
  if (hasRequiredBootstrap) return bootstrap;
32
32
  hasRequiredBootstrap = 1;
33
33
  bootstrap = async ({ strapi: strapi2 }) => {
34
- strapi2.log.info("🚀 [magic-mail] Bootstrap starting...");
34
+ strapi2.log.info("[BOOTSTRAP] [magic-mail] Starting...");
35
35
  try {
36
36
  const licenseGuardService = strapi2.plugin("magic-mail").service("license-guard");
37
37
  setTimeout(async () => {
38
38
  const licenseStatus = await licenseGuardService.initialize();
39
39
  if (!licenseStatus.valid && licenseStatus.demo) {
40
40
  strapi2.log.error("╔════════════════════════════════════════════════════════════════╗");
41
- strapi2.log.error("║ MAGICMAIL - NO VALID LICENSE ║");
41
+ strapi2.log.error("║ [ERROR] MAGICMAIL - NO VALID LICENSE ║");
42
42
  strapi2.log.error("║ ║");
43
43
  strapi2.log.error("║ This plugin requires a valid license to operate. ║");
44
44
  strapi2.log.error("║ Please activate your license via Admin UI: ║");
@@ -47,7 +47,7 @@ function requireBootstrap() {
47
47
  strapi2.log.error('║ Click "Generate Free License" to get started! ║');
48
48
  strapi2.log.error("╚════════════════════════════════════════════════════════════════╝");
49
49
  } else if (licenseStatus.gracePeriod) {
50
- strapi2.log.warn("⚠️ Running on grace period (license server unreachable)");
50
+ strapi2.log.warn("[WARNING] Running on grace period (license server unreachable)");
51
51
  }
52
52
  }, 2e3);
53
53
  const accountManager2 = strapi2.plugin("magic-mail").service("account-manager");
@@ -56,7 +56,7 @@ function requireBootstrap() {
56
56
  if (originalEmailService && originalEmailService.send) {
57
57
  const originalSend = originalEmailService.send.bind(originalEmailService);
58
58
  originalEmailService.send = async (emailData) => {
59
- strapi2.log.info("[magic-mail] 📧 Email intercepted from native Strapi service");
59
+ strapi2.log.info("[magic-mail] [EMAIL] Intercepted from native Strapi service");
60
60
  strapi2.log.debug("[magic-mail] Email data:", {
61
61
  to: emailData.to,
62
62
  subject: emailData.subject,
@@ -69,19 +69,19 @@ function requireBootstrap() {
69
69
  emailData.templateData = emailData.data;
70
70
  }
71
71
  const result = await emailRouter2.send(emailData);
72
- strapi2.log.info("[magic-mail] Email routed successfully through MagicMail");
72
+ strapi2.log.info("[magic-mail] [SUCCESS] Email routed successfully through MagicMail");
73
73
  return result;
74
74
  } catch (magicMailError) {
75
- strapi2.log.warn("[magic-mail] ⚠️ MagicMail routing failed, falling back to original service");
75
+ strapi2.log.warn("[magic-mail] [WARNING] MagicMail routing failed, falling back to original service");
76
76
  strapi2.log.error("[magic-mail] Error:", magicMailError.message);
77
77
  return await originalSend(emailData);
78
78
  }
79
79
  };
80
- strapi2.log.info("[magic-mail] Native email service overridden!");
81
- strapi2.log.info("[magic-mail] 💡 All strapi.plugins.email.services.email.send() calls will route through MagicMail");
80
+ strapi2.log.info("[magic-mail] [SUCCESS] Native email service overridden!");
81
+ strapi2.log.info("[magic-mail] [INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail");
82
82
  } else {
83
- strapi2.log.warn("[magic-mail] ⚠️ Native email service not found - MagicMail will work standalone");
84
- strapi2.log.warn("[magic-mail] 💡 Make sure @strapi/plugin-email is installed");
83
+ strapi2.log.warn("[magic-mail] [WARNING] Native email service not found - MagicMail will work standalone");
84
+ strapi2.log.warn("[magic-mail] [INFO] Make sure @strapi/plugin-email is installed");
85
85
  }
86
86
  const hourlyResetInterval = setInterval(async () => {
87
87
  try {
@@ -91,7 +91,7 @@ function requireBootstrap() {
91
91
  }
92
92
  const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
93
93
  await accountMgr.resetCounters("hourly");
94
- strapi2.log.info("[magic-mail] Hourly counters reset");
94
+ strapi2.log.info("[magic-mail] [RESET] Hourly counters reset");
95
95
  } catch (err) {
96
96
  console.error("[magic-mail] Hourly reset error:", err.message);
97
97
  }
@@ -109,7 +109,7 @@ function requireBootstrap() {
109
109
  }
110
110
  const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
111
111
  await accountMgr.resetCounters("daily");
112
- strapi2.log.info("[magic-mail] Daily counters reset");
112
+ strapi2.log.info("[magic-mail] [RESET] Daily counters reset");
113
113
  const dailyResetInterval = setInterval(async () => {
114
114
  try {
115
115
  if (!strapi2 || !strapi2.plugin) {
@@ -118,7 +118,7 @@ function requireBootstrap() {
118
118
  }
119
119
  const accountMgr2 = strapi2.plugin("magic-mail").service("account-manager");
120
120
  await accountMgr2.resetCounters("daily");
121
- strapi2.log.info("[magic-mail] Daily counters reset");
121
+ strapi2.log.info("[magic-mail] [RESET] Daily counters reset");
122
122
  } catch (err) {
123
123
  console.error("[magic-mail] Daily reset error:", err.message);
124
124
  }
@@ -128,10 +128,10 @@ function requireBootstrap() {
128
128
  console.error("[magic-mail] Initial daily reset error:", err.message);
129
129
  }
130
130
  }, msUntilMidnight);
131
- strapi2.log.info("[magic-mail] Counter reset schedules initialized");
132
- strapi2.log.info("[magic-mail] Bootstrap complete");
131
+ strapi2.log.info("[magic-mail] [SUCCESS] Counter reset schedules initialized");
132
+ strapi2.log.info("[magic-mail] [SUCCESS] Bootstrap complete");
133
133
  } catch (err) {
134
- strapi2.log.error("[magic-mail] Bootstrap error:", err);
134
+ strapi2.log.error("[magic-mail] [ERROR] Bootstrap error:", err);
135
135
  }
136
136
  };
137
137
  return bootstrap;
@@ -366,7 +366,7 @@ function requireAccounts() {
366
366
  ctx.throw(403, `Provider "${accountData.provider}" requires a Premium license or higher. Please upgrade your license.`);
367
367
  return;
368
368
  }
369
- const currentAccounts = await strapi.entityService.count("plugin::magic-mail.email-account");
369
+ const currentAccounts = await strapi.documents("plugin::magic-mail.email-account").count();
370
370
  const maxAccounts = await licenseGuard2.getMaxAccounts();
371
371
  if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
372
372
  ctx.throw(403, `Account limit reached (${maxAccounts}). Upgrade your license to add more accounts.`);
@@ -447,9 +447,9 @@ function requireAccounts() {
447
447
  ctx.throw(400, "testEmail is required");
448
448
  }
449
449
  strapi.log.info("[magic-mail] 🧪 Testing Strapi Email Service integration...");
450
- strapi.log.info('[magic-mail] 📧 Calling strapi.plugin("email").service("email").send()');
450
+ strapi.log.info('[magic-mail] [EMAIL] Calling strapi.plugin("email").service("email").send()');
451
451
  if (accountName) {
452
- strapi.log.info(`[magic-mail] 🎯 Forcing specific account: ${accountName}`);
452
+ strapi.log.info(`[magic-mail] [FORCE] Forcing specific account: ${accountName}`);
453
453
  }
454
454
  const result = await strapi.plugin("email").service("email").send({
455
455
  to: testEmail,
@@ -476,6 +476,15 @@ function requireAccounts() {
476
476
  <li>Statistics tracking</li>
477
477
  </ul>
478
478
  </div>
479
+ <div style="background: #DCFCE7; border: 1px solid #22C55E; border-radius: 8px; padding: 15px; margin: 20px 0;">
480
+ <h3 style="margin-top: 0; color: #15803D;">Security Features Active</h3>
481
+ <ul style="margin: 10px 0; padding-left: 20px;">
482
+ <li>TLS/SSL Encryption enforced</li>
483
+ <li>Email content validated</li>
484
+ <li>Proper headers included</li>
485
+ <li>Message-ID generated</li>
486
+ </ul>
487
+ </div>
479
488
  <p style="color: #6B7280; font-size: 14px; margin-top: 30px;">
480
489
  Sent at: ${(/* @__PURE__ */ new Date()).toLocaleString()}<br>
481
490
  Via: MagicMail Email Router
@@ -486,7 +495,7 @@ function requireAccounts() {
486
495
  accountName: accountName || null
487
496
  // Force specific account if provided
488
497
  });
489
- strapi.log.info("[magic-mail] Strapi Email Service test completed");
498
+ strapi.log.info("[magic-mail] [SUCCESS] Strapi Email Service test completed");
490
499
  ctx.body = {
491
500
  success: true,
492
501
  message: "Email sent via Strapi Email Service (intercepted by MagicMail)",
@@ -498,7 +507,7 @@ function requireAccounts() {
498
507
  }
499
508
  };
500
509
  } catch (err) {
501
- strapi.log.error("[magic-mail] Strapi Email Service test failed:", err);
510
+ strapi.log.error("[magic-mail] [ERROR] Strapi Email Service test failed:", err);
502
511
  ctx.body = {
503
512
  success: false,
504
513
  message: "Failed to send test email",
@@ -575,7 +584,7 @@ function requireOauth$1() {
575
584
  </style>
576
585
  </head>
577
586
  <body>
578
- <div class="error">❌ OAuth Authorization Failed</div>
587
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
579
588
  <p>Error: ${error}</p>
580
589
  <p>You can close this window and try again.</p>
581
590
  <script>
@@ -609,7 +618,7 @@ function requireOauth$1() {
609
618
  </style>
610
619
  </head>
611
620
  <body>
612
- <div class="success">✅</div>
621
+ <div class="success">[SUCCESS]</div>
613
622
  <div class="message">Gmail OAuth Authorized!</div>
614
623
  <div class="note">Closing window...</div>
615
624
  <script>
@@ -684,7 +693,7 @@ function requireOauth$1() {
684
693
  </style>
685
694
  </head>
686
695
  <body>
687
- <div class="error">❌ OAuth Authorization Failed</div>
696
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
688
697
  <p>Error: ${error}</p>
689
698
  <p>You can close this window and try again.</p>
690
699
  <script>
@@ -718,7 +727,7 @@ function requireOauth$1() {
718
727
  </style>
719
728
  </head>
720
729
  <body>
721
- <div class="success">✅</div>
730
+ <div class="success">[SUCCESS]</div>
722
731
  <div class="message">Microsoft OAuth Authorized!</div>
723
732
  <div class="note">Closing window...</div>
724
733
  <script>
@@ -789,7 +798,7 @@ function requireOauth$1() {
789
798
  </style>
790
799
  </head>
791
800
  <body>
792
- <div class="error">❌ OAuth Authorization Failed</div>
801
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
793
802
  <p>Error: ${error}</p>
794
803
  <p>You can close this window and try again.</p>
795
804
  <script>
@@ -823,7 +832,7 @@ function requireOauth$1() {
823
832
  </style>
824
833
  </head>
825
834
  <body>
826
- <div class="success">✅</div>
835
+ <div class="success">[SUCCESS]</div>
827
836
  <div class="message">Yahoo Mail OAuth Authorized!</div>
828
837
  <div class="note">Closing window...</div>
829
838
  <script>
@@ -873,7 +882,7 @@ function requireOauth$1() {
873
882
  ctx.throw(403, `OAuth provider "${provider}" requires a Premium license or higher. Please upgrade your license.`);
874
883
  return;
875
884
  }
876
- const currentAccounts = await strapi.entityService.count("plugin::magic-mail.email-account");
885
+ const currentAccounts = await strapi.documents("plugin::magic-mail.email-account").count();
877
886
  const maxAccounts = await licenseGuard2.getMaxAccounts();
878
887
  if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
879
888
  ctx.throw(403, `Account limit reached (${maxAccounts}). Upgrade your license to add more accounts.`);
@@ -928,7 +937,7 @@ function requireOauth$1() {
928
937
  accountDetails.config
929
938
  // contains clientId and clientSecret
930
939
  );
931
- strapi.log.info("[magic-mail] OAuth account created successfully");
940
+ strapi.log.info("[magic-mail] [SUCCESS] OAuth account created successfully");
932
941
  ctx.body = {
933
942
  success: true,
934
943
  data: account,
@@ -948,14 +957,15 @@ var hasRequiredRoutingRules;
948
957
  function requireRoutingRules() {
949
958
  if (hasRequiredRoutingRules) return routingRules;
950
959
  hasRequiredRoutingRules = 1;
960
+ const ROUTING_RULE_UID = "plugin::magic-mail.routing-rule";
951
961
  routingRules = {
952
962
  /**
953
963
  * Get all routing rules
954
964
  */
955
965
  async getAll(ctx) {
956
966
  try {
957
- const rules = await strapi.entityService.findMany("plugin::magic-mail.routing-rule", {
958
- sort: { priority: "desc" }
967
+ const rules = await strapi.documents(ROUTING_RULE_UID).findMany({
968
+ sort: [{ priority: "desc" }]
959
969
  });
960
970
  ctx.body = {
961
971
  data: rules,
@@ -972,7 +982,9 @@ function requireRoutingRules() {
972
982
  async getOne(ctx) {
973
983
  try {
974
984
  const { ruleId } = ctx.params;
975
- const rule = await strapi.entityService.findOne("plugin::magic-mail.routing-rule", ruleId);
985
+ const rule = await strapi.documents(ROUTING_RULE_UID).findOne({
986
+ documentId: ruleId
987
+ });
976
988
  if (!rule) {
977
989
  ctx.throw(404, "Routing rule not found");
978
990
  }
@@ -990,20 +1002,20 @@ function requireRoutingRules() {
990
1002
  async create(ctx) {
991
1003
  try {
992
1004
  const licenseGuard2 = strapi.plugin("magic-mail").service("license-guard");
993
- const currentRules = await strapi.entityService.count("plugin::magic-mail.routing-rule");
1005
+ const currentRules = await strapi.documents(ROUTING_RULE_UID).count();
994
1006
  const maxRules = await licenseGuard2.getMaxRoutingRules();
995
1007
  if (maxRules !== -1 && currentRules >= maxRules) {
996
1008
  ctx.throw(403, `Routing rule limit reached (${maxRules}). Upgrade to Advanced license for unlimited rules.`);
997
1009
  return;
998
1010
  }
999
- const rule = await strapi.entityService.create("plugin::magic-mail.routing-rule", {
1011
+ const rule = await strapi.documents(ROUTING_RULE_UID).create({
1000
1012
  data: ctx.request.body
1001
1013
  });
1002
1014
  ctx.body = {
1003
1015
  data: rule,
1004
1016
  message: "Routing rule created successfully"
1005
1017
  };
1006
- strapi.log.info(`[magic-mail] Routing rule created: ${rule.name}`);
1018
+ strapi.log.info(`[magic-mail] [SUCCESS] Routing rule created: ${rule.name}`);
1007
1019
  } catch (err) {
1008
1020
  strapi.log.error("[magic-mail] Error creating routing rule:", err);
1009
1021
  ctx.throw(err.status || 500, err.message || "Error creating routing rule");
@@ -1015,14 +1027,15 @@ function requireRoutingRules() {
1015
1027
  async update(ctx) {
1016
1028
  try {
1017
1029
  const { ruleId } = ctx.params;
1018
- const rule = await strapi.entityService.update("plugin::magic-mail.routing-rule", ruleId, {
1030
+ const rule = await strapi.documents(ROUTING_RULE_UID).update({
1031
+ documentId: ruleId,
1019
1032
  data: ctx.request.body
1020
1033
  });
1021
1034
  ctx.body = {
1022
1035
  data: rule,
1023
1036
  message: "Routing rule updated successfully"
1024
1037
  };
1025
- strapi.log.info(`[magic-mail] Routing rule updated: ${rule.name}`);
1038
+ strapi.log.info(`[magic-mail] [SUCCESS] Routing rule updated: ${rule.name}`);
1026
1039
  } catch (err) {
1027
1040
  strapi.log.error("[magic-mail] Error updating routing rule:", err);
1028
1041
  ctx.throw(500, err.message || "Error updating routing rule");
@@ -1034,7 +1047,9 @@ function requireRoutingRules() {
1034
1047
  async delete(ctx) {
1035
1048
  try {
1036
1049
  const { ruleId } = ctx.params;
1037
- await strapi.entityService.delete("plugin::magic-mail.routing-rule", ruleId);
1050
+ await strapi.documents(ROUTING_RULE_UID).delete({
1051
+ documentId: ruleId
1052
+ });
1038
1053
  ctx.body = {
1039
1054
  message: "Routing rule deleted successfully"
1040
1055
  };
@@ -1190,7 +1205,7 @@ function requireFeatures() {
1190
1205
  */
1191
1206
  hasFeature(licenseData, featureName) {
1192
1207
  if (!licenseData) {
1193
- console.log(`[features.js] ⚠️ No license data → using FREE tier`);
1208
+ console.log(`[features.js] [WARNING] No license data → using FREE tier`);
1194
1209
  return this.free.features.includes(featureName);
1195
1210
  }
1196
1211
  let isEnterprise = false;
@@ -1216,19 +1231,19 @@ function requireFeatures() {
1216
1231
  isPremium = true;
1217
1232
  }
1218
1233
  if (isEnterprise && this.enterprise.features.includes(featureName)) {
1219
- console.log(`[features.js] ENTERPRISE tier has feature "${featureName}"`);
1234
+ console.log(`[features.js] [SUCCESS] ENTERPRISE tier has feature "${featureName}"`);
1220
1235
  return true;
1221
1236
  }
1222
1237
  if (isAdvanced && this.advanced.features.includes(featureName)) {
1223
- console.log(`[features.js] ADVANCED tier has feature "${featureName}"`);
1238
+ console.log(`[features.js] [SUCCESS] ADVANCED tier has feature "${featureName}"`);
1224
1239
  return true;
1225
1240
  }
1226
1241
  if (isPremium && this.premium.features.includes(featureName)) {
1227
- console.log(`[features.js] PREMIUM tier has feature "${featureName}"`);
1242
+ console.log(`[features.js] [SUCCESS] PREMIUM tier has feature "${featureName}"`);
1228
1243
  return true;
1229
1244
  }
1230
1245
  const inFree = this.free.features.includes(featureName);
1231
- console.log(`[features.js] ${inFree ? "" : ""} FREE tier check for "${featureName}": ${inFree}`);
1246
+ console.log(`[features.js] ${inFree ? "[SUCCESS]" : "[ERROR]"} FREE tier check for "${featureName}": ${inFree}`);
1232
1247
  return inFree;
1233
1248
  },
1234
1249
  /**
@@ -1386,7 +1401,7 @@ function requireLicense() {
1386
1401
  const licenseGuard2 = strapi2.plugin("magic-mail").service("license-guard");
1387
1402
  const verification = await licenseGuard2.verifyLicense(trimmedKey);
1388
1403
  if (!verification.valid) {
1389
- strapi2.log.warn(`[magic-mail] ⚠️ Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
1404
+ strapi2.log.warn(`[magic-mail] [WARNING] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
1390
1405
  return ctx.badRequest("Invalid or expired license key");
1391
1406
  }
1392
1407
  const license2 = await licenseGuard2.getLicenseByKey(trimmedKey);
@@ -1394,7 +1409,7 @@ function requireLicense() {
1394
1409
  return ctx.badRequest("License not found");
1395
1410
  }
1396
1411
  if (license2.email.toLowerCase() !== trimmedEmail) {
1397
- strapi2.log.warn(`[magic-mail] ⚠️ Email mismatch for license key`);
1412
+ strapi2.log.warn(`[magic-mail] [WARNING] Email mismatch for license key`);
1398
1413
  return ctx.badRequest("Email address does not match this license key");
1399
1414
  }
1400
1415
  await licenseGuard2.storeLicenseKey(trimmedKey);
@@ -1404,7 +1419,7 @@ function requireLicense() {
1404
1419
  pingInterval,
1405
1420
  data: verification.data
1406
1421
  };
1407
- strapi2.log.info(`[magic-mail] License validated and stored`);
1422
+ strapi2.log.info(`[magic-mail] [SUCCESS] License validated and stored`);
1408
1423
  return ctx.send({
1409
1424
  success: true,
1410
1425
  message: "License activated successfully",
@@ -1448,9 +1463,11 @@ function requireLicense() {
1448
1463
  const maxAccounts = await licenseGuard2.getMaxAccounts();
1449
1464
  const maxRules = await licenseGuard2.getMaxRoutingRules();
1450
1465
  const maxTemplates = await licenseGuard2.getMaxEmailTemplates();
1451
- const currentAccounts = await strapi2.entityService.count("plugin::magic-mail.email-account");
1452
- const currentRules = await strapi2.entityService.count("plugin::magic-mail.routing-rule");
1453
- const currentTemplates = await strapi2.entityService.count("plugin::magic-mail.email-template");
1466
+ const [currentAccounts, currentRules, currentTemplates] = await Promise.all([
1467
+ strapi2.documents("plugin::magic-mail.email-account").count(),
1468
+ strapi2.documents("plugin::magic-mail.routing-rule").count(),
1469
+ strapi2.documents("plugin::magic-mail.email-template").count()
1470
+ ]);
1454
1471
  let tier = "free";
1455
1472
  if (license2?.featureEnterprise === true || license2?.features?.enterprise === true) tier = "enterprise";
1456
1473
  else if (license2?.featureAdvanced === true || license2?.features?.advanced === true) tier = "advanced";
@@ -1859,6 +1876,9 @@ var hasRequiredAnalytics$1;
1859
1876
  function requireAnalytics$1() {
1860
1877
  if (hasRequiredAnalytics$1) return analytics$1;
1861
1878
  hasRequiredAnalytics$1 = 1;
1879
+ const EMAIL_LOG_UID = "plugin::magic-mail.email-log";
1880
+ const EMAIL_EVENT_UID = "plugin::magic-mail.email-event";
1881
+ const EMAIL_ACCOUNT_UID = "plugin::magic-mail.email-account";
1862
1882
  analytics$1 = ({ strapi: strapi2 }) => ({
1863
1883
  /**
1864
1884
  * Tracking pixel endpoint
@@ -1898,7 +1918,8 @@ function requireAnalytics$1() {
1898
1918
  async getStats(ctx) {
1899
1919
  try {
1900
1920
  const filters = {
1901
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
1921
+ // userId is documentId (string) in Strapi v5, NOT parseInt!
1922
+ userId: ctx.query.userId || null,
1902
1923
  templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
1903
1924
  accountId: ctx.query.accountId ? parseInt(ctx.query.accountId) : null,
1904
1925
  dateFrom: ctx.query.dateFrom || null,
@@ -1921,7 +1942,8 @@ function requireAnalytics$1() {
1921
1942
  async getEmailLogs(ctx) {
1922
1943
  try {
1923
1944
  const filters = {
1924
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
1945
+ // userId is documentId (string) in Strapi v5, NOT parseInt!
1946
+ userId: ctx.query.userId || null,
1925
1947
  templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
1926
1948
  search: ctx.query.search || null
1927
1949
  };
@@ -1961,11 +1983,12 @@ function requireAnalytics$1() {
1961
1983
  /**
1962
1984
  * Get user email activity
1963
1985
  * GET /magic-mail/analytics/users/:userId
1986
+ * Note: userId is documentId (string) in Strapi v5
1964
1987
  */
1965
1988
  async getUserActivity(ctx) {
1966
1989
  try {
1967
1990
  const { userId } = ctx.params;
1968
- const activity = await strapi2.plugin("magic-mail").service("analytics").getUserActivity(parseInt(userId));
1991
+ const activity = await strapi2.plugin("magic-mail").service("analytics").getUserActivity(userId);
1969
1992
  return ctx.send({
1970
1993
  success: true,
1971
1994
  data: activity
@@ -1980,19 +2003,19 @@ function requireAnalytics$1() {
1980
2003
  */
1981
2004
  async debug(ctx) {
1982
2005
  try {
1983
- strapi2.log.info("[magic-mail] 🔍 Running Analytics Debug...");
1984
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
2006
+ strapi2.log.info("[magic-mail] [CHECK] Running Analytics Debug...");
2007
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
1985
2008
  limit: 10,
1986
- orderBy: { sentAt: "DESC" }
2009
+ sort: [{ sentAt: "desc" }]
1987
2010
  });
1988
- const emailEvents = await strapi2.db.query("plugin::magic-mail.email-event").findMany({
2011
+ const emailEvents = await strapi2.documents(EMAIL_EVENT_UID).findMany({
1989
2012
  limit: 20,
1990
- orderBy: { timestamp: "DESC" },
2013
+ sort: [{ timestamp: "desc" }],
1991
2014
  populate: ["emailLog"]
1992
2015
  });
1993
2016
  const analyticsService = strapi2.plugin("magic-mail").service("analytics");
1994
2017
  const stats = await analyticsService.getStats();
1995
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
2018
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
1996
2019
  filters: { isActive: true },
1997
2020
  fields: ["id", "name", "provider", "fromEmail", "emailsSentToday", "totalEmailsSent"]
1998
2021
  });
@@ -2056,19 +2079,20 @@ function requireAnalytics$1() {
2056
2079
  async deleteEmailLog(ctx) {
2057
2080
  try {
2058
2081
  const { emailId } = ctx.params;
2059
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
2060
- where: { emailId }
2082
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
2083
+ filters: { emailId }
2061
2084
  });
2062
2085
  if (!emailLog) {
2063
2086
  return ctx.notFound("Email log not found");
2064
2087
  }
2065
- await strapi2.db.query("plugin::magic-mail.email-event").deleteMany({
2066
- where: { emailLog: emailLog.id }
2067
- });
2068
- await strapi2.db.query("plugin::magic-mail.email-log").delete({
2069
- where: { id: emailLog.id }
2088
+ const events = await strapi2.documents(EMAIL_EVENT_UID).findMany({
2089
+ filters: { emailLog: { documentId: emailLog.documentId } }
2070
2090
  });
2071
- strapi2.log.info(`[magic-mail] 🗑️ Deleted email log: ${emailId}`);
2091
+ for (const event of events) {
2092
+ await strapi2.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
2093
+ }
2094
+ await strapi2.documents(EMAIL_LOG_UID).delete({ documentId: emailLog.documentId });
2095
+ strapi2.log.info(`[magic-mail] [DELETE] Deleted email log: ${emailId}`);
2072
2096
  return ctx.send({
2073
2097
  success: true,
2074
2098
  message: "Email log deleted successfully"
@@ -2085,33 +2109,36 @@ function requireAnalytics$1() {
2085
2109
  async clearAllEmailLogs(ctx) {
2086
2110
  try {
2087
2111
  const { olderThan } = ctx.query;
2088
- const where = {};
2112
+ const filters = {};
2089
2113
  if (olderThan) {
2090
- where.sentAt = { $lt: new Date(olderThan) };
2114
+ filters.sentAt = { $lt: new Date(olderThan) };
2091
2115
  }
2092
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
2093
- where,
2094
- select: ["id"]
2116
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
2117
+ filters,
2118
+ fields: ["id", "documentId"],
2119
+ limit: 1e5
2095
2120
  });
2096
- const emailLogIds = emailLogs.map((log) => log.id);
2097
- if (emailLogIds.length === 0) {
2121
+ if (emailLogs.length === 0) {
2098
2122
  return ctx.send({
2099
2123
  success: true,
2100
2124
  message: "No email logs to delete",
2101
2125
  deletedCount: 0
2102
2126
  });
2103
2127
  }
2104
- await strapi2.db.query("plugin::magic-mail.email-event").deleteMany({
2105
- where: { emailLog: { $in: emailLogIds } }
2106
- });
2107
- await strapi2.db.query("plugin::magic-mail.email-log").deleteMany({
2108
- where: { id: { $in: emailLogIds } }
2109
- });
2110
- strapi2.log.info(`[magic-mail] 🗑️ Cleared ${emailLogIds.length} email logs`);
2128
+ for (const log of emailLogs) {
2129
+ const events = await strapi2.documents(EMAIL_EVENT_UID).findMany({
2130
+ filters: { emailLog: { documentId: log.documentId } }
2131
+ });
2132
+ for (const event of events) {
2133
+ await strapi2.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
2134
+ }
2135
+ await strapi2.documents(EMAIL_LOG_UID).delete({ documentId: log.documentId });
2136
+ }
2137
+ strapi2.log.info(`[magic-mail] [DELETE] Cleared ${emailLogs.length} email logs`);
2111
2138
  return ctx.send({
2112
2139
  success: true,
2113
- message: `Successfully deleted ${emailLogIds.length} email log(s)`,
2114
- deletedCount: emailLogIds.length
2140
+ message: `Successfully deleted ${emailLogs.length} email log(s)`,
2141
+ deletedCount: emailLogs.length
2115
2142
  });
2116
2143
  } catch (error) {
2117
2144
  strapi2.log.error("[magic-mail] Error clearing email logs:", error);
@@ -2126,18 +2153,16 @@ var hasRequiredTest;
2126
2153
  function requireTest() {
2127
2154
  if (hasRequiredTest) return test;
2128
2155
  hasRequiredTest = 1;
2156
+ const EMAIL_TEMPLATE_UID = "plugin::magic-mail.email-template";
2157
+ const EMAIL_TEMPLATE_VERSION_UID = "plugin::magic-mail.email-template-version";
2129
2158
  test = {
2130
2159
  /**
2131
2160
  * Test Template-Version Relations
2132
- *
2133
- * Tests beide Richtungen:
2134
- * 1. Version → Template beim Erstellen
2135
- * 2. Template → Version nachträglich via connect
2136
2161
  */
2137
2162
  async testRelations(ctx) {
2138
2163
  try {
2139
2164
  console.log("\n" + "=".repeat(60));
2140
- console.log("🧪 TEST: Template ↔ Version Relations");
2165
+ console.log("🧪 TEST: Template ↔ Version Relations (Document Service API)");
2141
2166
  console.log("=".repeat(60));
2142
2167
  let test1Success = false;
2143
2168
  let test1ReverseSuccess = false;
@@ -2147,257 +2172,192 @@ function requireTest() {
2147
2172
  let test3a_hasTemplate = false;
2148
2173
  let test3b_twoVersions = false;
2149
2174
  let test3b_allHaveTemplate = false;
2150
- console.log("\n📝 TEST 1: Version → Template Verbindung\n");
2151
- const testTemplate = await strapi.entityService.create(
2152
- "plugin::magic-mail.email-template",
2153
- {
2154
- data: {
2155
- templateReferenceId: Math.floor(Math.random() * 1e6),
2156
- name: "Test Template Relations",
2157
- subject: "Test Subject",
2158
- bodyHtml: "<p>Test HTML</p>",
2159
- bodyText: "Test Text",
2160
- category: "custom",
2161
- isActive: true
2162
- }
2163
- }
2164
- );
2165
- console.log(`✅ Template erstellt: ID ${testTemplate.id}`);
2166
- const version1 = await strapi.entityService.create(
2167
- "plugin::magic-mail.email-template-version",
2168
- {
2169
- data: {
2170
- template: testTemplate.id,
2171
- // 👈 Direkte Verbindung beim Erstellen
2172
- versionNumber: 1,
2173
- name: "Version 1 von Test",
2174
- subject: "Test Subject V1",
2175
- bodyHtml: "<p>Version 1 HTML</p>",
2176
- bodyText: "Version 1 Text"
2177
- }
2175
+ console.log("\n[TEST] TEST 1: Version → Template Verbindung\n");
2176
+ const testTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).create({
2177
+ data: {
2178
+ templateReferenceId: Math.floor(Math.random() * 1e6),
2179
+ name: "Test Template Relations",
2180
+ subject: "Test Subject",
2181
+ bodyHtml: "<p>Test HTML</p>",
2182
+ bodyText: "Test Text",
2183
+ category: "custom",
2184
+ isActive: true
2178
2185
  }
2179
- );
2180
- console.log(`✅ Version erstellt: ID ${version1.id}, versionNumber: ${version1.versionNumber}`);
2181
- const versionCheck = await strapi.entityService.findOne(
2182
- "plugin::magic-mail.email-template-version",
2183
- version1.id,
2184
- {
2185
- populate: ["template"]
2186
+ });
2187
+ console.log(`[SUCCESS] Template erstellt: documentId ${testTemplate.documentId}`);
2188
+ const version1 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).create({
2189
+ data: {
2190
+ template: testTemplate.documentId,
2191
+ versionNumber: 1,
2192
+ name: "Version 1 von Test",
2193
+ subject: "Test Subject V1",
2194
+ bodyHtml: "<p>Version 1 HTML</p>",
2195
+ bodyText: "Version 1 Text"
2186
2196
  }
2187
- );
2188
- console.log("\n🔍 Prüfung Version Template:");
2197
+ });
2198
+ console.log(`[SUCCESS] Version erstellt: documentId ${version1.documentId}, versionNumber: ${version1.versionNumber}`);
2199
+ const versionCheck = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2200
+ documentId: version1.documentId,
2201
+ populate: ["template"]
2202
+ });
2203
+ console.log("\n[CHECK] Prüfung Version → Template:");
2189
2204
  test1Success = !!versionCheck.template;
2190
2205
  if (test1Success) {
2191
- console.log(` SUCCESS: Version ${versionCheck.id} → Template ${versionCheck.template.id}`);
2192
- console.log(` 📋 Template: "${versionCheck.template.name}"`);
2206
+ console.log(` [SUCCESS] SUCCESS: Version → Template ${versionCheck.template.documentId}`);
2193
2207
  } else {
2194
- console.log(` FEHLER: Version ${versionCheck.id} hat KEINE Template-Verbindung!`);
2208
+ console.log(` [ERROR] FEHLER: Version hat KEINE Template-Verbindung!`);
2195
2209
  }
2196
- const templateCheck1 = await strapi.entityService.findOne(
2197
- "plugin::magic-mail.email-template",
2198
- testTemplate.id,
2199
- {
2200
- populate: ["versions"]
2201
- }
2202
- );
2203
- console.log("\n🔍 Prüfung Template → Versions:");
2210
+ const templateCheck1 = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2211
+ documentId: testTemplate.documentId,
2212
+ populate: ["versions"]
2213
+ });
2214
+ console.log("\n[CHECK] Prüfung Template → Versions:");
2204
2215
  test1ReverseSuccess = templateCheck1.versions && templateCheck1.versions.length > 0;
2205
2216
  if (test1ReverseSuccess) {
2206
- console.log(` SUCCESS: Template ${templateCheck1.id} hat ${templateCheck1.versions.length} Version(en)`);
2207
- templateCheck1.versions.forEach((v) => {
2208
- console.log(` 📋 Version ${v.id}: versionNumber ${v.versionNumber}`);
2209
- });
2217
+ console.log(` [SUCCESS] SUCCESS: Template hat ${templateCheck1.versions.length} Version(en)`);
2210
2218
  } else {
2211
- console.log(` FEHLER: Template ${templateCheck1.id} hat KEINE Versionen!`);
2212
- }
2213
- console.log("\n\n📝 TEST 2: Nachträgliche Verbindung (Template Update)\n");
2214
- const version2 = await strapi.entityService.create(
2215
- "plugin::magic-mail.email-template-version",
2216
- {
2217
- data: {
2218
- versionNumber: 2,
2219
- name: "Version 2 ohne Template",
2220
- subject: "Test Subject V2",
2221
- bodyHtml: "<p>Version 2 HTML</p>",
2222
- bodyText: "Version 2 Text"
2223
- }
2224
- }
2225
- );
2226
- console.log(`✅ Version 2 erstellt: ID ${version2.id} (ohne Template)`);
2227
- await strapi.entityService.update(
2228
- "plugin::magic-mail.email-template",
2229
- testTemplate.id,
2230
- {
2231
- data: {
2232
- versions: {
2233
- connect: [version2.id]
2234
- // 👈 Nachträgliche Verbindung
2235
- }
2236
- }
2219
+ console.log(` [ERROR] FEHLER: Template hat KEINE Versionen!`);
2220
+ }
2221
+ console.log("\n\n[TEST] TEST 2: Nachträgliche Verbindung\n");
2222
+ const version2 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).create({
2223
+ data: {
2224
+ versionNumber: 2,
2225
+ name: "Version 2 ohne Template",
2226
+ subject: "Test Subject V2",
2227
+ bodyHtml: "<p>Version 2 HTML</p>",
2228
+ bodyText: "Version 2 Text"
2237
2229
  }
2238
- );
2239
- console.log(`✅ Template updated: Version ${version2.id} verbunden`);
2240
- const templateCheck2 = await strapi.entityService.findOne(
2241
- "plugin::magic-mail.email-template",
2242
- testTemplate.id,
2243
- {
2244
- populate: ["versions"]
2230
+ });
2231
+ console.log(`[SUCCESS] Version 2 erstellt: documentId ${version2.documentId} (ohne Template)`);
2232
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).update({
2233
+ documentId: version2.documentId,
2234
+ data: {
2235
+ template: testTemplate.documentId
2245
2236
  }
2246
- );
2247
- console.log("\n🔍 Prüfung nach Template Update:");
2237
+ });
2238
+ console.log(`[SUCCESS] Version 2 mit Template verbunden`);
2239
+ const templateCheck2 = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2240
+ documentId: testTemplate.documentId,
2241
+ populate: ["versions"]
2242
+ });
2243
+ console.log("\n[CHECK] Prüfung nach Update:");
2248
2244
  test2Success = templateCheck2.versions && templateCheck2.versions.length >= 2;
2249
2245
  if (test2Success) {
2250
- console.log(` SUCCESS: Template hat jetzt ${templateCheck2.versions.length} Versionen`);
2251
- templateCheck2.versions.forEach((v) => {
2252
- console.log(` 📋 Version ${v.id}: versionNumber ${v.versionNumber}, "${v.name}"`);
2253
- });
2246
+ console.log(` [SUCCESS] SUCCESS: Template hat jetzt ${templateCheck2.versions.length} Versionen`);
2254
2247
  } else {
2255
- console.log(` FEHLER: Template hat nur ${templateCheck2.versions?.length || 0} Version(en)!`);
2248
+ console.log(` [ERROR] FEHLER: Template hat nur ${templateCheck2.versions?.length || 0} Version(en)!`);
2256
2249
  }
2257
- const version2Check = await strapi.entityService.findOne(
2258
- "plugin::magic-mail.email-template-version",
2259
- version2.id,
2260
- {
2261
- populate: ["template"]
2262
- }
2263
- );
2264
- console.log("\n🔍 Prüfung Version 2 → Template:");
2250
+ const version2Check = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2251
+ documentId: version2.documentId,
2252
+ populate: ["template"]
2253
+ });
2265
2254
  test2ReverseSuccess = !!version2Check.template;
2266
2255
  if (test2ReverseSuccess) {
2267
- console.log(` SUCCESS: Version ${version2Check.id} → Template ${version2Check.template.id}`);
2268
- console.log(` 📋 Template: "${version2Check.template.name}"`);
2256
+ console.log(` [SUCCESS] SUCCESS: Version 2 → Template verbunden`);
2269
2257
  } else {
2270
- console.log(` FEHLER: Version ${version2Check.id} hat KEINE Template-Verbindung!`);
2271
- }
2272
- console.log("\n\n📝 TEST 3: Template Update (Auto-Versionierung)\n");
2273
- const autoTemplate = await strapi.entityService.create(
2274
- "plugin::magic-mail.email-template",
2275
- {
2276
- data: {
2277
- templateReferenceId: Math.floor(Math.random() * 1e6),
2278
- name: "Auto Version Test",
2279
- subject: "Original Subject",
2280
- bodyHtml: "<p>Original HTML</p>",
2281
- bodyText: "Original Text",
2282
- category: "custom",
2283
- isActive: true
2284
- }
2258
+ console.log(` [ERROR] FEHLER: Version 2 hat KEINE Template-Verbindung!`);
2259
+ }
2260
+ console.log("\n\n[TEST] TEST 3: Template Update (Auto-Versionierung)\n");
2261
+ const autoTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).create({
2262
+ data: {
2263
+ templateReferenceId: Math.floor(Math.random() * 1e6),
2264
+ name: "Auto Version Test",
2265
+ subject: "Original Subject",
2266
+ bodyHtml: "<p>Original HTML</p>",
2267
+ bodyText: "Original Text",
2268
+ category: "custom",
2269
+ isActive: true
2285
2270
  }
2286
- );
2287
- console.log(`✅ Template erstellt: ID ${autoTemplate.id}, name: "${autoTemplate.name}"`);
2288
- const beforeUpdate = await strapi.entityService.findOne(
2289
- "plugin::magic-mail.email-template",
2290
- autoTemplate.id,
2291
- { populate: ["versions"] }
2292
- );
2293
- console.log(` 📊 Versionen vor Update: ${beforeUpdate.versions?.length || 0}`);
2294
- console.log("\n🔄 Führe Template-Update aus...");
2271
+ });
2272
+ console.log(`[SUCCESS] Template erstellt: documentId ${autoTemplate.documentId}`);
2295
2273
  const emailDesignerService = strapi.plugin("magic-mail").service("email-designer");
2296
- await emailDesignerService.update(autoTemplate.id, {
2274
+ await emailDesignerService.update(autoTemplate.documentId, {
2297
2275
  subject: "Updated Subject V1",
2298
2276
  bodyHtml: "<p>Updated HTML V1</p>",
2299
2277
  bodyText: "Updated Text V1"
2300
2278
  });
2301
- console.log(" Template updated");
2302
- const afterFirstUpdate = await strapi.entityService.findOne(
2303
- "plugin::magic-mail.email-template",
2304
- autoTemplate.id,
2305
- { populate: ["versions"] }
2306
- );
2307
- console.log("\n🔍 Prüfung nach 1. Update:");
2279
+ console.log("[SUCCESS] Template updated");
2280
+ const afterFirstUpdate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2281
+ documentId: autoTemplate.documentId,
2282
+ populate: ["versions"]
2283
+ });
2284
+ console.log("\n[CHECK] Prüfung nach 1. Update:");
2308
2285
  test3a_versionCreated = afterFirstUpdate.versions && afterFirstUpdate.versions.length === 1;
2309
2286
  if (test3a_versionCreated) {
2310
- console.log(` SUCCESS: Automatisch 1 Version erstellt`);
2311
- const autoVersion1 = await strapi.entityService.findOne(
2312
- "plugin::magic-mail.email-template-version",
2313
- afterFirstUpdate.versions[0].id,
2314
- { populate: ["template"] }
2315
- );
2287
+ console.log(` [SUCCESS] SUCCESS: Automatisch 1 Version erstellt`);
2288
+ const autoVersion1 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2289
+ documentId: afterFirstUpdate.versions[0].documentId,
2290
+ populate: ["template"]
2291
+ });
2316
2292
  test3a_hasTemplate = !!autoVersion1.template;
2317
2293
  if (test3a_hasTemplate) {
2318
- console.log(` SUCCESS: Version ${autoVersion1.id} hat Template-Verbindung (Template ID: ${autoVersion1.template.id})`);
2319
- console.log(` 📋 Version: versionNumber ${autoVersion1.versionNumber}, subject: "${autoVersion1.subject}"`);
2294
+ console.log(` [SUCCESS] SUCCESS: Version hat Template-Verbindung`);
2320
2295
  } else {
2321
- console.log(` FEHLER: Version ${autoVersion1.id} hat KEINE Template-Verbindung!`);
2296
+ console.log(` [ERROR] FEHLER: Version hat KEINE Template-Verbindung!`);
2322
2297
  }
2323
2298
  } else {
2324
- console.log(` FEHLER: Keine Version erstellt! Versionen: ${afterFirstUpdate.versions?.length || 0}`);
2299
+ console.log(` [ERROR] FEHLER: Keine Version erstellt!`);
2325
2300
  }
2326
- console.log("\n🔄 Führe 2. Template-Update aus...");
2327
- await emailDesignerService.update(autoTemplate.id, {
2301
+ await emailDesignerService.update(autoTemplate.documentId, {
2328
2302
  subject: "Updated Subject V2",
2329
2303
  bodyHtml: "<p>Updated HTML V2</p>",
2330
2304
  bodyText: "Updated Text V2"
2331
2305
  });
2332
- console.log("✅ Template updated (2. Mal)");
2333
- const afterSecondUpdate = await strapi.entityService.findOne(
2334
- "plugin::magic-mail.email-template",
2335
- autoTemplate.id,
2336
- { populate: ["versions"] }
2337
- );
2338
- console.log("\n🔍 Prüfung nach 2. Update:");
2306
+ const afterSecondUpdate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2307
+ documentId: autoTemplate.documentId,
2308
+ populate: ["versions"]
2309
+ });
2310
+ console.log("\n[CHECK] Prüfung nach 2. Update:");
2339
2311
  test3b_twoVersions = afterSecondUpdate.versions && afterSecondUpdate.versions.length === 2;
2340
2312
  if (test3b_twoVersions) {
2341
- console.log(` SUCCESS: Jetzt 2 Versionen vorhanden`);
2313
+ console.log(` [SUCCESS] SUCCESS: Jetzt 2 Versionen vorhanden`);
2342
2314
  let allVersionsHaveTemplate = true;
2343
2315
  for (const version3 of afterSecondUpdate.versions) {
2344
- const fullVersion = await strapi.entityService.findOne(
2345
- "plugin::magic-mail.email-template-version",
2346
- version3.id,
2347
- { populate: ["template"] }
2348
- );
2349
- if (fullVersion.template) {
2350
- console.log(` ✅ Version ${fullVersion.id} (v${fullVersion.versionNumber}): Template-Verbindung OK`);
2351
- } else {
2352
- console.log(` ❌ Version ${fullVersion.id} (v${fullVersion.versionNumber}): KEINE Template-Verbindung!`);
2316
+ const fullVersion = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2317
+ documentId: version3.documentId,
2318
+ populate: ["template"]
2319
+ });
2320
+ if (!fullVersion.template) {
2353
2321
  allVersionsHaveTemplate = false;
2354
2322
  }
2355
2323
  }
2356
2324
  test3b_allHaveTemplate = allVersionsHaveTemplate;
2357
2325
  if (allVersionsHaveTemplate) {
2358
- console.log(` SUCCESS: Alle Versionen haben Template-Verbindung!`);
2326
+ console.log(` [SUCCESS] SUCCESS: Alle Versionen haben Template-Verbindung!`);
2327
+ } else {
2328
+ console.log(` [ERROR] FEHLER: Nicht alle Versionen haben Template-Verbindung!`);
2359
2329
  }
2360
2330
  } else {
2361
- console.log(` FEHLER: Falsche Anzahl Versionen! Erwartet: 2, Gefunden: ${afterSecondUpdate.versions?.length || 0}`);
2331
+ console.log(` [ERROR] FEHLER: Falsche Anzahl Versionen!`);
2362
2332
  }
2363
2333
  console.log("\n🧹 Cleanup Test 3...");
2364
2334
  if (afterSecondUpdate.versions) {
2365
2335
  for (const version3 of afterSecondUpdate.versions) {
2366
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version3.id);
2336
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version3.documentId });
2367
2337
  }
2368
2338
  }
2369
- await strapi.entityService.delete("plugin::magic-mail.email-template", autoTemplate.id);
2370
- console.log(" Test 3 Daten gelöscht");
2339
+ await strapi.documents(EMAIL_TEMPLATE_UID).delete({ documentId: autoTemplate.documentId });
2340
+ console.log(" [SUCCESS] Test 3 Daten gelöscht");
2371
2341
  console.log("\n\n" + "=".repeat(60));
2372
- console.log("📊 ZUSAMMENFASSUNG");
2342
+ console.log("[STATS] ZUSAMMENFASSUNG");
2373
2343
  console.log("=".repeat(60));
2374
- const finalTemplate = await strapi.entityService.findOne(
2375
- "plugin::magic-mail.email-template",
2376
- testTemplate.id,
2377
- {
2378
- populate: ["versions"]
2379
- }
2380
- );
2344
+ const finalTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2345
+ documentId: testTemplate.documentId,
2346
+ populate: ["versions"]
2347
+ });
2381
2348
  console.log(`
2382
- 📋 Template: "${finalTemplate.name}" (ID: ${finalTemplate.id})`);
2383
- console.log(` Anzahl Versionen im Template: ${finalTemplate.versions?.length || 0}`);
2384
- if (finalTemplate.versions && finalTemplate.versions.length > 0) {
2385
- finalTemplate.versions.forEach((v) => {
2386
- console.log(` - Version ${v.id}: versionNumber ${v.versionNumber}`);
2387
- });
2388
- }
2349
+ [INFO] Template: "${finalTemplate.name}" (documentId: ${finalTemplate.documentId})`);
2350
+ console.log(` Anzahl Versionen: ${finalTemplate.versions?.length || 0}`);
2389
2351
  console.log("\n🧹 Aufräumen...");
2390
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version1.id);
2391
- console.log(` ✅ Version ${version1.id} gelöscht`);
2392
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version2.id);
2393
- console.log(` Version ${version2.id} gelöscht`);
2394
- await strapi.entityService.delete("plugin::magic-mail.email-template", testTemplate.id);
2395
- console.log(` ✅ Template ${testTemplate.id} gelöscht`);
2396
- console.log("\n✅ Test abgeschlossen!\n");
2352
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version1.documentId });
2353
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version2.documentId });
2354
+ await strapi.documents(EMAIL_TEMPLATE_UID).delete({ documentId: testTemplate.documentId });
2355
+ console.log(" [SUCCESS] Alle Test-Daten gelöscht");
2356
+ console.log("\n[SUCCESS] Test abgeschlossen!\n");
2397
2357
  const allSuccess = test1Success && test1ReverseSuccess && test2Success && test2ReverseSuccess && test3a_versionCreated && test3a_hasTemplate && test3b_twoVersions && test3b_allHaveTemplate;
2398
2358
  ctx.body = {
2399
2359
  success: allSuccess,
2400
- message: allSuccess ? "Alle Tests erfolgreich! " : "Einige Tests fehlgeschlagen ",
2360
+ message: allSuccess ? "Alle Tests erfolgreich! [SUCCESS]" : "Einige Tests fehlgeschlagen [ERROR]",
2401
2361
  tests: {
2402
2362
  test1_version_to_template: test1Success,
2403
2363
  test1_template_to_version: test1ReverseSuccess,
@@ -2407,15 +2367,10 @@ function requireTest() {
2407
2367
  test3_auto_version_has_template: test3a_hasTemplate,
2408
2368
  test3_two_auto_versions: test3b_twoVersions,
2409
2369
  test3_all_auto_versions_have_template: test3b_allHaveTemplate
2410
- },
2411
- template: {
2412
- id: testTemplate.id,
2413
- name: testTemplate.name,
2414
- versionsCount: finalTemplate.versions?.length || 0
2415
2370
  }
2416
2371
  };
2417
2372
  } catch (error) {
2418
- console.error("\n FEHLER:", error.message);
2373
+ console.error("\n[ERROR] FEHLER:", error.message);
2419
2374
  console.error(error.stack);
2420
2375
  ctx.throw(500, error);
2421
2376
  }
@@ -3009,7 +2964,7 @@ function requireEncryption() {
3009
2964
  if (envKey) {
3010
2965
  return crypto.createHash("sha256").update(envKey).digest();
3011
2966
  }
3012
- console.warn("[magic-mail] ⚠️ No MAGIC_MAIL_ENCRYPTION_KEY found. Using fallback.");
2967
+ console.warn("[magic-mail] [WARNING] No MAGIC_MAIL_ENCRYPTION_KEY found. Using fallback.");
3013
2968
  return crypto.createHash("sha256").update("magic-mail-default-key").digest();
3014
2969
  }
3015
2970
  function encryptCredentials(data) {
@@ -3088,12 +3043,17 @@ function requireEmailRouter() {
3088
3043
  // Template Reference ID
3089
3044
  templateData,
3090
3045
  // Data for template rendering
3091
- data
3046
+ data,
3092
3047
  // Alias for templateData (for native Strapi compatibility)
3048
+ skipLinkTracking = false
3049
+ // Skip link rewriting for sensitive URLs (e.g., Magic Links)
3093
3050
  } = emailData;
3094
3051
  if (!templateData && data) {
3095
3052
  templateData = data;
3096
3053
  }
3054
+ if (skipLinkTracking) {
3055
+ strapi2.log.info(`[magic-mail] [SKIP-TRACK] skipLinkTracking=true received for email to: ${to}`);
3056
+ }
3097
3057
  let renderedTemplate = null;
3098
3058
  if (templateId || emailData.templateReferenceId) {
3099
3059
  try {
@@ -3106,10 +3066,10 @@ function requireEmailRouter() {
3106
3066
  if (!resolvedTemplateReferenceId && templateId) {
3107
3067
  const numericTemplateId = Number(templateId);
3108
3068
  if (!Number.isNaN(numericTemplateId) && Number.isInteger(numericTemplateId)) {
3109
- strapi2.log.info(`[magic-mail] 🔍 Looking up template by ID: ${numericTemplateId}`);
3069
+ strapi2.log.info(`[magic-mail] [CHECK] Looking up template by ID: ${numericTemplateId}`);
3110
3070
  templateRecord = await strapi2.plugin("magic-mail").service("email-designer").findOne(numericTemplateId);
3111
3071
  if (!templateRecord) {
3112
- strapi2.log.error(`[magic-mail] Template with ID ${numericTemplateId} not found in database`);
3072
+ strapi2.log.error(`[magic-mail] [ERROR] Template with ID ${numericTemplateId} not found in database`);
3113
3073
  throw new Error(`Template with ID ${numericTemplateId} not found`);
3114
3074
  }
3115
3075
  if (!templateRecord.templateReferenceId) {
@@ -3117,7 +3077,7 @@ function requireEmailRouter() {
3117
3077
  }
3118
3078
  resolvedTemplateReferenceId = String(templateRecord.templateReferenceId).trim();
3119
3079
  strapi2.log.info(
3120
- `[magic-mail] Found template: ID=${templateRecord.id}, referenceId="${resolvedTemplateReferenceId}", name="${templateRecord.name}"`
3080
+ `[magic-mail] [SUCCESS] Found template: ID=${templateRecord.id}, referenceId="${resolvedTemplateReferenceId}", name="${templateRecord.name}"`
3121
3081
  );
3122
3082
  } else {
3123
3083
  resolvedTemplateReferenceId = String(templateId).trim();
@@ -3133,14 +3093,14 @@ function requireEmailRouter() {
3133
3093
  subject = subject || renderedTemplate.subject;
3134
3094
  type = type || renderedTemplate.category;
3135
3095
  strapi2.log.info(
3136
- `[magic-mail] 📧 Rendered template reference "${resolvedTemplateReferenceId}" (requested ID: ${templateId ?? "n/a"}): ${renderedTemplate.templateName}`
3096
+ `[magic-mail] [EMAIL] Rendered template reference "${resolvedTemplateReferenceId}" (requested ID: ${templateId ?? "n/a"}): ${renderedTemplate.templateName}`
3137
3097
  );
3138
3098
  emailData.templateReferenceId = resolvedTemplateReferenceId;
3139
3099
  if (!emailData.templateName) {
3140
3100
  emailData.templateName = templateRecord?.name || renderedTemplate.templateName;
3141
3101
  }
3142
3102
  } catch (error) {
3143
- strapi2.log.error(`[magic-mail] Template rendering failed: ${error.message}`);
3103
+ strapi2.log.error(`[magic-mail] [ERROR] Template rendering failed: ${error.message}`);
3144
3104
  throw new Error(`Template rendering failed: ${error.message}`);
3145
3105
  }
3146
3106
  }
@@ -3169,10 +3129,14 @@ function requireEmailRouter() {
3169
3129
  });
3170
3130
  recipientHash = analyticsService.generateRecipientHash(emailLog.emailId, to);
3171
3131
  html = analyticsService.injectTrackingPixel(html, emailLog.emailId, recipientHash);
3172
- html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
3173
- strapi2.log.info(`[magic-mail] 📊 Tracking enabled for email: ${emailLog.emailId}`);
3132
+ if (!skipLinkTracking) {
3133
+ html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
3134
+ strapi2.log.info(`[magic-mail] [STATS] Full tracking enabled for email: ${emailLog.emailId}`);
3135
+ } else {
3136
+ strapi2.log.info(`[magic-mail] [STATS] Open tracking enabled, link tracking DISABLED for email: ${emailLog.emailId}`);
3137
+ }
3174
3138
  } catch (error) {
3175
- strapi2.log.error(`[magic-mail] ⚠️ Tracking setup failed (continuing without tracking):`, error.message);
3139
+ strapi2.log.error(`[magic-mail] [WARNING] Tracking setup failed (continuing without tracking):`, error.message);
3176
3140
  }
3177
3141
  }
3178
3142
  emailData.html = html;
@@ -3183,7 +3147,7 @@ function requireEmailRouter() {
3183
3147
  if (priority === "high") {
3184
3148
  const hasFeature = await licenseGuard2.hasFeature("priority-headers");
3185
3149
  if (!hasFeature) {
3186
- strapi2.log.warn("[magic-mail] ⚠️ High priority emails require Advanced license - using normal priority");
3150
+ strapi2.log.warn("[magic-mail] [WARNING] High priority emails require Advanced license - using normal priority");
3187
3151
  emailData.priority = "normal";
3188
3152
  }
3189
3153
  }
@@ -3207,8 +3171,8 @@ function requireEmailRouter() {
3207
3171
  const result = await this.sendViaAccount(account, emailData);
3208
3172
  if (emailLog) {
3209
3173
  try {
3210
- await strapi2.db.query("plugin::magic-mail.email-log").update({
3211
- where: { id: emailLog.id },
3174
+ await strapi2.documents("plugin::magic-mail.email-log").update({
3175
+ documentId: emailLog.documentId,
3212
3176
  data: {
3213
3177
  accountId: account.id,
3214
3178
  accountName: account.name,
@@ -3219,15 +3183,15 @@ function requireEmailRouter() {
3219
3183
  strapi2.log.error("[magic-mail] Failed to update email log:", error.message);
3220
3184
  }
3221
3185
  }
3222
- await this.updateAccountStats(account.id);
3223
- strapi2.log.info(`[magic-mail] Email sent to ${to} via ${account.name}`);
3186
+ await this.updateAccountStats(account.documentId);
3187
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email sent to ${to} via ${account.name}`);
3224
3188
  return {
3225
3189
  success: true,
3226
3190
  accountUsed: account.name,
3227
3191
  messageId: result.messageId
3228
3192
  };
3229
3193
  } catch (error) {
3230
- strapi2.log.error("[magic-mail] Email send failed:", error);
3194
+ strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
3231
3195
  throw error;
3232
3196
  }
3233
3197
  },
@@ -3235,21 +3199,21 @@ function requireEmailRouter() {
3235
3199
  * Select best account based on rules
3236
3200
  */
3237
3201
  async selectAccount(type, priority, excludeIds = [], emailData = {}) {
3238
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
3202
+ const accounts2 = await strapi2.documents("plugin::magic-mail.email-account").findMany({
3239
3203
  filters: {
3240
3204
  isActive: true,
3241
3205
  id: { $notIn: excludeIds }
3242
3206
  },
3243
- sort: { priority: "desc" }
3207
+ sort: [{ priority: "desc" }]
3244
3208
  });
3245
3209
  if (!accounts2 || accounts2.length === 0) {
3246
3210
  return null;
3247
3211
  }
3248
- const allRules = await strapi2.entityService.findMany("plugin::magic-mail.routing-rule", {
3212
+ const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
3249
3213
  filters: {
3250
3214
  isActive: true
3251
3215
  },
3252
- sort: { priority: "desc" }
3216
+ sort: [{ priority: "desc" }]
3253
3217
  });
3254
3218
  for (const rule of allRules) {
3255
3219
  let matches = false;
@@ -3273,13 +3237,13 @@ function requireEmailRouter() {
3273
3237
  if (matches) {
3274
3238
  const account = accounts2.find((a) => a.name === rule.accountName);
3275
3239
  if (account) {
3276
- strapi2.log.info(`[magic-mail] 🎯 Routing rule matched: ${rule.name} ${account.name}`);
3240
+ strapi2.log.info(`[magic-mail] [ROUTE] Routing rule matched: ${rule.name} -> ${account.name}`);
3277
3241
  return account;
3278
3242
  }
3279
3243
  if (rule.fallbackAccountName) {
3280
3244
  const fallbackAccount = accounts2.find((a) => a.name === rule.fallbackAccountName);
3281
3245
  if (fallbackAccount) {
3282
- strapi2.log.info(`[magic-mail] 🔄 Using fallback account: ${fallbackAccount.name}`);
3246
+ strapi2.log.info(`[magic-mail] [FALLBACK] Using fallback account: ${fallbackAccount.name}`);
3283
3247
  return fallbackAccount;
3284
3248
  }
3285
3249
  }
@@ -3383,7 +3347,7 @@ function requireEmailRouter() {
3383
3347
  mailOptions.headers["List-Unsubscribe-Post"] = "List-Unsubscribe=One-Click";
3384
3348
  mailOptions.headers["Precedence"] = "bulk";
3385
3349
  } else {
3386
- strapi2.log.warn("[magic-mail] ⚠️ Marketing email without unsubscribe URL - may violate GDPR/CAN-SPAM");
3350
+ strapi2.log.warn("[magic-mail] [WARNING] Marketing email without unsubscribe URL - may violate GDPR/CAN-SPAM");
3387
3351
  }
3388
3352
  }
3389
3353
  if (emailData.headers && typeof emailData.headers === "object") {
@@ -3429,14 +3393,15 @@ function requireEmailRouter() {
3429
3393
  config2.clientSecret
3430
3394
  );
3431
3395
  currentAccessToken = newTokens.accessToken;
3432
- strapi2.log.info("[magic-mail] Token refreshed successfully");
3396
+ strapi2.log.info("[magic-mail] [SUCCESS] Token refreshed successfully");
3433
3397
  const { encryptCredentials } = requireEncryption();
3434
3398
  const updatedOAuth = encryptCredentials({
3435
3399
  ...oauth2,
3436
3400
  accessToken: newTokens.accessToken,
3437
3401
  expiresAt: newTokens.expiresAt
3438
3402
  });
3439
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3403
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3404
+ documentId: account.documentId,
3440
3405
  data: { oauth: updatedOAuth }
3441
3406
  });
3442
3407
  } catch (refreshErr) {
@@ -3555,13 +3520,19 @@ function requireEmailRouter() {
3555
3520
  throw new Error(`Gmail API error: ${errorData.error?.message || response.statusText}`);
3556
3521
  }
3557
3522
  const result = await response.json();
3558
- strapi2.log.info("[magic-mail] Email sent via Gmail API");
3523
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Gmail API");
3559
3524
  return {
3560
3525
  messageId: result.id,
3561
3526
  response: "OK"
3562
3527
  };
3563
3528
  } catch (err) {
3564
- strapi2.log.error("[magic-mail] Gmail API send failed:", err);
3529
+ strapi2.log.error("[magic-mail] Gmail API send failed:", err.message || err);
3530
+ strapi2.log.error("[magic-mail] Error details:", {
3531
+ name: err.name,
3532
+ code: err.code,
3533
+ cause: err.cause?.message || err.cause,
3534
+ stack: err.stack?.split("\n").slice(0, 3).join("\n")
3535
+ });
3565
3536
  throw err;
3566
3537
  }
3567
3538
  },
@@ -3604,14 +3575,15 @@ function requireEmailRouter() {
3604
3575
  config2.tenantId
3605
3576
  );
3606
3577
  currentAccessToken = newTokens.accessToken;
3607
- strapi2.log.info("[magic-mail] Microsoft token refreshed successfully");
3578
+ strapi2.log.info("[magic-mail] [SUCCESS] Microsoft token refreshed successfully");
3608
3579
  const { encryptCredentials } = requireEncryption();
3609
3580
  const updatedOAuth = encryptCredentials({
3610
3581
  ...oauth2,
3611
3582
  accessToken: newTokens.accessToken,
3612
3583
  expiresAt: newTokens.expiresAt
3613
3584
  });
3614
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3585
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3586
+ documentId: account.documentId,
3615
3587
  data: { oauth: updatedOAuth }
3616
3588
  });
3617
3589
  } catch (refreshErr) {
@@ -3721,7 +3693,7 @@ function requireEmailRouter() {
3721
3693
  strapi2.log.error("[magic-mail] Response status:", response.status);
3722
3694
  throw new Error(`Microsoft Graph API error: ${response.status} - ${response.statusText}`);
3723
3695
  }
3724
- strapi2.log.info("[magic-mail] Email sent via Microsoft Graph API with MIME + custom headers");
3696
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Microsoft Graph API with MIME + custom headers");
3725
3697
  strapi2.log.info("[magic-mail] Microsoft adds From/DKIM automatically for DMARC compliance");
3726
3698
  return {
3727
3699
  messageId: `microsoft-${Date.now()}`,
@@ -3763,14 +3735,15 @@ function requireEmailRouter() {
3763
3735
  config2.clientSecret
3764
3736
  );
3765
3737
  currentAccessToken = newTokens.accessToken;
3766
- strapi2.log.info("[magic-mail] Token refreshed successfully");
3738
+ strapi2.log.info("[magic-mail] [SUCCESS] Token refreshed successfully");
3767
3739
  const { encryptCredentials } = requireEncryption();
3768
3740
  const updatedOAuth = encryptCredentials({
3769
3741
  ...oauth2,
3770
3742
  accessToken: newTokens.accessToken,
3771
3743
  expiresAt: newTokens.expiresAt
3772
3744
  });
3773
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3745
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3746
+ documentId: account.documentId,
3774
3747
  data: { oauth: updatedOAuth }
3775
3748
  });
3776
3749
  } catch (refreshErr) {
@@ -3816,7 +3789,7 @@ function requireEmailRouter() {
3816
3789
  strapi2.log.info(`[magic-mail] Sending email with ${mailOptions.attachments.length} attachment(s)`);
3817
3790
  }
3818
3791
  const result = await transporter.sendMail(mailOptions);
3819
- strapi2.log.info("[magic-mail] Email sent via Yahoo OAuth");
3792
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Yahoo OAuth");
3820
3793
  return {
3821
3794
  messageId: result.messageId,
3822
3795
  response: result.response
@@ -3911,7 +3884,7 @@ function requireEmailRouter() {
3911
3884
  strapi2.log.error("[magic-mail] SendGrid API error:", errorText);
3912
3885
  throw new Error(`SendGrid API error: ${response.statusText}`);
3913
3886
  }
3914
- strapi2.log.info("[magic-mail] Email sent via SendGrid API");
3887
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via SendGrid API");
3915
3888
  return {
3916
3889
  messageId: response.headers.get("x-message-id") || `sendgrid-${Date.now()}`,
3917
3890
  response: "Accepted"
@@ -3994,7 +3967,7 @@ function requireEmailRouter() {
3994
3967
  throw new Error(`Mailgun API error: ${response.statusText}`);
3995
3968
  }
3996
3969
  const result = await response.json();
3997
- strapi2.log.info("[magic-mail] Email sent via Mailgun API");
3970
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Mailgun API");
3998
3971
  return {
3999
3972
  messageId: result.id || `mailgun-${Date.now()}`,
4000
3973
  response: result.message || "Queued"
@@ -4018,10 +3991,15 @@ function requireEmailRouter() {
4018
3991
  },
4019
3992
  /**
4020
3993
  * Update account statistics
3994
+ * Note: This function now expects documentId
4021
3995
  */
4022
- async updateAccountStats(accountId) {
4023
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4024
- await strapi2.entityService.update("plugin::magic-mail.email-account", accountId, {
3996
+ async updateAccountStats(documentId) {
3997
+ const account = await strapi2.documents("plugin::magic-mail.email-account").findOne({
3998
+ documentId
3999
+ });
4000
+ if (!account) return;
4001
+ await strapi2.documents("plugin::magic-mail.email-account").update({
4002
+ documentId,
4025
4003
  data: {
4026
4004
  emailsSentToday: (account.emailsSentToday || 0) + 1,
4027
4005
  emailsSentThisHour: (account.emailsSentThisHour || 0) + 1,
@@ -4042,7 +4020,7 @@ function requireEmailRouter() {
4042
4020
  * Get account by name
4043
4021
  */
4044
4022
  async getAccountByName(name) {
4045
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4023
+ const accounts2 = await strapi2.documents("plugin::magic-mail.email-account").findMany({
4046
4024
  filters: { name, isActive: true },
4047
4025
  limit: 1
4048
4026
  });
@@ -4092,7 +4070,7 @@ function requireEmailRouter() {
4092
4070
  if (html && !text) {
4093
4071
  strapi2.log.warn("[magic-mail] Email has HTML but no text alternative - may reduce deliverability");
4094
4072
  }
4095
- strapi2.log.info("[magic-mail] Email security validation passed");
4073
+ strapi2.log.info("[magic-mail] [SUCCESS] Email security validation passed");
4096
4074
  },
4097
4075
  /**
4098
4076
  * Add security headers to email data
@@ -4132,7 +4110,24 @@ function requireAccountManager() {
4132
4110
  if (hasRequiredAccountManager) return accountManager;
4133
4111
  hasRequiredAccountManager = 1;
4134
4112
  const { encryptCredentials, decryptCredentials } = requireEncryption();
4113
+ const EMAIL_ACCOUNT_UID = "plugin::magic-mail.email-account";
4135
4114
  accountManager = ({ strapi: strapi2 }) => ({
4115
+ /**
4116
+ * Resolves account ID to documentId (handles both numeric id and documentId)
4117
+ * @param {string|number} idOrDocumentId - Either numeric id or documentId
4118
+ * @returns {Promise<string|null>} The documentId or null if not found
4119
+ */
4120
+ async resolveDocumentId(idOrDocumentId) {
4121
+ if (idOrDocumentId && !/^\d+$/.test(String(idOrDocumentId))) {
4122
+ return String(idOrDocumentId);
4123
+ }
4124
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4125
+ filters: { id: Number(idOrDocumentId) },
4126
+ fields: ["documentId"],
4127
+ limit: 1
4128
+ });
4129
+ return accounts2.length > 0 ? accounts2[0].documentId : null;
4130
+ },
4136
4131
  /**
4137
4132
  * Create new email account
4138
4133
  */
@@ -4154,7 +4149,7 @@ function requireAccountManager() {
4154
4149
  if (isPrimary) {
4155
4150
  await this.unsetAllPrimary();
4156
4151
  }
4157
- const account = await strapi2.entityService.create("plugin::magic-mail.email-account", {
4152
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).create({
4158
4153
  data: {
4159
4154
  name,
4160
4155
  provider,
@@ -4172,14 +4167,20 @@ function requireAccountManager() {
4172
4167
  totalEmailsSent: 0
4173
4168
  }
4174
4169
  });
4175
- strapi2.log.info(`[magic-mail] Email account created: ${name}`);
4170
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email account created: ${name}`);
4176
4171
  return account;
4177
4172
  },
4178
4173
  /**
4179
4174
  * Update email account
4180
4175
  */
4181
- async updateAccount(accountId, accountData) {
4182
- const existingAccount = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4176
+ async updateAccount(idOrDocumentId, accountData) {
4177
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4178
+ if (!documentId) {
4179
+ throw new Error("Account not found");
4180
+ }
4181
+ const existingAccount = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4182
+ documentId
4183
+ });
4183
4184
  if (!existingAccount) {
4184
4185
  throw new Error("Account not found");
4185
4186
  }
@@ -4201,7 +4202,8 @@ function requireAccountManager() {
4201
4202
  if (isPrimary && !existingAccount.isPrimary) {
4202
4203
  await this.unsetAllPrimary();
4203
4204
  }
4204
- const updatedAccount = await strapi2.entityService.update("plugin::magic-mail.email-account", accountId, {
4205
+ const updatedAccount = await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4206
+ documentId,
4205
4207
  data: {
4206
4208
  name,
4207
4209
  description,
@@ -4217,14 +4219,20 @@ function requireAccountManager() {
4217
4219
  hourlyLimit
4218
4220
  }
4219
4221
  });
4220
- strapi2.log.info(`[magic-mail] Email account updated: ${name} (Active: ${isActive})`);
4222
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email account updated: ${name} (Active: ${isActive})`);
4221
4223
  return updatedAccount;
4222
4224
  },
4223
4225
  /**
4224
4226
  * Test email account
4225
4227
  */
4226
- async testAccount(accountId, testEmail, testOptions = {}) {
4227
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4228
+ async testAccount(idOrDocumentId, testEmail, testOptions = {}) {
4229
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4230
+ if (!documentId) {
4231
+ throw new Error("Account not found");
4232
+ }
4233
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4234
+ documentId
4235
+ });
4228
4236
  if (!account) {
4229
4237
  throw new Error("Account not found");
4230
4238
  }
@@ -4303,8 +4311,8 @@ If you receive this, your email account is configured correctly!`,
4303
4311
  * Get all accounts
4304
4312
  */
4305
4313
  async getAllAccounts() {
4306
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4307
- sort: { priority: "desc" }
4314
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4315
+ sort: [{ priority: "desc" }]
4308
4316
  });
4309
4317
  return accounts2.map((account) => ({
4310
4318
  ...account,
@@ -4314,8 +4322,14 @@ If you receive this, your email account is configured correctly!`,
4314
4322
  /**
4315
4323
  * Get single account with decrypted config (for editing)
4316
4324
  */
4317
- async getAccountWithDecryptedConfig(accountId) {
4318
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4325
+ async getAccountWithDecryptedConfig(idOrDocumentId) {
4326
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4327
+ if (!documentId) {
4328
+ throw new Error("Account not found");
4329
+ }
4330
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4331
+ documentId
4332
+ });
4319
4333
  if (!account) {
4320
4334
  throw new Error("Account not found");
4321
4335
  }
@@ -4328,19 +4342,24 @@ If you receive this, your email account is configured correctly!`,
4328
4342
  /**
4329
4343
  * Delete account
4330
4344
  */
4331
- async deleteAccount(accountId) {
4332
- await strapi2.entityService.delete("plugin::magic-mail.email-account", accountId);
4333
- strapi2.log.info(`[magic-mail] Account deleted: ${accountId}`);
4345
+ async deleteAccount(idOrDocumentId) {
4346
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4347
+ if (!documentId) {
4348
+ throw new Error("Account not found");
4349
+ }
4350
+ await strapi2.documents(EMAIL_ACCOUNT_UID).delete({ documentId });
4351
+ strapi2.log.info(`[magic-mail] Account deleted: ${documentId}`);
4334
4352
  },
4335
4353
  /**
4336
4354
  * Unset all primary flags
4337
4355
  */
4338
4356
  async unsetAllPrimary() {
4339
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4357
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4340
4358
  filters: { isPrimary: true }
4341
4359
  });
4342
4360
  for (const account of accounts2) {
4343
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
4361
+ await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4362
+ documentId: account.documentId,
4344
4363
  data: { isPrimary: false }
4345
4364
  });
4346
4365
  }
@@ -4349,7 +4368,7 @@ If you receive this, your email account is configured correctly!`,
4349
4368
  * Reset daily/hourly counters (called by cron)
4350
4369
  */
4351
4370
  async resetCounters(type = "daily") {
4352
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account");
4371
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({});
4353
4372
  for (const account of accounts2) {
4354
4373
  const updateData = {};
4355
4374
  if (type === "daily") {
@@ -4357,11 +4376,12 @@ If you receive this, your email account is configured correctly!`,
4357
4376
  } else if (type === "hourly") {
4358
4377
  updateData.emailsSentThisHour = 0;
4359
4378
  }
4360
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
4379
+ await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4380
+ documentId: account.documentId,
4361
4381
  data: updateData
4362
4382
  });
4363
4383
  }
4364
- strapi2.log.info(`[magic-mail] ${type} counters reset`);
4384
+ strapi2.log.info(`[magic-mail] [SUCCESS] ${type} counters reset`);
4365
4385
  }
4366
4386
  });
4367
4387
  return accountManager;
@@ -4419,7 +4439,7 @@ function requireOauth() {
4419
4439
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
4420
4440
  }
4421
4441
  const tokens = await response.json();
4422
- strapi2.log.info("[magic-mail] Tokens received from Google");
4442
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Google");
4423
4443
  if (!tokens.access_token) {
4424
4444
  throw new Error("No access token received from Google");
4425
4445
  }
@@ -4433,7 +4453,7 @@ function requireOauth() {
4433
4453
  throw new Error("Failed to get user email from Google");
4434
4454
  }
4435
4455
  const userInfo = await userInfoResponse.json();
4436
- strapi2.log.info(`[magic-mail] Got user email from Google: ${userInfo.email}`);
4456
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got user email from Google: ${userInfo.email}`);
4437
4457
  if (!userInfo.email) {
4438
4458
  strapi2.log.error("[magic-mail] userInfo:", userInfo);
4439
4459
  throw new Error("Google did not provide email address");
@@ -4537,7 +4557,7 @@ function requireOauth() {
4537
4557
  throw new Error(`Failed to exchange code for tokens: ${response.status} - ${errorData}`);
4538
4558
  }
4539
4559
  const tokens = await response.json();
4540
- strapi2.log.info("[magic-mail] Tokens received from Microsoft");
4560
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Microsoft");
4541
4561
  strapi2.log.info("[magic-mail] Has access_token:", !!tokens.access_token);
4542
4562
  strapi2.log.info("[magic-mail] Has refresh_token:", !!tokens.refresh_token);
4543
4563
  strapi2.log.info("[magic-mail] Has id_token:", !!tokens.id_token);
@@ -4550,7 +4570,7 @@ function requireOauth() {
4550
4570
  const payloadBase64 = tokens.id_token.split(".")[1];
4551
4571
  const payload = JSON.parse(Buffer.from(payloadBase64, "base64").toString());
4552
4572
  email = payload.email || payload.preferred_username || payload.upn;
4553
- strapi2.log.info(`[magic-mail] Got email from Microsoft ID token: ${email}`);
4573
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft ID token: ${email}`);
4554
4574
  } catch (jwtErr) {
4555
4575
  strapi2.log.warn("[magic-mail] Could not decode ID token:", jwtErr.message);
4556
4576
  }
@@ -4572,7 +4592,7 @@ function requireOauth() {
4572
4592
  const userInfo = await userInfoResponse.json();
4573
4593
  strapi2.log.info("[magic-mail] User info from Graph:", JSON.stringify(userInfo, null, 2));
4574
4594
  email = userInfo.mail || userInfo.userPrincipalName;
4575
- strapi2.log.info(`[magic-mail] Got email from Microsoft Graph: ${email}`);
4595
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft Graph: ${email}`);
4576
4596
  }
4577
4597
  if (!email) {
4578
4598
  strapi2.log.error("[magic-mail] Microsoft did not provide email - ID token and Graph API both failed");
@@ -4616,7 +4636,7 @@ function requireOauth() {
4616
4636
  throw new Error(`Failed to refresh Microsoft tokens: ${response.status}`);
4617
4637
  }
4618
4638
  const tokens = await response.json();
4619
- strapi2.log.info("[magic-mail] Microsoft tokens refreshed successfully");
4639
+ strapi2.log.info("[magic-mail] [SUCCESS] Microsoft tokens refreshed successfully");
4620
4640
  return {
4621
4641
  accessToken: tokens.access_token,
4622
4642
  expiresAt: new Date(Date.now() + (tokens.expires_in || 3600) * 1e3)
@@ -4671,7 +4691,7 @@ function requireOauth() {
4671
4691
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
4672
4692
  }
4673
4693
  const tokens = await response.json();
4674
- strapi2.log.info("[magic-mail] Tokens received from Yahoo");
4694
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Yahoo");
4675
4695
  if (!tokens.access_token) {
4676
4696
  throw new Error("No access token received from Yahoo");
4677
4697
  }
@@ -4686,7 +4706,7 @@ function requireOauth() {
4686
4706
  }
4687
4707
  const userInfo = await userInfoResponse.json();
4688
4708
  const email = userInfo.email;
4689
- strapi2.log.info(`[magic-mail] Got email from Yahoo: ${email}`);
4709
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Yahoo: ${email}`);
4690
4710
  if (!email) {
4691
4711
  throw new Error("Yahoo did not provide email address");
4692
4712
  }
@@ -4747,7 +4767,7 @@ function requireOauth() {
4747
4767
  refreshToken: tokenData.refreshToken,
4748
4768
  expiresAt: tokenData.expiresAt
4749
4769
  });
4750
- const account = await strapi2.entityService.create("plugin::magic-mail.email-account", {
4770
+ const account = await strapi2.documents("plugin::magic-mail.email-account").create({
4751
4771
  data: {
4752
4772
  name: accountDetails.name,
4753
4773
  description: accountDetails.description || "",
@@ -4757,7 +4777,7 @@ function requireOauth() {
4757
4777
  oauth: encryptedOAuth,
4758
4778
  // OAuth tokens
4759
4779
  fromEmail: tokenData.email,
4760
- // Use email from Google, not from accountDetails
4780
+ // [SUCCESS] Use email from Google, not from accountDetails
4761
4781
  fromName: accountDetails.fromName || tokenData.email.split("@")[0],
4762
4782
  replyTo: accountDetails.replyTo || tokenData.email,
4763
4783
  isActive: true,
@@ -4770,13 +4790,13 @@ function requireOauth() {
4770
4790
  totalEmailsSent: 0
4771
4791
  }
4772
4792
  });
4773
- strapi2.log.info(`[magic-mail] OAuth account created: ${accountDetails.name} (${tokenData.email})`);
4793
+ strapi2.log.info(`[magic-mail] [SUCCESS] OAuth account created: ${accountDetails.name} (${tokenData.email})`);
4774
4794
  return account;
4775
4795
  }
4776
4796
  });
4777
4797
  return oauth;
4778
4798
  }
4779
- const version = "2.0.1";
4799
+ const version = "2.0.3";
4780
4800
  const require$$2 = {
4781
4801
  version
4782
4802
  };
@@ -4870,14 +4890,14 @@ function requireLicenseGuard() {
4870
4890
  });
4871
4891
  const data = await response.json();
4872
4892
  if (data.success) {
4873
- strapi2.log.info("[magic-mail] License created:", data.data.licenseKey);
4893
+ strapi2.log.info("[magic-mail] [SUCCESS] License created:", data.data.licenseKey);
4874
4894
  return data.data;
4875
4895
  } else {
4876
- strapi2.log.error("[magic-mail] License creation failed:", data);
4896
+ strapi2.log.error("[magic-mail] [ERROR] License creation failed:", data);
4877
4897
  return null;
4878
4898
  }
4879
4899
  } catch (error) {
4880
- strapi2.log.error("[magic-mail] Error creating license:", error);
4900
+ strapi2.log.error("[magic-mail] [ERROR] Error creating license:", error);
4881
4901
  return null;
4882
4902
  }
4883
4903
  },
@@ -4905,10 +4925,10 @@ function requireLicenseGuard() {
4905
4925
  }
4906
4926
  } catch (error) {
4907
4927
  if (allowGracePeriod) {
4908
- strapi2.log.warn("[magic-mail] ⚠️ License verification timeout - grace period active");
4928
+ strapi2.log.warn("[magic-mail] [WARNING] License verification timeout - grace period active");
4909
4929
  return { valid: true, data: null, gracePeriod: true };
4910
4930
  }
4911
- strapi2.log.error("[magic-mail] License verification error:", error.message);
4931
+ strapi2.log.error("[magic-mail] [ERROR] License verification error:", error.message);
4912
4932
  return { valid: false, data: null };
4913
4933
  }
4914
4934
  },
@@ -4961,7 +4981,7 @@ function requireLicenseGuard() {
4961
4981
  name: "magic-mail"
4962
4982
  });
4963
4983
  await pluginStore.set({ key: "licenseKey", value: licenseKey });
4964
- strapi2.log.info(`[magic-mail] License key stored: ${licenseKey.substring(0, 8)}...`);
4984
+ strapi2.log.info(`[magic-mail] [SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
4965
4985
  },
4966
4986
  startPinging(licenseKey, intervalMinutes = 15) {
4967
4987
  this.pingLicense(licenseKey);
@@ -4990,7 +5010,7 @@ function requireLicenseGuard() {
4990
5010
  const license2 = await this.getLicenseByKey(licenseKey);
4991
5011
  return license2;
4992
5012
  } catch (error) {
4993
- strapi2.log.error(`[magic-mail] Error loading license:`, error);
5013
+ strapi2.log.error(`[magic-mail] [ERROR] Error loading license:`, error);
4994
5014
  return null;
4995
5015
  }
4996
5016
  },
@@ -5040,7 +5060,7 @@ function requireLicenseGuard() {
5040
5060
  */
5041
5061
  async initialize() {
5042
5062
  try {
5043
- strapi2.log.info("🔐 Initializing License Guard...");
5063
+ strapi2.log.info("[INIT] Initializing License Guard...");
5044
5064
  const pluginStore = strapi2.store({
5045
5065
  type: "plugin",
5046
5066
  name: "magic-mail"
@@ -5058,53 +5078,53 @@ function requireLicenseGuard() {
5058
5078
  strapi2.log.info("──────────────────────────────────────────────────────────");
5059
5079
  strapi2.log.info(`📦 Plugin Store Check:`);
5060
5080
  if (licenseKey) {
5061
- strapi2.log.info(` License Key found: ${licenseKey}`);
5062
- strapi2.log.info(` 🔑 Key (short): ${licenseKey.substring(0, 10)}...`);
5081
+ strapi2.log.info(` [SUCCESS] License Key found: ${licenseKey}`);
5082
+ strapi2.log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
5063
5083
  if (lastValidated) {
5064
5084
  const lastValidatedDate = new Date(lastValidated);
5065
5085
  const hoursAgo = Math.floor((now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60));
5066
- strapi2.log.info(` 🕐 Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
5086
+ strapi2.log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
5067
5087
  } else {
5068
- strapi2.log.info(` 🕐 Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
5088
+ strapi2.log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
5069
5089
  }
5070
5090
  } else {
5071
- strapi2.log.info(` No license key stored`);
5091
+ strapi2.log.info(` [ERROR] No license key stored`);
5072
5092
  }
5073
5093
  strapi2.log.info("──────────────────────────────────────────────────────────");
5074
5094
  if (!licenseKey) {
5075
- strapi2.log.info("📄 No license found - Running in demo mode");
5076
- strapi2.log.info("💡 Create a license in the admin panel to activate full features");
5095
+ strapi2.log.info("[DEMO] No license found - Running in demo mode");
5096
+ strapi2.log.info("[INFO] Create a license in the admin panel to activate full features");
5077
5097
  return {
5078
5098
  valid: false,
5079
5099
  demo: true,
5080
5100
  data: null
5081
5101
  };
5082
5102
  }
5083
- strapi2.log.info("📄 Verifying stored license key...");
5103
+ strapi2.log.info("[VERIFY] Verifying stored license key...");
5084
5104
  const verification = await this.verifyLicense(licenseKey, withinGracePeriod);
5085
5105
  if (verification.valid) {
5086
5106
  const license2 = await this.getLicenseByKey(licenseKey);
5087
- strapi2.log.info(`✅ License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
5107
+ strapi2.log.info(`[SUCCESS] License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
5088
5108
  await pluginStore.set({
5089
5109
  key: "lastValidated",
5090
5110
  value: now.toISOString()
5091
5111
  });
5092
- strapi2.log.info(" License is valid and active");
5112
+ strapi2.log.info("[SUCCESS] License is valid and active");
5093
5113
  const pingInterval = this.startPinging(licenseKey, 15);
5094
- strapi2.log.info("📡 Started pinging license every 15 minutes");
5114
+ strapi2.log.info("[PING] Started pinging license every 15 minutes");
5095
5115
  strapi2.licenseGuardMagicMail = {
5096
5116
  licenseKey,
5097
5117
  pingInterval,
5098
5118
  data: verification.data
5099
5119
  };
5100
5120
  strapi2.log.info("╔════════════════════════════════════════════════════════════════╗");
5101
- strapi2.log.info("║ MAGIC MAIL PLUGIN LICENSE ACTIVE ║");
5121
+ strapi2.log.info("║ [SUCCESS] MAGIC MAIL PLUGIN LICENSE ACTIVE ║");
5102
5122
  strapi2.log.info("║ ║");
5103
5123
  strapi2.log.info(`║ License: ${licenseKey.padEnd(38, " ")}║`);
5104
5124
  strapi2.log.info(`║ User: ${(license2?.firstName + " " + license2?.lastName).padEnd(41, " ")}║`);
5105
5125
  strapi2.log.info(`║ Email: ${(license2?.email || "N/A").padEnd(40, " ")}║`);
5106
5126
  strapi2.log.info("║ ║");
5107
- strapi2.log.info("║ 🔄 Auto-pinging every 15 minutes ║");
5127
+ strapi2.log.info("║ [AUTO] Pinging every 15 minutes ║");
5108
5128
  strapi2.log.info("╚════════════════════════════════════════════════════════════════╝");
5109
5129
  return {
5110
5130
  valid: true,
@@ -5113,9 +5133,9 @@ function requireLicenseGuard() {
5113
5133
  gracePeriod: verification.gracePeriod || false
5114
5134
  };
5115
5135
  } else {
5116
- strapi2.log.error(`❌ License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
5136
+ strapi2.log.error(`[ERROR] License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
5117
5137
  strapi2.log.info("──────────────────────────────────────────────────────────");
5118
- strapi2.log.info("⚠️ Running in demo mode with limited features");
5138
+ strapi2.log.info("[WARNING] Running in demo mode with limited features");
5119
5139
  return {
5120
5140
  valid: false,
5121
5141
  demo: true,
@@ -5124,7 +5144,7 @@ function requireLicenseGuard() {
5124
5144
  };
5125
5145
  }
5126
5146
  } catch (error) {
5127
- strapi2.log.error(" Error initializing License Guard:", error);
5147
+ strapi2.log.error("[ERROR] Error initializing License Guard:", error);
5128
5148
  return {
5129
5149
  valid: false,
5130
5150
  demo: true,
@@ -5144,6 +5164,8 @@ function requireEmailDesigner() {
5144
5164
  const Mustache = require$$0__default$2.default;
5145
5165
  const htmlToTextLib = require$$1__default$1.default;
5146
5166
  const decode = require$$2__default.default;
5167
+ const EMAIL_TEMPLATE_UID = "plugin::magic-mail.email-template";
5168
+ const EMAIL_TEMPLATE_VERSION_UID = "plugin::magic-mail.email-template-version";
5147
5169
  const convertHtmlToText = (html, options2 = { wordwrap: 130 }) => {
5148
5170
  try {
5149
5171
  if (!html || typeof html !== "string") {
@@ -5181,24 +5203,36 @@ function requireEmailDesigner() {
5181
5203
  * Get all templates
5182
5204
  */
5183
5205
  async findAll(filters = {}) {
5184
- return strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5206
+ return strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5185
5207
  filters,
5186
- sort: { createdAt: "desc" }
5208
+ sort: [{ createdAt: "desc" }]
5187
5209
  });
5188
5210
  },
5189
5211
  /**
5190
- * Get template by ID with populated versions
5212
+ * Get template by ID (documentId) with populated versions
5191
5213
  */
5192
- async findOne(id) {
5193
- return strapi2.entityService.findOne("plugin::magic-mail.email-template", id, {
5214
+ async findOne(documentId) {
5215
+ return strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5216
+ documentId,
5194
5217
  populate: ["versions"]
5195
5218
  });
5196
5219
  },
5220
+ /**
5221
+ * Get template by numeric ID (for backward compatibility)
5222
+ */
5223
+ async findById(id) {
5224
+ const results = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5225
+ filters: { id },
5226
+ limit: 1,
5227
+ populate: ["versions"]
5228
+ });
5229
+ return results.length > 0 ? results[0] : null;
5230
+ },
5197
5231
  /**
5198
5232
  * Get template by reference ID
5199
5233
  */
5200
5234
  async findByReferenceId(templateReferenceId) {
5201
- const results = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5235
+ const results = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5202
5236
  filters: { templateReferenceId },
5203
5237
  limit: 1
5204
5238
  });
@@ -5206,17 +5240,11 @@ function requireEmailDesigner() {
5206
5240
  },
5207
5241
  /**
5208
5242
  * Create new template with automatic initial version
5209
- *
5210
- * Steps:
5211
- * 1. Check license limits
5212
- * 2. Validate reference ID is unique
5213
- * 3. Create template
5214
- * 4. Create initial version (if versioning enabled)
5215
5243
  */
5216
5244
  async create(data) {
5217
- strapi2.log.info("[magic-mail] 📝 Creating new template...");
5245
+ strapi2.log.info("[magic-mail] [TEST] Creating new template...");
5218
5246
  const maxTemplates = await strapi2.plugin("magic-mail").service("license-guard").getMaxEmailTemplates();
5219
- const currentCount = await strapi2.db.query("plugin::magic-mail.email-template").count();
5247
+ const currentCount = await strapi2.documents(EMAIL_TEMPLATE_UID).count();
5220
5248
  if (maxTemplates !== -1 && currentCount >= maxTemplates) {
5221
5249
  throw new Error(
5222
5250
  `Template limit reached (${maxTemplates}). Upgrade your license to create more templates.`
@@ -5228,17 +5256,17 @@ function requireEmailDesigner() {
5228
5256
  throw new Error(`Template with reference ID ${data.templateReferenceId} already exists`);
5229
5257
  }
5230
5258
  }
5231
- const template = await strapi2.entityService.create("plugin::magic-mail.email-template", {
5259
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).create({
5232
5260
  data: {
5233
5261
  ...data,
5234
5262
  isActive: data.isActive !== void 0 ? data.isActive : true
5235
5263
  }
5236
5264
  });
5237
- strapi2.log.info(`[magic-mail] Template created: ID=${template.id}, name="${template.name}"`);
5265
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template created: documentId=${template.documentId}, name="${template.name}"`);
5238
5266
  const hasVersioning = await strapi2.plugin("magic-mail").service("license-guard").hasFeature("email-designer-versioning");
5239
5267
  if (hasVersioning) {
5240
- strapi2.log.info("[magic-mail] 💾 Creating initial version...");
5241
- await this.createVersion(template.id, {
5268
+ strapi2.log.info("[magic-mail] [SAVE] Creating initial version...");
5269
+ await this.createVersion(template.documentId, {
5242
5270
  name: data.name,
5243
5271
  subject: data.subject,
5244
5272
  design: data.design,
@@ -5246,33 +5274,26 @@ function requireEmailDesigner() {
5246
5274
  bodyText: data.bodyText,
5247
5275
  tags: data.tags
5248
5276
  });
5249
- strapi2.log.info("[magic-mail] Initial version created");
5277
+ strapi2.log.info("[magic-mail] [SUCCESS] Initial version created");
5250
5278
  } else {
5251
- strapi2.log.info("[magic-mail] ⏭️ Versioning not enabled, skipping initial version");
5279
+ strapi2.log.info("[magic-mail] [SKIP] Versioning not enabled, skipping initial version");
5252
5280
  }
5253
5281
  return template;
5254
5282
  },
5255
5283
  /**
5256
5284
  * Update template with automatic version snapshot
5257
- *
5258
- * Steps:
5259
- * 1. Load existing template
5260
- * 2. Create version snapshot of CURRENT state (before update)
5261
- * 3. Update template with new data
5262
- *
5263
- * IMPORTANT: Version is created BEFORE update to preserve old state!
5264
- */
5265
- async update(id, data) {
5266
- strapi2.log.info(`[magic-mail] 🔄 Updating template ID: ${id}`);
5267
- const template = await this.findOne(id);
5285
+ */
5286
+ async update(documentId, data) {
5287
+ strapi2.log.info(`[magic-mail] [UPDATE] Updating template documentId: ${documentId}`);
5288
+ const template = await this.findOne(documentId);
5268
5289
  if (!template) {
5269
5290
  throw new Error("Template not found");
5270
5291
  }
5271
- strapi2.log.info(`[magic-mail] 📋 Found template: ID=${template.id}, name="${template.name}"`);
5292
+ strapi2.log.info(`[magic-mail] [INFO] Found template: documentId=${template.documentId}, name="${template.name}"`);
5272
5293
  const hasVersioning = await strapi2.plugin("magic-mail").service("license-guard").hasFeature("email-designer-versioning");
5273
5294
  if (hasVersioning) {
5274
- strapi2.log.info("[magic-mail] 💾 Creating version snapshot before update...");
5275
- await this.createVersion(template.id, {
5295
+ strapi2.log.info("[magic-mail] [SAVE] Creating version snapshot before update...");
5296
+ await this.createVersion(template.documentId, {
5276
5297
  name: template.name,
5277
5298
  subject: template.subject,
5278
5299
  design: template.design,
@@ -5280,66 +5301,62 @@ function requireEmailDesigner() {
5280
5301
  bodyText: template.bodyText,
5281
5302
  tags: template.tags
5282
5303
  });
5283
- strapi2.log.info("[magic-mail] Version snapshot created");
5284
- } else {
5285
- strapi2.log.info("[magic-mail] ⏭️ Versioning not enabled, skipping version snapshot");
5304
+ strapi2.log.info("[magic-mail] [SUCCESS] Version snapshot created");
5286
5305
  }
5287
5306
  const updateData = { ...data };
5288
5307
  if ("versions" in updateData) {
5289
5308
  delete updateData.versions;
5290
- strapi2.log.warn("[magic-mail] ⚠️ Removed versions field from update data to prevent relation overwrite");
5309
+ strapi2.log.warn("[magic-mail] [WARNING] Removed versions field from update data");
5291
5310
  }
5292
- const updated = await strapi2.entityService.update("plugin::magic-mail.email-template", id, {
5311
+ const updated = await strapi2.documents(EMAIL_TEMPLATE_UID).update({
5312
+ documentId,
5293
5313
  data: updateData
5294
5314
  });
5295
- strapi2.log.info(`[magic-mail] Template updated: ID=${updated.id}, versions preserved`);
5315
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template updated: documentId=${updated.documentId}`);
5296
5316
  return updated;
5297
5317
  },
5298
5318
  /**
5299
5319
  * Delete template and all its versions
5300
- *
5301
- * Uses Document Service for version deletion to ensure cascading delete
5302
5320
  */
5303
- async delete(id) {
5304
- strapi2.log.info(`[magic-mail] 🗑️ Deleting template ID: ${id}`);
5305
- const template = await this.findOne(id);
5321
+ async delete(documentId) {
5322
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting template documentId: ${documentId}`);
5323
+ const template = await this.findOne(documentId);
5306
5324
  if (!template) {
5307
5325
  throw new Error("Template not found");
5308
5326
  }
5309
- strapi2.log.info(`[magic-mail] 🗑️ Template: ID=${template.id}, name="${template.name}"`);
5310
- const allVersions = await strapi2.documents("plugin::magic-mail.email-template-version").findMany({
5327
+ strapi2.log.info(`[magic-mail] [DELETE] Template: documentId=${template.documentId}, name="${template.name}"`);
5328
+ const allVersions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5311
5329
  filters: {
5312
5330
  template: {
5313
5331
  documentId: template.documentId
5314
5332
  }
5315
5333
  }
5316
5334
  });
5317
- strapi2.log.info(`[magic-mail] 🗑️ Found ${allVersions.length} versions to delete`);
5335
+ strapi2.log.info(`[magic-mail] [DELETE] Found ${allVersions.length} versions to delete`);
5318
5336
  for (const version2 of allVersions) {
5319
5337
  try {
5320
- await strapi2.documents("plugin::magic-mail.email-template-version").delete({ documentId: version2.documentId });
5321
- strapi2.log.info(`[magic-mail] 🗑️ Deleted version #${version2.versionNumber}`);
5338
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5339
+ documentId: version2.documentId
5340
+ });
5341
+ strapi2.log.info(`[magic-mail] [DELETE] Deleted version #${version2.versionNumber}`);
5322
5342
  } catch (versionError) {
5323
- strapi2.log.warn(`[magic-mail] ⚠️ Failed to delete version ${version2.id}: ${versionError.message}`);
5343
+ strapi2.log.warn(`[magic-mail] [WARNING] Failed to delete version: ${versionError.message}`);
5324
5344
  }
5325
5345
  }
5326
- const result = await strapi2.entityService.delete("plugin::magic-mail.email-template", id);
5327
- strapi2.log.info(`[magic-mail] Template "${template.name}" and ${allVersions.length} versions deleted`);
5346
+ const result = await strapi2.documents(EMAIL_TEMPLATE_UID).delete({ documentId });
5347
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template "${template.name}" and ${allVersions.length} versions deleted`);
5328
5348
  return result;
5329
5349
  },
5330
5350
  /**
5331
5351
  * Duplicate template
5332
- *
5333
- * Creates a copy of an existing template with " copy" suffix
5334
- * Does NOT copy versions, starts fresh
5335
5352
  */
5336
- async duplicate(id) {
5337
- strapi2.log.info(`[magic-mail] 📋 Duplicating template ID: ${id}`);
5338
- const original = await this.findOne(id);
5353
+ async duplicate(documentId) {
5354
+ strapi2.log.info(`[magic-mail] [INFO] Duplicating template documentId: ${documentId}`);
5355
+ const original = await this.findOne(documentId);
5339
5356
  if (!original) {
5340
5357
  throw new Error("Template not found");
5341
5358
  }
5342
- strapi2.log.info(`[magic-mail] 📦 Original template: ID=${original.id}, name="${original.name}"`);
5359
+ strapi2.log.info(`[magic-mail] [PACKAGE] Original template: documentId=${original.documentId}, name="${original.name}"`);
5343
5360
  const duplicateData = {
5344
5361
  name: `${original.name} copy`,
5345
5362
  subject: original.subject,
@@ -5349,11 +5366,10 @@ function requireEmailDesigner() {
5349
5366
  category: original.category,
5350
5367
  tags: original.tags,
5351
5368
  isActive: original.isActive,
5352
- // Generate new templateReferenceId (unique ID)
5353
5369
  templateReferenceId: Date.now() + Math.floor(Math.random() * 1e3)
5354
5370
  };
5355
5371
  const duplicated = await this.create(duplicateData);
5356
- strapi2.log.info(`[magic-mail] Template duplicated: ID=${duplicated.id}, name="${duplicated.name}"`);
5372
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}`);
5357
5373
  return duplicated;
5358
5374
  },
5359
5375
  // ============================================================
@@ -5361,134 +5377,81 @@ function requireEmailDesigner() {
5361
5377
  // ============================================================
5362
5378
  /**
5363
5379
  * Create a new version for a template
5364
- *
5365
- * CRITICAL: This is THE ONLY function that creates versions!
5366
- *
5367
- * Steps:
5368
- * 1. Verify template exists
5369
- * 2. Calculate next version number
5370
- * 3. Create version WITH template relation
5371
- *
5372
- * @param {number} templateId - Numeric ID of template
5373
- * @param {object} data - Version data (name, subject, bodyHtml, etc)
5374
- * @returns {object} Created version
5375
- */
5376
- async createVersion(templateId, data) {
5377
- strapi2.log.info(`[magic-mail] 📸 Creating version for template ID: ${templateId}`);
5378
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId);
5380
+ */
5381
+ async createVersion(templateDocumentId, data) {
5382
+ strapi2.log.info(`[magic-mail] [SNAPSHOT] Creating version for template documentId: ${templateDocumentId}`);
5383
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5384
+ documentId: templateDocumentId
5385
+ });
5379
5386
  if (!template) {
5380
- throw new Error(`Template ${templateId} not found`);
5387
+ throw new Error(`Template ${templateDocumentId} not found`);
5381
5388
  }
5382
- strapi2.log.info(`[magic-mail] 📦 Template found: ID=${template.id}, name="${template.name}"`);
5383
- const existingVersions = await strapi2.entityService.findMany("plugin::magic-mail.email-template-version", {
5389
+ strapi2.log.info(`[magic-mail] [PACKAGE] Template found: documentId=${template.documentId}, name="${template.name}"`);
5390
+ const existingVersions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5384
5391
  filters: {
5385
5392
  template: {
5386
- id: templateId
5387
- // Use numeric ID in filter
5393
+ documentId: templateDocumentId
5388
5394
  }
5389
5395
  },
5390
- sort: { versionNumber: "desc" }
5396
+ sort: [{ versionNumber: "desc" }]
5391
5397
  });
5392
5398
  const versionNumber = existingVersions.length > 0 ? Math.max(...existingVersions.map((v) => v.versionNumber || 0)) + 1 : 1;
5393
- strapi2.log.info(`[magic-mail] 📊 Existing versions: ${existingVersions.length} → Next version: #${versionNumber}`);
5394
- const createdVersion = await strapi2.entityService.create("plugin::magic-mail.email-template-version", {
5399
+ strapi2.log.info(`[magic-mail] [STATS] Existing versions: ${existingVersions.length} → Next version: #${versionNumber}`);
5400
+ const createdVersion = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).create({
5395
5401
  data: {
5396
5402
  versionNumber,
5397
5403
  ...data,
5398
- template: {
5399
- connect: [templateId]
5400
- // ✅ Use connect array for Strapi v5!
5401
- }
5404
+ template: templateDocumentId
5405
+ // Document Service handles relations with documentId
5402
5406
  }
5403
5407
  });
5404
- strapi2.log.info(`[magic-mail] 📝 Version created with connect: ID=${createdVersion.id}`);
5405
- const verifiedVersion = await strapi2.entityService.findOne(
5406
- "plugin::magic-mail.email-template-version",
5407
- createdVersion.id,
5408
- {
5409
- populate: ["template"]
5410
- }
5411
- );
5412
- strapi2.log.info(
5413
- `[magic-mail] ✅ Version created successfully:
5414
- - Version ID: ${createdVersion.id}
5415
- - Version #: ${versionNumber}
5416
- - Template ID: ${templateId}
5417
- - Has template relation: ${!!verifiedVersion.template}
5418
- - Template in DB: ${verifiedVersion.template?.id || "NULL"}`
5419
- );
5420
- if (!verifiedVersion.template) {
5421
- strapi2.log.error(
5422
- `[magic-mail] ❌ CRITICAL: Version ${createdVersion.id} was created but template relation was NOT set!
5423
- This is a Strapi v5 relation bug. Investigating...`
5424
- );
5425
- }
5426
- return verifiedVersion;
5408
+ strapi2.log.info(`[magic-mail] [SUCCESS] Version created: documentId=${createdVersion.documentId}, v${versionNumber}`);
5409
+ return createdVersion;
5427
5410
  },
5428
5411
  /**
5429
5412
  * Get all versions for a template
5430
5413
  */
5431
- async getVersions(templateId) {
5432
- strapi2.log.info(`[magic-mail] 📜 Fetching versions for template ID: ${templateId}`);
5433
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5414
+ async getVersions(templateDocumentId) {
5415
+ strapi2.log.info(`[magic-mail] 📜 Fetching versions for template documentId: ${templateDocumentId}`);
5416
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5417
+ documentId: templateDocumentId,
5434
5418
  populate: ["versions"]
5435
5419
  });
5436
5420
  if (!template) {
5437
5421
  throw new Error("Template not found");
5438
5422
  }
5439
- strapi2.log.info(`[magic-mail] 📦 Template has ${template.versions?.length || 0} versions in relation`);
5423
+ strapi2.log.info(`[magic-mail] [PACKAGE] Template has ${template.versions?.length || 0} versions`);
5440
5424
  if (template.versions && template.versions.length > 0) {
5441
5425
  const sortedVersions = [...template.versions].sort((a, b) => b.versionNumber - a.versionNumber);
5442
- strapi2.log.info(`[magic-mail] ✅ Returning ${sortedVersions.length} versions from template populate`);
5443
5426
  return sortedVersions;
5444
5427
  }
5445
- strapi2.log.warn(`[magic-mail] ⚠️ Template has no populated versions, trying filter...`);
5446
- const versions = await strapi2.entityService.findMany("plugin::magic-mail.email-template-version", {
5428
+ const versions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5447
5429
  filters: {
5448
5430
  template: {
5449
- id: templateId
5431
+ documentId: templateDocumentId
5450
5432
  }
5451
5433
  },
5452
- sort: { versionNumber: "desc" },
5453
- populate: ["template"]
5434
+ sort: [{ versionNumber: "desc" }]
5454
5435
  });
5455
- strapi2.log.info(`[magic-mail] Found ${versions.length} versions via filter`);
5436
+ strapi2.log.info(`[magic-mail] [SUCCESS] Found ${versions.length} versions`);
5456
5437
  return versions;
5457
5438
  },
5458
5439
  /**
5459
5440
  * Restore template from a specific version
5460
- *
5461
- * Updates the template with data from the version
5462
- * This will create a NEW version snapshot (via update logic)
5463
5441
  */
5464
- async restoreVersion(templateId, versionId) {
5465
- strapi2.log.info(`[magic-mail] 🔄 Restoring template ${templateId} from version ${versionId}`);
5466
- const version2 = await strapi2.entityService.findOne("plugin::magic-mail.email-template-version", versionId, {
5442
+ async restoreVersion(templateDocumentId, versionDocumentId) {
5443
+ strapi2.log.info(`[magic-mail] [RESTORE] Restoring template ${templateDocumentId} from version ${versionDocumentId}`);
5444
+ const version2 = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
5445
+ documentId: versionDocumentId,
5467
5446
  populate: ["template"]
5468
5447
  });
5469
5448
  if (!version2) {
5470
5449
  throw new Error("Version not found");
5471
5450
  }
5472
- strapi2.log.info(`[magic-mail] 📦 Version found: ID=${version2.id}, versionNumber=${version2.versionNumber}, has template: ${!!version2.template}`);
5473
- if (version2.template?.id) {
5474
- if (version2.template.id !== parseInt(templateId)) {
5475
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} belongs to template ${version2.template.id}, not ${templateId}`);
5476
- throw new Error("Version does not belong to this template");
5477
- }
5478
- strapi2.log.info(`[magic-mail] ✅ Version has correct template relation`);
5479
- } else {
5480
- strapi2.log.warn(`[magic-mail] ⚠️ Version ${versionId} has no template relation, checking template's versions array...`);
5481
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5482
- populate: ["versions"]
5483
- });
5484
- const versionExists = template.versions && template.versions.some((v) => v.id === parseInt(versionId));
5485
- if (!versionExists) {
5486
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} not found in template ${templateId} versions array`);
5487
- throw new Error("Version does not belong to this template");
5488
- }
5489
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} found in template's versions array (old version without relation)`);
5451
+ if (version2.template?.documentId !== templateDocumentId) {
5452
+ throw new Error("Version does not belong to this template");
5490
5453
  }
5491
- const restored = await this.update(templateId, {
5454
+ const restored = await this.update(templateDocumentId, {
5492
5455
  name: version2.name,
5493
5456
  subject: version2.subject,
5494
5457
  design: version2.design,
@@ -5496,93 +5459,65 @@ function requireEmailDesigner() {
5496
5459
  bodyText: version2.bodyText,
5497
5460
  tags: version2.tags
5498
5461
  });
5499
- strapi2.log.info(`[magic-mail] Template restored from version #${version2.versionNumber}`);
5462
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template restored from version #${version2.versionNumber}`);
5500
5463
  return restored;
5501
5464
  },
5502
5465
  /**
5503
5466
  * Delete a single version
5504
- *
5505
- * @param {number} templateId - Template ID (for verification)
5506
- * @param {number} versionId - Version ID to delete
5507
5467
  */
5508
- async deleteVersion(templateId, versionId) {
5509
- strapi2.log.info(`[magic-mail] 🗑️ Deleting version ${versionId} from template ${templateId}`);
5510
- const version2 = await strapi2.entityService.findOne("plugin::magic-mail.email-template-version", versionId, {
5468
+ async deleteVersion(templateDocumentId, versionDocumentId) {
5469
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting version ${versionDocumentId}`);
5470
+ const version2 = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
5471
+ documentId: versionDocumentId,
5511
5472
  populate: ["template"]
5512
5473
  });
5513
5474
  if (!version2) {
5514
5475
  throw new Error("Version not found");
5515
5476
  }
5516
- if (version2.template?.id) {
5517
- if (version2.template.id !== parseInt(templateId)) {
5518
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} belongs to template ${version2.template.id}, not ${templateId}`);
5519
- throw new Error("Version does not belong to this template");
5520
- }
5521
- strapi2.log.info(`[magic-mail] ✅ Version has correct template relation`);
5522
- } else {
5523
- strapi2.log.warn(`[magic-mail] ⚠️ Version ${versionId} has no template relation, checking template's versions array...`);
5524
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5525
- populate: ["versions"]
5526
- });
5527
- const versionExists = template.versions && template.versions.some((v) => v.id === parseInt(versionId));
5528
- if (!versionExists) {
5529
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} not found in template ${templateId} versions array`);
5530
- throw new Error("Version does not belong to this template");
5531
- }
5532
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} found in template's versions array`);
5477
+ if (version2.template?.documentId !== templateDocumentId) {
5478
+ throw new Error("Version does not belong to this template");
5533
5479
  }
5534
- await strapi2.entityService.delete("plugin::magic-mail.email-template-version", versionId);
5535
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} (v${version2.versionNumber}) deleted successfully`);
5480
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5481
+ documentId: versionDocumentId
5482
+ });
5483
+ strapi2.log.info(`[magic-mail] [SUCCESS] Version v${version2.versionNumber} deleted`);
5536
5484
  return { success: true, message: "Version deleted" };
5537
5485
  },
5538
5486
  /**
5539
5487
  * Delete all versions for a template
5540
- *
5541
- * @param {number} templateId - Template ID
5542
5488
  */
5543
- async deleteAllVersions(templateId) {
5544
- strapi2.log.info(`[magic-mail] 🗑️ Deleting all versions for template ${templateId}`);
5545
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5489
+ async deleteAllVersions(templateDocumentId) {
5490
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting all versions for template ${templateDocumentId}`);
5491
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5492
+ documentId: templateDocumentId,
5546
5493
  populate: ["versions"]
5547
5494
  });
5548
5495
  if (!template) {
5549
5496
  throw new Error("Template not found");
5550
5497
  }
5551
5498
  const versionCount = template.versions?.length || 0;
5552
- strapi2.log.info(`[magic-mail] 📊 Found ${versionCount} versions to delete`);
5553
5499
  if (versionCount === 0) {
5554
5500
  return { success: true, message: "No versions to delete", deletedCount: 0 };
5555
5501
  }
5556
5502
  let deletedCount = 0;
5557
- const errors = [];
5558
5503
  for (const version2 of template.versions) {
5559
5504
  try {
5560
- await strapi2.entityService.delete("plugin::magic-mail.email-template-version", version2.id);
5505
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5506
+ documentId: version2.documentId
5507
+ });
5561
5508
  deletedCount++;
5562
- strapi2.log.info(`[magic-mail] 🗑️ Deleted version #${version2.versionNumber} (ID: ${version2.id})`);
5563
5509
  } catch (error) {
5564
- strapi2.log.error(`[magic-mail] Failed to delete version ${version2.id}: ${error.message}`);
5565
- errors.push({ versionId: version2.id, error: error.message });
5510
+ strapi2.log.error(`[magic-mail] [ERROR] Failed to delete version: ${error.message}`);
5566
5511
  }
5567
5512
  }
5568
- strapi2.log.info(`[magic-mail] Deleted ${deletedCount}/${versionCount} versions`);
5569
- return {
5570
- success: true,
5571
- message: `Deleted ${deletedCount} of ${versionCount} versions`,
5572
- deletedCount,
5573
- failedCount: versionCount - deletedCount,
5574
- errors: errors.length > 0 ? errors : void 0
5575
- };
5513
+ strapi2.log.info(`[magic-mail] [SUCCESS] Deleted ${deletedCount}/${versionCount} versions`);
5514
+ return { success: true, deletedCount };
5576
5515
  },
5577
5516
  // ============================================================
5578
5517
  // RENDERING
5579
5518
  // ============================================================
5580
5519
  /**
5581
5520
  * Render template with dynamic data using Mustache
5582
- *
5583
- * @param {number} templateReferenceId - Template reference ID
5584
- * @param {object} data - Dynamic data for Mustache
5585
- * @returns {object} Rendered HTML, text, and subject
5586
5521
  */
5587
5522
  async renderTemplate(templateReferenceId, data = {}) {
5588
5523
  const template = await this.findByReferenceId(templateReferenceId);
@@ -5614,17 +5549,17 @@ function requireEmailDesigner() {
5614
5549
  };
5615
5550
  },
5616
5551
  // ============================================================
5617
- // IMPORT/EXPORT (Advanced+ License)
5552
+ // IMPORT/EXPORT
5618
5553
  // ============================================================
5619
5554
  /**
5620
5555
  * Export templates as JSON
5621
5556
  */
5622
- async exportTemplates(templateIds = []) {
5623
- strapi2.log.info("[magic-mail] 📤 Exporting templates...");
5557
+ async exportTemplates(templateDocumentIds = []) {
5558
+ strapi2.log.info("[magic-mail] [EXPORT] Exporting templates...");
5624
5559
  let templates;
5625
- if (templateIds.length > 0) {
5626
- templates = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5627
- filters: { id: { $in: templateIds } }
5560
+ if (templateDocumentIds.length > 0) {
5561
+ templates = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5562
+ filters: { documentId: { $in: templateDocumentIds } }
5628
5563
  });
5629
5564
  } else {
5630
5565
  templates = await this.findAll();
@@ -5639,26 +5574,24 @@ function requireEmailDesigner() {
5639
5574
  category: template.category,
5640
5575
  tags: template.tags
5641
5576
  }));
5642
- strapi2.log.info(`[magic-mail] Exported ${exported.length} templates`);
5577
+ strapi2.log.info(`[magic-mail] [SUCCESS] Exported ${exported.length} templates`);
5643
5578
  return exported;
5644
5579
  },
5645
5580
  /**
5646
5581
  * Import templates from JSON
5647
5582
  */
5648
5583
  async importTemplates(templates) {
5649
- strapi2.log.info(`[magic-mail] 📥 Importing ${templates.length} templates...`);
5584
+ strapi2.log.info(`[magic-mail] [IMPORT] Importing ${templates.length} templates...`);
5650
5585
  const results = [];
5651
5586
  for (const templateData of templates) {
5652
5587
  try {
5653
5588
  const existing = await this.findByReferenceId(templateData.templateReferenceId);
5654
5589
  if (existing) {
5655
- const updated = await this.update(existing.id, templateData);
5590
+ const updated = await this.update(existing.documentId, templateData);
5656
5591
  results.push({ success: true, action: "updated", template: updated });
5657
- strapi2.log.info(`[magic-mail] ✅ Updated template: ${templateData.name}`);
5658
5592
  } else {
5659
5593
  const created = await this.create(templateData);
5660
5594
  results.push({ success: true, action: "created", template: created });
5661
- strapi2.log.info(`[magic-mail] ✅ Created template: ${templateData.name}`);
5662
5595
  }
5663
5596
  } catch (error) {
5664
5597
  results.push({
@@ -5667,11 +5600,8 @@ function requireEmailDesigner() {
5667
5600
  error: error.message,
5668
5601
  templateName: templateData.name
5669
5602
  });
5670
- strapi2.log.error(`[magic-mail] ❌ Failed to import ${templateData.name}: ${error.message}`);
5671
5603
  }
5672
5604
  }
5673
- const successful = results.filter((r) => r.success).length;
5674
- strapi2.log.info(`[magic-mail] ✅ Import completed: ${successful}/${templates.length} templates`);
5675
5605
  return results;
5676
5606
  },
5677
5607
  // ============================================================
@@ -5681,7 +5611,7 @@ function requireEmailDesigner() {
5681
5611
  * Get template statistics
5682
5612
  */
5683
5613
  async getStats() {
5684
- const allTemplates = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5614
+ const allTemplates = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5685
5615
  fields: ["isActive", "category"]
5686
5616
  });
5687
5617
  const total = allTemplates.length;
@@ -5706,9 +5636,7 @@ function requireEmailDesigner() {
5706
5636
  // STRAPI CORE EMAIL TEMPLATES
5707
5637
  // ============================================================
5708
5638
  /**
5709
- * Get Strapi core email template (reset-password, email-confirmation)
5710
- *
5711
- * These are stored in users-permissions plugin store
5639
+ * Get Strapi core email template
5712
5640
  */
5713
5641
  async getCoreTemplate(coreEmailType) {
5714
5642
  if (!["reset-password", "email-confirmation"].includes(coreEmailType)) {
@@ -5725,8 +5653,8 @@ function requireEmailDesigner() {
5725
5653
  if (emailConfig && emailConfig[pluginStoreEmailKey]) {
5726
5654
  data = emailConfig[pluginStoreEmailKey];
5727
5655
  }
5728
- const messageConverted = data && data.options && data.options.message ? data.options.message.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5729
- const subjectConverted = data && data.options && data.options.object ? data.options.object.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5656
+ const messageConverted = data?.options?.message ? data.options.message.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5657
+ const subjectConverted = data?.options?.object ? data.options.object.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5730
5658
  return {
5731
5659
  from: data?.options?.from || null,
5732
5660
  message: messageConverted || "",
@@ -5754,14 +5682,14 @@ function requireEmailDesigner() {
5754
5682
  emailsConfig[pluginStoreEmailKey] = {
5755
5683
  ...emailsConfig[pluginStoreEmailKey],
5756
5684
  options: {
5757
- ...emailsConfig[pluginStoreEmailKey] ? emailsConfig[pluginStoreEmailKey].options : {},
5685
+ ...emailsConfig[pluginStoreEmailKey]?.options || {},
5758
5686
  message: data.message.replace(/{{/g, "<%").replace(/}}/g, "%>"),
5759
5687
  object: data.subject.replace(/{{/g, "<%").replace(/}}/g, "%>")
5760
5688
  },
5761
5689
  design: data.design
5762
5690
  };
5763
5691
  await pluginStore.set({ key: "email", value: emailsConfig });
5764
- strapi2.log.info(`[magic-mail] Core email template updated: ${pluginStoreEmailKey}`);
5692
+ strapi2.log.info(`[magic-mail] [SUCCESS] Core email template updated: ${pluginStoreEmailKey}`);
5765
5693
  return { message: "Saved" };
5766
5694
  }
5767
5695
  });
@@ -5773,6 +5701,9 @@ function requireAnalytics() {
5773
5701
  if (hasRequiredAnalytics) return analytics;
5774
5702
  hasRequiredAnalytics = 1;
5775
5703
  const crypto = require$$0__default.default;
5704
+ const EMAIL_LOG_UID = "plugin::magic-mail.email-log";
5705
+ const EMAIL_EVENT_UID = "plugin::magic-mail.email-event";
5706
+ const EMAIL_LINK_UID = "plugin::magic-mail.email-link";
5776
5707
  analytics = ({ strapi: strapi2 }) => ({
5777
5708
  /**
5778
5709
  * Generate unique email ID for tracking
@@ -5791,7 +5722,7 @@ function requireAnalytics() {
5791
5722
  */
5792
5723
  async createEmailLog(data) {
5793
5724
  const emailId = this.generateEmailId();
5794
- const logEntry = await strapi2.db.query("plugin::magic-mail.email-log").create({
5725
+ const logEntry = await strapi2.documents(EMAIL_LOG_UID).create({
5795
5726
  data: {
5796
5727
  emailId,
5797
5728
  user: data.userId || null,
@@ -5806,9 +5737,9 @@ function requireAnalytics() {
5806
5737
  metadata: data.metadata || {}
5807
5738
  }
5808
5739
  });
5809
- strapi2.log.info(`[magic-mail] Email log created: ${emailId}`);
5740
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email log created: ${emailId}`);
5810
5741
  if (data.templateId) {
5811
- strapi2.log.info(`[magic-mail] 📋 Template tracked: ${data.templateName || "Unknown"} (ID: ${data.templateId})`);
5742
+ strapi2.log.info(`[magic-mail] [INFO] Template tracked: ${data.templateName || "Unknown"} (ID: ${data.templateId})`);
5812
5743
  }
5813
5744
  return logEntry;
5814
5745
  },
@@ -5817,8 +5748,8 @@ function requireAnalytics() {
5817
5748
  */
5818
5749
  async recordOpen(emailId, recipientHash, req) {
5819
5750
  try {
5820
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5821
- where: { emailId }
5751
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5752
+ filters: { emailId }
5822
5753
  });
5823
5754
  if (!emailLog) {
5824
5755
  strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
@@ -5830,17 +5761,17 @@ function requireAnalytics() {
5830
5761
  return null;
5831
5762
  }
5832
5763
  const now = /* @__PURE__ */ new Date();
5833
- await strapi2.db.query("plugin::magic-mail.email-log").update({
5834
- where: { id: emailLog.id },
5764
+ await strapi2.documents(EMAIL_LOG_UID).update({
5765
+ documentId: emailLog.documentId,
5835
5766
  data: {
5836
- openCount: emailLog.openCount + 1,
5767
+ openCount: (emailLog.openCount || 0) + 1,
5837
5768
  firstOpenedAt: emailLog.firstOpenedAt || now,
5838
5769
  lastOpenedAt: now
5839
5770
  }
5840
5771
  });
5841
- const event = await strapi2.db.query("plugin::magic-mail.email-event").create({
5772
+ const event = await strapi2.documents(EMAIL_EVENT_UID).create({
5842
5773
  data: {
5843
- emailLog: emailLog.id,
5774
+ emailLog: emailLog.documentId,
5844
5775
  type: "open",
5845
5776
  timestamp: now,
5846
5777
  ipAddress: req.ip || req.headers["x-forwarded-for"] || null,
@@ -5848,7 +5779,7 @@ function requireAnalytics() {
5848
5779
  location: this.parseLocation(req)
5849
5780
  }
5850
5781
  });
5851
- strapi2.log.info(`[magic-mail] 📧 Email opened: ${emailId} (count: ${emailLog.openCount + 1})`);
5782
+ strapi2.log.info(`[magic-mail] [EMAIL] Email opened: ${emailId} (count: ${(emailLog.openCount || 0) + 1})`);
5852
5783
  return event;
5853
5784
  } catch (error) {
5854
5785
  strapi2.log.error("[magic-mail] Error recording open:", error);
@@ -5860,8 +5791,8 @@ function requireAnalytics() {
5860
5791
  */
5861
5792
  async recordClick(emailId, linkHash, recipientHash, targetUrl, req) {
5862
5793
  try {
5863
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5864
- where: { emailId }
5794
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5795
+ filters: { emailId }
5865
5796
  });
5866
5797
  if (!emailLog) {
5867
5798
  return null;
@@ -5871,15 +5802,15 @@ function requireAnalytics() {
5871
5802
  return null;
5872
5803
  }
5873
5804
  const now = /* @__PURE__ */ new Date();
5874
- await strapi2.db.query("plugin::magic-mail.email-log").update({
5875
- where: { id: emailLog.id },
5805
+ await strapi2.documents(EMAIL_LOG_UID).update({
5806
+ documentId: emailLog.documentId,
5876
5807
  data: {
5877
- clickCount: emailLog.clickCount + 1
5808
+ clickCount: (emailLog.clickCount || 0) + 1
5878
5809
  }
5879
5810
  });
5880
- const event = await strapi2.db.query("plugin::magic-mail.email-event").create({
5811
+ const event = await strapi2.documents(EMAIL_EVENT_UID).create({
5881
5812
  data: {
5882
- emailLog: emailLog.id,
5813
+ emailLog: emailLog.documentId,
5883
5814
  type: "click",
5884
5815
  timestamp: now,
5885
5816
  ipAddress: req.ip || req.headers["x-forwarded-for"] || null,
@@ -5888,7 +5819,7 @@ function requireAnalytics() {
5888
5819
  linkUrl: targetUrl
5889
5820
  }
5890
5821
  });
5891
- strapi2.log.info(`[magic-mail] 🖱️ Link clicked: ${emailId} ${targetUrl}`);
5822
+ strapi2.log.info(`[magic-mail] [CLICK] Link clicked: ${emailId} -> ${targetUrl}`);
5892
5823
  return event;
5893
5824
  } catch (error) {
5894
5825
  strapi2.log.error("[magic-mail] Error recording click:", error);
@@ -5897,34 +5828,37 @@ function requireAnalytics() {
5897
5828
  },
5898
5829
  /**
5899
5830
  * Get analytics statistics
5831
+ * Note: Document Service doesn't have count() - using findMany for counting
5900
5832
  */
5901
5833
  async getStats(filters = {}) {
5902
- const where = {};
5834
+ const baseFilters = {};
5903
5835
  if (filters.userId) {
5904
- where.user = filters.userId;
5836
+ baseFilters.user = { documentId: filters.userId };
5905
5837
  }
5906
5838
  if (filters.templateId) {
5907
- where.templateId = filters.templateId;
5839
+ baseFilters.templateId = filters.templateId;
5908
5840
  }
5909
5841
  if (filters.accountId) {
5910
- where.accountId = filters.accountId;
5842
+ baseFilters.accountId = filters.accountId;
5911
5843
  }
5912
5844
  if (filters.dateFrom) {
5913
- where.sentAt = { $gte: new Date(filters.dateFrom) };
5845
+ baseFilters.sentAt = { $gte: new Date(filters.dateFrom) };
5914
5846
  }
5915
5847
  if (filters.dateTo) {
5916
- where.sentAt = { ...where.sentAt, $lte: new Date(filters.dateTo) };
5848
+ baseFilters.sentAt = { ...baseFilters.sentAt, $lte: new Date(filters.dateTo) };
5917
5849
  }
5918
5850
  const [totalSent, totalOpened, totalClicked, totalBounced] = await Promise.all([
5919
- strapi2.db.query("plugin::magic-mail.email-log").count({ where }),
5920
- strapi2.db.query("plugin::magic-mail.email-log").count({
5921
- where: { ...where, openCount: { $gt: 0 } }
5851
+ strapi2.documents(EMAIL_LOG_UID).count({
5852
+ filters: baseFilters
5922
5853
  }),
5923
- strapi2.db.query("plugin::magic-mail.email-log").count({
5924
- where: { ...where, clickCount: { $gt: 0 } }
5854
+ strapi2.documents(EMAIL_LOG_UID).count({
5855
+ filters: { ...baseFilters, openCount: { $gt: 0 } }
5925
5856
  }),
5926
- strapi2.db.query("plugin::magic-mail.email-log").count({
5927
- where: { ...where, bounced: true }
5857
+ strapi2.documents(EMAIL_LOG_UID).count({
5858
+ filters: { ...baseFilters, clickCount: { $gt: 0 } }
5859
+ }),
5860
+ strapi2.documents(EMAIL_LOG_UID).count({
5861
+ filters: { ...baseFilters, bounced: true }
5928
5862
  })
5929
5863
  ]);
5930
5864
  const openRate = totalSent > 0 ? totalOpened / totalSent * 100 : 0;
@@ -5946,7 +5880,7 @@ function requireAnalytics() {
5946
5880
  async getEmailLogs(filters = {}, pagination = {}) {
5947
5881
  const where = {};
5948
5882
  if (filters.userId) {
5949
- where.user = filters.userId;
5883
+ where.user = { documentId: filters.userId };
5950
5884
  }
5951
5885
  if (filters.templateId) {
5952
5886
  where.templateId = filters.templateId;
@@ -5961,14 +5895,17 @@ function requireAnalytics() {
5961
5895
  const page = pagination.page || 1;
5962
5896
  const pageSize = pagination.pageSize || 25;
5963
5897
  const [logs, total] = await Promise.all([
5964
- strapi2.db.query("plugin::magic-mail.email-log").findMany({
5965
- where,
5966
- orderBy: { sentAt: "desc" },
5898
+ strapi2.documents(EMAIL_LOG_UID).findMany({
5899
+ filters: where,
5900
+ sort: [{ sentAt: "desc" }],
5967
5901
  limit: pageSize,
5968
5902
  offset: (page - 1) * pageSize,
5969
5903
  populate: ["user"]
5970
5904
  }),
5971
- strapi2.db.query("plugin::magic-mail.email-log").count({ where })
5905
+ // Get total count using native count() method
5906
+ strapi2.documents(EMAIL_LOG_UID).count({
5907
+ filters: where
5908
+ })
5972
5909
  ]);
5973
5910
  return {
5974
5911
  data: logs,
@@ -5984,8 +5921,8 @@ function requireAnalytics() {
5984
5921
  * Get email log details with events
5985
5922
  */
5986
5923
  async getEmailLogDetails(emailId) {
5987
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5988
- where: { emailId },
5924
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5925
+ filters: { emailId },
5989
5926
  populate: ["user", "events"]
5990
5927
  });
5991
5928
  return emailLog;
@@ -5994,9 +5931,9 @@ function requireAnalytics() {
5994
5931
  * Get user email activity
5995
5932
  */
5996
5933
  async getUserActivity(userId) {
5997
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
5998
- where: { user: userId },
5999
- orderBy: { sentAt: "desc" },
5934
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
5935
+ filters: { user: { documentId: userId } },
5936
+ sort: [{ sentAt: "desc" }],
6000
5937
  limit: 50
6001
5938
  });
6002
5939
  const stats = await this.getStats({ userId });
@@ -6034,8 +5971,8 @@ function requireAnalytics() {
6034
5971
  */
6035
5972
  async rewriteLinksForTracking(html, emailId, recipientHash) {
6036
5973
  const baseUrl = strapi2.config.get("server.url") || "http://localhost:1337";
6037
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
6038
- where: { emailId }
5974
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5975
+ filters: { emailId }
6039
5976
  });
6040
5977
  if (!emailLog) {
6041
5978
  strapi2.log.error(`[magic-mail] Cannot rewrite links: Email log not found for ${emailId}`);
@@ -6049,13 +5986,13 @@ function requireAnalytics() {
6049
5986
  while ((match = linkRegex.exec(html)) !== null) {
6050
5987
  match[0];
6051
5988
  const originalUrl = match[1];
6052
- strapi2.log.debug(`[magic-mail] 🔍 Found link: ${originalUrl.substring(0, 100)}${originalUrl.length > 100 ? "..." : ""}`);
5989
+ strapi2.log.debug(`[magic-mail] [CHECK] Found link: ${originalUrl.substring(0, 100)}${originalUrl.length > 100 ? "..." : ""}`);
6053
5990
  if (originalUrl.startsWith("#") || originalUrl.includes("/track/click/")) {
6054
- strapi2.log.debug(`[magic-mail] ⏭️ Skipping (anchor or already tracked)`);
5991
+ strapi2.log.debug(`[magic-mail] [SKIP] Skipping (anchor or already tracked)`);
6055
5992
  continue;
6056
5993
  }
6057
5994
  if (!originalUrl.match(/^https?:\/\//i) && !originalUrl.startsWith("/")) {
6058
- strapi2.log.debug(`[magic-mail] ⏭️ Skipping relative URL: ${originalUrl}`);
5995
+ strapi2.log.debug(`[magic-mail] [SKIP] Skipping relative URL: ${originalUrl}`);
6059
5996
  continue;
6060
5997
  }
6061
5998
  const linkHash = crypto.createHash("md5").update(originalUrl).digest("hex").substring(0, 8);
@@ -6065,7 +6002,7 @@ function requireAnalytics() {
6065
6002
  });
6066
6003
  const trackingUrl = `${baseUrl}/api/magic-mail/track/click/${emailId}/${linkHash}/${recipientHash}`;
6067
6004
  linkCount++;
6068
- strapi2.log.info(`[magic-mail] 🔗 Link ${linkCount}: ${originalUrl} → ${trackingUrl}`);
6005
+ strapi2.log.info(`[magic-mail] [LINK] Link ${linkCount}: ${originalUrl} → ${trackingUrl}`);
6069
6006
  replacements.push({
6070
6007
  from: originalUrl,
6071
6008
  to: trackingUrl
@@ -6073,7 +6010,7 @@ function requireAnalytics() {
6073
6010
  }
6074
6011
  for (const mapping of linkMappings) {
6075
6012
  try {
6076
- await this.storeLinkMapping(emailLog.id, mapping.linkHash, mapping.originalUrl);
6013
+ await this.storeLinkMapping(emailLog.documentId, mapping.linkHash, mapping.originalUrl);
6077
6014
  } catch (err) {
6078
6015
  strapi2.log.error("[magic-mail] Error storing link mapping:", err);
6079
6016
  }
@@ -6083,20 +6020,20 @@ function requireAnalytics() {
6083
6020
  result = result.replace(replacement.from, replacement.to);
6084
6021
  }
6085
6022
  if (linkCount > 0) {
6086
- strapi2.log.info(`[magic-mail] Rewrote ${linkCount} links for click tracking`);
6023
+ strapi2.log.info(`[magic-mail] [SUCCESS] Rewrote ${linkCount} links for click tracking`);
6087
6024
  } else {
6088
- strapi2.log.warn(`[magic-mail] ⚠️ No links found in email HTML for tracking!`);
6025
+ strapi2.log.warn(`[magic-mail] [WARNING] No links found in email HTML for tracking!`);
6089
6026
  }
6090
6027
  return result;
6091
6028
  },
6092
6029
  /**
6093
6030
  * Store link mapping in database
6094
6031
  */
6095
- async storeLinkMapping(emailLogId, linkHash, originalUrl) {
6032
+ async storeLinkMapping(emailLogDocId, linkHash, originalUrl) {
6096
6033
  try {
6097
- const existing = await strapi2.db.query("plugin::magic-mail.email-link").findOne({
6098
- where: {
6099
- emailLog: emailLogId,
6034
+ const existing = await strapi2.documents(EMAIL_LINK_UID).findFirst({
6035
+ filters: {
6036
+ emailLog: { documentId: emailLogDocId },
6100
6037
  linkHash
6101
6038
  }
6102
6039
  });
@@ -6104,15 +6041,15 @@ function requireAnalytics() {
6104
6041
  strapi2.log.debug(`[magic-mail] Link mapping already exists for ${linkHash}`);
6105
6042
  return existing;
6106
6043
  }
6107
- const linkMapping = await strapi2.db.query("plugin::magic-mail.email-link").create({
6044
+ const linkMapping = await strapi2.documents(EMAIL_LINK_UID).create({
6108
6045
  data: {
6109
- emailLog: emailLogId,
6046
+ emailLog: emailLogDocId,
6110
6047
  linkHash,
6111
6048
  originalUrl,
6112
6049
  clickCount: 0
6113
6050
  }
6114
6051
  });
6115
- strapi2.log.debug(`[magic-mail] 💾 Stored link mapping: ${linkHash} → ${originalUrl}`);
6052
+ strapi2.log.debug(`[magic-mail] [SAVE] Stored link mapping: ${linkHash} → ${originalUrl}`);
6116
6053
  return linkMapping;
6117
6054
  } catch (error) {
6118
6055
  strapi2.log.error("[magic-mail] Error storing link mapping:", error);
@@ -6124,16 +6061,16 @@ function requireAnalytics() {
6124
6061
  */
6125
6062
  async getOriginalUrlFromHash(emailId, linkHash) {
6126
6063
  try {
6127
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
6128
- where: { emailId }
6064
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
6065
+ filters: { emailId }
6129
6066
  });
6130
6067
  if (!emailLog) {
6131
6068
  strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
6132
6069
  return null;
6133
6070
  }
6134
- const linkMapping = await strapi2.db.query("plugin::magic-mail.email-link").findOne({
6135
- where: {
6136
- emailLog: emailLog.id,
6071
+ const linkMapping = await strapi2.documents(EMAIL_LINK_UID).findFirst({
6072
+ filters: {
6073
+ emailLog: { documentId: emailLog.documentId },
6137
6074
  linkHash
6138
6075
  }
6139
6076
  });
@@ -6142,10 +6079,10 @@ function requireAnalytics() {
6142
6079
  return null;
6143
6080
  }
6144
6081
  const now = /* @__PURE__ */ new Date();
6145
- await strapi2.db.query("plugin::magic-mail.email-link").update({
6146
- where: { id: linkMapping.id },
6082
+ await strapi2.documents(EMAIL_LINK_UID).update({
6083
+ documentId: linkMapping.documentId,
6147
6084
  data: {
6148
- clickCount: linkMapping.clickCount + 1,
6085
+ clickCount: (linkMapping.clickCount || 0) + 1,
6149
6086
  firstClickedAt: linkMapping.firstClickedAt || now,
6150
6087
  lastClickedAt: now
6151
6088
  }