Files
yogibook_aury_new/public/include/event_mailer.php
T
2026-09-18 09:52:51 +02:00

300 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Motore email del modulo Eventi (PHPMailer, legge le MAIL_* dal .env).
*
* Requisito una tantum: composer require phpmailer/phpmailer
*
* Builder per i 5 tipi:
* A) yse_mail_booking() prenotazione (confermata o lista d'attesa)
* B) yse_mail_user_cancel() disdetta fatta dall'utente
* C) yse_mail_event_cancel() evento annullato dall'insegnante (a ciascun iscritto)
* E) yse_mail_promotion() promozione da lista d'attesa (con RICONFERMA)
* D) yse_mail_reminder() promemoria prima dell'evento
*
* Le copie alla scuola (CC) sono decise per-tipo dalla pagina "Opzioni Eventi".
* L'indirizzo di copia è option.event_notify_email.
*/
// Assicura l'autoload (di norma già caricato da db-functions.php)
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
$__al = dirname(__DIR__, 2) . '/vendor/autoload.php';
if (is_file($__al)) {
require_once $__al;
}
}
if (!defined('YB_PUBLIC_BASE')) {
define('YB_PUBLIC_BASE', 'https://yogibook.yogasoul.it/');
}
/* ---------- Opzioni ---------- */
function yse_mail_options(): array
{
static $opt = null;
if ($opt !== null) {
return $opt;
}
$row = [];
try {
$pdo = DBHandlerSelect::getInstance()->getConnection();
$row = $pdo->query("SELECT * FROM `option` LIMIT 1")->fetch(PDO::FETCH_ASSOC) ?: [];
} catch (Throwable $e) {
$row = [];
}
$opt = [
'cc_email' => trim((string) ($row['event_notify_email'] ?? '')),
'cc' => [
'booking' => ($row['event_cc_booking'] ?? 'N') === 'Y',
'user_cancel' => ($row['event_cc_user_cancel'] ?? 'N') === 'Y',
'event_cancel' => ($row['event_cc_event_cancel'] ?? 'N') === 'Y',
'reminder' => ($row['event_cc_reminder'] ?? 'N') === 'Y',
'promotion' => ($row['event_cc_promotion'] ?? 'N') === 'Y',
],
];
return $opt;
}
/* ---------- Invio base ---------- */
function yse_send(string $to, string $toName, string $subject, string $html, bool $ccSchool): bool
{
$env = $_ENV;
try {
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
$mail->isSMTP();
$mail->Host = $env['MAIL_HOST'] ?? '';
$mail->SMTPAuth = true;
$mail->Username = $env['MAIL_USERNAME'] ?? '';
$mail->Password = $env['MAIL_PASSWORD'] ?? '';
$enc = strtolower($env['MAIL_ENCRYPTION'] ?? 'ssl');
$mail->SMTPSecure = ($enc === 'tls')
? \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS
: \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = (int) ($env['MAIL_PORT'] ?? 465);
$mail->CharSet = 'UTF-8';
$mail->setFrom($env['MAIL_FROM_ADDRESS'] ?? 'info@yogasoul.it', $env['MAIL_FROM_NAME'] ?? 'YogiBook');
$mail->addAddress($to, $toName);
if ($ccSchool) {
$ccEmail = yse_mail_options()['cc_email'];
if ($ccEmail !== '' && strcasecmp($ccEmail, $to) !== 0) {
$mail->addCC($ccEmail);
}
}
$mail->isHTML(true);
$mail->Subject = $subject;
$mail->Body = $html;
$mail->AltBody = trim(preg_replace(
'/\n{3,}/',
"\n\n",
strip_tags(str_replace(['</p>', '<br>', '<br/>', '<br />', '</div>'], "\n", $html))
));
return $mail->send();
} catch (Throwable $e) {
error_log('[event mail] ' . $e->getMessage());
return false;
}
}
/* ---------- Helper contenuto ---------- */
function yse_h($v): string
{
return htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
}
function yse_fmt_datetime(array $event): string
{
$mesi = [
1 => 'gennaio',
2 => 'febbraio',
3 => 'marzo',
4 => 'aprile',
5 => 'maggio',
6 => 'giugno',
7 => 'luglio',
8 => 'agosto',
9 => 'settembre',
10 => 'ottobre',
11 => 'novembre',
12 => 'dicembre'
];
$t = strtotime($event['starts_at']);
$s = (int) date('j', $t) . ' ' . $mesi[(int) date('n', $t)] . ' ' . date('Y', $t) . ' · ' . date('H:i', $t);
if (!empty($event['ends_at'])) {
$s .= '–' . date('H:i', strtotime($event['ends_at']));
}
return $s;
}
function yse_maps_link(array $event): string
{
$q = trim((string) ($event['address'] ?? ''));
if ($q === '' && !empty($event['lat']) && !empty($event['lng'])) {
$q = $event['lat'] . ',' . $event['lng'];
}
return $q !== '' ? 'https://www.google.com/maps/search/?api=1&query=' . rawurlencode($q) : '';
}
function yse_event_info_block(array $event): string
{
$accent = (isset($event['color']) && preg_match('/^#[0-9a-fA-F]{6}$/', $event['color'])) ? $event['color'] : '#4CAF50';
$when = yse_h(yse_fmt_datetime($event));
$addr = trim((string) ($event['address'] ?? ''));
$maps = yse_maps_link($event);
$rows = '<tr><td style="padding:6px 0;color:#8c837c;width:90px;">Quando</td><td style="padding:6px 0;color:#2b2622;font-weight:600;">' . $when . '</td></tr>';
if ($addr !== '') {
$mapsLink = $maps !== '' ? ' &nbsp;<a href="' . yse_h($maps) . '" style="color:' . $accent . ';">apri mappa</a>' : '';
$rows .= '<tr><td style="padding:6px 0;color:#8c837c;">Dove</td><td style="padding:6px 0;color:#2b2622;font-weight:600;">' . yse_h($addr) . $mapsLink . '</td></tr>';
}
$info = '';
foreach ([['suitable_for', 'Per chi è adatto'], ['what_to_bring', 'Cosa portare'], ['instructions', 'Istruzioni']] as $f) {
$val = trim((string) ($event[$f[0]] ?? ''));
if ($val !== '') {
$info .= '<p style="margin:10px 0 0;"><strong style="color:#2b2622;">' . $f[1] . ':</strong><br>' . nl2br(yse_h($val)) . '</p>';
}
}
$html = '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:14px;border-collapse:collapse;margin:10px 0;">' . $rows . '</table>';
if ($info !== '') {
$html .= '<div style="background:#faf8f6;border-radius:10px;padding:12px 14px;font-size:14px;color:#4a433d;">' . $info . '</div>';
}
return $html;
}
function yse_email_layout(array $event, string $heading, string $bodyHtml): string
{
$accent = (isset($event['color']) && preg_match('/^#[0-9a-fA-F]{6}$/', $event['color'])) ? $event['color'] : '#4CAF50';
$from = $_ENV['MAIL_FROM_NAME'] ?? 'YogaSoul';
$title = yse_h($event['title'] ?? '');
return '
<div style="background:#f2efec;padding:24px 0;font-family:Arial,Helvetica,sans-serif;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr><td align="center">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" style="max-width:600px;width:100%;background:#fff;border-radius:16px;overflow:hidden;">
<tr><td style="background:' . $accent . ';height:6px;"></td></tr>
<tr><td style="padding:28px 30px 6px;">
<div style="font-size:13px;letter-spacing:.05em;text-transform:uppercase;color:#8c837c;">' . yse_h($from) . '</div>
<h1 style="margin:6px 0 2px;font-size:22px;color:#2b2622;">' . $heading . '</h1>
<div style="font-size:17px;color:' . $accent . ';font-weight:600;">' . $title . '</div>
</td></tr>
<tr><td style="padding:10px 30px 26px;color:#4a433d;font-size:15px;line-height:1.6;">' . $bodyHtml . '</td></tr>
<tr><td style="padding:16px 30px;background:#faf8f6;color:#9ca3af;font-size:12px;">Questa email è stata inviata da ' . yse_h($from) . '.</td></tr>
</table>
</td></tr></table>
</div>';
}
function yse_button(string $url, string $label, string $accent): string
{
return '<a href="' . yse_h($url) . '" style="display:inline-block;background:' . $accent . ';color:#fff;text-decoration:none;font-weight:600;padding:12px 22px;border-radius:10px;">' . yse_h($label) . '</a>';
}
function yse_cancel_url(array $booking): string
{
return YB_PUBLIC_BASE . 'apiwp/cancel.php?token=' . rawurlencode($booking['token']);
}
function yse_confirm_url(array $booking): string
{
return YB_PUBLIC_BASE . 'apiwp/confirm.php?token=' . rawurlencode($booking['token']);
}
/* ---------- Builder per tipo ---------- */
/** A) Prenotazione (confermata o lista d'attesa) */
function yse_mail_booking(array $booking, array $event): bool
{
$accent = $event['color'] ?? '#4CAF50';
$waiting = ($booking['status'] ?? '') === 'waiting';
$parts = explode(' ', trim($booking['name']));
$name = $parts[0] ?? '';
if ($waiting) {
$heading = "Sei in lista d'attesa";
$intro = '<p>Ciao ' . yse_h($name) . ", ti abbiamo messo in lista d'attesa per questo evento. Ti avviseremo appena si libera un posto.</p>";
} else {
$heading = 'Prenotazione confermata';
$intro = '<p>Ciao ' . yse_h($name) . ', la tua prenotazione è confermata. Ecco i dettagli:</p>';
}
$body = $intro;
$body .= yse_event_info_block($event);
$body .= '<p style="margin-top:8px;">Posti prenotati: <strong>' . (int) $booking['seats'] . '</strong></p>';
$body .= '<p style="margin:22px 0 6px;">Se non puoi più partecipare, puoi annullare qui:</p>';
$body .= '<p>' . yse_button(yse_cancel_url($booking), 'Annulla prenotazione', $accent) . '</p>';
$subject = ($waiting ? "Lista d'attesa: " : 'Prenotazione confermata: ') . $event['title'];
$html = yse_email_layout($event, $heading, $body);
return yse_send($booking['email'], $booking['name'], $subject, $html, yse_mail_options()['cc']['booking']);
}
/** B) Disdetta fatta dall'utente */
function yse_mail_user_cancel(array $booking, array $event): bool
{
$parts = explode(' ', trim($booking['name']));
$name = $parts[0] ?? '';
$body = '<p>Ciao ' . yse_h($name) . ', la tua prenotazione per questo evento è stata <strong>annullata</strong>.</p>';
$body .= yse_event_info_block($event);
$body .= '<p style="margin-top:14px;">Ci dispiace non vederti questa volta. A presto!</p>';
$subject = 'Prenotazione annullata: ' . $event['title'];
$html = yse_email_layout($event, 'Prenotazione annullata', $body);
return yse_send($booking['email'], $booking['name'], $subject, $html, yse_mail_options()['cc']['user_cancel']);
}
/** C) Evento annullato dall'insegnante (a ciascun iscritto) */
function yse_mail_event_cancel(array $booking, array $event): bool
{
$parts = explode(' ', trim($booking['name']));
$name = $parts[0] ?? '';
$body = '<p>Ciao ' . yse_h($name) . ", ci dispiace: l'evento è stato <strong>annullato</strong>.</p>";
$body .= yse_event_info_block($event);
$body .= '<p style="margin-top:14px;">La tua prenotazione è stata annullata automaticamente. Per informazioni, rispondi pure a questa email.</p>';
$subject = 'Evento annullato: ' . $event['title'];
$html = yse_email_layout($event, 'Evento annullato', $body);
return yse_send($booking['email'], $booking['name'], $subject, $html, yse_mail_options()['cc']['event_cancel']);
}
/** E) Promozione da lista d'attesa — con RICONFERMA */
function yse_mail_promotion(array $booking, array $event): bool
{
$accent = $event['color'] ?? '#4CAF50';
$parts = explode(' ', trim($booking['name']));
$name = $parts[0] ?? '';
$body = '<p>Ciao ' . yse_h($name) . ", buone notizie: si è liberato un posto e tocca a te!</p>";
$body .= yse_event_info_block($event);
$body .= '<p style="margin:22px 0 6px;"><strong>Conferma entro breve</strong> per tenere il posto:</p>';
$body .= '<p>' . yse_button(yse_confirm_url($booking), 'Confermo, ci sarò', $accent) . '</p>';
$body .= '<p style="margin-top:16px;font-size:13px;color:#8c837c;">Se non puoi partecipare, <a href="' . yse_h(yse_cancel_url($booking)) . '" style="color:' . $accent . ';">annulla qui</a> così offriamo il posto a un\'altra persona.</p>';
$subject = 'Si è liberato un posto: ' . $event['title'];
$html = yse_email_layout($event, 'Un posto per te', $body);
return yse_send($booking['email'], $booking['name'], $subject, $html, yse_mail_options()['cc']['promotion']);
}
/** D) Promemoria prima dell'evento (testo e punto di ritrovo opzionali) */
function yse_mail_reminder(array $booking, array $event, string $message = '', string $meetingLink = ''): bool
{
$accent = $event['color'] ?? '#4CAF50';
$parts = explode(' ', trim($booking['name']));
$name = $parts[0] ?? '';
$note = $message !== '' ? nl2br(yse_h($message)) : 'Ti ricordiamo il tuo prossimo appuntamento.';
$body = '<p>Ciao ' . yse_h($name) . ',<br>' . $note . '</p>';
$body .= yse_event_info_block($event);
if ($meetingLink !== '') {
$body .= '<p style="margin:16px 0 6px;"><strong>Punto di ritrovo:</strong> <a href="' . yse_h($meetingLink) . '" style="color:' . $accent . ';">apri la posizione sulla mappa</a></p>';
}
$body .= '<p style="margin:22px 0 6px;">Se non puoi più partecipare, avvisaci annullando:</p>';
$body .= '<p>' . yse_button(yse_cancel_url($booking), 'Annulla prenotazione', $accent) . '</p>';
$subject = 'Promemoria: ' . $event['title'];
$html = yse_email_layout($event, 'Ci vediamo presto', $body);
return yse_send($booking['email'], $booking['name'], $subject, $html, yse_mail_options()['cc']['reminder']);
}