strapi-plugin-magic-mail 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,14 +23,14 @@ function requireBootstrap() {
23
23
  if (hasRequiredBootstrap) return bootstrap;
24
24
  hasRequiredBootstrap = 1;
25
25
  bootstrap = async ({ strapi: strapi2 }) => {
26
- strapi2.log.info("🚀 [magic-mail] Bootstrap starting...");
26
+ strapi2.log.info("[BOOTSTRAP] [magic-mail] Starting...");
27
27
  try {
28
28
  const licenseGuardService = strapi2.plugin("magic-mail").service("license-guard");
29
29
  setTimeout(async () => {
30
30
  const licenseStatus = await licenseGuardService.initialize();
31
31
  if (!licenseStatus.valid && licenseStatus.demo) {
32
32
  strapi2.log.error("╔════════════════════════════════════════════════════════════════╗");
33
- strapi2.log.error("║ MAGICMAIL - NO VALID LICENSE ║");
33
+ strapi2.log.error("║ [ERROR] MAGICMAIL - NO VALID LICENSE ║");
34
34
  strapi2.log.error("║ ║");
35
35
  strapi2.log.error("║ This plugin requires a valid license to operate. ║");
36
36
  strapi2.log.error("║ Please activate your license via Admin UI: ║");
@@ -39,7 +39,7 @@ function requireBootstrap() {
39
39
  strapi2.log.error('║ Click "Generate Free License" to get started! ║');
40
40
  strapi2.log.error("╚════════════════════════════════════════════════════════════════╝");
41
41
  } else if (licenseStatus.gracePeriod) {
42
- strapi2.log.warn("⚠️ Running on grace period (license server unreachable)");
42
+ strapi2.log.warn("[WARNING] Running on grace period (license server unreachable)");
43
43
  }
44
44
  }, 2e3);
45
45
  const accountManager2 = strapi2.plugin("magic-mail").service("account-manager");
@@ -48,7 +48,7 @@ function requireBootstrap() {
48
48
  if (originalEmailService && originalEmailService.send) {
49
49
  const originalSend = originalEmailService.send.bind(originalEmailService);
50
50
  originalEmailService.send = async (emailData) => {
51
- strapi2.log.info("[magic-mail] 📧 Email intercepted from native Strapi service");
51
+ strapi2.log.info("[magic-mail] [EMAIL] Intercepted from native Strapi service");
52
52
  strapi2.log.debug("[magic-mail] Email data:", {
53
53
  to: emailData.to,
54
54
  subject: emailData.subject,
@@ -61,19 +61,19 @@ function requireBootstrap() {
61
61
  emailData.templateData = emailData.data;
62
62
  }
63
63
  const result = await emailRouter2.send(emailData);
64
- strapi2.log.info("[magic-mail] Email routed successfully through MagicMail");
64
+ strapi2.log.info("[magic-mail] [SUCCESS] Email routed successfully through MagicMail");
65
65
  return result;
66
66
  } catch (magicMailError) {
67
- strapi2.log.warn("[magic-mail] ⚠️ MagicMail routing failed, falling back to original service");
67
+ strapi2.log.warn("[magic-mail] [WARNING] MagicMail routing failed, falling back to original service");
68
68
  strapi2.log.error("[magic-mail] Error:", magicMailError.message);
69
69
  return await originalSend(emailData);
70
70
  }
71
71
  };
72
- strapi2.log.info("[magic-mail] Native email service overridden!");
73
- strapi2.log.info("[magic-mail] 💡 All strapi.plugins.email.services.email.send() calls will route through MagicMail");
72
+ strapi2.log.info("[magic-mail] [SUCCESS] Native email service overridden!");
73
+ strapi2.log.info("[magic-mail] [INFO] All strapi.plugins.email.services.email.send() calls will route through MagicMail");
74
74
  } else {
75
- strapi2.log.warn("[magic-mail] ⚠️ Native email service not found - MagicMail will work standalone");
76
- strapi2.log.warn("[magic-mail] 💡 Make sure @strapi/plugin-email is installed");
75
+ strapi2.log.warn("[magic-mail] [WARNING] Native email service not found - MagicMail will work standalone");
76
+ strapi2.log.warn("[magic-mail] [INFO] Make sure @strapi/plugin-email is installed");
77
77
  }
78
78
  const hourlyResetInterval = setInterval(async () => {
79
79
  try {
@@ -83,7 +83,7 @@ function requireBootstrap() {
83
83
  }
84
84
  const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
85
85
  await accountMgr.resetCounters("hourly");
86
- strapi2.log.info("[magic-mail] Hourly counters reset");
86
+ strapi2.log.info("[magic-mail] [RESET] Hourly counters reset");
87
87
  } catch (err) {
88
88
  console.error("[magic-mail] Hourly reset error:", err.message);
89
89
  }
@@ -101,7 +101,7 @@ function requireBootstrap() {
101
101
  }
102
102
  const accountMgr = strapi2.plugin("magic-mail").service("account-manager");
103
103
  await accountMgr.resetCounters("daily");
104
- strapi2.log.info("[magic-mail] Daily counters reset");
104
+ strapi2.log.info("[magic-mail] [RESET] Daily counters reset");
105
105
  const dailyResetInterval = setInterval(async () => {
106
106
  try {
107
107
  if (!strapi2 || !strapi2.plugin) {
@@ -110,7 +110,7 @@ function requireBootstrap() {
110
110
  }
111
111
  const accountMgr2 = strapi2.plugin("magic-mail").service("account-manager");
112
112
  await accountMgr2.resetCounters("daily");
113
- strapi2.log.info("[magic-mail] Daily counters reset");
113
+ strapi2.log.info("[magic-mail] [RESET] Daily counters reset");
114
114
  } catch (err) {
115
115
  console.error("[magic-mail] Daily reset error:", err.message);
116
116
  }
@@ -120,10 +120,10 @@ function requireBootstrap() {
120
120
  console.error("[magic-mail] Initial daily reset error:", err.message);
121
121
  }
122
122
  }, msUntilMidnight);
123
- strapi2.log.info("[magic-mail] Counter reset schedules initialized");
124
- strapi2.log.info("[magic-mail] Bootstrap complete");
123
+ strapi2.log.info("[magic-mail] [SUCCESS] Counter reset schedules initialized");
124
+ strapi2.log.info("[magic-mail] [SUCCESS] Bootstrap complete");
125
125
  } catch (err) {
126
- strapi2.log.error("[magic-mail] Bootstrap error:", err);
126
+ strapi2.log.error("[magic-mail] [ERROR] Bootstrap error:", err);
127
127
  }
128
128
  };
129
129
  return bootstrap;
@@ -358,7 +358,7 @@ function requireAccounts() {
358
358
  ctx.throw(403, `Provider "${accountData.provider}" requires a Premium license or higher. Please upgrade your license.`);
359
359
  return;
360
360
  }
361
- const currentAccounts = await strapi.entityService.count("plugin::magic-mail.email-account");
361
+ const currentAccounts = await strapi.documents("plugin::magic-mail.email-account").count();
362
362
  const maxAccounts = await licenseGuard2.getMaxAccounts();
363
363
  if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
364
364
  ctx.throw(403, `Account limit reached (${maxAccounts}). Upgrade your license to add more accounts.`);
@@ -439,9 +439,9 @@ function requireAccounts() {
439
439
  ctx.throw(400, "testEmail is required");
440
440
  }
441
441
  strapi.log.info("[magic-mail] 🧪 Testing Strapi Email Service integration...");
442
- strapi.log.info('[magic-mail] 📧 Calling strapi.plugin("email").service("email").send()');
442
+ strapi.log.info('[magic-mail] [EMAIL] Calling strapi.plugin("email").service("email").send()');
443
443
  if (accountName) {
444
- strapi.log.info(`[magic-mail] 🎯 Forcing specific account: ${accountName}`);
444
+ strapi.log.info(`[magic-mail] [FORCE] Forcing specific account: ${accountName}`);
445
445
  }
446
446
  const result = await strapi.plugin("email").service("email").send({
447
447
  to: testEmail,
@@ -468,6 +468,15 @@ function requireAccounts() {
468
468
  <li>Statistics tracking</li>
469
469
  </ul>
470
470
  </div>
471
+ <div style="background: #DCFCE7; border: 1px solid #22C55E; border-radius: 8px; padding: 15px; margin: 20px 0;">
472
+ <h3 style="margin-top: 0; color: #15803D;">Security Features Active</h3>
473
+ <ul style="margin: 10px 0; padding-left: 20px;">
474
+ <li>TLS/SSL Encryption enforced</li>
475
+ <li>Email content validated</li>
476
+ <li>Proper headers included</li>
477
+ <li>Message-ID generated</li>
478
+ </ul>
479
+ </div>
471
480
  <p style="color: #6B7280; font-size: 14px; margin-top: 30px;">
472
481
  Sent at: ${(/* @__PURE__ */ new Date()).toLocaleString()}<br>
473
482
  Via: MagicMail Email Router
@@ -478,7 +487,7 @@ function requireAccounts() {
478
487
  accountName: accountName || null
479
488
  // Force specific account if provided
480
489
  });
481
- strapi.log.info("[magic-mail] Strapi Email Service test completed");
490
+ strapi.log.info("[magic-mail] [SUCCESS] Strapi Email Service test completed");
482
491
  ctx.body = {
483
492
  success: true,
484
493
  message: "Email sent via Strapi Email Service (intercepted by MagicMail)",
@@ -490,7 +499,7 @@ function requireAccounts() {
490
499
  }
491
500
  };
492
501
  } catch (err) {
493
- strapi.log.error("[magic-mail] Strapi Email Service test failed:", err);
502
+ strapi.log.error("[magic-mail] [ERROR] Strapi Email Service test failed:", err);
494
503
  ctx.body = {
495
504
  success: false,
496
505
  message: "Failed to send test email",
@@ -567,7 +576,7 @@ function requireOauth$1() {
567
576
  </style>
568
577
  </head>
569
578
  <body>
570
- <div class="error">❌ OAuth Authorization Failed</div>
579
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
571
580
  <p>Error: ${error}</p>
572
581
  <p>You can close this window and try again.</p>
573
582
  <script>
@@ -601,7 +610,7 @@ function requireOauth$1() {
601
610
  </style>
602
611
  </head>
603
612
  <body>
604
- <div class="success">✅</div>
613
+ <div class="success">[SUCCESS]</div>
605
614
  <div class="message">Gmail OAuth Authorized!</div>
606
615
  <div class="note">Closing window...</div>
607
616
  <script>
@@ -676,7 +685,7 @@ function requireOauth$1() {
676
685
  </style>
677
686
  </head>
678
687
  <body>
679
- <div class="error">❌ OAuth Authorization Failed</div>
688
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
680
689
  <p>Error: ${error}</p>
681
690
  <p>You can close this window and try again.</p>
682
691
  <script>
@@ -710,7 +719,7 @@ function requireOauth$1() {
710
719
  </style>
711
720
  </head>
712
721
  <body>
713
- <div class="success">✅</div>
722
+ <div class="success">[SUCCESS]</div>
714
723
  <div class="message">Microsoft OAuth Authorized!</div>
715
724
  <div class="note">Closing window...</div>
716
725
  <script>
@@ -781,7 +790,7 @@ function requireOauth$1() {
781
790
  </style>
782
791
  </head>
783
792
  <body>
784
- <div class="error">❌ OAuth Authorization Failed</div>
793
+ <div class="error">[ERROR] OAuth Authorization Failed</div>
785
794
  <p>Error: ${error}</p>
786
795
  <p>You can close this window and try again.</p>
787
796
  <script>
@@ -815,7 +824,7 @@ function requireOauth$1() {
815
824
  </style>
816
825
  </head>
817
826
  <body>
818
- <div class="success">✅</div>
827
+ <div class="success">[SUCCESS]</div>
819
828
  <div class="message">Yahoo Mail OAuth Authorized!</div>
820
829
  <div class="note">Closing window...</div>
821
830
  <script>
@@ -865,7 +874,7 @@ function requireOauth$1() {
865
874
  ctx.throw(403, `OAuth provider "${provider}" requires a Premium license or higher. Please upgrade your license.`);
866
875
  return;
867
876
  }
868
- const currentAccounts = await strapi.entityService.count("plugin::magic-mail.email-account");
877
+ const currentAccounts = await strapi.documents("plugin::magic-mail.email-account").count();
869
878
  const maxAccounts = await licenseGuard2.getMaxAccounts();
870
879
  if (maxAccounts !== -1 && currentAccounts >= maxAccounts) {
871
880
  ctx.throw(403, `Account limit reached (${maxAccounts}). Upgrade your license to add more accounts.`);
@@ -920,7 +929,7 @@ function requireOauth$1() {
920
929
  accountDetails.config
921
930
  // contains clientId and clientSecret
922
931
  );
923
- strapi.log.info("[magic-mail] OAuth account created successfully");
932
+ strapi.log.info("[magic-mail] [SUCCESS] OAuth account created successfully");
924
933
  ctx.body = {
925
934
  success: true,
926
935
  data: account,
@@ -940,14 +949,15 @@ var hasRequiredRoutingRules;
940
949
  function requireRoutingRules() {
941
950
  if (hasRequiredRoutingRules) return routingRules;
942
951
  hasRequiredRoutingRules = 1;
952
+ const ROUTING_RULE_UID = "plugin::magic-mail.routing-rule";
943
953
  routingRules = {
944
954
  /**
945
955
  * Get all routing rules
946
956
  */
947
957
  async getAll(ctx) {
948
958
  try {
949
- const rules = await strapi.entityService.findMany("plugin::magic-mail.routing-rule", {
950
- sort: { priority: "desc" }
959
+ const rules = await strapi.documents(ROUTING_RULE_UID).findMany({
960
+ sort: [{ priority: "desc" }]
951
961
  });
952
962
  ctx.body = {
953
963
  data: rules,
@@ -964,7 +974,9 @@ function requireRoutingRules() {
964
974
  async getOne(ctx) {
965
975
  try {
966
976
  const { ruleId } = ctx.params;
967
- const rule = await strapi.entityService.findOne("plugin::magic-mail.routing-rule", ruleId);
977
+ const rule = await strapi.documents(ROUTING_RULE_UID).findOne({
978
+ documentId: ruleId
979
+ });
968
980
  if (!rule) {
969
981
  ctx.throw(404, "Routing rule not found");
970
982
  }
@@ -982,20 +994,20 @@ function requireRoutingRules() {
982
994
  async create(ctx) {
983
995
  try {
984
996
  const licenseGuard2 = strapi.plugin("magic-mail").service("license-guard");
985
- const currentRules = await strapi.entityService.count("plugin::magic-mail.routing-rule");
997
+ const currentRules = await strapi.documents(ROUTING_RULE_UID).count();
986
998
  const maxRules = await licenseGuard2.getMaxRoutingRules();
987
999
  if (maxRules !== -1 && currentRules >= maxRules) {
988
1000
  ctx.throw(403, `Routing rule limit reached (${maxRules}). Upgrade to Advanced license for unlimited rules.`);
989
1001
  return;
990
1002
  }
991
- const rule = await strapi.entityService.create("plugin::magic-mail.routing-rule", {
1003
+ const rule = await strapi.documents(ROUTING_RULE_UID).create({
992
1004
  data: ctx.request.body
993
1005
  });
994
1006
  ctx.body = {
995
1007
  data: rule,
996
1008
  message: "Routing rule created successfully"
997
1009
  };
998
- strapi.log.info(`[magic-mail] Routing rule created: ${rule.name}`);
1010
+ strapi.log.info(`[magic-mail] [SUCCESS] Routing rule created: ${rule.name}`);
999
1011
  } catch (err) {
1000
1012
  strapi.log.error("[magic-mail] Error creating routing rule:", err);
1001
1013
  ctx.throw(err.status || 500, err.message || "Error creating routing rule");
@@ -1007,14 +1019,15 @@ function requireRoutingRules() {
1007
1019
  async update(ctx) {
1008
1020
  try {
1009
1021
  const { ruleId } = ctx.params;
1010
- const rule = await strapi.entityService.update("plugin::magic-mail.routing-rule", ruleId, {
1022
+ const rule = await strapi.documents(ROUTING_RULE_UID).update({
1023
+ documentId: ruleId,
1011
1024
  data: ctx.request.body
1012
1025
  });
1013
1026
  ctx.body = {
1014
1027
  data: rule,
1015
1028
  message: "Routing rule updated successfully"
1016
1029
  };
1017
- strapi.log.info(`[magic-mail] Routing rule updated: ${rule.name}`);
1030
+ strapi.log.info(`[magic-mail] [SUCCESS] Routing rule updated: ${rule.name}`);
1018
1031
  } catch (err) {
1019
1032
  strapi.log.error("[magic-mail] Error updating routing rule:", err);
1020
1033
  ctx.throw(500, err.message || "Error updating routing rule");
@@ -1026,7 +1039,9 @@ function requireRoutingRules() {
1026
1039
  async delete(ctx) {
1027
1040
  try {
1028
1041
  const { ruleId } = ctx.params;
1029
- await strapi.entityService.delete("plugin::magic-mail.routing-rule", ruleId);
1042
+ await strapi.documents(ROUTING_RULE_UID).delete({
1043
+ documentId: ruleId
1044
+ });
1030
1045
  ctx.body = {
1031
1046
  message: "Routing rule deleted successfully"
1032
1047
  };
@@ -1182,7 +1197,7 @@ function requireFeatures() {
1182
1197
  */
1183
1198
  hasFeature(licenseData, featureName) {
1184
1199
  if (!licenseData) {
1185
- console.log(`[features.js] ⚠️ No license data → using FREE tier`);
1200
+ console.log(`[features.js] [WARNING] No license data → using FREE tier`);
1186
1201
  return this.free.features.includes(featureName);
1187
1202
  }
1188
1203
  let isEnterprise = false;
@@ -1208,19 +1223,19 @@ function requireFeatures() {
1208
1223
  isPremium = true;
1209
1224
  }
1210
1225
  if (isEnterprise && this.enterprise.features.includes(featureName)) {
1211
- console.log(`[features.js] ENTERPRISE tier has feature "${featureName}"`);
1226
+ console.log(`[features.js] [SUCCESS] ENTERPRISE tier has feature "${featureName}"`);
1212
1227
  return true;
1213
1228
  }
1214
1229
  if (isAdvanced && this.advanced.features.includes(featureName)) {
1215
- console.log(`[features.js] ADVANCED tier has feature "${featureName}"`);
1230
+ console.log(`[features.js] [SUCCESS] ADVANCED tier has feature "${featureName}"`);
1216
1231
  return true;
1217
1232
  }
1218
1233
  if (isPremium && this.premium.features.includes(featureName)) {
1219
- console.log(`[features.js] PREMIUM tier has feature "${featureName}"`);
1234
+ console.log(`[features.js] [SUCCESS] PREMIUM tier has feature "${featureName}"`);
1220
1235
  return true;
1221
1236
  }
1222
1237
  const inFree = this.free.features.includes(featureName);
1223
- console.log(`[features.js] ${inFree ? "" : ""} FREE tier check for "${featureName}": ${inFree}`);
1238
+ console.log(`[features.js] ${inFree ? "[SUCCESS]" : "[ERROR]"} FREE tier check for "${featureName}": ${inFree}`);
1224
1239
  return inFree;
1225
1240
  },
1226
1241
  /**
@@ -1378,7 +1393,7 @@ function requireLicense() {
1378
1393
  const licenseGuard2 = strapi2.plugin("magic-mail").service("license-guard");
1379
1394
  const verification = await licenseGuard2.verifyLicense(trimmedKey);
1380
1395
  if (!verification.valid) {
1381
- strapi2.log.warn(`[magic-mail] ⚠️ Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
1396
+ strapi2.log.warn(`[magic-mail] [WARNING] Invalid license key attempted: ${trimmedKey.substring(0, 8)}...`);
1382
1397
  return ctx.badRequest("Invalid or expired license key");
1383
1398
  }
1384
1399
  const license2 = await licenseGuard2.getLicenseByKey(trimmedKey);
@@ -1386,7 +1401,7 @@ function requireLicense() {
1386
1401
  return ctx.badRequest("License not found");
1387
1402
  }
1388
1403
  if (license2.email.toLowerCase() !== trimmedEmail) {
1389
- strapi2.log.warn(`[magic-mail] ⚠️ Email mismatch for license key`);
1404
+ strapi2.log.warn(`[magic-mail] [WARNING] Email mismatch for license key`);
1390
1405
  return ctx.badRequest("Email address does not match this license key");
1391
1406
  }
1392
1407
  await licenseGuard2.storeLicenseKey(trimmedKey);
@@ -1396,7 +1411,7 @@ function requireLicense() {
1396
1411
  pingInterval,
1397
1412
  data: verification.data
1398
1413
  };
1399
- strapi2.log.info(`[magic-mail] License validated and stored`);
1414
+ strapi2.log.info(`[magic-mail] [SUCCESS] License validated and stored`);
1400
1415
  return ctx.send({
1401
1416
  success: true,
1402
1417
  message: "License activated successfully",
@@ -1440,9 +1455,11 @@ function requireLicense() {
1440
1455
  const maxAccounts = await licenseGuard2.getMaxAccounts();
1441
1456
  const maxRules = await licenseGuard2.getMaxRoutingRules();
1442
1457
  const maxTemplates = await licenseGuard2.getMaxEmailTemplates();
1443
- const currentAccounts = await strapi2.entityService.count("plugin::magic-mail.email-account");
1444
- const currentRules = await strapi2.entityService.count("plugin::magic-mail.routing-rule");
1445
- const currentTemplates = await strapi2.entityService.count("plugin::magic-mail.email-template");
1458
+ const [currentAccounts, currentRules, currentTemplates] = await Promise.all([
1459
+ strapi2.documents("plugin::magic-mail.email-account").count(),
1460
+ strapi2.documents("plugin::magic-mail.routing-rule").count(),
1461
+ strapi2.documents("plugin::magic-mail.email-template").count()
1462
+ ]);
1446
1463
  let tier = "free";
1447
1464
  if (license2?.featureEnterprise === true || license2?.features?.enterprise === true) tier = "enterprise";
1448
1465
  else if (license2?.featureAdvanced === true || license2?.features?.advanced === true) tier = "advanced";
@@ -1851,6 +1868,9 @@ var hasRequiredAnalytics$1;
1851
1868
  function requireAnalytics$1() {
1852
1869
  if (hasRequiredAnalytics$1) return analytics$1;
1853
1870
  hasRequiredAnalytics$1 = 1;
1871
+ const EMAIL_LOG_UID = "plugin::magic-mail.email-log";
1872
+ const EMAIL_EVENT_UID = "plugin::magic-mail.email-event";
1873
+ const EMAIL_ACCOUNT_UID = "plugin::magic-mail.email-account";
1854
1874
  analytics$1 = ({ strapi: strapi2 }) => ({
1855
1875
  /**
1856
1876
  * Tracking pixel endpoint
@@ -1890,7 +1910,8 @@ function requireAnalytics$1() {
1890
1910
  async getStats(ctx) {
1891
1911
  try {
1892
1912
  const filters = {
1893
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
1913
+ // userId is documentId (string) in Strapi v5, NOT parseInt!
1914
+ userId: ctx.query.userId || null,
1894
1915
  templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
1895
1916
  accountId: ctx.query.accountId ? parseInt(ctx.query.accountId) : null,
1896
1917
  dateFrom: ctx.query.dateFrom || null,
@@ -1913,7 +1934,8 @@ function requireAnalytics$1() {
1913
1934
  async getEmailLogs(ctx) {
1914
1935
  try {
1915
1936
  const filters = {
1916
- userId: ctx.query.userId ? parseInt(ctx.query.userId) : null,
1937
+ // userId is documentId (string) in Strapi v5, NOT parseInt!
1938
+ userId: ctx.query.userId || null,
1917
1939
  templateId: ctx.query.templateId ? parseInt(ctx.query.templateId) : null,
1918
1940
  search: ctx.query.search || null
1919
1941
  };
@@ -1953,11 +1975,12 @@ function requireAnalytics$1() {
1953
1975
  /**
1954
1976
  * Get user email activity
1955
1977
  * GET /magic-mail/analytics/users/:userId
1978
+ * Note: userId is documentId (string) in Strapi v5
1956
1979
  */
1957
1980
  async getUserActivity(ctx) {
1958
1981
  try {
1959
1982
  const { userId } = ctx.params;
1960
- const activity = await strapi2.plugin("magic-mail").service("analytics").getUserActivity(parseInt(userId));
1983
+ const activity = await strapi2.plugin("magic-mail").service("analytics").getUserActivity(userId);
1961
1984
  return ctx.send({
1962
1985
  success: true,
1963
1986
  data: activity
@@ -1972,19 +1995,19 @@ function requireAnalytics$1() {
1972
1995
  */
1973
1996
  async debug(ctx) {
1974
1997
  try {
1975
- strapi2.log.info("[magic-mail] 🔍 Running Analytics Debug...");
1976
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
1998
+ strapi2.log.info("[magic-mail] [CHECK] Running Analytics Debug...");
1999
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
1977
2000
  limit: 10,
1978
- orderBy: { sentAt: "DESC" }
2001
+ sort: [{ sentAt: "desc" }]
1979
2002
  });
1980
- const emailEvents = await strapi2.db.query("plugin::magic-mail.email-event").findMany({
2003
+ const emailEvents = await strapi2.documents(EMAIL_EVENT_UID).findMany({
1981
2004
  limit: 20,
1982
- orderBy: { timestamp: "DESC" },
2005
+ sort: [{ timestamp: "desc" }],
1983
2006
  populate: ["emailLog"]
1984
2007
  });
1985
2008
  const analyticsService = strapi2.plugin("magic-mail").service("analytics");
1986
2009
  const stats = await analyticsService.getStats();
1987
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
2010
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
1988
2011
  filters: { isActive: true },
1989
2012
  fields: ["id", "name", "provider", "fromEmail", "emailsSentToday", "totalEmailsSent"]
1990
2013
  });
@@ -2048,19 +2071,20 @@ function requireAnalytics$1() {
2048
2071
  async deleteEmailLog(ctx) {
2049
2072
  try {
2050
2073
  const { emailId } = ctx.params;
2051
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
2052
- where: { emailId }
2074
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
2075
+ filters: { emailId }
2053
2076
  });
2054
2077
  if (!emailLog) {
2055
2078
  return ctx.notFound("Email log not found");
2056
2079
  }
2057
- await strapi2.db.query("plugin::magic-mail.email-event").deleteMany({
2058
- where: { emailLog: emailLog.id }
2059
- });
2060
- await strapi2.db.query("plugin::magic-mail.email-log").delete({
2061
- where: { id: emailLog.id }
2080
+ const events = await strapi2.documents(EMAIL_EVENT_UID).findMany({
2081
+ filters: { emailLog: { documentId: emailLog.documentId } }
2062
2082
  });
2063
- strapi2.log.info(`[magic-mail] 🗑️ Deleted email log: ${emailId}`);
2083
+ for (const event of events) {
2084
+ await strapi2.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
2085
+ }
2086
+ await strapi2.documents(EMAIL_LOG_UID).delete({ documentId: emailLog.documentId });
2087
+ strapi2.log.info(`[magic-mail] [DELETE] Deleted email log: ${emailId}`);
2064
2088
  return ctx.send({
2065
2089
  success: true,
2066
2090
  message: "Email log deleted successfully"
@@ -2077,33 +2101,36 @@ function requireAnalytics$1() {
2077
2101
  async clearAllEmailLogs(ctx) {
2078
2102
  try {
2079
2103
  const { olderThan } = ctx.query;
2080
- const where = {};
2104
+ const filters = {};
2081
2105
  if (olderThan) {
2082
- where.sentAt = { $lt: new Date(olderThan) };
2106
+ filters.sentAt = { $lt: new Date(olderThan) };
2083
2107
  }
2084
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
2085
- where,
2086
- select: ["id"]
2108
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
2109
+ filters,
2110
+ fields: ["id", "documentId"],
2111
+ limit: 1e5
2087
2112
  });
2088
- const emailLogIds = emailLogs.map((log) => log.id);
2089
- if (emailLogIds.length === 0) {
2113
+ if (emailLogs.length === 0) {
2090
2114
  return ctx.send({
2091
2115
  success: true,
2092
2116
  message: "No email logs to delete",
2093
2117
  deletedCount: 0
2094
2118
  });
2095
2119
  }
2096
- await strapi2.db.query("plugin::magic-mail.email-event").deleteMany({
2097
- where: { emailLog: { $in: emailLogIds } }
2098
- });
2099
- await strapi2.db.query("plugin::magic-mail.email-log").deleteMany({
2100
- where: { id: { $in: emailLogIds } }
2101
- });
2102
- strapi2.log.info(`[magic-mail] 🗑️ Cleared ${emailLogIds.length} email logs`);
2120
+ for (const log of emailLogs) {
2121
+ const events = await strapi2.documents(EMAIL_EVENT_UID).findMany({
2122
+ filters: { emailLog: { documentId: log.documentId } }
2123
+ });
2124
+ for (const event of events) {
2125
+ await strapi2.documents(EMAIL_EVENT_UID).delete({ documentId: event.documentId });
2126
+ }
2127
+ await strapi2.documents(EMAIL_LOG_UID).delete({ documentId: log.documentId });
2128
+ }
2129
+ strapi2.log.info(`[magic-mail] [DELETE] Cleared ${emailLogs.length} email logs`);
2103
2130
  return ctx.send({
2104
2131
  success: true,
2105
- message: `Successfully deleted ${emailLogIds.length} email log(s)`,
2106
- deletedCount: emailLogIds.length
2132
+ message: `Successfully deleted ${emailLogs.length} email log(s)`,
2133
+ deletedCount: emailLogs.length
2107
2134
  });
2108
2135
  } catch (error) {
2109
2136
  strapi2.log.error("[magic-mail] Error clearing email logs:", error);
@@ -2118,18 +2145,16 @@ var hasRequiredTest;
2118
2145
  function requireTest() {
2119
2146
  if (hasRequiredTest) return test;
2120
2147
  hasRequiredTest = 1;
2148
+ const EMAIL_TEMPLATE_UID = "plugin::magic-mail.email-template";
2149
+ const EMAIL_TEMPLATE_VERSION_UID = "plugin::magic-mail.email-template-version";
2121
2150
  test = {
2122
2151
  /**
2123
2152
  * Test Template-Version Relations
2124
- *
2125
- * Tests beide Richtungen:
2126
- * 1. Version → Template beim Erstellen
2127
- * 2. Template → Version nachträglich via connect
2128
2153
  */
2129
2154
  async testRelations(ctx) {
2130
2155
  try {
2131
2156
  console.log("\n" + "=".repeat(60));
2132
- console.log("🧪 TEST: Template ↔ Version Relations");
2157
+ console.log("🧪 TEST: Template ↔ Version Relations (Document Service API)");
2133
2158
  console.log("=".repeat(60));
2134
2159
  let test1Success = false;
2135
2160
  let test1ReverseSuccess = false;
@@ -2139,257 +2164,192 @@ function requireTest() {
2139
2164
  let test3a_hasTemplate = false;
2140
2165
  let test3b_twoVersions = false;
2141
2166
  let test3b_allHaveTemplate = false;
2142
- console.log("\n📝 TEST 1: Version → Template Verbindung\n");
2143
- const testTemplate = await strapi.entityService.create(
2144
- "plugin::magic-mail.email-template",
2145
- {
2146
- data: {
2147
- templateReferenceId: Math.floor(Math.random() * 1e6),
2148
- name: "Test Template Relations",
2149
- subject: "Test Subject",
2150
- bodyHtml: "<p>Test HTML</p>",
2151
- bodyText: "Test Text",
2152
- category: "custom",
2153
- isActive: true
2154
- }
2155
- }
2156
- );
2157
- console.log(`✅ Template erstellt: ID ${testTemplate.id}`);
2158
- const version1 = await strapi.entityService.create(
2159
- "plugin::magic-mail.email-template-version",
2160
- {
2161
- data: {
2162
- template: testTemplate.id,
2163
- // 👈 Direkte Verbindung beim Erstellen
2164
- versionNumber: 1,
2165
- name: "Version 1 von Test",
2166
- subject: "Test Subject V1",
2167
- bodyHtml: "<p>Version 1 HTML</p>",
2168
- bodyText: "Version 1 Text"
2169
- }
2167
+ console.log("\n[TEST] TEST 1: Version → Template Verbindung\n");
2168
+ const testTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).create({
2169
+ data: {
2170
+ templateReferenceId: Math.floor(Math.random() * 1e6),
2171
+ name: "Test Template Relations",
2172
+ subject: "Test Subject",
2173
+ bodyHtml: "<p>Test HTML</p>",
2174
+ bodyText: "Test Text",
2175
+ category: "custom",
2176
+ isActive: true
2170
2177
  }
2171
- );
2172
- console.log(`✅ Version erstellt: ID ${version1.id}, versionNumber: ${version1.versionNumber}`);
2173
- const versionCheck = await strapi.entityService.findOne(
2174
- "plugin::magic-mail.email-template-version",
2175
- version1.id,
2176
- {
2177
- populate: ["template"]
2178
+ });
2179
+ console.log(`[SUCCESS] Template erstellt: documentId ${testTemplate.documentId}`);
2180
+ const version1 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).create({
2181
+ data: {
2182
+ template: testTemplate.documentId,
2183
+ versionNumber: 1,
2184
+ name: "Version 1 von Test",
2185
+ subject: "Test Subject V1",
2186
+ bodyHtml: "<p>Version 1 HTML</p>",
2187
+ bodyText: "Version 1 Text"
2178
2188
  }
2179
- );
2180
- console.log("\n🔍 Prüfung Version Template:");
2189
+ });
2190
+ console.log(`[SUCCESS] Version erstellt: documentId ${version1.documentId}, versionNumber: ${version1.versionNumber}`);
2191
+ const versionCheck = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2192
+ documentId: version1.documentId,
2193
+ populate: ["template"]
2194
+ });
2195
+ console.log("\n[CHECK] Prüfung Version → Template:");
2181
2196
  test1Success = !!versionCheck.template;
2182
2197
  if (test1Success) {
2183
- console.log(` SUCCESS: Version ${versionCheck.id} → Template ${versionCheck.template.id}`);
2184
- console.log(` 📋 Template: "${versionCheck.template.name}"`);
2198
+ console.log(` [SUCCESS] SUCCESS: Version → Template ${versionCheck.template.documentId}`);
2185
2199
  } else {
2186
- console.log(` FEHLER: Version ${versionCheck.id} hat KEINE Template-Verbindung!`);
2200
+ console.log(` [ERROR] FEHLER: Version hat KEINE Template-Verbindung!`);
2187
2201
  }
2188
- const templateCheck1 = await strapi.entityService.findOne(
2189
- "plugin::magic-mail.email-template",
2190
- testTemplate.id,
2191
- {
2192
- populate: ["versions"]
2193
- }
2194
- );
2195
- console.log("\n🔍 Prüfung Template → Versions:");
2202
+ const templateCheck1 = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2203
+ documentId: testTemplate.documentId,
2204
+ populate: ["versions"]
2205
+ });
2206
+ console.log("\n[CHECK] Prüfung Template → Versions:");
2196
2207
  test1ReverseSuccess = templateCheck1.versions && templateCheck1.versions.length > 0;
2197
2208
  if (test1ReverseSuccess) {
2198
- console.log(` SUCCESS: Template ${templateCheck1.id} hat ${templateCheck1.versions.length} Version(en)`);
2199
- templateCheck1.versions.forEach((v) => {
2200
- console.log(` 📋 Version ${v.id}: versionNumber ${v.versionNumber}`);
2201
- });
2209
+ console.log(` [SUCCESS] SUCCESS: Template hat ${templateCheck1.versions.length} Version(en)`);
2202
2210
  } else {
2203
- console.log(` FEHLER: Template ${templateCheck1.id} hat KEINE Versionen!`);
2204
- }
2205
- console.log("\n\n📝 TEST 2: Nachträgliche Verbindung (Template Update)\n");
2206
- const version2 = await strapi.entityService.create(
2207
- "plugin::magic-mail.email-template-version",
2208
- {
2209
- data: {
2210
- versionNumber: 2,
2211
- name: "Version 2 ohne Template",
2212
- subject: "Test Subject V2",
2213
- bodyHtml: "<p>Version 2 HTML</p>",
2214
- bodyText: "Version 2 Text"
2215
- }
2216
- }
2217
- );
2218
- console.log(`✅ Version 2 erstellt: ID ${version2.id} (ohne Template)`);
2219
- await strapi.entityService.update(
2220
- "plugin::magic-mail.email-template",
2221
- testTemplate.id,
2222
- {
2223
- data: {
2224
- versions: {
2225
- connect: [version2.id]
2226
- // 👈 Nachträgliche Verbindung
2227
- }
2228
- }
2211
+ console.log(` [ERROR] FEHLER: Template hat KEINE Versionen!`);
2212
+ }
2213
+ console.log("\n\n[TEST] TEST 2: Nachträgliche Verbindung\n");
2214
+ const version2 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).create({
2215
+ data: {
2216
+ versionNumber: 2,
2217
+ name: "Version 2 ohne Template",
2218
+ subject: "Test Subject V2",
2219
+ bodyHtml: "<p>Version 2 HTML</p>",
2220
+ bodyText: "Version 2 Text"
2229
2221
  }
2230
- );
2231
- console.log(`✅ Template updated: Version ${version2.id} verbunden`);
2232
- const templateCheck2 = await strapi.entityService.findOne(
2233
- "plugin::magic-mail.email-template",
2234
- testTemplate.id,
2235
- {
2236
- populate: ["versions"]
2222
+ });
2223
+ console.log(`[SUCCESS] Version 2 erstellt: documentId ${version2.documentId} (ohne Template)`);
2224
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).update({
2225
+ documentId: version2.documentId,
2226
+ data: {
2227
+ template: testTemplate.documentId
2237
2228
  }
2238
- );
2239
- console.log("\n🔍 Prüfung nach Template Update:");
2229
+ });
2230
+ console.log(`[SUCCESS] Version 2 mit Template verbunden`);
2231
+ const templateCheck2 = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2232
+ documentId: testTemplate.documentId,
2233
+ populate: ["versions"]
2234
+ });
2235
+ console.log("\n[CHECK] Prüfung nach Update:");
2240
2236
  test2Success = templateCheck2.versions && templateCheck2.versions.length >= 2;
2241
2237
  if (test2Success) {
2242
- console.log(` SUCCESS: Template hat jetzt ${templateCheck2.versions.length} Versionen`);
2243
- templateCheck2.versions.forEach((v) => {
2244
- console.log(` 📋 Version ${v.id}: versionNumber ${v.versionNumber}, "${v.name}"`);
2245
- });
2238
+ console.log(` [SUCCESS] SUCCESS: Template hat jetzt ${templateCheck2.versions.length} Versionen`);
2246
2239
  } else {
2247
- console.log(` FEHLER: Template hat nur ${templateCheck2.versions?.length || 0} Version(en)!`);
2240
+ console.log(` [ERROR] FEHLER: Template hat nur ${templateCheck2.versions?.length || 0} Version(en)!`);
2248
2241
  }
2249
- const version2Check = await strapi.entityService.findOne(
2250
- "plugin::magic-mail.email-template-version",
2251
- version2.id,
2252
- {
2253
- populate: ["template"]
2254
- }
2255
- );
2256
- console.log("\n🔍 Prüfung Version 2 → Template:");
2242
+ const version2Check = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2243
+ documentId: version2.documentId,
2244
+ populate: ["template"]
2245
+ });
2257
2246
  test2ReverseSuccess = !!version2Check.template;
2258
2247
  if (test2ReverseSuccess) {
2259
- console.log(` SUCCESS: Version ${version2Check.id} → Template ${version2Check.template.id}`);
2260
- console.log(` 📋 Template: "${version2Check.template.name}"`);
2248
+ console.log(` [SUCCESS] SUCCESS: Version 2 → Template verbunden`);
2261
2249
  } else {
2262
- console.log(` FEHLER: Version ${version2Check.id} hat KEINE Template-Verbindung!`);
2263
- }
2264
- console.log("\n\n📝 TEST 3: Template Update (Auto-Versionierung)\n");
2265
- const autoTemplate = await strapi.entityService.create(
2266
- "plugin::magic-mail.email-template",
2267
- {
2268
- data: {
2269
- templateReferenceId: Math.floor(Math.random() * 1e6),
2270
- name: "Auto Version Test",
2271
- subject: "Original Subject",
2272
- bodyHtml: "<p>Original HTML</p>",
2273
- bodyText: "Original Text",
2274
- category: "custom",
2275
- isActive: true
2276
- }
2250
+ console.log(` [ERROR] FEHLER: Version 2 hat KEINE Template-Verbindung!`);
2251
+ }
2252
+ console.log("\n\n[TEST] TEST 3: Template Update (Auto-Versionierung)\n");
2253
+ const autoTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).create({
2254
+ data: {
2255
+ templateReferenceId: Math.floor(Math.random() * 1e6),
2256
+ name: "Auto Version Test",
2257
+ subject: "Original Subject",
2258
+ bodyHtml: "<p>Original HTML</p>",
2259
+ bodyText: "Original Text",
2260
+ category: "custom",
2261
+ isActive: true
2277
2262
  }
2278
- );
2279
- console.log(`✅ Template erstellt: ID ${autoTemplate.id}, name: "${autoTemplate.name}"`);
2280
- const beforeUpdate = await strapi.entityService.findOne(
2281
- "plugin::magic-mail.email-template",
2282
- autoTemplate.id,
2283
- { populate: ["versions"] }
2284
- );
2285
- console.log(` 📊 Versionen vor Update: ${beforeUpdate.versions?.length || 0}`);
2286
- console.log("\n🔄 Führe Template-Update aus...");
2263
+ });
2264
+ console.log(`[SUCCESS] Template erstellt: documentId ${autoTemplate.documentId}`);
2287
2265
  const emailDesignerService = strapi.plugin("magic-mail").service("email-designer");
2288
- await emailDesignerService.update(autoTemplate.id, {
2266
+ await emailDesignerService.update(autoTemplate.documentId, {
2289
2267
  subject: "Updated Subject V1",
2290
2268
  bodyHtml: "<p>Updated HTML V1</p>",
2291
2269
  bodyText: "Updated Text V1"
2292
2270
  });
2293
- console.log(" Template updated");
2294
- const afterFirstUpdate = await strapi.entityService.findOne(
2295
- "plugin::magic-mail.email-template",
2296
- autoTemplate.id,
2297
- { populate: ["versions"] }
2298
- );
2299
- console.log("\n🔍 Prüfung nach 1. Update:");
2271
+ console.log("[SUCCESS] Template updated");
2272
+ const afterFirstUpdate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2273
+ documentId: autoTemplate.documentId,
2274
+ populate: ["versions"]
2275
+ });
2276
+ console.log("\n[CHECK] Prüfung nach 1. Update:");
2300
2277
  test3a_versionCreated = afterFirstUpdate.versions && afterFirstUpdate.versions.length === 1;
2301
2278
  if (test3a_versionCreated) {
2302
- console.log(` SUCCESS: Automatisch 1 Version erstellt`);
2303
- const autoVersion1 = await strapi.entityService.findOne(
2304
- "plugin::magic-mail.email-template-version",
2305
- afterFirstUpdate.versions[0].id,
2306
- { populate: ["template"] }
2307
- );
2279
+ console.log(` [SUCCESS] SUCCESS: Automatisch 1 Version erstellt`);
2280
+ const autoVersion1 = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2281
+ documentId: afterFirstUpdate.versions[0].documentId,
2282
+ populate: ["template"]
2283
+ });
2308
2284
  test3a_hasTemplate = !!autoVersion1.template;
2309
2285
  if (test3a_hasTemplate) {
2310
- console.log(` SUCCESS: Version ${autoVersion1.id} hat Template-Verbindung (Template ID: ${autoVersion1.template.id})`);
2311
- console.log(` 📋 Version: versionNumber ${autoVersion1.versionNumber}, subject: "${autoVersion1.subject}"`);
2286
+ console.log(` [SUCCESS] SUCCESS: Version hat Template-Verbindung`);
2312
2287
  } else {
2313
- console.log(` FEHLER: Version ${autoVersion1.id} hat KEINE Template-Verbindung!`);
2288
+ console.log(` [ERROR] FEHLER: Version hat KEINE Template-Verbindung!`);
2314
2289
  }
2315
2290
  } else {
2316
- console.log(` FEHLER: Keine Version erstellt! Versionen: ${afterFirstUpdate.versions?.length || 0}`);
2291
+ console.log(` [ERROR] FEHLER: Keine Version erstellt!`);
2317
2292
  }
2318
- console.log("\n🔄 Führe 2. Template-Update aus...");
2319
- await emailDesignerService.update(autoTemplate.id, {
2293
+ await emailDesignerService.update(autoTemplate.documentId, {
2320
2294
  subject: "Updated Subject V2",
2321
2295
  bodyHtml: "<p>Updated HTML V2</p>",
2322
2296
  bodyText: "Updated Text V2"
2323
2297
  });
2324
- console.log("✅ Template updated (2. Mal)");
2325
- const afterSecondUpdate = await strapi.entityService.findOne(
2326
- "plugin::magic-mail.email-template",
2327
- autoTemplate.id,
2328
- { populate: ["versions"] }
2329
- );
2330
- console.log("\n🔍 Prüfung nach 2. Update:");
2298
+ const afterSecondUpdate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2299
+ documentId: autoTemplate.documentId,
2300
+ populate: ["versions"]
2301
+ });
2302
+ console.log("\n[CHECK] Prüfung nach 2. Update:");
2331
2303
  test3b_twoVersions = afterSecondUpdate.versions && afterSecondUpdate.versions.length === 2;
2332
2304
  if (test3b_twoVersions) {
2333
- console.log(` SUCCESS: Jetzt 2 Versionen vorhanden`);
2305
+ console.log(` [SUCCESS] SUCCESS: Jetzt 2 Versionen vorhanden`);
2334
2306
  let allVersionsHaveTemplate = true;
2335
2307
  for (const version3 of afterSecondUpdate.versions) {
2336
- const fullVersion = await strapi.entityService.findOne(
2337
- "plugin::magic-mail.email-template-version",
2338
- version3.id,
2339
- { populate: ["template"] }
2340
- );
2341
- if (fullVersion.template) {
2342
- console.log(` ✅ Version ${fullVersion.id} (v${fullVersion.versionNumber}): Template-Verbindung OK`);
2343
- } else {
2344
- console.log(` ❌ Version ${fullVersion.id} (v${fullVersion.versionNumber}): KEINE Template-Verbindung!`);
2308
+ const fullVersion = await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
2309
+ documentId: version3.documentId,
2310
+ populate: ["template"]
2311
+ });
2312
+ if (!fullVersion.template) {
2345
2313
  allVersionsHaveTemplate = false;
2346
2314
  }
2347
2315
  }
2348
2316
  test3b_allHaveTemplate = allVersionsHaveTemplate;
2349
2317
  if (allVersionsHaveTemplate) {
2350
- console.log(` SUCCESS: Alle Versionen haben Template-Verbindung!`);
2318
+ console.log(` [SUCCESS] SUCCESS: Alle Versionen haben Template-Verbindung!`);
2319
+ } else {
2320
+ console.log(` [ERROR] FEHLER: Nicht alle Versionen haben Template-Verbindung!`);
2351
2321
  }
2352
2322
  } else {
2353
- console.log(` FEHLER: Falsche Anzahl Versionen! Erwartet: 2, Gefunden: ${afterSecondUpdate.versions?.length || 0}`);
2323
+ console.log(` [ERROR] FEHLER: Falsche Anzahl Versionen!`);
2354
2324
  }
2355
2325
  console.log("\n🧹 Cleanup Test 3...");
2356
2326
  if (afterSecondUpdate.versions) {
2357
2327
  for (const version3 of afterSecondUpdate.versions) {
2358
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version3.id);
2328
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version3.documentId });
2359
2329
  }
2360
2330
  }
2361
- await strapi.entityService.delete("plugin::magic-mail.email-template", autoTemplate.id);
2362
- console.log(" Test 3 Daten gelöscht");
2331
+ await strapi.documents(EMAIL_TEMPLATE_UID).delete({ documentId: autoTemplate.documentId });
2332
+ console.log(" [SUCCESS] Test 3 Daten gelöscht");
2363
2333
  console.log("\n\n" + "=".repeat(60));
2364
- console.log("📊 ZUSAMMENFASSUNG");
2334
+ console.log("[STATS] ZUSAMMENFASSUNG");
2365
2335
  console.log("=".repeat(60));
2366
- const finalTemplate = await strapi.entityService.findOne(
2367
- "plugin::magic-mail.email-template",
2368
- testTemplate.id,
2369
- {
2370
- populate: ["versions"]
2371
- }
2372
- );
2336
+ const finalTemplate = await strapi.documents(EMAIL_TEMPLATE_UID).findOne({
2337
+ documentId: testTemplate.documentId,
2338
+ populate: ["versions"]
2339
+ });
2373
2340
  console.log(`
2374
- 📋 Template: "${finalTemplate.name}" (ID: ${finalTemplate.id})`);
2375
- console.log(` Anzahl Versionen im Template: ${finalTemplate.versions?.length || 0}`);
2376
- if (finalTemplate.versions && finalTemplate.versions.length > 0) {
2377
- finalTemplate.versions.forEach((v) => {
2378
- console.log(` - Version ${v.id}: versionNumber ${v.versionNumber}`);
2379
- });
2380
- }
2341
+ [INFO] Template: "${finalTemplate.name}" (documentId: ${finalTemplate.documentId})`);
2342
+ console.log(` Anzahl Versionen: ${finalTemplate.versions?.length || 0}`);
2381
2343
  console.log("\n🧹 Aufräumen...");
2382
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version1.id);
2383
- console.log(` ✅ Version ${version1.id} gelöscht`);
2384
- await strapi.entityService.delete("plugin::magic-mail.email-template-version", version2.id);
2385
- console.log(` Version ${version2.id} gelöscht`);
2386
- await strapi.entityService.delete("plugin::magic-mail.email-template", testTemplate.id);
2387
- console.log(` ✅ Template ${testTemplate.id} gelöscht`);
2388
- console.log("\n✅ Test abgeschlossen!\n");
2344
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version1.documentId });
2345
+ await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version2.documentId });
2346
+ await strapi.documents(EMAIL_TEMPLATE_UID).delete({ documentId: testTemplate.documentId });
2347
+ console.log(" [SUCCESS] Alle Test-Daten gelöscht");
2348
+ console.log("\n[SUCCESS] Test abgeschlossen!\n");
2389
2349
  const allSuccess = test1Success && test1ReverseSuccess && test2Success && test2ReverseSuccess && test3a_versionCreated && test3a_hasTemplate && test3b_twoVersions && test3b_allHaveTemplate;
2390
2350
  ctx.body = {
2391
2351
  success: allSuccess,
2392
- message: allSuccess ? "Alle Tests erfolgreich! " : "Einige Tests fehlgeschlagen ",
2352
+ message: allSuccess ? "Alle Tests erfolgreich! [SUCCESS]" : "Einige Tests fehlgeschlagen [ERROR]",
2393
2353
  tests: {
2394
2354
  test1_version_to_template: test1Success,
2395
2355
  test1_template_to_version: test1ReverseSuccess,
@@ -2399,15 +2359,10 @@ function requireTest() {
2399
2359
  test3_auto_version_has_template: test3a_hasTemplate,
2400
2360
  test3_two_auto_versions: test3b_twoVersions,
2401
2361
  test3_all_auto_versions_have_template: test3b_allHaveTemplate
2402
- },
2403
- template: {
2404
- id: testTemplate.id,
2405
- name: testTemplate.name,
2406
- versionsCount: finalTemplate.versions?.length || 0
2407
2362
  }
2408
2363
  };
2409
2364
  } catch (error) {
2410
- console.error("\n FEHLER:", error.message);
2365
+ console.error("\n[ERROR] FEHLER:", error.message);
2411
2366
  console.error(error.stack);
2412
2367
  ctx.throw(500, error);
2413
2368
  }
@@ -3001,7 +2956,7 @@ function requireEncryption() {
3001
2956
  if (envKey) {
3002
2957
  return crypto.createHash("sha256").update(envKey).digest();
3003
2958
  }
3004
- console.warn("[magic-mail] ⚠️ No MAGIC_MAIL_ENCRYPTION_KEY found. Using fallback.");
2959
+ console.warn("[magic-mail] [WARNING] No MAGIC_MAIL_ENCRYPTION_KEY found. Using fallback.");
3005
2960
  return crypto.createHash("sha256").update("magic-mail-default-key").digest();
3006
2961
  }
3007
2962
  function encryptCredentials(data) {
@@ -3080,12 +3035,17 @@ function requireEmailRouter() {
3080
3035
  // Template Reference ID
3081
3036
  templateData,
3082
3037
  // Data for template rendering
3083
- data
3038
+ data,
3084
3039
  // Alias for templateData (for native Strapi compatibility)
3040
+ skipLinkTracking = false
3041
+ // Skip link rewriting for sensitive URLs (e.g., Magic Links)
3085
3042
  } = emailData;
3086
3043
  if (!templateData && data) {
3087
3044
  templateData = data;
3088
3045
  }
3046
+ if (skipLinkTracking) {
3047
+ strapi2.log.info(`[magic-mail] [SKIP-TRACK] skipLinkTracking=true received for email to: ${to}`);
3048
+ }
3089
3049
  let renderedTemplate = null;
3090
3050
  if (templateId || emailData.templateReferenceId) {
3091
3051
  try {
@@ -3098,10 +3058,10 @@ function requireEmailRouter() {
3098
3058
  if (!resolvedTemplateReferenceId && templateId) {
3099
3059
  const numericTemplateId = Number(templateId);
3100
3060
  if (!Number.isNaN(numericTemplateId) && Number.isInteger(numericTemplateId)) {
3101
- strapi2.log.info(`[magic-mail] 🔍 Looking up template by ID: ${numericTemplateId}`);
3061
+ strapi2.log.info(`[magic-mail] [CHECK] Looking up template by ID: ${numericTemplateId}`);
3102
3062
  templateRecord = await strapi2.plugin("magic-mail").service("email-designer").findOne(numericTemplateId);
3103
3063
  if (!templateRecord) {
3104
- strapi2.log.error(`[magic-mail] Template with ID ${numericTemplateId} not found in database`);
3064
+ strapi2.log.error(`[magic-mail] [ERROR] Template with ID ${numericTemplateId} not found in database`);
3105
3065
  throw new Error(`Template with ID ${numericTemplateId} not found`);
3106
3066
  }
3107
3067
  if (!templateRecord.templateReferenceId) {
@@ -3109,7 +3069,7 @@ function requireEmailRouter() {
3109
3069
  }
3110
3070
  resolvedTemplateReferenceId = String(templateRecord.templateReferenceId).trim();
3111
3071
  strapi2.log.info(
3112
- `[magic-mail] Found template: ID=${templateRecord.id}, referenceId="${resolvedTemplateReferenceId}", name="${templateRecord.name}"`
3072
+ `[magic-mail] [SUCCESS] Found template: ID=${templateRecord.id}, referenceId="${resolvedTemplateReferenceId}", name="${templateRecord.name}"`
3113
3073
  );
3114
3074
  } else {
3115
3075
  resolvedTemplateReferenceId = String(templateId).trim();
@@ -3125,14 +3085,14 @@ function requireEmailRouter() {
3125
3085
  subject = subject || renderedTemplate.subject;
3126
3086
  type = type || renderedTemplate.category;
3127
3087
  strapi2.log.info(
3128
- `[magic-mail] 📧 Rendered template reference "${resolvedTemplateReferenceId}" (requested ID: ${templateId ?? "n/a"}): ${renderedTemplate.templateName}`
3088
+ `[magic-mail] [EMAIL] Rendered template reference "${resolvedTemplateReferenceId}" (requested ID: ${templateId ?? "n/a"}): ${renderedTemplate.templateName}`
3129
3089
  );
3130
3090
  emailData.templateReferenceId = resolvedTemplateReferenceId;
3131
3091
  if (!emailData.templateName) {
3132
3092
  emailData.templateName = templateRecord?.name || renderedTemplate.templateName;
3133
3093
  }
3134
3094
  } catch (error) {
3135
- strapi2.log.error(`[magic-mail] Template rendering failed: ${error.message}`);
3095
+ strapi2.log.error(`[magic-mail] [ERROR] Template rendering failed: ${error.message}`);
3136
3096
  throw new Error(`Template rendering failed: ${error.message}`);
3137
3097
  }
3138
3098
  }
@@ -3161,10 +3121,14 @@ function requireEmailRouter() {
3161
3121
  });
3162
3122
  recipientHash = analyticsService.generateRecipientHash(emailLog.emailId, to);
3163
3123
  html = analyticsService.injectTrackingPixel(html, emailLog.emailId, recipientHash);
3164
- html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
3165
- strapi2.log.info(`[magic-mail] 📊 Tracking enabled for email: ${emailLog.emailId}`);
3124
+ if (!skipLinkTracking) {
3125
+ html = await analyticsService.rewriteLinksForTracking(html, emailLog.emailId, recipientHash);
3126
+ strapi2.log.info(`[magic-mail] [STATS] Full tracking enabled for email: ${emailLog.emailId}`);
3127
+ } else {
3128
+ strapi2.log.info(`[magic-mail] [STATS] Open tracking enabled, link tracking DISABLED for email: ${emailLog.emailId}`);
3129
+ }
3166
3130
  } catch (error) {
3167
- strapi2.log.error(`[magic-mail] ⚠️ Tracking setup failed (continuing without tracking):`, error.message);
3131
+ strapi2.log.error(`[magic-mail] [WARNING] Tracking setup failed (continuing without tracking):`, error.message);
3168
3132
  }
3169
3133
  }
3170
3134
  emailData.html = html;
@@ -3175,7 +3139,7 @@ function requireEmailRouter() {
3175
3139
  if (priority === "high") {
3176
3140
  const hasFeature = await licenseGuard2.hasFeature("priority-headers");
3177
3141
  if (!hasFeature) {
3178
- strapi2.log.warn("[magic-mail] ⚠️ High priority emails require Advanced license - using normal priority");
3142
+ strapi2.log.warn("[magic-mail] [WARNING] High priority emails require Advanced license - using normal priority");
3179
3143
  emailData.priority = "normal";
3180
3144
  }
3181
3145
  }
@@ -3199,8 +3163,8 @@ function requireEmailRouter() {
3199
3163
  const result = await this.sendViaAccount(account, emailData);
3200
3164
  if (emailLog) {
3201
3165
  try {
3202
- await strapi2.db.query("plugin::magic-mail.email-log").update({
3203
- where: { id: emailLog.id },
3166
+ await strapi2.documents("plugin::magic-mail.email-log").update({
3167
+ documentId: emailLog.documentId,
3204
3168
  data: {
3205
3169
  accountId: account.id,
3206
3170
  accountName: account.name,
@@ -3211,15 +3175,15 @@ function requireEmailRouter() {
3211
3175
  strapi2.log.error("[magic-mail] Failed to update email log:", error.message);
3212
3176
  }
3213
3177
  }
3214
- await this.updateAccountStats(account.id);
3215
- strapi2.log.info(`[magic-mail] Email sent to ${to} via ${account.name}`);
3178
+ await this.updateAccountStats(account.documentId);
3179
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email sent to ${to} via ${account.name}`);
3216
3180
  return {
3217
3181
  success: true,
3218
3182
  accountUsed: account.name,
3219
3183
  messageId: result.messageId
3220
3184
  };
3221
3185
  } catch (error) {
3222
- strapi2.log.error("[magic-mail] Email send failed:", error);
3186
+ strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
3223
3187
  throw error;
3224
3188
  }
3225
3189
  },
@@ -3227,21 +3191,21 @@ function requireEmailRouter() {
3227
3191
  * Select best account based on rules
3228
3192
  */
3229
3193
  async selectAccount(type, priority, excludeIds = [], emailData = {}) {
3230
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
3194
+ const accounts2 = await strapi2.documents("plugin::magic-mail.email-account").findMany({
3231
3195
  filters: {
3232
3196
  isActive: true,
3233
3197
  id: { $notIn: excludeIds }
3234
3198
  },
3235
- sort: { priority: "desc" }
3199
+ sort: [{ priority: "desc" }]
3236
3200
  });
3237
3201
  if (!accounts2 || accounts2.length === 0) {
3238
3202
  return null;
3239
3203
  }
3240
- const allRules = await strapi2.entityService.findMany("plugin::magic-mail.routing-rule", {
3204
+ const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
3241
3205
  filters: {
3242
3206
  isActive: true
3243
3207
  },
3244
- sort: { priority: "desc" }
3208
+ sort: [{ priority: "desc" }]
3245
3209
  });
3246
3210
  for (const rule of allRules) {
3247
3211
  let matches = false;
@@ -3265,13 +3229,13 @@ function requireEmailRouter() {
3265
3229
  if (matches) {
3266
3230
  const account = accounts2.find((a) => a.name === rule.accountName);
3267
3231
  if (account) {
3268
- strapi2.log.info(`[magic-mail] 🎯 Routing rule matched: ${rule.name} ${account.name}`);
3232
+ strapi2.log.info(`[magic-mail] [ROUTE] Routing rule matched: ${rule.name} -> ${account.name}`);
3269
3233
  return account;
3270
3234
  }
3271
3235
  if (rule.fallbackAccountName) {
3272
3236
  const fallbackAccount = accounts2.find((a) => a.name === rule.fallbackAccountName);
3273
3237
  if (fallbackAccount) {
3274
- strapi2.log.info(`[magic-mail] 🔄 Using fallback account: ${fallbackAccount.name}`);
3238
+ strapi2.log.info(`[magic-mail] [FALLBACK] Using fallback account: ${fallbackAccount.name}`);
3275
3239
  return fallbackAccount;
3276
3240
  }
3277
3241
  }
@@ -3375,7 +3339,7 @@ function requireEmailRouter() {
3375
3339
  mailOptions.headers["List-Unsubscribe-Post"] = "List-Unsubscribe=One-Click";
3376
3340
  mailOptions.headers["Precedence"] = "bulk";
3377
3341
  } else {
3378
- strapi2.log.warn("[magic-mail] ⚠️ Marketing email without unsubscribe URL - may violate GDPR/CAN-SPAM");
3342
+ strapi2.log.warn("[magic-mail] [WARNING] Marketing email without unsubscribe URL - may violate GDPR/CAN-SPAM");
3379
3343
  }
3380
3344
  }
3381
3345
  if (emailData.headers && typeof emailData.headers === "object") {
@@ -3421,14 +3385,15 @@ function requireEmailRouter() {
3421
3385
  config2.clientSecret
3422
3386
  );
3423
3387
  currentAccessToken = newTokens.accessToken;
3424
- strapi2.log.info("[magic-mail] Token refreshed successfully");
3388
+ strapi2.log.info("[magic-mail] [SUCCESS] Token refreshed successfully");
3425
3389
  const { encryptCredentials } = requireEncryption();
3426
3390
  const updatedOAuth = encryptCredentials({
3427
3391
  ...oauth2,
3428
3392
  accessToken: newTokens.accessToken,
3429
3393
  expiresAt: newTokens.expiresAt
3430
3394
  });
3431
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3395
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3396
+ documentId: account.documentId,
3432
3397
  data: { oauth: updatedOAuth }
3433
3398
  });
3434
3399
  } catch (refreshErr) {
@@ -3547,13 +3512,19 @@ function requireEmailRouter() {
3547
3512
  throw new Error(`Gmail API error: ${errorData.error?.message || response.statusText}`);
3548
3513
  }
3549
3514
  const result = await response.json();
3550
- strapi2.log.info("[magic-mail] Email sent via Gmail API");
3515
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Gmail API");
3551
3516
  return {
3552
3517
  messageId: result.id,
3553
3518
  response: "OK"
3554
3519
  };
3555
3520
  } catch (err) {
3556
- strapi2.log.error("[magic-mail] Gmail API send failed:", err);
3521
+ strapi2.log.error("[magic-mail] Gmail API send failed:", err.message || err);
3522
+ strapi2.log.error("[magic-mail] Error details:", {
3523
+ name: err.name,
3524
+ code: err.code,
3525
+ cause: err.cause?.message || err.cause,
3526
+ stack: err.stack?.split("\n").slice(0, 3).join("\n")
3527
+ });
3557
3528
  throw err;
3558
3529
  }
3559
3530
  },
@@ -3596,14 +3567,15 @@ function requireEmailRouter() {
3596
3567
  config2.tenantId
3597
3568
  );
3598
3569
  currentAccessToken = newTokens.accessToken;
3599
- strapi2.log.info("[magic-mail] Microsoft token refreshed successfully");
3570
+ strapi2.log.info("[magic-mail] [SUCCESS] Microsoft token refreshed successfully");
3600
3571
  const { encryptCredentials } = requireEncryption();
3601
3572
  const updatedOAuth = encryptCredentials({
3602
3573
  ...oauth2,
3603
3574
  accessToken: newTokens.accessToken,
3604
3575
  expiresAt: newTokens.expiresAt
3605
3576
  });
3606
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3577
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3578
+ documentId: account.documentId,
3607
3579
  data: { oauth: updatedOAuth }
3608
3580
  });
3609
3581
  } catch (refreshErr) {
@@ -3713,7 +3685,7 @@ function requireEmailRouter() {
3713
3685
  strapi2.log.error("[magic-mail] Response status:", response.status);
3714
3686
  throw new Error(`Microsoft Graph API error: ${response.status} - ${response.statusText}`);
3715
3687
  }
3716
- strapi2.log.info("[magic-mail] Email sent via Microsoft Graph API with MIME + custom headers");
3688
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Microsoft Graph API with MIME + custom headers");
3717
3689
  strapi2.log.info("[magic-mail] Microsoft adds From/DKIM automatically for DMARC compliance");
3718
3690
  return {
3719
3691
  messageId: `microsoft-${Date.now()}`,
@@ -3755,14 +3727,15 @@ function requireEmailRouter() {
3755
3727
  config2.clientSecret
3756
3728
  );
3757
3729
  currentAccessToken = newTokens.accessToken;
3758
- strapi2.log.info("[magic-mail] Token refreshed successfully");
3730
+ strapi2.log.info("[magic-mail] [SUCCESS] Token refreshed successfully");
3759
3731
  const { encryptCredentials } = requireEncryption();
3760
3732
  const updatedOAuth = encryptCredentials({
3761
3733
  ...oauth2,
3762
3734
  accessToken: newTokens.accessToken,
3763
3735
  expiresAt: newTokens.expiresAt
3764
3736
  });
3765
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
3737
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3738
+ documentId: account.documentId,
3766
3739
  data: { oauth: updatedOAuth }
3767
3740
  });
3768
3741
  } catch (refreshErr) {
@@ -3808,7 +3781,7 @@ function requireEmailRouter() {
3808
3781
  strapi2.log.info(`[magic-mail] Sending email with ${mailOptions.attachments.length} attachment(s)`);
3809
3782
  }
3810
3783
  const result = await transporter.sendMail(mailOptions);
3811
- strapi2.log.info("[magic-mail] Email sent via Yahoo OAuth");
3784
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Yahoo OAuth");
3812
3785
  return {
3813
3786
  messageId: result.messageId,
3814
3787
  response: result.response
@@ -3903,7 +3876,7 @@ function requireEmailRouter() {
3903
3876
  strapi2.log.error("[magic-mail] SendGrid API error:", errorText);
3904
3877
  throw new Error(`SendGrid API error: ${response.statusText}`);
3905
3878
  }
3906
- strapi2.log.info("[magic-mail] Email sent via SendGrid API");
3879
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via SendGrid API");
3907
3880
  return {
3908
3881
  messageId: response.headers.get("x-message-id") || `sendgrid-${Date.now()}`,
3909
3882
  response: "Accepted"
@@ -3986,7 +3959,7 @@ function requireEmailRouter() {
3986
3959
  throw new Error(`Mailgun API error: ${response.statusText}`);
3987
3960
  }
3988
3961
  const result = await response.json();
3989
- strapi2.log.info("[magic-mail] Email sent via Mailgun API");
3962
+ strapi2.log.info("[magic-mail] [SUCCESS] Email sent via Mailgun API");
3990
3963
  return {
3991
3964
  messageId: result.id || `mailgun-${Date.now()}`,
3992
3965
  response: result.message || "Queued"
@@ -4010,10 +3983,15 @@ function requireEmailRouter() {
4010
3983
  },
4011
3984
  /**
4012
3985
  * Update account statistics
3986
+ * Note: This function now expects documentId
4013
3987
  */
4014
- async updateAccountStats(accountId) {
4015
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4016
- await strapi2.entityService.update("plugin::magic-mail.email-account", accountId, {
3988
+ async updateAccountStats(documentId) {
3989
+ const account = await strapi2.documents("plugin::magic-mail.email-account").findOne({
3990
+ documentId
3991
+ });
3992
+ if (!account) return;
3993
+ await strapi2.documents("plugin::magic-mail.email-account").update({
3994
+ documentId,
4017
3995
  data: {
4018
3996
  emailsSentToday: (account.emailsSentToday || 0) + 1,
4019
3997
  emailsSentThisHour: (account.emailsSentThisHour || 0) + 1,
@@ -4034,7 +4012,7 @@ function requireEmailRouter() {
4034
4012
  * Get account by name
4035
4013
  */
4036
4014
  async getAccountByName(name) {
4037
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4015
+ const accounts2 = await strapi2.documents("plugin::magic-mail.email-account").findMany({
4038
4016
  filters: { name, isActive: true },
4039
4017
  limit: 1
4040
4018
  });
@@ -4084,7 +4062,7 @@ function requireEmailRouter() {
4084
4062
  if (html && !text) {
4085
4063
  strapi2.log.warn("[magic-mail] Email has HTML but no text alternative - may reduce deliverability");
4086
4064
  }
4087
- strapi2.log.info("[magic-mail] Email security validation passed");
4065
+ strapi2.log.info("[magic-mail] [SUCCESS] Email security validation passed");
4088
4066
  },
4089
4067
  /**
4090
4068
  * Add security headers to email data
@@ -4124,7 +4102,24 @@ function requireAccountManager() {
4124
4102
  if (hasRequiredAccountManager) return accountManager;
4125
4103
  hasRequiredAccountManager = 1;
4126
4104
  const { encryptCredentials, decryptCredentials } = requireEncryption();
4105
+ const EMAIL_ACCOUNT_UID = "plugin::magic-mail.email-account";
4127
4106
  accountManager = ({ strapi: strapi2 }) => ({
4107
+ /**
4108
+ * Resolves account ID to documentId (handles both numeric id and documentId)
4109
+ * @param {string|number} idOrDocumentId - Either numeric id or documentId
4110
+ * @returns {Promise<string|null>} The documentId or null if not found
4111
+ */
4112
+ async resolveDocumentId(idOrDocumentId) {
4113
+ if (idOrDocumentId && !/^\d+$/.test(String(idOrDocumentId))) {
4114
+ return String(idOrDocumentId);
4115
+ }
4116
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4117
+ filters: { id: Number(idOrDocumentId) },
4118
+ fields: ["documentId"],
4119
+ limit: 1
4120
+ });
4121
+ return accounts2.length > 0 ? accounts2[0].documentId : null;
4122
+ },
4128
4123
  /**
4129
4124
  * Create new email account
4130
4125
  */
@@ -4146,7 +4141,7 @@ function requireAccountManager() {
4146
4141
  if (isPrimary) {
4147
4142
  await this.unsetAllPrimary();
4148
4143
  }
4149
- const account = await strapi2.entityService.create("plugin::magic-mail.email-account", {
4144
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).create({
4150
4145
  data: {
4151
4146
  name,
4152
4147
  provider,
@@ -4164,14 +4159,20 @@ function requireAccountManager() {
4164
4159
  totalEmailsSent: 0
4165
4160
  }
4166
4161
  });
4167
- strapi2.log.info(`[magic-mail] Email account created: ${name}`);
4162
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email account created: ${name}`);
4168
4163
  return account;
4169
4164
  },
4170
4165
  /**
4171
4166
  * Update email account
4172
4167
  */
4173
- async updateAccount(accountId, accountData) {
4174
- const existingAccount = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4168
+ async updateAccount(idOrDocumentId, accountData) {
4169
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4170
+ if (!documentId) {
4171
+ throw new Error("Account not found");
4172
+ }
4173
+ const existingAccount = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4174
+ documentId
4175
+ });
4175
4176
  if (!existingAccount) {
4176
4177
  throw new Error("Account not found");
4177
4178
  }
@@ -4193,7 +4194,8 @@ function requireAccountManager() {
4193
4194
  if (isPrimary && !existingAccount.isPrimary) {
4194
4195
  await this.unsetAllPrimary();
4195
4196
  }
4196
- const updatedAccount = await strapi2.entityService.update("plugin::magic-mail.email-account", accountId, {
4197
+ const updatedAccount = await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4198
+ documentId,
4197
4199
  data: {
4198
4200
  name,
4199
4201
  description,
@@ -4209,14 +4211,20 @@ function requireAccountManager() {
4209
4211
  hourlyLimit
4210
4212
  }
4211
4213
  });
4212
- strapi2.log.info(`[magic-mail] Email account updated: ${name} (Active: ${isActive})`);
4214
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email account updated: ${name} (Active: ${isActive})`);
4213
4215
  return updatedAccount;
4214
4216
  },
4215
4217
  /**
4216
4218
  * Test email account
4217
4219
  */
4218
- async testAccount(accountId, testEmail, testOptions = {}) {
4219
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4220
+ async testAccount(idOrDocumentId, testEmail, testOptions = {}) {
4221
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4222
+ if (!documentId) {
4223
+ throw new Error("Account not found");
4224
+ }
4225
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4226
+ documentId
4227
+ });
4220
4228
  if (!account) {
4221
4229
  throw new Error("Account not found");
4222
4230
  }
@@ -4295,8 +4303,8 @@ If you receive this, your email account is configured correctly!`,
4295
4303
  * Get all accounts
4296
4304
  */
4297
4305
  async getAllAccounts() {
4298
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4299
- sort: { priority: "desc" }
4306
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4307
+ sort: [{ priority: "desc" }]
4300
4308
  });
4301
4309
  return accounts2.map((account) => ({
4302
4310
  ...account,
@@ -4306,8 +4314,14 @@ If you receive this, your email account is configured correctly!`,
4306
4314
  /**
4307
4315
  * Get single account with decrypted config (for editing)
4308
4316
  */
4309
- async getAccountWithDecryptedConfig(accountId) {
4310
- const account = await strapi2.entityService.findOne("plugin::magic-mail.email-account", accountId);
4317
+ async getAccountWithDecryptedConfig(idOrDocumentId) {
4318
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4319
+ if (!documentId) {
4320
+ throw new Error("Account not found");
4321
+ }
4322
+ const account = await strapi2.documents(EMAIL_ACCOUNT_UID).findOne({
4323
+ documentId
4324
+ });
4311
4325
  if (!account) {
4312
4326
  throw new Error("Account not found");
4313
4327
  }
@@ -4320,19 +4334,24 @@ If you receive this, your email account is configured correctly!`,
4320
4334
  /**
4321
4335
  * Delete account
4322
4336
  */
4323
- async deleteAccount(accountId) {
4324
- await strapi2.entityService.delete("plugin::magic-mail.email-account", accountId);
4325
- strapi2.log.info(`[magic-mail] Account deleted: ${accountId}`);
4337
+ async deleteAccount(idOrDocumentId) {
4338
+ const documentId = await this.resolveDocumentId(idOrDocumentId);
4339
+ if (!documentId) {
4340
+ throw new Error("Account not found");
4341
+ }
4342
+ await strapi2.documents(EMAIL_ACCOUNT_UID).delete({ documentId });
4343
+ strapi2.log.info(`[magic-mail] Account deleted: ${documentId}`);
4326
4344
  },
4327
4345
  /**
4328
4346
  * Unset all primary flags
4329
4347
  */
4330
4348
  async unsetAllPrimary() {
4331
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account", {
4349
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({
4332
4350
  filters: { isPrimary: true }
4333
4351
  });
4334
4352
  for (const account of accounts2) {
4335
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
4353
+ await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4354
+ documentId: account.documentId,
4336
4355
  data: { isPrimary: false }
4337
4356
  });
4338
4357
  }
@@ -4341,7 +4360,7 @@ If you receive this, your email account is configured correctly!`,
4341
4360
  * Reset daily/hourly counters (called by cron)
4342
4361
  */
4343
4362
  async resetCounters(type = "daily") {
4344
- const accounts2 = await strapi2.entityService.findMany("plugin::magic-mail.email-account");
4363
+ const accounts2 = await strapi2.documents(EMAIL_ACCOUNT_UID).findMany({});
4345
4364
  for (const account of accounts2) {
4346
4365
  const updateData = {};
4347
4366
  if (type === "daily") {
@@ -4349,11 +4368,12 @@ If you receive this, your email account is configured correctly!`,
4349
4368
  } else if (type === "hourly") {
4350
4369
  updateData.emailsSentThisHour = 0;
4351
4370
  }
4352
- await strapi2.entityService.update("plugin::magic-mail.email-account", account.id, {
4371
+ await strapi2.documents(EMAIL_ACCOUNT_UID).update({
4372
+ documentId: account.documentId,
4353
4373
  data: updateData
4354
4374
  });
4355
4375
  }
4356
- strapi2.log.info(`[magic-mail] ${type} counters reset`);
4376
+ strapi2.log.info(`[magic-mail] [SUCCESS] ${type} counters reset`);
4357
4377
  }
4358
4378
  });
4359
4379
  return accountManager;
@@ -4411,7 +4431,7 @@ function requireOauth() {
4411
4431
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
4412
4432
  }
4413
4433
  const tokens = await response.json();
4414
- strapi2.log.info("[magic-mail] Tokens received from Google");
4434
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Google");
4415
4435
  if (!tokens.access_token) {
4416
4436
  throw new Error("No access token received from Google");
4417
4437
  }
@@ -4425,7 +4445,7 @@ function requireOauth() {
4425
4445
  throw new Error("Failed to get user email from Google");
4426
4446
  }
4427
4447
  const userInfo = await userInfoResponse.json();
4428
- strapi2.log.info(`[magic-mail] Got user email from Google: ${userInfo.email}`);
4448
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got user email from Google: ${userInfo.email}`);
4429
4449
  if (!userInfo.email) {
4430
4450
  strapi2.log.error("[magic-mail] userInfo:", userInfo);
4431
4451
  throw new Error("Google did not provide email address");
@@ -4529,7 +4549,7 @@ function requireOauth() {
4529
4549
  throw new Error(`Failed to exchange code for tokens: ${response.status} - ${errorData}`);
4530
4550
  }
4531
4551
  const tokens = await response.json();
4532
- strapi2.log.info("[magic-mail] Tokens received from Microsoft");
4552
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Microsoft");
4533
4553
  strapi2.log.info("[magic-mail] Has access_token:", !!tokens.access_token);
4534
4554
  strapi2.log.info("[magic-mail] Has refresh_token:", !!tokens.refresh_token);
4535
4555
  strapi2.log.info("[magic-mail] Has id_token:", !!tokens.id_token);
@@ -4542,7 +4562,7 @@ function requireOauth() {
4542
4562
  const payloadBase64 = tokens.id_token.split(".")[1];
4543
4563
  const payload = JSON.parse(Buffer.from(payloadBase64, "base64").toString());
4544
4564
  email = payload.email || payload.preferred_username || payload.upn;
4545
- strapi2.log.info(`[magic-mail] Got email from Microsoft ID token: ${email}`);
4565
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft ID token: ${email}`);
4546
4566
  } catch (jwtErr) {
4547
4567
  strapi2.log.warn("[magic-mail] Could not decode ID token:", jwtErr.message);
4548
4568
  }
@@ -4564,7 +4584,7 @@ function requireOauth() {
4564
4584
  const userInfo = await userInfoResponse.json();
4565
4585
  strapi2.log.info("[magic-mail] User info from Graph:", JSON.stringify(userInfo, null, 2));
4566
4586
  email = userInfo.mail || userInfo.userPrincipalName;
4567
- strapi2.log.info(`[magic-mail] Got email from Microsoft Graph: ${email}`);
4587
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Microsoft Graph: ${email}`);
4568
4588
  }
4569
4589
  if (!email) {
4570
4590
  strapi2.log.error("[magic-mail] Microsoft did not provide email - ID token and Graph API both failed");
@@ -4608,7 +4628,7 @@ function requireOauth() {
4608
4628
  throw new Error(`Failed to refresh Microsoft tokens: ${response.status}`);
4609
4629
  }
4610
4630
  const tokens = await response.json();
4611
- strapi2.log.info("[magic-mail] Microsoft tokens refreshed successfully");
4631
+ strapi2.log.info("[magic-mail] [SUCCESS] Microsoft tokens refreshed successfully");
4612
4632
  return {
4613
4633
  accessToken: tokens.access_token,
4614
4634
  expiresAt: new Date(Date.now() + (tokens.expires_in || 3600) * 1e3)
@@ -4663,7 +4683,7 @@ function requireOauth() {
4663
4683
  throw new Error(`Failed to exchange code for tokens: ${response.status}`);
4664
4684
  }
4665
4685
  const tokens = await response.json();
4666
- strapi2.log.info("[magic-mail] Tokens received from Yahoo");
4686
+ strapi2.log.info("[magic-mail] [SUCCESS] Tokens received from Yahoo");
4667
4687
  if (!tokens.access_token) {
4668
4688
  throw new Error("No access token received from Yahoo");
4669
4689
  }
@@ -4678,7 +4698,7 @@ function requireOauth() {
4678
4698
  }
4679
4699
  const userInfo = await userInfoResponse.json();
4680
4700
  const email = userInfo.email;
4681
- strapi2.log.info(`[magic-mail] Got email from Yahoo: ${email}`);
4701
+ strapi2.log.info(`[magic-mail] [SUCCESS] Got email from Yahoo: ${email}`);
4682
4702
  if (!email) {
4683
4703
  throw new Error("Yahoo did not provide email address");
4684
4704
  }
@@ -4739,7 +4759,7 @@ function requireOauth() {
4739
4759
  refreshToken: tokenData.refreshToken,
4740
4760
  expiresAt: tokenData.expiresAt
4741
4761
  });
4742
- const account = await strapi2.entityService.create("plugin::magic-mail.email-account", {
4762
+ const account = await strapi2.documents("plugin::magic-mail.email-account").create({
4743
4763
  data: {
4744
4764
  name: accountDetails.name,
4745
4765
  description: accountDetails.description || "",
@@ -4749,7 +4769,7 @@ function requireOauth() {
4749
4769
  oauth: encryptedOAuth,
4750
4770
  // OAuth tokens
4751
4771
  fromEmail: tokenData.email,
4752
- // Use email from Google, not from accountDetails
4772
+ // [SUCCESS] Use email from Google, not from accountDetails
4753
4773
  fromName: accountDetails.fromName || tokenData.email.split("@")[0],
4754
4774
  replyTo: accountDetails.replyTo || tokenData.email,
4755
4775
  isActive: true,
@@ -4762,13 +4782,13 @@ function requireOauth() {
4762
4782
  totalEmailsSent: 0
4763
4783
  }
4764
4784
  });
4765
- strapi2.log.info(`[magic-mail] OAuth account created: ${accountDetails.name} (${tokenData.email})`);
4785
+ strapi2.log.info(`[magic-mail] [SUCCESS] OAuth account created: ${accountDetails.name} (${tokenData.email})`);
4766
4786
  return account;
4767
4787
  }
4768
4788
  });
4769
4789
  return oauth;
4770
4790
  }
4771
- const version = "2.0.1";
4791
+ const version = "2.0.2";
4772
4792
  const require$$2 = {
4773
4793
  version
4774
4794
  };
@@ -4862,14 +4882,14 @@ function requireLicenseGuard() {
4862
4882
  });
4863
4883
  const data = await response.json();
4864
4884
  if (data.success) {
4865
- strapi2.log.info("[magic-mail] License created:", data.data.licenseKey);
4885
+ strapi2.log.info("[magic-mail] [SUCCESS] License created:", data.data.licenseKey);
4866
4886
  return data.data;
4867
4887
  } else {
4868
- strapi2.log.error("[magic-mail] License creation failed:", data);
4888
+ strapi2.log.error("[magic-mail] [ERROR] License creation failed:", data);
4869
4889
  return null;
4870
4890
  }
4871
4891
  } catch (error) {
4872
- strapi2.log.error("[magic-mail] Error creating license:", error);
4892
+ strapi2.log.error("[magic-mail] [ERROR] Error creating license:", error);
4873
4893
  return null;
4874
4894
  }
4875
4895
  },
@@ -4897,10 +4917,10 @@ function requireLicenseGuard() {
4897
4917
  }
4898
4918
  } catch (error) {
4899
4919
  if (allowGracePeriod) {
4900
- strapi2.log.warn("[magic-mail] ⚠️ License verification timeout - grace period active");
4920
+ strapi2.log.warn("[magic-mail] [WARNING] License verification timeout - grace period active");
4901
4921
  return { valid: true, data: null, gracePeriod: true };
4902
4922
  }
4903
- strapi2.log.error("[magic-mail] License verification error:", error.message);
4923
+ strapi2.log.error("[magic-mail] [ERROR] License verification error:", error.message);
4904
4924
  return { valid: false, data: null };
4905
4925
  }
4906
4926
  },
@@ -4953,7 +4973,7 @@ function requireLicenseGuard() {
4953
4973
  name: "magic-mail"
4954
4974
  });
4955
4975
  await pluginStore.set({ key: "licenseKey", value: licenseKey });
4956
- strapi2.log.info(`[magic-mail] License key stored: ${licenseKey.substring(0, 8)}...`);
4976
+ strapi2.log.info(`[magic-mail] [SUCCESS] License key stored: ${licenseKey.substring(0, 8)}...`);
4957
4977
  },
4958
4978
  startPinging(licenseKey, intervalMinutes = 15) {
4959
4979
  this.pingLicense(licenseKey);
@@ -4982,7 +5002,7 @@ function requireLicenseGuard() {
4982
5002
  const license2 = await this.getLicenseByKey(licenseKey);
4983
5003
  return license2;
4984
5004
  } catch (error) {
4985
- strapi2.log.error(`[magic-mail] Error loading license:`, error);
5005
+ strapi2.log.error(`[magic-mail] [ERROR] Error loading license:`, error);
4986
5006
  return null;
4987
5007
  }
4988
5008
  },
@@ -5032,7 +5052,7 @@ function requireLicenseGuard() {
5032
5052
  */
5033
5053
  async initialize() {
5034
5054
  try {
5035
- strapi2.log.info("🔐 Initializing License Guard...");
5055
+ strapi2.log.info("[INIT] Initializing License Guard...");
5036
5056
  const pluginStore = strapi2.store({
5037
5057
  type: "plugin",
5038
5058
  name: "magic-mail"
@@ -5050,53 +5070,53 @@ function requireLicenseGuard() {
5050
5070
  strapi2.log.info("──────────────────────────────────────────────────────────");
5051
5071
  strapi2.log.info(`📦 Plugin Store Check:`);
5052
5072
  if (licenseKey) {
5053
- strapi2.log.info(` License Key found: ${licenseKey}`);
5054
- strapi2.log.info(` 🔑 Key (short): ${licenseKey.substring(0, 10)}...`);
5073
+ strapi2.log.info(` [SUCCESS] License Key found: ${licenseKey}`);
5074
+ strapi2.log.info(` [LICENSE] Key (short): ${licenseKey.substring(0, 10)}...`);
5055
5075
  if (lastValidated) {
5056
5076
  const lastValidatedDate = new Date(lastValidated);
5057
5077
  const hoursAgo = Math.floor((now.getTime() - lastValidatedDate.getTime()) / (1e3 * 60 * 60));
5058
- strapi2.log.info(` 🕐 Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
5078
+ strapi2.log.info(` [TIME] Last validated: ${hoursAgo}h ago (Grace: ${withinGracePeriod ? "ACTIVE" : "EXPIRED"})`);
5059
5079
  } else {
5060
- strapi2.log.info(` 🕐 Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
5080
+ strapi2.log.info(` [TIME] Last validated: Never (Grace: ACTIVE for first ${gracePeriodHours}h)`);
5061
5081
  }
5062
5082
  } else {
5063
- strapi2.log.info(` No license key stored`);
5083
+ strapi2.log.info(` [ERROR] No license key stored`);
5064
5084
  }
5065
5085
  strapi2.log.info("──────────────────────────────────────────────────────────");
5066
5086
  if (!licenseKey) {
5067
- strapi2.log.info("📄 No license found - Running in demo mode");
5068
- strapi2.log.info("💡 Create a license in the admin panel to activate full features");
5087
+ strapi2.log.info("[DEMO] No license found - Running in demo mode");
5088
+ strapi2.log.info("[INFO] Create a license in the admin panel to activate full features");
5069
5089
  return {
5070
5090
  valid: false,
5071
5091
  demo: true,
5072
5092
  data: null
5073
5093
  };
5074
5094
  }
5075
- strapi2.log.info("📄 Verifying stored license key...");
5095
+ strapi2.log.info("[VERIFY] Verifying stored license key...");
5076
5096
  const verification = await this.verifyLicense(licenseKey, withinGracePeriod);
5077
5097
  if (verification.valid) {
5078
5098
  const license2 = await this.getLicenseByKey(licenseKey);
5079
- strapi2.log.info(`✅ License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
5099
+ strapi2.log.info(`[SUCCESS] License verified online: ACTIVE (Key: ${licenseKey.substring(0, 10)}...)`);
5080
5100
  await pluginStore.set({
5081
5101
  key: "lastValidated",
5082
5102
  value: now.toISOString()
5083
5103
  });
5084
- strapi2.log.info(" License is valid and active");
5104
+ strapi2.log.info("[SUCCESS] License is valid and active");
5085
5105
  const pingInterval = this.startPinging(licenseKey, 15);
5086
- strapi2.log.info("📡 Started pinging license every 15 minutes");
5106
+ strapi2.log.info("[PING] Started pinging license every 15 minutes");
5087
5107
  strapi2.licenseGuardMagicMail = {
5088
5108
  licenseKey,
5089
5109
  pingInterval,
5090
5110
  data: verification.data
5091
5111
  };
5092
5112
  strapi2.log.info("╔════════════════════════════════════════════════════════════════╗");
5093
- strapi2.log.info("║ MAGIC MAIL PLUGIN LICENSE ACTIVE ║");
5113
+ strapi2.log.info("║ [SUCCESS] MAGIC MAIL PLUGIN LICENSE ACTIVE ║");
5094
5114
  strapi2.log.info("║ ║");
5095
5115
  strapi2.log.info(`║ License: ${licenseKey.padEnd(38, " ")}║`);
5096
5116
  strapi2.log.info(`║ User: ${(license2?.firstName + " " + license2?.lastName).padEnd(41, " ")}║`);
5097
5117
  strapi2.log.info(`║ Email: ${(license2?.email || "N/A").padEnd(40, " ")}║`);
5098
5118
  strapi2.log.info("║ ║");
5099
- strapi2.log.info("║ 🔄 Auto-pinging every 15 minutes ║");
5119
+ strapi2.log.info("║ [AUTO] Pinging every 15 minutes ║");
5100
5120
  strapi2.log.info("╚════════════════════════════════════════════════════════════════╝");
5101
5121
  return {
5102
5122
  valid: true,
@@ -5105,9 +5125,9 @@ function requireLicenseGuard() {
5105
5125
  gracePeriod: verification.gracePeriod || false
5106
5126
  };
5107
5127
  } else {
5108
- strapi2.log.error(`❌ License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
5128
+ strapi2.log.error(`[ERROR] License validation failed (Key: ${licenseKey.substring(0, 10)}...)`);
5109
5129
  strapi2.log.info("──────────────────────────────────────────────────────────");
5110
- strapi2.log.info("⚠️ Running in demo mode with limited features");
5130
+ strapi2.log.info("[WARNING] Running in demo mode with limited features");
5111
5131
  return {
5112
5132
  valid: false,
5113
5133
  demo: true,
@@ -5116,7 +5136,7 @@ function requireLicenseGuard() {
5116
5136
  };
5117
5137
  }
5118
5138
  } catch (error) {
5119
- strapi2.log.error(" Error initializing License Guard:", error);
5139
+ strapi2.log.error("[ERROR] Error initializing License Guard:", error);
5120
5140
  return {
5121
5141
  valid: false,
5122
5142
  demo: true,
@@ -5136,6 +5156,8 @@ function requireEmailDesigner() {
5136
5156
  const Mustache = require$$0$3;
5137
5157
  const htmlToTextLib = require$$1$2;
5138
5158
  const decode = require$$2$2;
5159
+ const EMAIL_TEMPLATE_UID = "plugin::magic-mail.email-template";
5160
+ const EMAIL_TEMPLATE_VERSION_UID = "plugin::magic-mail.email-template-version";
5139
5161
  const convertHtmlToText = (html, options2 = { wordwrap: 130 }) => {
5140
5162
  try {
5141
5163
  if (!html || typeof html !== "string") {
@@ -5173,24 +5195,36 @@ function requireEmailDesigner() {
5173
5195
  * Get all templates
5174
5196
  */
5175
5197
  async findAll(filters = {}) {
5176
- return strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5198
+ return strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5177
5199
  filters,
5178
- sort: { createdAt: "desc" }
5200
+ sort: [{ createdAt: "desc" }]
5179
5201
  });
5180
5202
  },
5181
5203
  /**
5182
- * Get template by ID with populated versions
5204
+ * Get template by ID (documentId) with populated versions
5183
5205
  */
5184
- async findOne(id) {
5185
- return strapi2.entityService.findOne("plugin::magic-mail.email-template", id, {
5206
+ async findOne(documentId) {
5207
+ return strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5208
+ documentId,
5186
5209
  populate: ["versions"]
5187
5210
  });
5188
5211
  },
5212
+ /**
5213
+ * Get template by numeric ID (for backward compatibility)
5214
+ */
5215
+ async findById(id) {
5216
+ const results = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5217
+ filters: { id },
5218
+ limit: 1,
5219
+ populate: ["versions"]
5220
+ });
5221
+ return results.length > 0 ? results[0] : null;
5222
+ },
5189
5223
  /**
5190
5224
  * Get template by reference ID
5191
5225
  */
5192
5226
  async findByReferenceId(templateReferenceId) {
5193
- const results = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5227
+ const results = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5194
5228
  filters: { templateReferenceId },
5195
5229
  limit: 1
5196
5230
  });
@@ -5198,17 +5232,11 @@ function requireEmailDesigner() {
5198
5232
  },
5199
5233
  /**
5200
5234
  * Create new template with automatic initial version
5201
- *
5202
- * Steps:
5203
- * 1. Check license limits
5204
- * 2. Validate reference ID is unique
5205
- * 3. Create template
5206
- * 4. Create initial version (if versioning enabled)
5207
5235
  */
5208
5236
  async create(data) {
5209
- strapi2.log.info("[magic-mail] 📝 Creating new template...");
5237
+ strapi2.log.info("[magic-mail] [TEST] Creating new template...");
5210
5238
  const maxTemplates = await strapi2.plugin("magic-mail").service("license-guard").getMaxEmailTemplates();
5211
- const currentCount = await strapi2.db.query("plugin::magic-mail.email-template").count();
5239
+ const currentCount = await strapi2.documents(EMAIL_TEMPLATE_UID).count();
5212
5240
  if (maxTemplates !== -1 && currentCount >= maxTemplates) {
5213
5241
  throw new Error(
5214
5242
  `Template limit reached (${maxTemplates}). Upgrade your license to create more templates.`
@@ -5220,17 +5248,17 @@ function requireEmailDesigner() {
5220
5248
  throw new Error(`Template with reference ID ${data.templateReferenceId} already exists`);
5221
5249
  }
5222
5250
  }
5223
- const template = await strapi2.entityService.create("plugin::magic-mail.email-template", {
5251
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).create({
5224
5252
  data: {
5225
5253
  ...data,
5226
5254
  isActive: data.isActive !== void 0 ? data.isActive : true
5227
5255
  }
5228
5256
  });
5229
- strapi2.log.info(`[magic-mail] Template created: ID=${template.id}, name="${template.name}"`);
5257
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template created: documentId=${template.documentId}, name="${template.name}"`);
5230
5258
  const hasVersioning = await strapi2.plugin("magic-mail").service("license-guard").hasFeature("email-designer-versioning");
5231
5259
  if (hasVersioning) {
5232
- strapi2.log.info("[magic-mail] 💾 Creating initial version...");
5233
- await this.createVersion(template.id, {
5260
+ strapi2.log.info("[magic-mail] [SAVE] Creating initial version...");
5261
+ await this.createVersion(template.documentId, {
5234
5262
  name: data.name,
5235
5263
  subject: data.subject,
5236
5264
  design: data.design,
@@ -5238,33 +5266,26 @@ function requireEmailDesigner() {
5238
5266
  bodyText: data.bodyText,
5239
5267
  tags: data.tags
5240
5268
  });
5241
- strapi2.log.info("[magic-mail] Initial version created");
5269
+ strapi2.log.info("[magic-mail] [SUCCESS] Initial version created");
5242
5270
  } else {
5243
- strapi2.log.info("[magic-mail] ⏭️ Versioning not enabled, skipping initial version");
5271
+ strapi2.log.info("[magic-mail] [SKIP] Versioning not enabled, skipping initial version");
5244
5272
  }
5245
5273
  return template;
5246
5274
  },
5247
5275
  /**
5248
5276
  * Update template with automatic version snapshot
5249
- *
5250
- * Steps:
5251
- * 1. Load existing template
5252
- * 2. Create version snapshot of CURRENT state (before update)
5253
- * 3. Update template with new data
5254
- *
5255
- * IMPORTANT: Version is created BEFORE update to preserve old state!
5256
- */
5257
- async update(id, data) {
5258
- strapi2.log.info(`[magic-mail] 🔄 Updating template ID: ${id}`);
5259
- const template = await this.findOne(id);
5277
+ */
5278
+ async update(documentId, data) {
5279
+ strapi2.log.info(`[magic-mail] [UPDATE] Updating template documentId: ${documentId}`);
5280
+ const template = await this.findOne(documentId);
5260
5281
  if (!template) {
5261
5282
  throw new Error("Template not found");
5262
5283
  }
5263
- strapi2.log.info(`[magic-mail] 📋 Found template: ID=${template.id}, name="${template.name}"`);
5284
+ strapi2.log.info(`[magic-mail] [INFO] Found template: documentId=${template.documentId}, name="${template.name}"`);
5264
5285
  const hasVersioning = await strapi2.plugin("magic-mail").service("license-guard").hasFeature("email-designer-versioning");
5265
5286
  if (hasVersioning) {
5266
- strapi2.log.info("[magic-mail] 💾 Creating version snapshot before update...");
5267
- await this.createVersion(template.id, {
5287
+ strapi2.log.info("[magic-mail] [SAVE] Creating version snapshot before update...");
5288
+ await this.createVersion(template.documentId, {
5268
5289
  name: template.name,
5269
5290
  subject: template.subject,
5270
5291
  design: template.design,
@@ -5272,66 +5293,62 @@ function requireEmailDesigner() {
5272
5293
  bodyText: template.bodyText,
5273
5294
  tags: template.tags
5274
5295
  });
5275
- strapi2.log.info("[magic-mail] Version snapshot created");
5276
- } else {
5277
- strapi2.log.info("[magic-mail] ⏭️ Versioning not enabled, skipping version snapshot");
5296
+ strapi2.log.info("[magic-mail] [SUCCESS] Version snapshot created");
5278
5297
  }
5279
5298
  const updateData = { ...data };
5280
5299
  if ("versions" in updateData) {
5281
5300
  delete updateData.versions;
5282
- strapi2.log.warn("[magic-mail] ⚠️ Removed versions field from update data to prevent relation overwrite");
5301
+ strapi2.log.warn("[magic-mail] [WARNING] Removed versions field from update data");
5283
5302
  }
5284
- const updated = await strapi2.entityService.update("plugin::magic-mail.email-template", id, {
5303
+ const updated = await strapi2.documents(EMAIL_TEMPLATE_UID).update({
5304
+ documentId,
5285
5305
  data: updateData
5286
5306
  });
5287
- strapi2.log.info(`[magic-mail] Template updated: ID=${updated.id}, versions preserved`);
5307
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template updated: documentId=${updated.documentId}`);
5288
5308
  return updated;
5289
5309
  },
5290
5310
  /**
5291
5311
  * Delete template and all its versions
5292
- *
5293
- * Uses Document Service for version deletion to ensure cascading delete
5294
5312
  */
5295
- async delete(id) {
5296
- strapi2.log.info(`[magic-mail] 🗑️ Deleting template ID: ${id}`);
5297
- const template = await this.findOne(id);
5313
+ async delete(documentId) {
5314
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting template documentId: ${documentId}`);
5315
+ const template = await this.findOne(documentId);
5298
5316
  if (!template) {
5299
5317
  throw new Error("Template not found");
5300
5318
  }
5301
- strapi2.log.info(`[magic-mail] 🗑️ Template: ID=${template.id}, name="${template.name}"`);
5302
- const allVersions = await strapi2.documents("plugin::magic-mail.email-template-version").findMany({
5319
+ strapi2.log.info(`[magic-mail] [DELETE] Template: documentId=${template.documentId}, name="${template.name}"`);
5320
+ const allVersions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5303
5321
  filters: {
5304
5322
  template: {
5305
5323
  documentId: template.documentId
5306
5324
  }
5307
5325
  }
5308
5326
  });
5309
- strapi2.log.info(`[magic-mail] 🗑️ Found ${allVersions.length} versions to delete`);
5327
+ strapi2.log.info(`[magic-mail] [DELETE] Found ${allVersions.length} versions to delete`);
5310
5328
  for (const version2 of allVersions) {
5311
5329
  try {
5312
- await strapi2.documents("plugin::magic-mail.email-template-version").delete({ documentId: version2.documentId });
5313
- strapi2.log.info(`[magic-mail] 🗑️ Deleted version #${version2.versionNumber}`);
5330
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5331
+ documentId: version2.documentId
5332
+ });
5333
+ strapi2.log.info(`[magic-mail] [DELETE] Deleted version #${version2.versionNumber}`);
5314
5334
  } catch (versionError) {
5315
- strapi2.log.warn(`[magic-mail] ⚠️ Failed to delete version ${version2.id}: ${versionError.message}`);
5335
+ strapi2.log.warn(`[magic-mail] [WARNING] Failed to delete version: ${versionError.message}`);
5316
5336
  }
5317
5337
  }
5318
- const result = await strapi2.entityService.delete("plugin::magic-mail.email-template", id);
5319
- strapi2.log.info(`[magic-mail] Template "${template.name}" and ${allVersions.length} versions deleted`);
5338
+ const result = await strapi2.documents(EMAIL_TEMPLATE_UID).delete({ documentId });
5339
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template "${template.name}" and ${allVersions.length} versions deleted`);
5320
5340
  return result;
5321
5341
  },
5322
5342
  /**
5323
5343
  * Duplicate template
5324
- *
5325
- * Creates a copy of an existing template with " copy" suffix
5326
- * Does NOT copy versions, starts fresh
5327
5344
  */
5328
- async duplicate(id) {
5329
- strapi2.log.info(`[magic-mail] 📋 Duplicating template ID: ${id}`);
5330
- const original = await this.findOne(id);
5345
+ async duplicate(documentId) {
5346
+ strapi2.log.info(`[magic-mail] [INFO] Duplicating template documentId: ${documentId}`);
5347
+ const original = await this.findOne(documentId);
5331
5348
  if (!original) {
5332
5349
  throw new Error("Template not found");
5333
5350
  }
5334
- strapi2.log.info(`[magic-mail] 📦 Original template: ID=${original.id}, name="${original.name}"`);
5351
+ strapi2.log.info(`[magic-mail] [PACKAGE] Original template: documentId=${original.documentId}, name="${original.name}"`);
5335
5352
  const duplicateData = {
5336
5353
  name: `${original.name} copy`,
5337
5354
  subject: original.subject,
@@ -5341,11 +5358,10 @@ function requireEmailDesigner() {
5341
5358
  category: original.category,
5342
5359
  tags: original.tags,
5343
5360
  isActive: original.isActive,
5344
- // Generate new templateReferenceId (unique ID)
5345
5361
  templateReferenceId: Date.now() + Math.floor(Math.random() * 1e3)
5346
5362
  };
5347
5363
  const duplicated = await this.create(duplicateData);
5348
- strapi2.log.info(`[magic-mail] Template duplicated: ID=${duplicated.id}, name="${duplicated.name}"`);
5364
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}`);
5349
5365
  return duplicated;
5350
5366
  },
5351
5367
  // ============================================================
@@ -5353,134 +5369,81 @@ function requireEmailDesigner() {
5353
5369
  // ============================================================
5354
5370
  /**
5355
5371
  * Create a new version for a template
5356
- *
5357
- * CRITICAL: This is THE ONLY function that creates versions!
5358
- *
5359
- * Steps:
5360
- * 1. Verify template exists
5361
- * 2. Calculate next version number
5362
- * 3. Create version WITH template relation
5363
- *
5364
- * @param {number} templateId - Numeric ID of template
5365
- * @param {object} data - Version data (name, subject, bodyHtml, etc)
5366
- * @returns {object} Created version
5367
- */
5368
- async createVersion(templateId, data) {
5369
- strapi2.log.info(`[magic-mail] 📸 Creating version for template ID: ${templateId}`);
5370
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId);
5372
+ */
5373
+ async createVersion(templateDocumentId, data) {
5374
+ strapi2.log.info(`[magic-mail] [SNAPSHOT] Creating version for template documentId: ${templateDocumentId}`);
5375
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5376
+ documentId: templateDocumentId
5377
+ });
5371
5378
  if (!template) {
5372
- throw new Error(`Template ${templateId} not found`);
5379
+ throw new Error(`Template ${templateDocumentId} not found`);
5373
5380
  }
5374
- strapi2.log.info(`[magic-mail] 📦 Template found: ID=${template.id}, name="${template.name}"`);
5375
- const existingVersions = await strapi2.entityService.findMany("plugin::magic-mail.email-template-version", {
5381
+ strapi2.log.info(`[magic-mail] [PACKAGE] Template found: documentId=${template.documentId}, name="${template.name}"`);
5382
+ const existingVersions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5376
5383
  filters: {
5377
5384
  template: {
5378
- id: templateId
5379
- // Use numeric ID in filter
5385
+ documentId: templateDocumentId
5380
5386
  }
5381
5387
  },
5382
- sort: { versionNumber: "desc" }
5388
+ sort: [{ versionNumber: "desc" }]
5383
5389
  });
5384
5390
  const versionNumber = existingVersions.length > 0 ? Math.max(...existingVersions.map((v) => v.versionNumber || 0)) + 1 : 1;
5385
- strapi2.log.info(`[magic-mail] 📊 Existing versions: ${existingVersions.length} → Next version: #${versionNumber}`);
5386
- const createdVersion = await strapi2.entityService.create("plugin::magic-mail.email-template-version", {
5391
+ strapi2.log.info(`[magic-mail] [STATS] Existing versions: ${existingVersions.length} → Next version: #${versionNumber}`);
5392
+ const createdVersion = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).create({
5387
5393
  data: {
5388
5394
  versionNumber,
5389
5395
  ...data,
5390
- template: {
5391
- connect: [templateId]
5392
- // ✅ Use connect array for Strapi v5!
5393
- }
5396
+ template: templateDocumentId
5397
+ // Document Service handles relations with documentId
5394
5398
  }
5395
5399
  });
5396
- strapi2.log.info(`[magic-mail] 📝 Version created with connect: ID=${createdVersion.id}`);
5397
- const verifiedVersion = await strapi2.entityService.findOne(
5398
- "plugin::magic-mail.email-template-version",
5399
- createdVersion.id,
5400
- {
5401
- populate: ["template"]
5402
- }
5403
- );
5404
- strapi2.log.info(
5405
- `[magic-mail] ✅ Version created successfully:
5406
- - Version ID: ${createdVersion.id}
5407
- - Version #: ${versionNumber}
5408
- - Template ID: ${templateId}
5409
- - Has template relation: ${!!verifiedVersion.template}
5410
- - Template in DB: ${verifiedVersion.template?.id || "NULL"}`
5411
- );
5412
- if (!verifiedVersion.template) {
5413
- strapi2.log.error(
5414
- `[magic-mail] ❌ CRITICAL: Version ${createdVersion.id} was created but template relation was NOT set!
5415
- This is a Strapi v5 relation bug. Investigating...`
5416
- );
5417
- }
5418
- return verifiedVersion;
5400
+ strapi2.log.info(`[magic-mail] [SUCCESS] Version created: documentId=${createdVersion.documentId}, v${versionNumber}`);
5401
+ return createdVersion;
5419
5402
  },
5420
5403
  /**
5421
5404
  * Get all versions for a template
5422
5405
  */
5423
- async getVersions(templateId) {
5424
- strapi2.log.info(`[magic-mail] 📜 Fetching versions for template ID: ${templateId}`);
5425
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5406
+ async getVersions(templateDocumentId) {
5407
+ strapi2.log.info(`[magic-mail] 📜 Fetching versions for template documentId: ${templateDocumentId}`);
5408
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5409
+ documentId: templateDocumentId,
5426
5410
  populate: ["versions"]
5427
5411
  });
5428
5412
  if (!template) {
5429
5413
  throw new Error("Template not found");
5430
5414
  }
5431
- strapi2.log.info(`[magic-mail] 📦 Template has ${template.versions?.length || 0} versions in relation`);
5415
+ strapi2.log.info(`[magic-mail] [PACKAGE] Template has ${template.versions?.length || 0} versions`);
5432
5416
  if (template.versions && template.versions.length > 0) {
5433
5417
  const sortedVersions = [...template.versions].sort((a, b) => b.versionNumber - a.versionNumber);
5434
- strapi2.log.info(`[magic-mail] ✅ Returning ${sortedVersions.length} versions from template populate`);
5435
5418
  return sortedVersions;
5436
5419
  }
5437
- strapi2.log.warn(`[magic-mail] ⚠️ Template has no populated versions, trying filter...`);
5438
- const versions = await strapi2.entityService.findMany("plugin::magic-mail.email-template-version", {
5420
+ const versions = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findMany({
5439
5421
  filters: {
5440
5422
  template: {
5441
- id: templateId
5423
+ documentId: templateDocumentId
5442
5424
  }
5443
5425
  },
5444
- sort: { versionNumber: "desc" },
5445
- populate: ["template"]
5426
+ sort: [{ versionNumber: "desc" }]
5446
5427
  });
5447
- strapi2.log.info(`[magic-mail] Found ${versions.length} versions via filter`);
5428
+ strapi2.log.info(`[magic-mail] [SUCCESS] Found ${versions.length} versions`);
5448
5429
  return versions;
5449
5430
  },
5450
5431
  /**
5451
5432
  * Restore template from a specific version
5452
- *
5453
- * Updates the template with data from the version
5454
- * This will create a NEW version snapshot (via update logic)
5455
5433
  */
5456
- async restoreVersion(templateId, versionId) {
5457
- strapi2.log.info(`[magic-mail] 🔄 Restoring template ${templateId} from version ${versionId}`);
5458
- const version2 = await strapi2.entityService.findOne("plugin::magic-mail.email-template-version", versionId, {
5434
+ async restoreVersion(templateDocumentId, versionDocumentId) {
5435
+ strapi2.log.info(`[magic-mail] [RESTORE] Restoring template ${templateDocumentId} from version ${versionDocumentId}`);
5436
+ const version2 = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
5437
+ documentId: versionDocumentId,
5459
5438
  populate: ["template"]
5460
5439
  });
5461
5440
  if (!version2) {
5462
5441
  throw new Error("Version not found");
5463
5442
  }
5464
- strapi2.log.info(`[magic-mail] 📦 Version found: ID=${version2.id}, versionNumber=${version2.versionNumber}, has template: ${!!version2.template}`);
5465
- if (version2.template?.id) {
5466
- if (version2.template.id !== parseInt(templateId)) {
5467
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} belongs to template ${version2.template.id}, not ${templateId}`);
5468
- throw new Error("Version does not belong to this template");
5469
- }
5470
- strapi2.log.info(`[magic-mail] ✅ Version has correct template relation`);
5471
- } else {
5472
- strapi2.log.warn(`[magic-mail] ⚠️ Version ${versionId} has no template relation, checking template's versions array...`);
5473
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5474
- populate: ["versions"]
5475
- });
5476
- const versionExists = template.versions && template.versions.some((v) => v.id === parseInt(versionId));
5477
- if (!versionExists) {
5478
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} not found in template ${templateId} versions array`);
5479
- throw new Error("Version does not belong to this template");
5480
- }
5481
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} found in template's versions array (old version without relation)`);
5443
+ if (version2.template?.documentId !== templateDocumentId) {
5444
+ throw new Error("Version does not belong to this template");
5482
5445
  }
5483
- const restored = await this.update(templateId, {
5446
+ const restored = await this.update(templateDocumentId, {
5484
5447
  name: version2.name,
5485
5448
  subject: version2.subject,
5486
5449
  design: version2.design,
@@ -5488,93 +5451,65 @@ function requireEmailDesigner() {
5488
5451
  bodyText: version2.bodyText,
5489
5452
  tags: version2.tags
5490
5453
  });
5491
- strapi2.log.info(`[magic-mail] Template restored from version #${version2.versionNumber}`);
5454
+ strapi2.log.info(`[magic-mail] [SUCCESS] Template restored from version #${version2.versionNumber}`);
5492
5455
  return restored;
5493
5456
  },
5494
5457
  /**
5495
5458
  * Delete a single version
5496
- *
5497
- * @param {number} templateId - Template ID (for verification)
5498
- * @param {number} versionId - Version ID to delete
5499
5459
  */
5500
- async deleteVersion(templateId, versionId) {
5501
- strapi2.log.info(`[magic-mail] 🗑️ Deleting version ${versionId} from template ${templateId}`);
5502
- const version2 = await strapi2.entityService.findOne("plugin::magic-mail.email-template-version", versionId, {
5460
+ async deleteVersion(templateDocumentId, versionDocumentId) {
5461
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting version ${versionDocumentId}`);
5462
+ const version2 = await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).findOne({
5463
+ documentId: versionDocumentId,
5503
5464
  populate: ["template"]
5504
5465
  });
5505
5466
  if (!version2) {
5506
5467
  throw new Error("Version not found");
5507
5468
  }
5508
- if (version2.template?.id) {
5509
- if (version2.template.id !== parseInt(templateId)) {
5510
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} belongs to template ${version2.template.id}, not ${templateId}`);
5511
- throw new Error("Version does not belong to this template");
5512
- }
5513
- strapi2.log.info(`[magic-mail] ✅ Version has correct template relation`);
5514
- } else {
5515
- strapi2.log.warn(`[magic-mail] ⚠️ Version ${versionId} has no template relation, checking template's versions array...`);
5516
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5517
- populate: ["versions"]
5518
- });
5519
- const versionExists = template.versions && template.versions.some((v) => v.id === parseInt(versionId));
5520
- if (!versionExists) {
5521
- strapi2.log.error(`[magic-mail] ❌ Version ${versionId} not found in template ${templateId} versions array`);
5522
- throw new Error("Version does not belong to this template");
5523
- }
5524
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} found in template's versions array`);
5469
+ if (version2.template?.documentId !== templateDocumentId) {
5470
+ throw new Error("Version does not belong to this template");
5525
5471
  }
5526
- await strapi2.entityService.delete("plugin::magic-mail.email-template-version", versionId);
5527
- strapi2.log.info(`[magic-mail] ✅ Version ${versionId} (v${version2.versionNumber}) deleted successfully`);
5472
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5473
+ documentId: versionDocumentId
5474
+ });
5475
+ strapi2.log.info(`[magic-mail] [SUCCESS] Version v${version2.versionNumber} deleted`);
5528
5476
  return { success: true, message: "Version deleted" };
5529
5477
  },
5530
5478
  /**
5531
5479
  * Delete all versions for a template
5532
- *
5533
- * @param {number} templateId - Template ID
5534
5480
  */
5535
- async deleteAllVersions(templateId) {
5536
- strapi2.log.info(`[magic-mail] 🗑️ Deleting all versions for template ${templateId}`);
5537
- const template = await strapi2.entityService.findOne("plugin::magic-mail.email-template", templateId, {
5481
+ async deleteAllVersions(templateDocumentId) {
5482
+ strapi2.log.info(`[magic-mail] [DELETE] Deleting all versions for template ${templateDocumentId}`);
5483
+ const template = await strapi2.documents(EMAIL_TEMPLATE_UID).findOne({
5484
+ documentId: templateDocumentId,
5538
5485
  populate: ["versions"]
5539
5486
  });
5540
5487
  if (!template) {
5541
5488
  throw new Error("Template not found");
5542
5489
  }
5543
5490
  const versionCount = template.versions?.length || 0;
5544
- strapi2.log.info(`[magic-mail] 📊 Found ${versionCount} versions to delete`);
5545
5491
  if (versionCount === 0) {
5546
5492
  return { success: true, message: "No versions to delete", deletedCount: 0 };
5547
5493
  }
5548
5494
  let deletedCount = 0;
5549
- const errors = [];
5550
5495
  for (const version2 of template.versions) {
5551
5496
  try {
5552
- await strapi2.entityService.delete("plugin::magic-mail.email-template-version", version2.id);
5497
+ await strapi2.documents(EMAIL_TEMPLATE_VERSION_UID).delete({
5498
+ documentId: version2.documentId
5499
+ });
5553
5500
  deletedCount++;
5554
- strapi2.log.info(`[magic-mail] 🗑️ Deleted version #${version2.versionNumber} (ID: ${version2.id})`);
5555
5501
  } catch (error) {
5556
- strapi2.log.error(`[magic-mail] Failed to delete version ${version2.id}: ${error.message}`);
5557
- errors.push({ versionId: version2.id, error: error.message });
5502
+ strapi2.log.error(`[magic-mail] [ERROR] Failed to delete version: ${error.message}`);
5558
5503
  }
5559
5504
  }
5560
- strapi2.log.info(`[magic-mail] Deleted ${deletedCount}/${versionCount} versions`);
5561
- return {
5562
- success: true,
5563
- message: `Deleted ${deletedCount} of ${versionCount} versions`,
5564
- deletedCount,
5565
- failedCount: versionCount - deletedCount,
5566
- errors: errors.length > 0 ? errors : void 0
5567
- };
5505
+ strapi2.log.info(`[magic-mail] [SUCCESS] Deleted ${deletedCount}/${versionCount} versions`);
5506
+ return { success: true, deletedCount };
5568
5507
  },
5569
5508
  // ============================================================
5570
5509
  // RENDERING
5571
5510
  // ============================================================
5572
5511
  /**
5573
5512
  * Render template with dynamic data using Mustache
5574
- *
5575
- * @param {number} templateReferenceId - Template reference ID
5576
- * @param {object} data - Dynamic data for Mustache
5577
- * @returns {object} Rendered HTML, text, and subject
5578
5513
  */
5579
5514
  async renderTemplate(templateReferenceId, data = {}) {
5580
5515
  const template = await this.findByReferenceId(templateReferenceId);
@@ -5606,17 +5541,17 @@ function requireEmailDesigner() {
5606
5541
  };
5607
5542
  },
5608
5543
  // ============================================================
5609
- // IMPORT/EXPORT (Advanced+ License)
5544
+ // IMPORT/EXPORT
5610
5545
  // ============================================================
5611
5546
  /**
5612
5547
  * Export templates as JSON
5613
5548
  */
5614
- async exportTemplates(templateIds = []) {
5615
- strapi2.log.info("[magic-mail] 📤 Exporting templates...");
5549
+ async exportTemplates(templateDocumentIds = []) {
5550
+ strapi2.log.info("[magic-mail] [EXPORT] Exporting templates...");
5616
5551
  let templates;
5617
- if (templateIds.length > 0) {
5618
- templates = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5619
- filters: { id: { $in: templateIds } }
5552
+ if (templateDocumentIds.length > 0) {
5553
+ templates = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5554
+ filters: { documentId: { $in: templateDocumentIds } }
5620
5555
  });
5621
5556
  } else {
5622
5557
  templates = await this.findAll();
@@ -5631,26 +5566,24 @@ function requireEmailDesigner() {
5631
5566
  category: template.category,
5632
5567
  tags: template.tags
5633
5568
  }));
5634
- strapi2.log.info(`[magic-mail] Exported ${exported.length} templates`);
5569
+ strapi2.log.info(`[magic-mail] [SUCCESS] Exported ${exported.length} templates`);
5635
5570
  return exported;
5636
5571
  },
5637
5572
  /**
5638
5573
  * Import templates from JSON
5639
5574
  */
5640
5575
  async importTemplates(templates) {
5641
- strapi2.log.info(`[magic-mail] 📥 Importing ${templates.length} templates...`);
5576
+ strapi2.log.info(`[magic-mail] [IMPORT] Importing ${templates.length} templates...`);
5642
5577
  const results = [];
5643
5578
  for (const templateData of templates) {
5644
5579
  try {
5645
5580
  const existing = await this.findByReferenceId(templateData.templateReferenceId);
5646
5581
  if (existing) {
5647
- const updated = await this.update(existing.id, templateData);
5582
+ const updated = await this.update(existing.documentId, templateData);
5648
5583
  results.push({ success: true, action: "updated", template: updated });
5649
- strapi2.log.info(`[magic-mail] ✅ Updated template: ${templateData.name}`);
5650
5584
  } else {
5651
5585
  const created = await this.create(templateData);
5652
5586
  results.push({ success: true, action: "created", template: created });
5653
- strapi2.log.info(`[magic-mail] ✅ Created template: ${templateData.name}`);
5654
5587
  }
5655
5588
  } catch (error) {
5656
5589
  results.push({
@@ -5659,11 +5592,8 @@ function requireEmailDesigner() {
5659
5592
  error: error.message,
5660
5593
  templateName: templateData.name
5661
5594
  });
5662
- strapi2.log.error(`[magic-mail] ❌ Failed to import ${templateData.name}: ${error.message}`);
5663
5595
  }
5664
5596
  }
5665
- const successful = results.filter((r) => r.success).length;
5666
- strapi2.log.info(`[magic-mail] ✅ Import completed: ${successful}/${templates.length} templates`);
5667
5597
  return results;
5668
5598
  },
5669
5599
  // ============================================================
@@ -5673,7 +5603,7 @@ function requireEmailDesigner() {
5673
5603
  * Get template statistics
5674
5604
  */
5675
5605
  async getStats() {
5676
- const allTemplates = await strapi2.entityService.findMany("plugin::magic-mail.email-template", {
5606
+ const allTemplates = await strapi2.documents(EMAIL_TEMPLATE_UID).findMany({
5677
5607
  fields: ["isActive", "category"]
5678
5608
  });
5679
5609
  const total = allTemplates.length;
@@ -5698,9 +5628,7 @@ function requireEmailDesigner() {
5698
5628
  // STRAPI CORE EMAIL TEMPLATES
5699
5629
  // ============================================================
5700
5630
  /**
5701
- * Get Strapi core email template (reset-password, email-confirmation)
5702
- *
5703
- * These are stored in users-permissions plugin store
5631
+ * Get Strapi core email template
5704
5632
  */
5705
5633
  async getCoreTemplate(coreEmailType) {
5706
5634
  if (!["reset-password", "email-confirmation"].includes(coreEmailType)) {
@@ -5717,8 +5645,8 @@ function requireEmailDesigner() {
5717
5645
  if (emailConfig && emailConfig[pluginStoreEmailKey]) {
5718
5646
  data = emailConfig[pluginStoreEmailKey];
5719
5647
  }
5720
- const messageConverted = data && data.options && data.options.message ? data.options.message.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5721
- const subjectConverted = data && data.options && data.options.object ? data.options.object.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5648
+ const messageConverted = data?.options?.message ? data.options.message.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5649
+ const subjectConverted = data?.options?.object ? data.options.object.replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}") : "";
5722
5650
  return {
5723
5651
  from: data?.options?.from || null,
5724
5652
  message: messageConverted || "",
@@ -5746,14 +5674,14 @@ function requireEmailDesigner() {
5746
5674
  emailsConfig[pluginStoreEmailKey] = {
5747
5675
  ...emailsConfig[pluginStoreEmailKey],
5748
5676
  options: {
5749
- ...emailsConfig[pluginStoreEmailKey] ? emailsConfig[pluginStoreEmailKey].options : {},
5677
+ ...emailsConfig[pluginStoreEmailKey]?.options || {},
5750
5678
  message: data.message.replace(/{{/g, "<%").replace(/}}/g, "%>"),
5751
5679
  object: data.subject.replace(/{{/g, "<%").replace(/}}/g, "%>")
5752
5680
  },
5753
5681
  design: data.design
5754
5682
  };
5755
5683
  await pluginStore.set({ key: "email", value: emailsConfig });
5756
- strapi2.log.info(`[magic-mail] Core email template updated: ${pluginStoreEmailKey}`);
5684
+ strapi2.log.info(`[magic-mail] [SUCCESS] Core email template updated: ${pluginStoreEmailKey}`);
5757
5685
  return { message: "Saved" };
5758
5686
  }
5759
5687
  });
@@ -5765,6 +5693,9 @@ function requireAnalytics() {
5765
5693
  if (hasRequiredAnalytics) return analytics;
5766
5694
  hasRequiredAnalytics = 1;
5767
5695
  const crypto = require$$0$1;
5696
+ const EMAIL_LOG_UID = "plugin::magic-mail.email-log";
5697
+ const EMAIL_EVENT_UID = "plugin::magic-mail.email-event";
5698
+ const EMAIL_LINK_UID = "plugin::magic-mail.email-link";
5768
5699
  analytics = ({ strapi: strapi2 }) => ({
5769
5700
  /**
5770
5701
  * Generate unique email ID for tracking
@@ -5783,7 +5714,7 @@ function requireAnalytics() {
5783
5714
  */
5784
5715
  async createEmailLog(data) {
5785
5716
  const emailId = this.generateEmailId();
5786
- const logEntry = await strapi2.db.query("plugin::magic-mail.email-log").create({
5717
+ const logEntry = await strapi2.documents(EMAIL_LOG_UID).create({
5787
5718
  data: {
5788
5719
  emailId,
5789
5720
  user: data.userId || null,
@@ -5798,9 +5729,9 @@ function requireAnalytics() {
5798
5729
  metadata: data.metadata || {}
5799
5730
  }
5800
5731
  });
5801
- strapi2.log.info(`[magic-mail] Email log created: ${emailId}`);
5732
+ strapi2.log.info(`[magic-mail] [SUCCESS] Email log created: ${emailId}`);
5802
5733
  if (data.templateId) {
5803
- strapi2.log.info(`[magic-mail] 📋 Template tracked: ${data.templateName || "Unknown"} (ID: ${data.templateId})`);
5734
+ strapi2.log.info(`[magic-mail] [INFO] Template tracked: ${data.templateName || "Unknown"} (ID: ${data.templateId})`);
5804
5735
  }
5805
5736
  return logEntry;
5806
5737
  },
@@ -5809,8 +5740,8 @@ function requireAnalytics() {
5809
5740
  */
5810
5741
  async recordOpen(emailId, recipientHash, req) {
5811
5742
  try {
5812
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5813
- where: { emailId }
5743
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5744
+ filters: { emailId }
5814
5745
  });
5815
5746
  if (!emailLog) {
5816
5747
  strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
@@ -5822,17 +5753,17 @@ function requireAnalytics() {
5822
5753
  return null;
5823
5754
  }
5824
5755
  const now = /* @__PURE__ */ new Date();
5825
- await strapi2.db.query("plugin::magic-mail.email-log").update({
5826
- where: { id: emailLog.id },
5756
+ await strapi2.documents(EMAIL_LOG_UID).update({
5757
+ documentId: emailLog.documentId,
5827
5758
  data: {
5828
- openCount: emailLog.openCount + 1,
5759
+ openCount: (emailLog.openCount || 0) + 1,
5829
5760
  firstOpenedAt: emailLog.firstOpenedAt || now,
5830
5761
  lastOpenedAt: now
5831
5762
  }
5832
5763
  });
5833
- const event = await strapi2.db.query("plugin::magic-mail.email-event").create({
5764
+ const event = await strapi2.documents(EMAIL_EVENT_UID).create({
5834
5765
  data: {
5835
- emailLog: emailLog.id,
5766
+ emailLog: emailLog.documentId,
5836
5767
  type: "open",
5837
5768
  timestamp: now,
5838
5769
  ipAddress: req.ip || req.headers["x-forwarded-for"] || null,
@@ -5840,7 +5771,7 @@ function requireAnalytics() {
5840
5771
  location: this.parseLocation(req)
5841
5772
  }
5842
5773
  });
5843
- strapi2.log.info(`[magic-mail] 📧 Email opened: ${emailId} (count: ${emailLog.openCount + 1})`);
5774
+ strapi2.log.info(`[magic-mail] [EMAIL] Email opened: ${emailId} (count: ${(emailLog.openCount || 0) + 1})`);
5844
5775
  return event;
5845
5776
  } catch (error) {
5846
5777
  strapi2.log.error("[magic-mail] Error recording open:", error);
@@ -5852,8 +5783,8 @@ function requireAnalytics() {
5852
5783
  */
5853
5784
  async recordClick(emailId, linkHash, recipientHash, targetUrl, req) {
5854
5785
  try {
5855
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5856
- where: { emailId }
5786
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5787
+ filters: { emailId }
5857
5788
  });
5858
5789
  if (!emailLog) {
5859
5790
  return null;
@@ -5863,15 +5794,15 @@ function requireAnalytics() {
5863
5794
  return null;
5864
5795
  }
5865
5796
  const now = /* @__PURE__ */ new Date();
5866
- await strapi2.db.query("plugin::magic-mail.email-log").update({
5867
- where: { id: emailLog.id },
5797
+ await strapi2.documents(EMAIL_LOG_UID).update({
5798
+ documentId: emailLog.documentId,
5868
5799
  data: {
5869
- clickCount: emailLog.clickCount + 1
5800
+ clickCount: (emailLog.clickCount || 0) + 1
5870
5801
  }
5871
5802
  });
5872
- const event = await strapi2.db.query("plugin::magic-mail.email-event").create({
5803
+ const event = await strapi2.documents(EMAIL_EVENT_UID).create({
5873
5804
  data: {
5874
- emailLog: emailLog.id,
5805
+ emailLog: emailLog.documentId,
5875
5806
  type: "click",
5876
5807
  timestamp: now,
5877
5808
  ipAddress: req.ip || req.headers["x-forwarded-for"] || null,
@@ -5880,7 +5811,7 @@ function requireAnalytics() {
5880
5811
  linkUrl: targetUrl
5881
5812
  }
5882
5813
  });
5883
- strapi2.log.info(`[magic-mail] 🖱️ Link clicked: ${emailId} ${targetUrl}`);
5814
+ strapi2.log.info(`[magic-mail] [CLICK] Link clicked: ${emailId} -> ${targetUrl}`);
5884
5815
  return event;
5885
5816
  } catch (error) {
5886
5817
  strapi2.log.error("[magic-mail] Error recording click:", error);
@@ -5889,34 +5820,37 @@ function requireAnalytics() {
5889
5820
  },
5890
5821
  /**
5891
5822
  * Get analytics statistics
5823
+ * Note: Document Service doesn't have count() - using findMany for counting
5892
5824
  */
5893
5825
  async getStats(filters = {}) {
5894
- const where = {};
5826
+ const baseFilters = {};
5895
5827
  if (filters.userId) {
5896
- where.user = filters.userId;
5828
+ baseFilters.user = { documentId: filters.userId };
5897
5829
  }
5898
5830
  if (filters.templateId) {
5899
- where.templateId = filters.templateId;
5831
+ baseFilters.templateId = filters.templateId;
5900
5832
  }
5901
5833
  if (filters.accountId) {
5902
- where.accountId = filters.accountId;
5834
+ baseFilters.accountId = filters.accountId;
5903
5835
  }
5904
5836
  if (filters.dateFrom) {
5905
- where.sentAt = { $gte: new Date(filters.dateFrom) };
5837
+ baseFilters.sentAt = { $gte: new Date(filters.dateFrom) };
5906
5838
  }
5907
5839
  if (filters.dateTo) {
5908
- where.sentAt = { ...where.sentAt, $lte: new Date(filters.dateTo) };
5840
+ baseFilters.sentAt = { ...baseFilters.sentAt, $lte: new Date(filters.dateTo) };
5909
5841
  }
5910
5842
  const [totalSent, totalOpened, totalClicked, totalBounced] = await Promise.all([
5911
- strapi2.db.query("plugin::magic-mail.email-log").count({ where }),
5912
- strapi2.db.query("plugin::magic-mail.email-log").count({
5913
- where: { ...where, openCount: { $gt: 0 } }
5843
+ strapi2.documents(EMAIL_LOG_UID).count({
5844
+ filters: baseFilters
5914
5845
  }),
5915
- strapi2.db.query("plugin::magic-mail.email-log").count({
5916
- where: { ...where, clickCount: { $gt: 0 } }
5846
+ strapi2.documents(EMAIL_LOG_UID).count({
5847
+ filters: { ...baseFilters, openCount: { $gt: 0 } }
5917
5848
  }),
5918
- strapi2.db.query("plugin::magic-mail.email-log").count({
5919
- where: { ...where, bounced: true }
5849
+ strapi2.documents(EMAIL_LOG_UID).count({
5850
+ filters: { ...baseFilters, clickCount: { $gt: 0 } }
5851
+ }),
5852
+ strapi2.documents(EMAIL_LOG_UID).count({
5853
+ filters: { ...baseFilters, bounced: true }
5920
5854
  })
5921
5855
  ]);
5922
5856
  const openRate = totalSent > 0 ? totalOpened / totalSent * 100 : 0;
@@ -5938,7 +5872,7 @@ function requireAnalytics() {
5938
5872
  async getEmailLogs(filters = {}, pagination = {}) {
5939
5873
  const where = {};
5940
5874
  if (filters.userId) {
5941
- where.user = filters.userId;
5875
+ where.user = { documentId: filters.userId };
5942
5876
  }
5943
5877
  if (filters.templateId) {
5944
5878
  where.templateId = filters.templateId;
@@ -5953,14 +5887,17 @@ function requireAnalytics() {
5953
5887
  const page = pagination.page || 1;
5954
5888
  const pageSize = pagination.pageSize || 25;
5955
5889
  const [logs, total] = await Promise.all([
5956
- strapi2.db.query("plugin::magic-mail.email-log").findMany({
5957
- where,
5958
- orderBy: { sentAt: "desc" },
5890
+ strapi2.documents(EMAIL_LOG_UID).findMany({
5891
+ filters: where,
5892
+ sort: [{ sentAt: "desc" }],
5959
5893
  limit: pageSize,
5960
5894
  offset: (page - 1) * pageSize,
5961
5895
  populate: ["user"]
5962
5896
  }),
5963
- strapi2.db.query("plugin::magic-mail.email-log").count({ where })
5897
+ // Get total count using native count() method
5898
+ strapi2.documents(EMAIL_LOG_UID).count({
5899
+ filters: where
5900
+ })
5964
5901
  ]);
5965
5902
  return {
5966
5903
  data: logs,
@@ -5976,8 +5913,8 @@ function requireAnalytics() {
5976
5913
  * Get email log details with events
5977
5914
  */
5978
5915
  async getEmailLogDetails(emailId) {
5979
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
5980
- where: { emailId },
5916
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5917
+ filters: { emailId },
5981
5918
  populate: ["user", "events"]
5982
5919
  });
5983
5920
  return emailLog;
@@ -5986,9 +5923,9 @@ function requireAnalytics() {
5986
5923
  * Get user email activity
5987
5924
  */
5988
5925
  async getUserActivity(userId) {
5989
- const emailLogs = await strapi2.db.query("plugin::magic-mail.email-log").findMany({
5990
- where: { user: userId },
5991
- orderBy: { sentAt: "desc" },
5926
+ const emailLogs = await strapi2.documents(EMAIL_LOG_UID).findMany({
5927
+ filters: { user: { documentId: userId } },
5928
+ sort: [{ sentAt: "desc" }],
5992
5929
  limit: 50
5993
5930
  });
5994
5931
  const stats = await this.getStats({ userId });
@@ -6026,8 +5963,8 @@ function requireAnalytics() {
6026
5963
  */
6027
5964
  async rewriteLinksForTracking(html, emailId, recipientHash) {
6028
5965
  const baseUrl = strapi2.config.get("server.url") || "http://localhost:1337";
6029
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
6030
- where: { emailId }
5966
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
5967
+ filters: { emailId }
6031
5968
  });
6032
5969
  if (!emailLog) {
6033
5970
  strapi2.log.error(`[magic-mail] Cannot rewrite links: Email log not found for ${emailId}`);
@@ -6041,13 +5978,13 @@ function requireAnalytics() {
6041
5978
  while ((match = linkRegex.exec(html)) !== null) {
6042
5979
  match[0];
6043
5980
  const originalUrl = match[1];
6044
- strapi2.log.debug(`[magic-mail] 🔍 Found link: ${originalUrl.substring(0, 100)}${originalUrl.length > 100 ? "..." : ""}`);
5981
+ strapi2.log.debug(`[magic-mail] [CHECK] Found link: ${originalUrl.substring(0, 100)}${originalUrl.length > 100 ? "..." : ""}`);
6045
5982
  if (originalUrl.startsWith("#") || originalUrl.includes("/track/click/")) {
6046
- strapi2.log.debug(`[magic-mail] ⏭️ Skipping (anchor or already tracked)`);
5983
+ strapi2.log.debug(`[magic-mail] [SKIP] Skipping (anchor or already tracked)`);
6047
5984
  continue;
6048
5985
  }
6049
5986
  if (!originalUrl.match(/^https?:\/\//i) && !originalUrl.startsWith("/")) {
6050
- strapi2.log.debug(`[magic-mail] ⏭️ Skipping relative URL: ${originalUrl}`);
5987
+ strapi2.log.debug(`[magic-mail] [SKIP] Skipping relative URL: ${originalUrl}`);
6051
5988
  continue;
6052
5989
  }
6053
5990
  const linkHash = crypto.createHash("md5").update(originalUrl).digest("hex").substring(0, 8);
@@ -6057,7 +5994,7 @@ function requireAnalytics() {
6057
5994
  });
6058
5995
  const trackingUrl = `${baseUrl}/api/magic-mail/track/click/${emailId}/${linkHash}/${recipientHash}`;
6059
5996
  linkCount++;
6060
- strapi2.log.info(`[magic-mail] 🔗 Link ${linkCount}: ${originalUrl} → ${trackingUrl}`);
5997
+ strapi2.log.info(`[magic-mail] [LINK] Link ${linkCount}: ${originalUrl} → ${trackingUrl}`);
6061
5998
  replacements.push({
6062
5999
  from: originalUrl,
6063
6000
  to: trackingUrl
@@ -6065,7 +6002,7 @@ function requireAnalytics() {
6065
6002
  }
6066
6003
  for (const mapping of linkMappings) {
6067
6004
  try {
6068
- await this.storeLinkMapping(emailLog.id, mapping.linkHash, mapping.originalUrl);
6005
+ await this.storeLinkMapping(emailLog.documentId, mapping.linkHash, mapping.originalUrl);
6069
6006
  } catch (err) {
6070
6007
  strapi2.log.error("[magic-mail] Error storing link mapping:", err);
6071
6008
  }
@@ -6075,20 +6012,20 @@ function requireAnalytics() {
6075
6012
  result = result.replace(replacement.from, replacement.to);
6076
6013
  }
6077
6014
  if (linkCount > 0) {
6078
- strapi2.log.info(`[magic-mail] Rewrote ${linkCount} links for click tracking`);
6015
+ strapi2.log.info(`[magic-mail] [SUCCESS] Rewrote ${linkCount} links for click tracking`);
6079
6016
  } else {
6080
- strapi2.log.warn(`[magic-mail] ⚠️ No links found in email HTML for tracking!`);
6017
+ strapi2.log.warn(`[magic-mail] [WARNING] No links found in email HTML for tracking!`);
6081
6018
  }
6082
6019
  return result;
6083
6020
  },
6084
6021
  /**
6085
6022
  * Store link mapping in database
6086
6023
  */
6087
- async storeLinkMapping(emailLogId, linkHash, originalUrl) {
6024
+ async storeLinkMapping(emailLogDocId, linkHash, originalUrl) {
6088
6025
  try {
6089
- const existing = await strapi2.db.query("plugin::magic-mail.email-link").findOne({
6090
- where: {
6091
- emailLog: emailLogId,
6026
+ const existing = await strapi2.documents(EMAIL_LINK_UID).findFirst({
6027
+ filters: {
6028
+ emailLog: { documentId: emailLogDocId },
6092
6029
  linkHash
6093
6030
  }
6094
6031
  });
@@ -6096,15 +6033,15 @@ function requireAnalytics() {
6096
6033
  strapi2.log.debug(`[magic-mail] Link mapping already exists for ${linkHash}`);
6097
6034
  return existing;
6098
6035
  }
6099
- const linkMapping = await strapi2.db.query("plugin::magic-mail.email-link").create({
6036
+ const linkMapping = await strapi2.documents(EMAIL_LINK_UID).create({
6100
6037
  data: {
6101
- emailLog: emailLogId,
6038
+ emailLog: emailLogDocId,
6102
6039
  linkHash,
6103
6040
  originalUrl,
6104
6041
  clickCount: 0
6105
6042
  }
6106
6043
  });
6107
- strapi2.log.debug(`[magic-mail] 💾 Stored link mapping: ${linkHash} → ${originalUrl}`);
6044
+ strapi2.log.debug(`[magic-mail] [SAVE] Stored link mapping: ${linkHash} → ${originalUrl}`);
6108
6045
  return linkMapping;
6109
6046
  } catch (error) {
6110
6047
  strapi2.log.error("[magic-mail] Error storing link mapping:", error);
@@ -6116,16 +6053,16 @@ function requireAnalytics() {
6116
6053
  */
6117
6054
  async getOriginalUrlFromHash(emailId, linkHash) {
6118
6055
  try {
6119
- const emailLog = await strapi2.db.query("plugin::magic-mail.email-log").findOne({
6120
- where: { emailId }
6056
+ const emailLog = await strapi2.documents(EMAIL_LOG_UID).findFirst({
6057
+ filters: { emailId }
6121
6058
  });
6122
6059
  if (!emailLog) {
6123
6060
  strapi2.log.warn(`[magic-mail] Email log not found: ${emailId}`);
6124
6061
  return null;
6125
6062
  }
6126
- const linkMapping = await strapi2.db.query("plugin::magic-mail.email-link").findOne({
6127
- where: {
6128
- emailLog: emailLog.id,
6063
+ const linkMapping = await strapi2.documents(EMAIL_LINK_UID).findFirst({
6064
+ filters: {
6065
+ emailLog: { documentId: emailLog.documentId },
6129
6066
  linkHash
6130
6067
  }
6131
6068
  });
@@ -6134,10 +6071,10 @@ function requireAnalytics() {
6134
6071
  return null;
6135
6072
  }
6136
6073
  const now = /* @__PURE__ */ new Date();
6137
- await strapi2.db.query("plugin::magic-mail.email-link").update({
6138
- where: { id: linkMapping.id },
6074
+ await strapi2.documents(EMAIL_LINK_UID).update({
6075
+ documentId: linkMapping.documentId,
6139
6076
  data: {
6140
- clickCount: linkMapping.clickCount + 1,
6077
+ clickCount: (linkMapping.clickCount || 0) + 1,
6141
6078
  firstClickedAt: linkMapping.firstClickedAt || now,
6142
6079
  lastClickedAt: now
6143
6080
  }