185 lines
6.1 KiB
PHP
185 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Email;
|
|
|
|
use App\Http\Controllers\Api\BaseApiController;
|
|
use App\Services\BroadcastEmail\BroadcastEmailComposerService;
|
|
use App\Services\BroadcastEmail\BroadcastEmailDispatchService;
|
|
use App\Services\BroadcastEmail\BroadcastEmailImageService;
|
|
use App\Services\BroadcastEmail\BroadcastEmailRecipientService;
|
|
use App\Services\BroadcastEmail\BroadcastEmailSenderOptionsService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
|
|
class BroadcastEmailController extends BaseApiController
|
|
{
|
|
private BroadcastEmailSenderOptionsService $senderOptions;
|
|
private BroadcastEmailRecipientService $recipients;
|
|
private BroadcastEmailComposerService $composer;
|
|
private BroadcastEmailDispatchService $dispatch;
|
|
private BroadcastEmailImageService $imageService;
|
|
|
|
public function __construct(
|
|
BroadcastEmailSenderOptionsService $senderOptions,
|
|
BroadcastEmailRecipientService $recipients,
|
|
BroadcastEmailComposerService $composer,
|
|
BroadcastEmailDispatchService $dispatch,
|
|
BroadcastEmailImageService $imageService
|
|
) {
|
|
parent::__construct();
|
|
$this->senderOptions = $senderOptions;
|
|
$this->recipients = $recipients;
|
|
$this->composer = $composer;
|
|
$this->dispatch = $dispatch;
|
|
$this->imageService = $imageService;
|
|
}
|
|
|
|
public function options(): JsonResponse
|
|
{
|
|
return response()->json([
|
|
'ok' => true,
|
|
'parents' => $this->recipients->parentsWithEmails(),
|
|
'fromOptions' => $this->senderOptions->listOptions(),
|
|
]);
|
|
}
|
|
|
|
public function send(Request $request): JsonResponse
|
|
{
|
|
$mode = (string) ($request->input('mode') ?? 'standard');
|
|
$subject = trim((string) ($request->input('subject') ?? ''));
|
|
$fromKey = trim((string) ($request->input('from_key') ?? 'general'));
|
|
$body = (string) ($request->input('body_html') ?? '');
|
|
$wrapLayout = (bool) $request->boolean('wrap_layout');
|
|
$preheader = (string) ($request->input('preheader') ?? '');
|
|
$ctaText = (string) ($request->input('cta_text') ?? '');
|
|
$ctaUrl = (string) ($request->input('cta_url') ?? '');
|
|
$testEmail = trim((string) ($request->input('test_email') ?? ''));
|
|
$isTestOnly = (bool) $request->boolean('send_test_only');
|
|
|
|
$body = $this->composer->sanitizeHtml($body);
|
|
|
|
if ($subject === '' || $body === '') {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => 'Subject and Body are required.',
|
|
], 422);
|
|
}
|
|
|
|
$personalize = $mode === 'personalized';
|
|
|
|
if ($isTestOnly) {
|
|
if ($testEmail === '') {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => 'Provide a test email address.',
|
|
], 422);
|
|
}
|
|
|
|
$result = $this->dispatch->sendTest([
|
|
'wrap_layout' => $wrapLayout,
|
|
'subject' => $subject,
|
|
'body_html' => $body,
|
|
'recipient_name' => 'Parent',
|
|
'preheader' => $preheader,
|
|
'cta_text' => $ctaText,
|
|
'cta_url' => $ctaUrl,
|
|
'personalize' => $personalize,
|
|
'test_email' => $testEmail,
|
|
'from_key' => $fromKey,
|
|
]);
|
|
|
|
return response()->json($result, $result['ok'] ? 200 : 500);
|
|
}
|
|
|
|
$rawIds = $request->input('parent_ids', []);
|
|
$ids = $this->normalizeIds($rawIds);
|
|
|
|
if (empty($ids)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => 'Please select at least one parent.',
|
|
], 422);
|
|
}
|
|
|
|
$recipients = $this->recipients->recipientsByIds($ids);
|
|
|
|
if (empty($recipients)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => 'No valid parent emails found.',
|
|
], 422);
|
|
}
|
|
|
|
$stats = $this->dispatch->sendBroadcast([
|
|
'wrap_layout' => $wrapLayout,
|
|
'subject' => $subject,
|
|
'body_html' => $body,
|
|
'preheader' => $preheader,
|
|
'cta_text' => $ctaText,
|
|
'cta_url' => $ctaUrl,
|
|
'personalize' => $personalize,
|
|
'from_key' => $fromKey,
|
|
'mode' => $mode,
|
|
], $recipients);
|
|
|
|
$message = sprintf(
|
|
'Broadcast finished. Mode: %s. Sent: %d/%d. Failures: %d.',
|
|
$stats['mode'],
|
|
$stats['sent'],
|
|
$stats['attempted'],
|
|
$stats['failed']
|
|
);
|
|
|
|
return response()->json([
|
|
'ok' => $stats['failed'] === 0,
|
|
'stats' => $stats,
|
|
'message' => $message,
|
|
]);
|
|
}
|
|
|
|
public function uploadImage(Request $request): JsonResponse
|
|
{
|
|
$file = $request->file('image');
|
|
if (!$file || !$file->isValid()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'No image uploaded',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->imageService->store($file);
|
|
if (!$result['ok']) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => $result['error'] ?? 'Upload failed',
|
|
], $result['status'] ?? 400);
|
|
}
|
|
|
|
$newHash = function_exists('csrf_hash') ? csrf_hash() : csrf_token();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'url' => $result['url'],
|
|
'csrf_hash' => $newHash,
|
|
])->header('X-CSRF-HASH', (string) $newHash);
|
|
}
|
|
|
|
private function normalizeIds($rawIds): array
|
|
{
|
|
$ids = [];
|
|
$raw = is_array($rawIds) ? $rawIds : [$rawIds];
|
|
|
|
foreach ($raw as $value) {
|
|
if (is_string($value) && strpos($value, ',') !== false) {
|
|
foreach (explode(',', $value) as $piece) {
|
|
$ids[] = (int) $piece;
|
|
}
|
|
continue;
|
|
}
|
|
$ids[] = (int) $value;
|
|
}
|
|
|
|
return array_values(array_unique(array_filter($ids)));
|
|
}
|
|
}
|