strapi-plugin-magic-mail 2.2.6 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -10
- package/dist/_chunks/{App-Bze8Ixs_.js → App-BMaJu77a.js} +787 -71
- package/dist/_chunks/{App-BZaHrE0R.mjs → App-DxiMl-Zd.mjs} +790 -74
- package/dist/_chunks/{de-DS04rP54.mjs → de-CpIQf94q.mjs} +21 -1
- package/dist/_chunks/{de-CN-G9j1S.js → de-YhjDItIL.js} +21 -1
- package/dist/_chunks/{en-BEFQJXvR.mjs → en-BHmOVzsP.mjs} +21 -1
- package/dist/_chunks/{en-BDc7Jk8u.js → en-BcdTnA2-.js} +21 -1
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +1124 -20
- package/dist/server/index.mjs +1122 -20
- package/package.json +10 -5
package/dist/server/index.mjs
CHANGED
|
@@ -4,6 +4,8 @@ import require$$1$1 from "os";
|
|
|
4
4
|
import require$$0$3 from "mustache";
|
|
5
5
|
import require$$1$2 from "html-to-text";
|
|
6
6
|
import require$$2$2 from "decode-html";
|
|
7
|
+
import require$$0$4 from "path";
|
|
8
|
+
import require$$1$3 from "fs";
|
|
7
9
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
8
10
|
function getDefaultExportFromCjs(x2) {
|
|
9
11
|
return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
|
|
@@ -257,7 +259,7 @@ const collectionName$5 = "magic_mail_routing_rules";
|
|
|
257
259
|
const info$5 = { "singularName": "routing-rule", "pluralName": "routing-rules", "displayName": "Email Routing Rule", "description": "Rules for routing emails to specific accounts" };
|
|
258
260
|
const options$5 = { "draftAndPublish": false };
|
|
259
261
|
const pluginOptions$5 = { "content-manager": { "visible": false }, "content-type-builder": { "visible": false } };
|
|
260
|
-
const attributes$5 = { "name": { "type": "string", "required": true, "unique": true }, "description": { "type": "text" }, "isActive": { "type": "boolean", "default": true, "required": true }, "priority": { "type": "integer", "default": 1, "min": 1 }, "matchType": { "type": "enumeration", "enum": ["emailType", "subject", "recipient", "template", "custom"], "required": true, "default": "emailType" }, "matchValue": { "type": "text", "required": true }, "accountName": { "type": "string", "required": true }, "fallbackAccountName": { "type": "string" } };
|
|
262
|
+
const attributes$5 = { "name": { "type": "string", "required": true, "unique": true }, "description": { "type": "text" }, "isActive": { "type": "boolean", "default": true, "required": true }, "priority": { "type": "integer", "default": 1, "min": 1 }, "matchType": { "type": "enumeration", "enum": ["emailType", "subject", "recipient", "template", "custom"], "required": true, "default": "emailType" }, "matchValue": { "type": "text", "required": true }, "accountName": { "type": "string", "required": true }, "fallbackAccountName": { "type": "string" }, "whatsappFallback": { "type": "boolean", "default": false }, "whatsappPhoneField": { "type": "string" } };
|
|
261
263
|
const require$$1 = {
|
|
262
264
|
kind: kind$5,
|
|
263
265
|
collectionName: collectionName$5,
|
|
@@ -394,6 +396,88 @@ function requireController() {
|
|
|
394
396
|
strapi.log.error("[magic-mail] Error sending email:", err);
|
|
395
397
|
ctx.throw(500, err.message || "Failed to send email");
|
|
396
398
|
}
|
|
399
|
+
},
|
|
400
|
+
/**
|
|
401
|
+
* Send message via Email or WhatsApp (unified API)
|
|
402
|
+
* POST /api/magic-mail/send-message
|
|
403
|
+
* Body: { channel: 'email' | 'whatsapp' | 'auto', to, phoneNumber, subject, message, ... }
|
|
404
|
+
*/
|
|
405
|
+
async sendMessage(ctx) {
|
|
406
|
+
try {
|
|
407
|
+
const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
|
|
408
|
+
const result = await emailRouter2.sendMessage(ctx.request.body);
|
|
409
|
+
ctx.body = {
|
|
410
|
+
success: true,
|
|
411
|
+
...result
|
|
412
|
+
};
|
|
413
|
+
} catch (err) {
|
|
414
|
+
strapi.log.error("[magic-mail] Error sending message:", err);
|
|
415
|
+
ctx.throw(500, err.message || "Failed to send message");
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
/**
|
|
419
|
+
* Send WhatsApp message
|
|
420
|
+
* POST /api/magic-mail/send-whatsapp
|
|
421
|
+
* Body: { phoneNumber, message, templateId?, templateData? }
|
|
422
|
+
*/
|
|
423
|
+
async sendWhatsApp(ctx) {
|
|
424
|
+
try {
|
|
425
|
+
const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
|
|
426
|
+
const result = await emailRouter2.sendWhatsApp(ctx.request.body);
|
|
427
|
+
ctx.body = {
|
|
428
|
+
success: true,
|
|
429
|
+
...result
|
|
430
|
+
};
|
|
431
|
+
} catch (err) {
|
|
432
|
+
strapi.log.error("[magic-mail] Error sending WhatsApp:", err);
|
|
433
|
+
ctx.throw(500, err.message || "Failed to send WhatsApp message");
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
/**
|
|
437
|
+
* Get WhatsApp connection status
|
|
438
|
+
* GET /api/magic-mail/whatsapp/status
|
|
439
|
+
*/
|
|
440
|
+
async getWhatsAppStatus(ctx) {
|
|
441
|
+
try {
|
|
442
|
+
const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
|
|
443
|
+
const status = emailRouter2.getWhatsAppStatus();
|
|
444
|
+
ctx.body = {
|
|
445
|
+
success: true,
|
|
446
|
+
data: status
|
|
447
|
+
};
|
|
448
|
+
} catch (err) {
|
|
449
|
+
strapi.log.error("[magic-mail] Error getting WhatsApp status:", err);
|
|
450
|
+
ctx.body = {
|
|
451
|
+
success: false,
|
|
452
|
+
data: {
|
|
453
|
+
isConnected: false,
|
|
454
|
+
status: "error",
|
|
455
|
+
error: err.message
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
/**
|
|
461
|
+
* Check if phone number is on WhatsApp
|
|
462
|
+
* GET /api/magic-mail/whatsapp/check/:phoneNumber
|
|
463
|
+
*/
|
|
464
|
+
async checkWhatsAppNumber(ctx) {
|
|
465
|
+
try {
|
|
466
|
+
const { phoneNumber } = ctx.params;
|
|
467
|
+
if (!phoneNumber) {
|
|
468
|
+
ctx.throw(400, "Phone number is required");
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const emailRouter2 = strapi.plugin("magic-mail").service("email-router");
|
|
472
|
+
const result = await emailRouter2.checkWhatsAppNumber(phoneNumber);
|
|
473
|
+
ctx.body = {
|
|
474
|
+
success: true,
|
|
475
|
+
data: result
|
|
476
|
+
};
|
|
477
|
+
} catch (err) {
|
|
478
|
+
strapi.log.error("[magic-mail] Error checking WhatsApp number:", err);
|
|
479
|
+
ctx.throw(500, err.message || "Failed to check phone number");
|
|
480
|
+
}
|
|
397
481
|
}
|
|
398
482
|
};
|
|
399
483
|
return controller;
|
|
@@ -512,7 +596,7 @@ function requireAccounts() {
|
|
|
512
596
|
if (!testEmail) {
|
|
513
597
|
ctx.throw(400, "testEmail is required");
|
|
514
598
|
}
|
|
515
|
-
strapi.log.info("[magic-mail]
|
|
599
|
+
strapi.log.info("[magic-mail] [TEST] Testing Strapi Email Service integration...");
|
|
516
600
|
strapi.log.info('[magic-mail] [EMAIL] Calling strapi.plugin("email").service("email").send()');
|
|
517
601
|
if (accountName) {
|
|
518
602
|
strapi.log.info(`[magic-mail] [FORCE] Forcing specific account: ${accountName}`);
|
|
@@ -2228,7 +2312,7 @@ function requireTest() {
|
|
|
2228
2312
|
async testRelations(ctx) {
|
|
2229
2313
|
try {
|
|
2230
2314
|
console.log("\n" + "=".repeat(60));
|
|
2231
|
-
console.log("
|
|
2315
|
+
console.log("[TEST] Template - Version Relations (Document Service API)");
|
|
2232
2316
|
console.log("=".repeat(60));
|
|
2233
2317
|
let test1Success = false;
|
|
2234
2318
|
let test1ReverseSuccess = false;
|
|
@@ -2396,7 +2480,7 @@ function requireTest() {
|
|
|
2396
2480
|
} else {
|
|
2397
2481
|
console.log(` [ERROR] FEHLER: Falsche Anzahl Versionen!`);
|
|
2398
2482
|
}
|
|
2399
|
-
console.log("\n
|
|
2483
|
+
console.log("\n[CLEANUP] Cleanup Test 3...");
|
|
2400
2484
|
if (afterSecondUpdate.versions) {
|
|
2401
2485
|
for (const version3 of afterSecondUpdate.versions) {
|
|
2402
2486
|
await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version3.documentId });
|
|
@@ -2414,7 +2498,7 @@ function requireTest() {
|
|
|
2414
2498
|
console.log(`
|
|
2415
2499
|
[INFO] Template: "${finalTemplate.name}" (documentId: ${finalTemplate.documentId})`);
|
|
2416
2500
|
console.log(` Anzahl Versionen: ${finalTemplate.versions?.length || 0}`);
|
|
2417
|
-
console.log("\n
|
|
2501
|
+
console.log("\n[CLEANUP] Aufraumen...");
|
|
2418
2502
|
await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version1.documentId });
|
|
2419
2503
|
await strapi.documents(EMAIL_TEMPLATE_VERSION_UID).delete({ documentId: version2.documentId });
|
|
2420
2504
|
await strapi.documents(EMAIL_TEMPLATE_UID).delete({ documentId: testTemplate.documentId });
|
|
@@ -2444,6 +2528,219 @@ function requireTest() {
|
|
|
2444
2528
|
};
|
|
2445
2529
|
return test;
|
|
2446
2530
|
}
|
|
2531
|
+
var whatsapp$1;
|
|
2532
|
+
var hasRequiredWhatsapp$1;
|
|
2533
|
+
function requireWhatsapp$1() {
|
|
2534
|
+
if (hasRequiredWhatsapp$1) return whatsapp$1;
|
|
2535
|
+
hasRequiredWhatsapp$1 = 1;
|
|
2536
|
+
whatsapp$1 = {
|
|
2537
|
+
/**
|
|
2538
|
+
* Check if WhatsApp/Baileys is available
|
|
2539
|
+
* GET /magic-mail/whatsapp/available
|
|
2540
|
+
*/
|
|
2541
|
+
async checkAvailable(ctx) {
|
|
2542
|
+
try {
|
|
2543
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2544
|
+
const available = await whatsappService.isAvailable();
|
|
2545
|
+
ctx.body = {
|
|
2546
|
+
success: true,
|
|
2547
|
+
data: {
|
|
2548
|
+
available,
|
|
2549
|
+
message: available ? "WhatsApp integration is available" : "Baileys not installed. Run: npm install @whiskeysockets/baileys pino qrcode"
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
} catch (error) {
|
|
2553
|
+
ctx.throw(500, error.message);
|
|
2554
|
+
}
|
|
2555
|
+
},
|
|
2556
|
+
/**
|
|
2557
|
+
* Get WhatsApp connection status
|
|
2558
|
+
* GET /magic-mail/whatsapp/status
|
|
2559
|
+
*/
|
|
2560
|
+
async getStatus(ctx) {
|
|
2561
|
+
try {
|
|
2562
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2563
|
+
const status = whatsappService.getStatus();
|
|
2564
|
+
const sessionInfo = await whatsappService.getSessionInfo();
|
|
2565
|
+
ctx.body = {
|
|
2566
|
+
success: true,
|
|
2567
|
+
data: {
|
|
2568
|
+
...status,
|
|
2569
|
+
session: sessionInfo
|
|
2570
|
+
}
|
|
2571
|
+
};
|
|
2572
|
+
} catch (error) {
|
|
2573
|
+
ctx.throw(500, error.message);
|
|
2574
|
+
}
|
|
2575
|
+
},
|
|
2576
|
+
/**
|
|
2577
|
+
* Connect to WhatsApp (generates QR code if needed)
|
|
2578
|
+
* POST /magic-mail/whatsapp/connect
|
|
2579
|
+
*/
|
|
2580
|
+
async connect(ctx) {
|
|
2581
|
+
try {
|
|
2582
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2583
|
+
const result = await whatsappService.connect();
|
|
2584
|
+
ctx.body = {
|
|
2585
|
+
success: result.success,
|
|
2586
|
+
data: result
|
|
2587
|
+
};
|
|
2588
|
+
} catch (error) {
|
|
2589
|
+
ctx.throw(500, error.message);
|
|
2590
|
+
}
|
|
2591
|
+
},
|
|
2592
|
+
/**
|
|
2593
|
+
* Disconnect from WhatsApp
|
|
2594
|
+
* POST /magic-mail/whatsapp/disconnect
|
|
2595
|
+
*/
|
|
2596
|
+
async disconnect(ctx) {
|
|
2597
|
+
try {
|
|
2598
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2599
|
+
const result = await whatsappService.disconnect();
|
|
2600
|
+
ctx.body = {
|
|
2601
|
+
success: result.success,
|
|
2602
|
+
data: result
|
|
2603
|
+
};
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
ctx.throw(500, error.message);
|
|
2606
|
+
}
|
|
2607
|
+
},
|
|
2608
|
+
/**
|
|
2609
|
+
* Send a test message
|
|
2610
|
+
* POST /magic-mail/whatsapp/send-test
|
|
2611
|
+
*/
|
|
2612
|
+
async sendTest(ctx) {
|
|
2613
|
+
try {
|
|
2614
|
+
const { phoneNumber, message } = ctx.request.body;
|
|
2615
|
+
if (!phoneNumber) {
|
|
2616
|
+
return ctx.badRequest("Phone number is required");
|
|
2617
|
+
}
|
|
2618
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2619
|
+
const testMessage = message || `[MagicMail Test] This is a test message sent at ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
|
|
2620
|
+
const result = await whatsappService.sendMessage(phoneNumber, testMessage);
|
|
2621
|
+
ctx.body = {
|
|
2622
|
+
success: result.success,
|
|
2623
|
+
data: result
|
|
2624
|
+
};
|
|
2625
|
+
} catch (error) {
|
|
2626
|
+
ctx.throw(500, error.message);
|
|
2627
|
+
}
|
|
2628
|
+
},
|
|
2629
|
+
/**
|
|
2630
|
+
* Send a message using a template
|
|
2631
|
+
* POST /magic-mail/whatsapp/send-template
|
|
2632
|
+
*/
|
|
2633
|
+
async sendTemplateMessage(ctx) {
|
|
2634
|
+
try {
|
|
2635
|
+
const { phoneNumber, templateName, variables } = ctx.request.body;
|
|
2636
|
+
if (!phoneNumber || !templateName) {
|
|
2637
|
+
return ctx.badRequest("Phone number and template name are required");
|
|
2638
|
+
}
|
|
2639
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2640
|
+
const result = await whatsappService.sendTemplateMessage(phoneNumber, templateName, variables || {});
|
|
2641
|
+
ctx.body = {
|
|
2642
|
+
success: result.success,
|
|
2643
|
+
data: result
|
|
2644
|
+
};
|
|
2645
|
+
} catch (error) {
|
|
2646
|
+
ctx.throw(500, error.message);
|
|
2647
|
+
}
|
|
2648
|
+
},
|
|
2649
|
+
/**
|
|
2650
|
+
* Check if a phone number is on WhatsApp
|
|
2651
|
+
* POST /magic-mail/whatsapp/check-number
|
|
2652
|
+
*/
|
|
2653
|
+
async checkNumber(ctx) {
|
|
2654
|
+
try {
|
|
2655
|
+
const { phoneNumber } = ctx.request.body;
|
|
2656
|
+
if (!phoneNumber) {
|
|
2657
|
+
return ctx.badRequest("Phone number is required");
|
|
2658
|
+
}
|
|
2659
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2660
|
+
const result = await whatsappService.checkNumber(phoneNumber);
|
|
2661
|
+
ctx.body = {
|
|
2662
|
+
success: result.success,
|
|
2663
|
+
data: result
|
|
2664
|
+
};
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
ctx.throw(500, error.message);
|
|
2667
|
+
}
|
|
2668
|
+
},
|
|
2669
|
+
/**
|
|
2670
|
+
* Get all WhatsApp templates
|
|
2671
|
+
* GET /magic-mail/whatsapp/templates
|
|
2672
|
+
*/
|
|
2673
|
+
async getTemplates(ctx) {
|
|
2674
|
+
try {
|
|
2675
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2676
|
+
const templates = await whatsappService.getTemplates();
|
|
2677
|
+
ctx.body = {
|
|
2678
|
+
success: true,
|
|
2679
|
+
data: templates
|
|
2680
|
+
};
|
|
2681
|
+
} catch (error) {
|
|
2682
|
+
ctx.throw(500, error.message);
|
|
2683
|
+
}
|
|
2684
|
+
},
|
|
2685
|
+
/**
|
|
2686
|
+
* Save a WhatsApp template
|
|
2687
|
+
* POST /magic-mail/whatsapp/templates
|
|
2688
|
+
*/
|
|
2689
|
+
async saveTemplate(ctx) {
|
|
2690
|
+
try {
|
|
2691
|
+
const { templateName, templateContent } = ctx.request.body;
|
|
2692
|
+
if (!templateName || !templateContent) {
|
|
2693
|
+
return ctx.badRequest("Template name and content are required");
|
|
2694
|
+
}
|
|
2695
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2696
|
+
const result = await whatsappService.saveTemplate(templateName, templateContent);
|
|
2697
|
+
ctx.body = {
|
|
2698
|
+
success: result.success,
|
|
2699
|
+
data: result
|
|
2700
|
+
};
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
ctx.throw(500, error.message);
|
|
2703
|
+
}
|
|
2704
|
+
},
|
|
2705
|
+
/**
|
|
2706
|
+
* Delete a WhatsApp template
|
|
2707
|
+
* DELETE /magic-mail/whatsapp/templates/:templateName
|
|
2708
|
+
*/
|
|
2709
|
+
async deleteTemplate(ctx) {
|
|
2710
|
+
try {
|
|
2711
|
+
const { templateName } = ctx.params;
|
|
2712
|
+
if (!templateName) {
|
|
2713
|
+
return ctx.badRequest("Template name is required");
|
|
2714
|
+
}
|
|
2715
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2716
|
+
const result = await whatsappService.deleteTemplate(templateName);
|
|
2717
|
+
ctx.body = {
|
|
2718
|
+
success: result.success,
|
|
2719
|
+
data: result
|
|
2720
|
+
};
|
|
2721
|
+
} catch (error) {
|
|
2722
|
+
ctx.throw(500, error.message);
|
|
2723
|
+
}
|
|
2724
|
+
},
|
|
2725
|
+
/**
|
|
2726
|
+
* Get session info
|
|
2727
|
+
* GET /magic-mail/whatsapp/session
|
|
2728
|
+
*/
|
|
2729
|
+
async getSession(ctx) {
|
|
2730
|
+
try {
|
|
2731
|
+
const whatsappService = strapi.plugin("magic-mail").service("whatsapp");
|
|
2732
|
+
const sessionInfo = await whatsappService.getSessionInfo();
|
|
2733
|
+
ctx.body = {
|
|
2734
|
+
success: true,
|
|
2735
|
+
data: sessionInfo
|
|
2736
|
+
};
|
|
2737
|
+
} catch (error) {
|
|
2738
|
+
ctx.throw(500, error.message);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
return whatsapp$1;
|
|
2743
|
+
}
|
|
2447
2744
|
var controllers;
|
|
2448
2745
|
var hasRequiredControllers;
|
|
2449
2746
|
function requireControllers() {
|
|
@@ -2457,6 +2754,7 @@ function requireControllers() {
|
|
|
2457
2754
|
const emailDesigner2 = requireEmailDesigner$1();
|
|
2458
2755
|
const analytics2 = requireAnalytics$1();
|
|
2459
2756
|
const test2 = requireTest();
|
|
2757
|
+
const whatsapp2 = requireWhatsapp$1();
|
|
2460
2758
|
controllers = {
|
|
2461
2759
|
controller: controller2,
|
|
2462
2760
|
accounts: accounts2,
|
|
@@ -2465,7 +2763,8 @@ function requireControllers() {
|
|
|
2465
2763
|
license: license2,
|
|
2466
2764
|
emailDesigner: emailDesigner2,
|
|
2467
2765
|
analytics: analytics2,
|
|
2468
|
-
test: test2
|
|
2766
|
+
test: test2,
|
|
2767
|
+
whatsapp: whatsapp2
|
|
2469
2768
|
};
|
|
2470
2769
|
return controllers;
|
|
2471
2770
|
}
|
|
@@ -2940,6 +3239,106 @@ function requireAdmin() {
|
|
|
2940
3239
|
policies: ["admin::isAuthenticatedAdmin"],
|
|
2941
3240
|
description: "Test template-version relations"
|
|
2942
3241
|
}
|
|
3242
|
+
},
|
|
3243
|
+
// WhatsApp Routes
|
|
3244
|
+
{
|
|
3245
|
+
method: "GET",
|
|
3246
|
+
path: "/whatsapp/available",
|
|
3247
|
+
handler: "whatsapp.checkAvailable",
|
|
3248
|
+
config: {
|
|
3249
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3250
|
+
description: "Check if WhatsApp/Baileys is available"
|
|
3251
|
+
}
|
|
3252
|
+
},
|
|
3253
|
+
{
|
|
3254
|
+
method: "GET",
|
|
3255
|
+
path: "/whatsapp/status",
|
|
3256
|
+
handler: "whatsapp.getStatus",
|
|
3257
|
+
config: {
|
|
3258
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3259
|
+
description: "Get WhatsApp connection status"
|
|
3260
|
+
}
|
|
3261
|
+
},
|
|
3262
|
+
{
|
|
3263
|
+
method: "POST",
|
|
3264
|
+
path: "/whatsapp/connect",
|
|
3265
|
+
handler: "whatsapp.connect",
|
|
3266
|
+
config: {
|
|
3267
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3268
|
+
description: "Connect to WhatsApp (generates QR if needed)"
|
|
3269
|
+
}
|
|
3270
|
+
},
|
|
3271
|
+
{
|
|
3272
|
+
method: "POST",
|
|
3273
|
+
path: "/whatsapp/disconnect",
|
|
3274
|
+
handler: "whatsapp.disconnect",
|
|
3275
|
+
config: {
|
|
3276
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3277
|
+
description: "Disconnect from WhatsApp"
|
|
3278
|
+
}
|
|
3279
|
+
},
|
|
3280
|
+
{
|
|
3281
|
+
method: "POST",
|
|
3282
|
+
path: "/whatsapp/send-test",
|
|
3283
|
+
handler: "whatsapp.sendTest",
|
|
3284
|
+
config: {
|
|
3285
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3286
|
+
description: "Send a test WhatsApp message"
|
|
3287
|
+
}
|
|
3288
|
+
},
|
|
3289
|
+
{
|
|
3290
|
+
method: "POST",
|
|
3291
|
+
path: "/whatsapp/send-template",
|
|
3292
|
+
handler: "whatsapp.sendTemplateMessage",
|
|
3293
|
+
config: {
|
|
3294
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3295
|
+
description: "Send WhatsApp message using template"
|
|
3296
|
+
}
|
|
3297
|
+
},
|
|
3298
|
+
{
|
|
3299
|
+
method: "POST",
|
|
3300
|
+
path: "/whatsapp/check-number",
|
|
3301
|
+
handler: "whatsapp.checkNumber",
|
|
3302
|
+
config: {
|
|
3303
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3304
|
+
description: "Check if phone number is on WhatsApp"
|
|
3305
|
+
}
|
|
3306
|
+
},
|
|
3307
|
+
{
|
|
3308
|
+
method: "GET",
|
|
3309
|
+
path: "/whatsapp/templates",
|
|
3310
|
+
handler: "whatsapp.getTemplates",
|
|
3311
|
+
config: {
|
|
3312
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3313
|
+
description: "Get all WhatsApp message templates"
|
|
3314
|
+
}
|
|
3315
|
+
},
|
|
3316
|
+
{
|
|
3317
|
+
method: "POST",
|
|
3318
|
+
path: "/whatsapp/templates",
|
|
3319
|
+
handler: "whatsapp.saveTemplate",
|
|
3320
|
+
config: {
|
|
3321
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3322
|
+
description: "Save a WhatsApp message template"
|
|
3323
|
+
}
|
|
3324
|
+
},
|
|
3325
|
+
{
|
|
3326
|
+
method: "DELETE",
|
|
3327
|
+
path: "/whatsapp/templates/:templateName",
|
|
3328
|
+
handler: "whatsapp.deleteTemplate",
|
|
3329
|
+
config: {
|
|
3330
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3331
|
+
description: "Delete a WhatsApp message template"
|
|
3332
|
+
}
|
|
3333
|
+
},
|
|
3334
|
+
{
|
|
3335
|
+
method: "GET",
|
|
3336
|
+
path: "/whatsapp/session",
|
|
3337
|
+
handler: "whatsapp.getSession",
|
|
3338
|
+
config: {
|
|
3339
|
+
policies: ["admin::isAuthenticatedAdmin"],
|
|
3340
|
+
description: "Get WhatsApp session info"
|
|
3341
|
+
}
|
|
2943
3342
|
}
|
|
2944
3343
|
]
|
|
2945
3344
|
};
|
|
@@ -2953,6 +3352,7 @@ function requireContentApi() {
|
|
|
2953
3352
|
contentApi = {
|
|
2954
3353
|
type: "content-api",
|
|
2955
3354
|
routes: [
|
|
3355
|
+
// ============= EMAIL ROUTES =============
|
|
2956
3356
|
{
|
|
2957
3357
|
method: "POST",
|
|
2958
3358
|
path: "/send",
|
|
@@ -2963,7 +3363,45 @@ function requireContentApi() {
|
|
|
2963
3363
|
description: "Send email via MagicMail router"
|
|
2964
3364
|
}
|
|
2965
3365
|
},
|
|
2966
|
-
//
|
|
3366
|
+
// ============= UNIFIED MESSAGE ROUTE =============
|
|
3367
|
+
{
|
|
3368
|
+
method: "POST",
|
|
3369
|
+
path: "/send-message",
|
|
3370
|
+
handler: "controller.sendMessage",
|
|
3371
|
+
config: {
|
|
3372
|
+
auth: false,
|
|
3373
|
+
description: "Send message via Email or WhatsApp (unified API)"
|
|
3374
|
+
}
|
|
3375
|
+
},
|
|
3376
|
+
// ============= WHATSAPP ROUTES =============
|
|
3377
|
+
{
|
|
3378
|
+
method: "POST",
|
|
3379
|
+
path: "/send-whatsapp",
|
|
3380
|
+
handler: "controller.sendWhatsApp",
|
|
3381
|
+
config: {
|
|
3382
|
+
auth: false,
|
|
3383
|
+
description: "Send WhatsApp message"
|
|
3384
|
+
}
|
|
3385
|
+
},
|
|
3386
|
+
{
|
|
3387
|
+
method: "GET",
|
|
3388
|
+
path: "/whatsapp/status",
|
|
3389
|
+
handler: "controller.getWhatsAppStatus",
|
|
3390
|
+
config: {
|
|
3391
|
+
auth: false,
|
|
3392
|
+
description: "Get WhatsApp connection status"
|
|
3393
|
+
}
|
|
3394
|
+
},
|
|
3395
|
+
{
|
|
3396
|
+
method: "GET",
|
|
3397
|
+
path: "/whatsapp/check/:phoneNumber",
|
|
3398
|
+
handler: "controller.checkWhatsAppNumber",
|
|
3399
|
+
config: {
|
|
3400
|
+
auth: false,
|
|
3401
|
+
description: "Check if phone number is on WhatsApp"
|
|
3402
|
+
}
|
|
3403
|
+
},
|
|
3404
|
+
// ============= TRACKING ROUTES =============
|
|
2967
3405
|
{
|
|
2968
3406
|
method: "GET",
|
|
2969
3407
|
path: "/track/open/:emailId/:recipientHash",
|
|
@@ -3043,7 +3481,7 @@ function requireEncryption() {
|
|
|
3043
3481
|
let encrypted = cipher.update(jsonData, "utf8", "hex");
|
|
3044
3482
|
encrypted += cipher.final("hex");
|
|
3045
3483
|
const authTag = cipher.getAuthTag();
|
|
3046
|
-
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}
|
|
3484
|
+
return { encrypted: `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}` };
|
|
3047
3485
|
} catch (err) {
|
|
3048
3486
|
console.error("[magic-mail] Encryption failed:", err);
|
|
3049
3487
|
throw new Error("Failed to encrypt credentials");
|
|
@@ -3053,7 +3491,8 @@ function requireEncryption() {
|
|
|
3053
3491
|
if (!encryptedData) return null;
|
|
3054
3492
|
try {
|
|
3055
3493
|
const key = getEncryptionKey();
|
|
3056
|
-
const
|
|
3494
|
+
const encryptedString = typeof encryptedData === "object" && encryptedData.encrypted ? encryptedData.encrypted : encryptedData;
|
|
3495
|
+
const parts = encryptedString.split(":");
|
|
3057
3496
|
if (parts.length !== 3) {
|
|
3058
3497
|
throw new Error("Invalid encrypted data format");
|
|
3059
3498
|
}
|
|
@@ -3127,7 +3566,7 @@ function requireEmailRouter() {
|
|
|
3127
3566
|
let templateRecord = null;
|
|
3128
3567
|
if (emailData.templateReferenceId) {
|
|
3129
3568
|
resolvedTemplateReferenceId = String(emailData.templateReferenceId).trim();
|
|
3130
|
-
strapi2.log.info(`[magic-mail]
|
|
3569
|
+
strapi2.log.info(`[magic-mail] [TEMPLATE] Using provided templateReferenceId="${resolvedTemplateReferenceId}"`);
|
|
3131
3570
|
}
|
|
3132
3571
|
if (!resolvedTemplateReferenceId && templateId) {
|
|
3133
3572
|
const numericTemplateId = Number(templateId);
|
|
@@ -3147,7 +3586,7 @@ function requireEmailRouter() {
|
|
|
3147
3586
|
);
|
|
3148
3587
|
} else {
|
|
3149
3588
|
resolvedTemplateReferenceId = String(templateId).trim();
|
|
3150
|
-
strapi2.log.info(`[magic-mail]
|
|
3589
|
+
strapi2.log.info(`[magic-mail] [TEMPLATE] Treating templateId value as referenceId="${resolvedTemplateReferenceId}"`);
|
|
3151
3590
|
}
|
|
3152
3591
|
}
|
|
3153
3592
|
if (!resolvedTemplateReferenceId) {
|
|
@@ -3208,6 +3647,39 @@ function requireEmailRouter() {
|
|
|
3208
3647
|
emailData.html = html;
|
|
3209
3648
|
emailData.text = text;
|
|
3210
3649
|
emailData.subject = subject;
|
|
3650
|
+
let matchedRule = null;
|
|
3651
|
+
try {
|
|
3652
|
+
const allRules = await strapi2.documents("plugin::magic-mail.routing-rule").findMany({
|
|
3653
|
+
filters: { isActive: true },
|
|
3654
|
+
sort: [{ priority: "desc" }]
|
|
3655
|
+
});
|
|
3656
|
+
for (const rule of allRules) {
|
|
3657
|
+
let matches = false;
|
|
3658
|
+
switch (rule.matchType) {
|
|
3659
|
+
case "emailType":
|
|
3660
|
+
matches = rule.matchValue === type;
|
|
3661
|
+
break;
|
|
3662
|
+
case "recipient":
|
|
3663
|
+
matches = to && to.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
3664
|
+
break;
|
|
3665
|
+
case "subject":
|
|
3666
|
+
matches = subject && subject.toLowerCase().includes(rule.matchValue.toLowerCase());
|
|
3667
|
+
break;
|
|
3668
|
+
case "template":
|
|
3669
|
+
matches = emailData.template && emailData.template === rule.matchValue;
|
|
3670
|
+
break;
|
|
3671
|
+
case "custom":
|
|
3672
|
+
matches = emailData.customField && emailData.customField === rule.matchValue;
|
|
3673
|
+
break;
|
|
3674
|
+
}
|
|
3675
|
+
if (matches) {
|
|
3676
|
+
matchedRule = rule;
|
|
3677
|
+
break;
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
} catch (ruleError) {
|
|
3681
|
+
strapi2.log.warn("[magic-mail] [WARNING] Failed to check routing rules for WhatsApp fallback:", ruleError.message);
|
|
3682
|
+
}
|
|
3211
3683
|
try {
|
|
3212
3684
|
const licenseGuard2 = strapi2.plugin("magic-mail").service("license-guard");
|
|
3213
3685
|
if (priority === "high") {
|
|
@@ -3227,7 +3699,7 @@ function requireEmailRouter() {
|
|
|
3227
3699
|
}
|
|
3228
3700
|
const canSend = await this.checkRateLimits(account);
|
|
3229
3701
|
if (!canSend) {
|
|
3230
|
-
const fallbackAccount = await this.selectAccount(type, priority, [account.
|
|
3702
|
+
const fallbackAccount = await this.selectAccount(type, priority, [account.documentId], emailData);
|
|
3231
3703
|
if (fallbackAccount) {
|
|
3232
3704
|
strapi2.log.info(`[magic-mail] Rate limit hit on ${account.name}, using fallback: ${fallbackAccount.name}`);
|
|
3233
3705
|
return await this.sendViaAccount(fallbackAccount, emailData);
|
|
@@ -3258,18 +3730,56 @@ function requireEmailRouter() {
|
|
|
3258
3730
|
};
|
|
3259
3731
|
} catch (error) {
|
|
3260
3732
|
strapi2.log.error("[magic-mail] [ERROR] Email send failed:", error);
|
|
3733
|
+
if (matchedRule?.whatsappFallback) {
|
|
3734
|
+
strapi2.log.info("[magic-mail] [FALLBACK] Email failed, attempting WhatsApp fallback...");
|
|
3735
|
+
try {
|
|
3736
|
+
const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
|
|
3737
|
+
const whatsappStatus = whatsapp2.getStatus();
|
|
3738
|
+
if (whatsappStatus.isConnected) {
|
|
3739
|
+
const phoneNumber = emailData.phoneNumber || emailData.whatsappPhone;
|
|
3740
|
+
if (phoneNumber) {
|
|
3741
|
+
const whatsappMessage = `*${subject}*
|
|
3742
|
+
|
|
3743
|
+
${text || "Email delivery failed. Please check your email settings."}`;
|
|
3744
|
+
const waResult = await whatsapp2.sendMessage(phoneNumber, whatsappMessage);
|
|
3745
|
+
if (waResult.success) {
|
|
3746
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp fallback sent to ${phoneNumber}`);
|
|
3747
|
+
return {
|
|
3748
|
+
success: true,
|
|
3749
|
+
fallbackUsed: "whatsapp",
|
|
3750
|
+
phoneNumber
|
|
3751
|
+
};
|
|
3752
|
+
} else {
|
|
3753
|
+
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback failed:", waResult.error);
|
|
3754
|
+
}
|
|
3755
|
+
} else {
|
|
3756
|
+
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but no phone number provided");
|
|
3757
|
+
}
|
|
3758
|
+
} else {
|
|
3759
|
+
strapi2.log.warn("[magic-mail] [WARNING] WhatsApp fallback enabled but WhatsApp not connected");
|
|
3760
|
+
}
|
|
3761
|
+
} catch (waError) {
|
|
3762
|
+
strapi2.log.error("[magic-mail] [ERROR] WhatsApp fallback error:", waError.message);
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3261
3765
|
throw error;
|
|
3262
3766
|
}
|
|
3263
3767
|
},
|
|
3264
3768
|
/**
|
|
3265
3769
|
* Select best account based on rules
|
|
3770
|
+
* @param {string} type - Email type (transactional, marketing, notification)
|
|
3771
|
+
* @param {string} priority - Priority level (high, normal, low)
|
|
3772
|
+
* @param {Array<string>} excludeDocumentIds - Array of documentIds to exclude from selection
|
|
3773
|
+
* @param {Object} emailData - Email data for routing rule matching
|
|
3774
|
+
* @returns {Promise<Object|null>} Selected account or null
|
|
3266
3775
|
*/
|
|
3267
|
-
async selectAccount(type, priority,
|
|
3776
|
+
async selectAccount(type, priority, excludeDocumentIds = [], emailData = {}) {
|
|
3777
|
+
const filters = { isActive: true };
|
|
3778
|
+
if (excludeDocumentIds.length > 0) {
|
|
3779
|
+
filters.documentId = { $notIn: excludeDocumentIds };
|
|
3780
|
+
}
|
|
3268
3781
|
const accounts2 = await strapi2.documents("plugin::magic-mail.email-account").findMany({
|
|
3269
|
-
filters
|
|
3270
|
-
isActive: true,
|
|
3271
|
-
id: { $notIn: excludeIds }
|
|
3272
|
-
},
|
|
3782
|
+
filters,
|
|
3273
3783
|
sort: [{ priority: "desc" }]
|
|
3274
3784
|
});
|
|
3275
3785
|
if (!accounts2 || accounts2.length === 0) {
|
|
@@ -4166,6 +4676,168 @@ function requireEmailRouter() {
|
|
|
4166
4676
|
...headers
|
|
4167
4677
|
}
|
|
4168
4678
|
};
|
|
4679
|
+
},
|
|
4680
|
+
// ============================================================================
|
|
4681
|
+
// UNIFIED MESSAGE API - Send via Email OR WhatsApp
|
|
4682
|
+
// ============================================================================
|
|
4683
|
+
/**
|
|
4684
|
+
* Send a message via WhatsApp
|
|
4685
|
+
* Same pattern as send() but for WhatsApp
|
|
4686
|
+
* @param {Object} messageData - { phoneNumber, message, templateId, templateData }
|
|
4687
|
+
* @returns {Promise<Object>} Send result
|
|
4688
|
+
*/
|
|
4689
|
+
async sendWhatsApp(messageData) {
|
|
4690
|
+
const {
|
|
4691
|
+
phoneNumber,
|
|
4692
|
+
message,
|
|
4693
|
+
templateId = null,
|
|
4694
|
+
templateData = {}
|
|
4695
|
+
} = messageData;
|
|
4696
|
+
if (!phoneNumber) {
|
|
4697
|
+
throw new Error("Phone number is required for WhatsApp messages");
|
|
4698
|
+
}
|
|
4699
|
+
const cleanPhone = phoneNumber.replace(/[^\d]/g, "");
|
|
4700
|
+
if (cleanPhone.length < 10) {
|
|
4701
|
+
throw new Error("Invalid phone number format. Use format: 491234567890 (country code + number)");
|
|
4702
|
+
}
|
|
4703
|
+
const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
|
|
4704
|
+
const status = whatsapp2.getStatus();
|
|
4705
|
+
if (!status.isConnected) {
|
|
4706
|
+
throw new Error("WhatsApp is not connected. Please connect WhatsApp first in the admin panel.");
|
|
4707
|
+
}
|
|
4708
|
+
let finalMessage = message;
|
|
4709
|
+
if (templateId) {
|
|
4710
|
+
try {
|
|
4711
|
+
const template = await whatsapp2.getTemplate(templateId);
|
|
4712
|
+
if (template) {
|
|
4713
|
+
finalMessage = template.content;
|
|
4714
|
+
Object.keys(templateData).forEach((key) => {
|
|
4715
|
+
finalMessage = finalMessage.replace(new RegExp(`{{${key}}}`, "g"), templateData[key]);
|
|
4716
|
+
});
|
|
4717
|
+
}
|
|
4718
|
+
} catch (error) {
|
|
4719
|
+
strapi2.log.warn(`[magic-mail] WhatsApp template ${templateId} not found, using plain message`);
|
|
4720
|
+
}
|
|
4721
|
+
}
|
|
4722
|
+
if (!finalMessage) {
|
|
4723
|
+
throw new Error("Message content is required");
|
|
4724
|
+
}
|
|
4725
|
+
strapi2.log.info(`[magic-mail] [WHATSAPP] Sending message to ${cleanPhone}`);
|
|
4726
|
+
const result = await whatsapp2.sendMessage(cleanPhone, finalMessage);
|
|
4727
|
+
if (result.success) {
|
|
4728
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] WhatsApp message sent to ${cleanPhone}`);
|
|
4729
|
+
return {
|
|
4730
|
+
success: true,
|
|
4731
|
+
channel: "whatsapp",
|
|
4732
|
+
phoneNumber: cleanPhone,
|
|
4733
|
+
jid: result.jid
|
|
4734
|
+
};
|
|
4735
|
+
} else {
|
|
4736
|
+
strapi2.log.error(`[magic-mail] [ERROR] WhatsApp send failed: ${result.error}`);
|
|
4737
|
+
throw new Error(result.error || "Failed to send WhatsApp message");
|
|
4738
|
+
}
|
|
4739
|
+
},
|
|
4740
|
+
/**
|
|
4741
|
+
* Unified send method - automatically chooses Email or WhatsApp
|
|
4742
|
+
* @param {Object} messageData - Combined email and WhatsApp data
|
|
4743
|
+
* @param {string} messageData.channel - 'email' | 'whatsapp' | 'auto' (default: 'auto')
|
|
4744
|
+
* @param {string} messageData.to - Email address (for email channel)
|
|
4745
|
+
* @param {string} messageData.phoneNumber - Phone number (for whatsapp channel)
|
|
4746
|
+
* @param {string} messageData.subject - Email subject
|
|
4747
|
+
* @param {string} messageData.message - Plain text message (used for WhatsApp, or as email text)
|
|
4748
|
+
* @param {string} messageData.html - HTML content (email only)
|
|
4749
|
+
* @param {string} messageData.templateId - Template ID (works for both channels)
|
|
4750
|
+
* @param {Object} messageData.templateData - Template variables
|
|
4751
|
+
* @returns {Promise<Object>} Send result with channel info
|
|
4752
|
+
*/
|
|
4753
|
+
async sendMessage(messageData) {
|
|
4754
|
+
const {
|
|
4755
|
+
channel = "auto",
|
|
4756
|
+
to,
|
|
4757
|
+
phoneNumber,
|
|
4758
|
+
subject,
|
|
4759
|
+
message,
|
|
4760
|
+
text,
|
|
4761
|
+
html,
|
|
4762
|
+
templateId,
|
|
4763
|
+
templateData,
|
|
4764
|
+
...rest
|
|
4765
|
+
} = messageData;
|
|
4766
|
+
let useChannel = channel;
|
|
4767
|
+
if (channel === "auto") {
|
|
4768
|
+
if (to && to.includes("@")) {
|
|
4769
|
+
useChannel = "email";
|
|
4770
|
+
} else if (phoneNumber) {
|
|
4771
|
+
useChannel = "whatsapp";
|
|
4772
|
+
} else {
|
|
4773
|
+
throw new Error("Either email (to) or phoneNumber is required");
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
strapi2.log.info(`[magic-mail] [SEND] Channel: ${useChannel}, to: ${to || phoneNumber}`);
|
|
4777
|
+
if (useChannel === "whatsapp") {
|
|
4778
|
+
if (!phoneNumber) {
|
|
4779
|
+
throw new Error("Phone number is required for WhatsApp channel");
|
|
4780
|
+
}
|
|
4781
|
+
return await this.sendWhatsApp({
|
|
4782
|
+
phoneNumber,
|
|
4783
|
+
message: message || text || subject,
|
|
4784
|
+
// Use message, fallback to text or subject
|
|
4785
|
+
templateId,
|
|
4786
|
+
templateData
|
|
4787
|
+
});
|
|
4788
|
+
} else {
|
|
4789
|
+
if (!to) {
|
|
4790
|
+
throw new Error("Email address (to) is required for email channel");
|
|
4791
|
+
}
|
|
4792
|
+
const result = await this.send({
|
|
4793
|
+
to,
|
|
4794
|
+
subject,
|
|
4795
|
+
text: text || message,
|
|
4796
|
+
html,
|
|
4797
|
+
templateId,
|
|
4798
|
+
templateData,
|
|
4799
|
+
phoneNumber,
|
|
4800
|
+
// Pass for WhatsApp fallback
|
|
4801
|
+
...rest
|
|
4802
|
+
});
|
|
4803
|
+
return {
|
|
4804
|
+
...result,
|
|
4805
|
+
channel: "email"
|
|
4806
|
+
};
|
|
4807
|
+
}
|
|
4808
|
+
},
|
|
4809
|
+
/**
|
|
4810
|
+
* Check WhatsApp connection status
|
|
4811
|
+
* @returns {Object} Connection status
|
|
4812
|
+
*/
|
|
4813
|
+
getWhatsAppStatus() {
|
|
4814
|
+
try {
|
|
4815
|
+
const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
|
|
4816
|
+
return whatsapp2.getStatus();
|
|
4817
|
+
} catch (error) {
|
|
4818
|
+
return {
|
|
4819
|
+
isConnected: false,
|
|
4820
|
+
status: "unavailable",
|
|
4821
|
+
error: error.message
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
},
|
|
4825
|
+
/**
|
|
4826
|
+
* Check if a phone number is registered on WhatsApp
|
|
4827
|
+
* @param {string} phoneNumber - Phone number to check
|
|
4828
|
+
* @returns {Promise<Object>} Check result
|
|
4829
|
+
*/
|
|
4830
|
+
async checkWhatsAppNumber(phoneNumber) {
|
|
4831
|
+
try {
|
|
4832
|
+
const whatsapp2 = strapi2.plugin("magic-mail").service("whatsapp");
|
|
4833
|
+
return await whatsapp2.checkNumber(phoneNumber);
|
|
4834
|
+
} catch (error) {
|
|
4835
|
+
return {
|
|
4836
|
+
success: false,
|
|
4837
|
+
exists: false,
|
|
4838
|
+
error: error.message
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4169
4841
|
}
|
|
4170
4842
|
});
|
|
4171
4843
|
return emailRouter;
|
|
@@ -4862,7 +5534,7 @@ function requireOauth() {
|
|
|
4862
5534
|
});
|
|
4863
5535
|
return oauth;
|
|
4864
5536
|
}
|
|
4865
|
-
const version = "2.
|
|
5537
|
+
const version = "2.3.0";
|
|
4866
5538
|
const require$$2 = {
|
|
4867
5539
|
version
|
|
4868
5540
|
};
|
|
@@ -6030,7 +6702,7 @@ function requireAnalytics() {
|
|
|
6030
6702
|
const randomToken = crypto.randomBytes(8).toString("hex");
|
|
6031
6703
|
const trackingUrl = `${baseUrl}/api/magic-mail/track/open/${emailId}/${recipientHash}?r=${randomToken}`;
|
|
6032
6704
|
const trackingPixel = `<img src="${trackingUrl}" width="1" height="1" style="display:none;" alt="" />`;
|
|
6033
|
-
strapi2.log.info(`[magic-mail]
|
|
6705
|
+
strapi2.log.info(`[magic-mail] [PIXEL] Tracking pixel URL: ${trackingUrl}`);
|
|
6034
6706
|
if (html.includes("</body>")) {
|
|
6035
6707
|
return html.replace("</body>", `${trackingPixel}</body>`);
|
|
6036
6708
|
}
|
|
@@ -6166,6 +6838,434 @@ function requireAnalytics() {
|
|
|
6166
6838
|
});
|
|
6167
6839
|
return analytics;
|
|
6168
6840
|
}
|
|
6841
|
+
var whatsapp;
|
|
6842
|
+
var hasRequiredWhatsapp;
|
|
6843
|
+
function requireWhatsapp() {
|
|
6844
|
+
if (hasRequiredWhatsapp) return whatsapp;
|
|
6845
|
+
hasRequiredWhatsapp = 1;
|
|
6846
|
+
const path = require$$0$4;
|
|
6847
|
+
const fs = require$$1$3;
|
|
6848
|
+
let baileys = null;
|
|
6849
|
+
const loadBaileys = async () => {
|
|
6850
|
+
if (!baileys) {
|
|
6851
|
+
try {
|
|
6852
|
+
baileys = require("@whiskeysockets/baileys");
|
|
6853
|
+
if (process.env.DEBUG) {
|
|
6854
|
+
console.log("[MagicMail WhatsApp] Baileys loaded successfully");
|
|
6855
|
+
}
|
|
6856
|
+
return true;
|
|
6857
|
+
} catch (error) {
|
|
6858
|
+
console.warn("[MagicMail WhatsApp] Baileys not installed. WhatsApp features disabled.");
|
|
6859
|
+
console.warn("[MagicMail WhatsApp] Install with: npm install @whiskeysockets/baileys pino qrcode");
|
|
6860
|
+
return false;
|
|
6861
|
+
}
|
|
6862
|
+
}
|
|
6863
|
+
return true;
|
|
6864
|
+
};
|
|
6865
|
+
whatsapp = ({ strapi: strapi2 }) => {
|
|
6866
|
+
let sock = null;
|
|
6867
|
+
let qrCode = null;
|
|
6868
|
+
let connectionStatus = "disconnected";
|
|
6869
|
+
let lastError = null;
|
|
6870
|
+
let eventListeners = [];
|
|
6871
|
+
let wasConnectedBefore = false;
|
|
6872
|
+
let reconnectAttempts = 0;
|
|
6873
|
+
const MAX_RECONNECT_ATTEMPTS = 3;
|
|
6874
|
+
const isDebugEnabled = async () => {
|
|
6875
|
+
try {
|
|
6876
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
6877
|
+
const settings = await pluginStore.get({ key: "settings" });
|
|
6878
|
+
return settings?.whatsapp_debug === true;
|
|
6879
|
+
} catch {
|
|
6880
|
+
return false;
|
|
6881
|
+
}
|
|
6882
|
+
};
|
|
6883
|
+
const debugLog = async (message) => {
|
|
6884
|
+
if (await isDebugEnabled()) {
|
|
6885
|
+
strapi2.log.info(message);
|
|
6886
|
+
}
|
|
6887
|
+
};
|
|
6888
|
+
const getAuthPath = () => {
|
|
6889
|
+
const strapiRoot = strapi2.dirs?.app?.root || process.cwd();
|
|
6890
|
+
return path.join(strapiRoot, ".magicmail-whatsapp-auth");
|
|
6891
|
+
};
|
|
6892
|
+
const emit = (event, data) => {
|
|
6893
|
+
eventListeners.forEach((listener) => {
|
|
6894
|
+
try {
|
|
6895
|
+
listener(event, data);
|
|
6896
|
+
} catch (e) {
|
|
6897
|
+
console.error("[MagicMail WhatsApp] Event listener error:", e);
|
|
6898
|
+
}
|
|
6899
|
+
});
|
|
6900
|
+
};
|
|
6901
|
+
const service = {
|
|
6902
|
+
/**
|
|
6903
|
+
* Check if Baileys is available
|
|
6904
|
+
* @returns {Promise<boolean>} True if Baileys is installed
|
|
6905
|
+
*/
|
|
6906
|
+
async isAvailable() {
|
|
6907
|
+
return await loadBaileys();
|
|
6908
|
+
},
|
|
6909
|
+
/**
|
|
6910
|
+
* Get current connection status
|
|
6911
|
+
* @returns {object} Status object with status, qrCode, lastError, isConnected
|
|
6912
|
+
*/
|
|
6913
|
+
getStatus() {
|
|
6914
|
+
return {
|
|
6915
|
+
status: connectionStatus,
|
|
6916
|
+
qrCode,
|
|
6917
|
+
lastError,
|
|
6918
|
+
isConnected: connectionStatus === "connected"
|
|
6919
|
+
};
|
|
6920
|
+
},
|
|
6921
|
+
/**
|
|
6922
|
+
* Add event listener for WhatsApp events
|
|
6923
|
+
* @param {function} callback - Callback function(event, data)
|
|
6924
|
+
* @returns {function} Unsubscribe function
|
|
6925
|
+
*/
|
|
6926
|
+
on(callback) {
|
|
6927
|
+
eventListeners.push(callback);
|
|
6928
|
+
return () => {
|
|
6929
|
+
eventListeners = eventListeners.filter((l) => l !== callback);
|
|
6930
|
+
};
|
|
6931
|
+
},
|
|
6932
|
+
/**
|
|
6933
|
+
* Initialize WhatsApp connection
|
|
6934
|
+
* @returns {Promise<object>} Connection result with success status
|
|
6935
|
+
*/
|
|
6936
|
+
async connect() {
|
|
6937
|
+
const available = await loadBaileys();
|
|
6938
|
+
if (!available) {
|
|
6939
|
+
lastError = "Baileys not installed. Run: npm install @whiskeysockets/baileys pino qrcode";
|
|
6940
|
+
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Baileys library not available");
|
|
6941
|
+
return { success: false, error: lastError };
|
|
6942
|
+
}
|
|
6943
|
+
if (sock && connectionStatus === "connected") {
|
|
6944
|
+
await debugLog("[MagicMail WhatsApp] Already connected");
|
|
6945
|
+
return { success: true, status: "already_connected" };
|
|
6946
|
+
}
|
|
6947
|
+
if (sock) {
|
|
6948
|
+
try {
|
|
6949
|
+
sock.end();
|
|
6950
|
+
} catch (e) {
|
|
6951
|
+
}
|
|
6952
|
+
sock = null;
|
|
6953
|
+
}
|
|
6954
|
+
return new Promise(async (resolve) => {
|
|
6955
|
+
try {
|
|
6956
|
+
connectionStatus = "connecting";
|
|
6957
|
+
emit("status", { status: connectionStatus });
|
|
6958
|
+
await debugLog("[MagicMail WhatsApp] Starting connection...");
|
|
6959
|
+
const authPath = getAuthPath();
|
|
6960
|
+
if (!fs.existsSync(authPath)) {
|
|
6961
|
+
fs.mkdirSync(authPath, { recursive: true });
|
|
6962
|
+
}
|
|
6963
|
+
await debugLog(`[MagicMail WhatsApp] Auth path: ${authPath}`);
|
|
6964
|
+
const { state, saveCreds } = await baileys.useMultiFileAuthState(authPath);
|
|
6965
|
+
await debugLog("[MagicMail WhatsApp] Auth state loaded");
|
|
6966
|
+
const pino = require("pino");
|
|
6967
|
+
const logger2 = pino({ level: "silent" });
|
|
6968
|
+
await debugLog("[MagicMail WhatsApp] Creating WhatsApp socket...");
|
|
6969
|
+
const makeSocket = baileys.default || baileys.makeWASocket;
|
|
6970
|
+
const browserConfig = baileys.Browsers.ubuntu("Chrome");
|
|
6971
|
+
await debugLog(`[MagicMail WhatsApp] Browser config: ${JSON.stringify(browserConfig)}`);
|
|
6972
|
+
sock = makeSocket({
|
|
6973
|
+
auth: state,
|
|
6974
|
+
logger: logger2,
|
|
6975
|
+
browser: browserConfig,
|
|
6976
|
+
syncFullHistory: false,
|
|
6977
|
+
markOnlineOnConnect: false,
|
|
6978
|
+
generateHighQualityLinkPreview: false,
|
|
6979
|
+
getMessage: async (key) => {
|
|
6980
|
+
return { conversation: "" };
|
|
6981
|
+
}
|
|
6982
|
+
});
|
|
6983
|
+
await debugLog("[MagicMail WhatsApp] Socket created, registering event handlers...");
|
|
6984
|
+
let resolved = false;
|
|
6985
|
+
const resolveOnce = (result) => {
|
|
6986
|
+
if (!resolved) {
|
|
6987
|
+
resolved = true;
|
|
6988
|
+
resolve(result);
|
|
6989
|
+
}
|
|
6990
|
+
};
|
|
6991
|
+
setTimeout(() => {
|
|
6992
|
+
if (!resolved) {
|
|
6993
|
+
strapi2.log.warn("[MagicMail WhatsApp] Connection timeout - no QR or connection");
|
|
6994
|
+
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
6995
|
+
}
|
|
6996
|
+
}, 3e4);
|
|
6997
|
+
sock.ev.on("connection.update", async (update) => {
|
|
6998
|
+
await debugLog(`[MagicMail WhatsApp] connection.update: ${JSON.stringify(update)}`);
|
|
6999
|
+
const { connection, lastDisconnect, qr } = update;
|
|
7000
|
+
if (qr) {
|
|
7001
|
+
await debugLog("[MagicMail WhatsApp] QR code received");
|
|
7002
|
+
try {
|
|
7003
|
+
const QRCode = require("qrcode");
|
|
7004
|
+
qrCode = await QRCode.toDataURL(qr);
|
|
7005
|
+
connectionStatus = "qr_pending";
|
|
7006
|
+
emit("qr", { qrCode });
|
|
7007
|
+
emit("status", { status: connectionStatus });
|
|
7008
|
+
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] QR Code generated - scan with WhatsApp");
|
|
7009
|
+
resolveOnce({ success: true, status: connectionStatus, qrCode });
|
|
7010
|
+
} catch (qrError) {
|
|
7011
|
+
strapi2.log.error("[MagicMail WhatsApp] QR generation error:", qrError.message);
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
if (connection === "close") {
|
|
7015
|
+
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
7016
|
+
const isLoggedOut = statusCode === baileys.DisconnectReason.loggedOut;
|
|
7017
|
+
const isRestartRequired = statusCode === baileys.DisconnectReason.restartRequired;
|
|
7018
|
+
const isConnectionFailure = statusCode === 405;
|
|
7019
|
+
await debugLog(`[MagicMail WhatsApp] Connection closed - statusCode: ${statusCode}`);
|
|
7020
|
+
if (isLoggedOut) {
|
|
7021
|
+
connectionStatus = "disconnected";
|
|
7022
|
+
lastError = "Logged out from WhatsApp";
|
|
7023
|
+
qrCode = null;
|
|
7024
|
+
wasConnectedBefore = false;
|
|
7025
|
+
reconnectAttempts = 0;
|
|
7026
|
+
try {
|
|
7027
|
+
fs.rmSync(authPath, { recursive: true, force: true });
|
|
7028
|
+
} catch (e) {
|
|
7029
|
+
}
|
|
7030
|
+
strapi2.log.warn("[MagicMail WhatsApp] Logged out - auth cleared");
|
|
7031
|
+
} else if (isRestartRequired) {
|
|
7032
|
+
await debugLog("[MagicMail WhatsApp] Restart required - reconnecting...");
|
|
7033
|
+
connectionStatus = "connecting";
|
|
7034
|
+
setTimeout(() => {
|
|
7035
|
+
service.connect();
|
|
7036
|
+
}, 1e3);
|
|
7037
|
+
} else if (isConnectionFailure && reconnectAttempts < 2) {
|
|
7038
|
+
reconnectAttempts++;
|
|
7039
|
+
await debugLog(`[MagicMail WhatsApp] Connection rejected (405) - retrying (${reconnectAttempts}/2)`);
|
|
7040
|
+
try {
|
|
7041
|
+
fs.rmSync(authPath, { recursive: true, force: true });
|
|
7042
|
+
} catch (e) {
|
|
7043
|
+
}
|
|
7044
|
+
connectionStatus = "disconnected";
|
|
7045
|
+
qrCode = null;
|
|
7046
|
+
setTimeout(() => {
|
|
7047
|
+
service.connect();
|
|
7048
|
+
}, 3e3);
|
|
7049
|
+
} else if (isConnectionFailure) {
|
|
7050
|
+
connectionStatus = "disconnected";
|
|
7051
|
+
lastError = "WhatsApp connection rejected (405). Please try again later.";
|
|
7052
|
+
strapi2.log.error("[MagicMail WhatsApp] [ERROR] Connection rejected after retries.");
|
|
7053
|
+
resolveOnce({ success: false, status: connectionStatus, error: lastError });
|
|
7054
|
+
} else if (wasConnectedBefore && reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
|
|
7055
|
+
reconnectAttempts++;
|
|
7056
|
+
connectionStatus = "connecting";
|
|
7057
|
+
await debugLog(`[MagicMail WhatsApp] Reconnecting (${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
|
|
7058
|
+
setTimeout(() => {
|
|
7059
|
+
service.connect();
|
|
7060
|
+
}, 3e3 * reconnectAttempts);
|
|
7061
|
+
} else if (!wasConnectedBefore) {
|
|
7062
|
+
connectionStatus = "disconnected";
|
|
7063
|
+
qrCode = null;
|
|
7064
|
+
await debugLog("[MagicMail WhatsApp] Connection closed - waiting for QR scan");
|
|
7065
|
+
} else {
|
|
7066
|
+
connectionStatus = "disconnected";
|
|
7067
|
+
lastError = "Max reconnect attempts reached";
|
|
7068
|
+
strapi2.log.warn("[MagicMail WhatsApp] Max reconnect attempts reached");
|
|
7069
|
+
}
|
|
7070
|
+
emit("status", { status: connectionStatus, error: lastError });
|
|
7071
|
+
}
|
|
7072
|
+
if (connection === "open") {
|
|
7073
|
+
connectionStatus = "connected";
|
|
7074
|
+
qrCode = null;
|
|
7075
|
+
lastError = null;
|
|
7076
|
+
wasConnectedBefore = true;
|
|
7077
|
+
reconnectAttempts = 0;
|
|
7078
|
+
emit("status", { status: connectionStatus });
|
|
7079
|
+
strapi2.log.info("[MagicMail WhatsApp] [SUCCESS] Connected successfully!");
|
|
7080
|
+
resolveOnce({ success: true, status: connectionStatus });
|
|
7081
|
+
}
|
|
7082
|
+
});
|
|
7083
|
+
sock.ev.on("creds.update", saveCreds);
|
|
7084
|
+
} catch (error) {
|
|
7085
|
+
lastError = error.message;
|
|
7086
|
+
connectionStatus = "disconnected";
|
|
7087
|
+
strapi2.log.error("[MagicMail WhatsApp] Connection error:", error);
|
|
7088
|
+
resolve({ success: false, error: error.message });
|
|
7089
|
+
}
|
|
7090
|
+
});
|
|
7091
|
+
},
|
|
7092
|
+
/**
|
|
7093
|
+
* Disconnect WhatsApp and clear session
|
|
7094
|
+
* @returns {Promise<object>} Result with success status
|
|
7095
|
+
*/
|
|
7096
|
+
async disconnect() {
|
|
7097
|
+
if (sock) {
|
|
7098
|
+
try {
|
|
7099
|
+
await sock.logout();
|
|
7100
|
+
} catch (e) {
|
|
7101
|
+
}
|
|
7102
|
+
sock = null;
|
|
7103
|
+
}
|
|
7104
|
+
connectionStatus = "disconnected";
|
|
7105
|
+
qrCode = null;
|
|
7106
|
+
emit("status", { status: connectionStatus });
|
|
7107
|
+
strapi2.log.info("[MagicMail WhatsApp] Disconnected");
|
|
7108
|
+
return { success: true };
|
|
7109
|
+
},
|
|
7110
|
+
/**
|
|
7111
|
+
* Send a text message to a phone number
|
|
7112
|
+
* @param {string} phoneNumber - Phone number with country code (e.g., "491234567890")
|
|
7113
|
+
* @param {string} message - Message text
|
|
7114
|
+
* @returns {Promise<object>} Result with success status
|
|
7115
|
+
*/
|
|
7116
|
+
async sendMessage(phoneNumber, message) {
|
|
7117
|
+
if (connectionStatus !== "connected" || !sock) {
|
|
7118
|
+
return {
|
|
7119
|
+
success: false,
|
|
7120
|
+
error: "WhatsApp not connected. Please connect first."
|
|
7121
|
+
};
|
|
7122
|
+
}
|
|
7123
|
+
try {
|
|
7124
|
+
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
7125
|
+
const jid = `${formattedNumber}@s.whatsapp.net`;
|
|
7126
|
+
const [exists] = await sock.onWhatsApp(formattedNumber);
|
|
7127
|
+
if (!exists?.exists) {
|
|
7128
|
+
return {
|
|
7129
|
+
success: false,
|
|
7130
|
+
error: `Phone number ${phoneNumber} is not registered on WhatsApp`
|
|
7131
|
+
};
|
|
7132
|
+
}
|
|
7133
|
+
await sock.sendMessage(jid, { text: message });
|
|
7134
|
+
await debugLog(`[MagicMail WhatsApp] Message sent to ${formattedNumber}`);
|
|
7135
|
+
return { success: true, jid };
|
|
7136
|
+
} catch (error) {
|
|
7137
|
+
strapi2.log.error("[MagicMail WhatsApp] Send error:", error);
|
|
7138
|
+
return { success: false, error: error.message };
|
|
7139
|
+
}
|
|
7140
|
+
},
|
|
7141
|
+
/**
|
|
7142
|
+
* Send message using a template
|
|
7143
|
+
* @param {string} phoneNumber - Phone number
|
|
7144
|
+
* @param {string} templateName - Template identifier
|
|
7145
|
+
* @param {object} variables - Template variables to replace
|
|
7146
|
+
* @returns {Promise<object>} Result with success status
|
|
7147
|
+
*/
|
|
7148
|
+
async sendTemplateMessage(phoneNumber, templateName, variables = {}) {
|
|
7149
|
+
try {
|
|
7150
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7151
|
+
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
7152
|
+
let template = templates[templateName];
|
|
7153
|
+
if (!template) {
|
|
7154
|
+
template = `*{{subject}}*
|
|
7155
|
+
|
|
7156
|
+
{{body}}`;
|
|
7157
|
+
}
|
|
7158
|
+
let message = template;
|
|
7159
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
7160
|
+
message = message.replace(new RegExp(`{{${key}}}`, "g"), value);
|
|
7161
|
+
}
|
|
7162
|
+
return this.sendMessage(phoneNumber, message);
|
|
7163
|
+
} catch (error) {
|
|
7164
|
+
return { success: false, error: error.message };
|
|
7165
|
+
}
|
|
7166
|
+
},
|
|
7167
|
+
/**
|
|
7168
|
+
* Check if a phone number is on WhatsApp
|
|
7169
|
+
* @param {string} phoneNumber - Phone number to check
|
|
7170
|
+
* @returns {Promise<object>} Result with exists boolean
|
|
7171
|
+
*/
|
|
7172
|
+
async checkNumber(phoneNumber) {
|
|
7173
|
+
if (connectionStatus !== "connected" || !sock) {
|
|
7174
|
+
return { success: false, error: "WhatsApp not connected" };
|
|
7175
|
+
}
|
|
7176
|
+
try {
|
|
7177
|
+
const formattedNumber = phoneNumber.replace(/[^\d]/g, "");
|
|
7178
|
+
const [result] = await sock.onWhatsApp(formattedNumber);
|
|
7179
|
+
return {
|
|
7180
|
+
success: true,
|
|
7181
|
+
exists: result?.exists || false,
|
|
7182
|
+
jid: result?.jid
|
|
7183
|
+
};
|
|
7184
|
+
} catch (error) {
|
|
7185
|
+
return { success: false, error: error.message };
|
|
7186
|
+
}
|
|
7187
|
+
},
|
|
7188
|
+
/**
|
|
7189
|
+
* Get session info
|
|
7190
|
+
* @returns {Promise<object|null>} Session info or null if not connected
|
|
7191
|
+
*/
|
|
7192
|
+
async getSessionInfo() {
|
|
7193
|
+
if (connectionStatus !== "connected" || !sock) {
|
|
7194
|
+
return null;
|
|
7195
|
+
}
|
|
7196
|
+
try {
|
|
7197
|
+
const user = sock.user;
|
|
7198
|
+
return {
|
|
7199
|
+
phoneNumber: user?.id?.split(":")[0] || user?.id?.split("@")[0],
|
|
7200
|
+
name: user?.name,
|
|
7201
|
+
platform: "WhatsApp Web"
|
|
7202
|
+
};
|
|
7203
|
+
} catch (error) {
|
|
7204
|
+
return null;
|
|
7205
|
+
}
|
|
7206
|
+
},
|
|
7207
|
+
/**
|
|
7208
|
+
* Reset connection state (for manual cleanup)
|
|
7209
|
+
*/
|
|
7210
|
+
reset() {
|
|
7211
|
+
sock = null;
|
|
7212
|
+
qrCode = null;
|
|
7213
|
+
connectionStatus = "disconnected";
|
|
7214
|
+
lastError = null;
|
|
7215
|
+
wasConnectedBefore = false;
|
|
7216
|
+
reconnectAttempts = 0;
|
|
7217
|
+
},
|
|
7218
|
+
/**
|
|
7219
|
+
* Save WhatsApp template
|
|
7220
|
+
* @param {string} templateName - Template identifier
|
|
7221
|
+
* @param {string} templateContent - Template content with {{variables}}
|
|
7222
|
+
* @returns {Promise<object>} Result with success status
|
|
7223
|
+
*/
|
|
7224
|
+
async saveTemplate(templateName, templateContent) {
|
|
7225
|
+
try {
|
|
7226
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7227
|
+
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
7228
|
+
templates[templateName] = templateContent;
|
|
7229
|
+
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
7230
|
+
return { success: true };
|
|
7231
|
+
} catch (error) {
|
|
7232
|
+
return { success: false, error: error.message };
|
|
7233
|
+
}
|
|
7234
|
+
},
|
|
7235
|
+
/**
|
|
7236
|
+
* Get all WhatsApp templates
|
|
7237
|
+
* @returns {Promise<object>} Templates object
|
|
7238
|
+
*/
|
|
7239
|
+
async getTemplates() {
|
|
7240
|
+
try {
|
|
7241
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7242
|
+
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
7243
|
+
return templates;
|
|
7244
|
+
} catch (error) {
|
|
7245
|
+
return {};
|
|
7246
|
+
}
|
|
7247
|
+
},
|
|
7248
|
+
/**
|
|
7249
|
+
* Delete a WhatsApp template
|
|
7250
|
+
* @param {string} templateName - Template identifier
|
|
7251
|
+
* @returns {Promise<object>} Result with success status
|
|
7252
|
+
*/
|
|
7253
|
+
async deleteTemplate(templateName) {
|
|
7254
|
+
try {
|
|
7255
|
+
const pluginStore = strapi2.store({ type: "plugin", name: "magic-mail" });
|
|
7256
|
+
const templates = await pluginStore.get({ key: "whatsapp_templates" }) || {};
|
|
7257
|
+
delete templates[templateName];
|
|
7258
|
+
await pluginStore.set({ key: "whatsapp_templates", value: templates });
|
|
7259
|
+
return { success: true };
|
|
7260
|
+
} catch (error) {
|
|
7261
|
+
return { success: false, error: error.message };
|
|
7262
|
+
}
|
|
7263
|
+
}
|
|
7264
|
+
};
|
|
7265
|
+
return service;
|
|
7266
|
+
};
|
|
7267
|
+
return whatsapp;
|
|
7268
|
+
}
|
|
6169
7269
|
var services;
|
|
6170
7270
|
var hasRequiredServices;
|
|
6171
7271
|
function requireServices() {
|
|
@@ -6177,13 +7277,15 @@ function requireServices() {
|
|
|
6177
7277
|
const licenseGuard2 = requireLicenseGuard();
|
|
6178
7278
|
const emailDesigner2 = requireEmailDesigner();
|
|
6179
7279
|
const analytics2 = requireAnalytics();
|
|
7280
|
+
const whatsapp2 = requireWhatsapp();
|
|
6180
7281
|
services = {
|
|
6181
7282
|
"email-router": emailRouter2,
|
|
6182
7283
|
"account-manager": accountManager2,
|
|
6183
7284
|
oauth: oauth2,
|
|
6184
7285
|
"license-guard": licenseGuard2,
|
|
6185
7286
|
"email-designer": emailDesigner2,
|
|
6186
|
-
analytics: analytics2
|
|
7287
|
+
analytics: analytics2,
|
|
7288
|
+
whatsapp: whatsapp2
|
|
6187
7289
|
};
|
|
6188
7290
|
return services;
|
|
6189
7291
|
}
|