add controllers, servoices
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\BroadcastEmail;
|
||||
|
||||
use Illuminate\Support\Facades\View;
|
||||
|
||||
class BroadcastEmailComposerService
|
||||
{
|
||||
public function sanitizeHtml(string $html): string
|
||||
{
|
||||
$html = preg_replace('#<(script|iframe)[^>]*>.*?</\\1>#is', '', $html);
|
||||
$html = preg_replace('/\\son\\w+="[^"]*"/i', '', $html);
|
||||
$html = preg_replace("/\\son\\w+='[^']*'/i", '', $html);
|
||||
return $html ?? '';
|
||||
}
|
||||
|
||||
public function compose(
|
||||
bool $wrapLayout,
|
||||
string $subject,
|
||||
string $body,
|
||||
string $recipientName,
|
||||
string $preheader = '',
|
||||
string $ctaText = '',
|
||||
string $ctaUrl = '',
|
||||
bool $personalize = true
|
||||
): string {
|
||||
$content = $personalize ? str_replace('{{name}}', $recipientName, $body) : $body;
|
||||
|
||||
if (!$wrapLayout) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if (!View::exists('emails.broadcast_wrapper')) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return view('emails.broadcast_wrapper', [
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
'preheader' => $preheader,
|
||||
'cta_text' => $ctaText,
|
||||
'cta_url' => $ctaUrl,
|
||||
])->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\BroadcastEmail;
|
||||
|
||||
use App\Services\EmailService;
|
||||
|
||||
class BroadcastEmailDispatchService
|
||||
{
|
||||
private EmailService $mailer;
|
||||
private BroadcastEmailComposerService $composer;
|
||||
|
||||
public function __construct(EmailService $mailer, BroadcastEmailComposerService $composer)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->composer = $composer;
|
||||
}
|
||||
|
||||
public function sendTest(array $payload): array
|
||||
{
|
||||
$html = $this->composer->compose(
|
||||
(bool) $payload['wrap_layout'],
|
||||
$payload['subject'],
|
||||
$payload['body_html'],
|
||||
$payload['recipient_name'],
|
||||
$payload['preheader'],
|
||||
$payload['cta_text'],
|
||||
$payload['cta_url'],
|
||||
(bool) $payload['personalize']
|
||||
);
|
||||
|
||||
$ok = $this->mailer->send(
|
||||
$payload['test_email'],
|
||||
'[TEST] ' . $payload['subject'],
|
||||
$html,
|
||||
$payload['from_key']
|
||||
);
|
||||
|
||||
return [
|
||||
'ok' => $ok,
|
||||
'message' => $ok
|
||||
? "Test email sent to {$payload['test_email']}."
|
||||
: 'Test email failed (mailer->send() returned false). Check logs.',
|
||||
];
|
||||
}
|
||||
|
||||
public function sendBroadcast(array $payload, array $recipients): array
|
||||
{
|
||||
$stats = [
|
||||
'attempted' => 0,
|
||||
'sent' => 0,
|
||||
'failed' => 0,
|
||||
'mode' => $payload['mode'],
|
||||
];
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$stats['attempted']++;
|
||||
$recipientName = $recipient['name'] ?: 'Parent';
|
||||
$html = $this->composer->compose(
|
||||
(bool) $payload['wrap_layout'],
|
||||
$payload['subject'],
|
||||
$payload['body_html'],
|
||||
$recipientName,
|
||||
$payload['preheader'],
|
||||
$payload['cta_text'],
|
||||
$payload['cta_url'],
|
||||
(bool) $payload['personalize']
|
||||
);
|
||||
|
||||
$ok = $this->mailer->send(
|
||||
(string) $recipient['email'],
|
||||
$payload['subject'],
|
||||
$html,
|
||||
$payload['from_key']
|
||||
);
|
||||
|
||||
$ok ? $stats['sent']++ : $stats['failed']++;
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\BroadcastEmail;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class BroadcastEmailImageService
|
||||
{
|
||||
private const MAX_SIZE_BYTES = 5242880;
|
||||
|
||||
private array $allowedTypes = [
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif',
|
||||
'image/webp' => 'webp',
|
||||
];
|
||||
|
||||
public function store(UploadedFile $file): array
|
||||
{
|
||||
$mime = strtolower((string) $file->getMimeType());
|
||||
if (!isset($this->allowedTypes[$mime])) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'status' => 415,
|
||||
'error' => 'Unsupported image type',
|
||||
];
|
||||
}
|
||||
|
||||
if ($file->getSize() > self::MAX_SIZE_BYTES) {
|
||||
return [
|
||||
'ok' => false,
|
||||
'status' => 413,
|
||||
'error' => 'Image too large (max 5MB)',
|
||||
];
|
||||
}
|
||||
|
||||
$targetDir = public_path('uploads/email');
|
||||
if (!is_dir($targetDir)) {
|
||||
@mkdir($targetDir, 0755, true);
|
||||
}
|
||||
|
||||
$ext = $this->allowedTypes[$mime];
|
||||
$newName = uniqid('em_', true) . '.' . $ext;
|
||||
$file->move($targetDir, $newName);
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'url' => asset('uploads/email/' . $newName),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\BroadcastEmail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class BroadcastEmailRecipientService
|
||||
{
|
||||
public function parentsWithEmails(): array
|
||||
{
|
||||
$parents = User::getParents();
|
||||
|
||||
return array_values(array_filter($parents, static function ($parent) {
|
||||
$email = $parent['email'] ?? '';
|
||||
return is_string($email) && trim($email) !== '';
|
||||
}));
|
||||
}
|
||||
|
||||
public function recipientsByIds(array $ids): array
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $ids))));
|
||||
if (empty($ids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return DB::table('users')
|
||||
->select('users.id', 'users.email', DB::raw('CONCAT(users.firstname, " ", users.lastname) AS name'))
|
||||
->whereIn('users.id', $ids)
|
||||
->whereNotNull('users.email')
|
||||
->where('users.email', '!=', '')
|
||||
->get()
|
||||
->map(fn ($row) => (array) $row)
|
||||
->all();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\BroadcastEmail;
|
||||
|
||||
class BroadcastEmailSenderOptionsService
|
||||
{
|
||||
public function listOptions(): array
|
||||
{
|
||||
$json = env('MAIL_SENDERS', '{}');
|
||||
$arr = json_decode($json, true);
|
||||
|
||||
if (!is_array($arr) || empty($arr)) {
|
||||
$smtpUser = getenv('SMTP_USER') ?: '';
|
||||
$name = 'Al Rahma Sunday School';
|
||||
return [[
|
||||
'key' => 'general',
|
||||
'label' => $name . ($smtpUser ? " <{$smtpUser}>" : ''),
|
||||
]];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($arr as $key => $info) {
|
||||
$name = $info['name'] ?? 'Sender';
|
||||
$email = $info['email'] ?? '';
|
||||
$out[] = [
|
||||
'key' => (string) $key,
|
||||
'label' => trim($name . ($email ? " <{$email}>" : '')),
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user