Files
easystream-main/f_core/f_classes/class.email.queue.php
SamiAhmed7777 d22b3e1c0d feat: Add complete Docker deployment with web-based setup wizard
Major additions:
- Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js)
- Production Docker configuration (docker-compose.prod.yml, .env.production)
- Database initialization SQL files (deploy/init_settings.sql)
- Template builder system with drag-and-drop UI
- Advanced features (OAuth, CDN, enhanced analytics, monetization)
- Comprehensive documentation (deployment guides, quick start, feature docs)
- Design system with accessibility and responsive layout
- Deployment automation scripts (deploy.ps1, generate-secrets.ps1)

Setup wizard allows customization of:
- Platform name and branding
- Domain configuration
- Membership tiers and pricing
- Admin credentials
- Feature toggles

Database includes 270+ tables for complete video streaming platform with
advanced features for analytics, moderation, template building, and monetization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-26 01:42:31 -07:00

298 lines
9.9 KiB
PHP

<?php
/**
* EasyStream Email Queue System
* SendGrid/AWS SES integration with queue processing
* Version: 1.0
*/
defined('_ISVALID') or header('Location: /error');
class VEmailQueue {
private static $db;
private static $sendgrid_api_key = null;
private static $from_email = 'noreply@easystream.com';
private static $from_name = 'EasyStream';
public static function init() {
self::$db = VDatabase::getInstance();
// Load configuration
$config = VGenerate::getConfig('email_config');
if ($config) {
self::$sendgrid_api_key = $config['sendgrid_api_key'] ?? null;
self::$from_email = $config['from_email'] ?? self::$from_email;
self::$from_name = $config['from_name'] ?? self::$from_name;
}
}
/**
* Queue email for sending
* @param int $usr_id User ID (optional)
* @param string $to_email Recipient email
* @param string $subject Email subject
* @param string $body_html HTML body
* @param array $options Additional options
* @return int Email ID
*/
public static function queueEmail($usr_id, $to_email, $subject, $body_html, $options = []) {
self::init();
$usr_id_val = $usr_id ? (int)$usr_id : 'NULL';
$to_email_safe = VDatabase::escape($to_email);
$to_name_safe = VDatabase::escape($options['to_name'] ?? '');
$subject_safe = VDatabase::escape($subject);
$body_html_safe = VDatabase::escape($body_html);
$body_text_safe = VDatabase::escape($options['body_text'] ?? strip_tags($body_html));
$template_safe = VDatabase::escape($options['template_name'] ?? '');
$template_data = VDatabase::escape(json_encode($options['template_data'] ?? []));
$priority = (int)($options['priority'] ?? 5);
$send_at = isset($options['send_at']) ? "'" . VDatabase::escape($options['send_at']) . "'" : 'NULL';
$sql = "INSERT INTO db_email_queue
(usr_id, to_email, to_name, subject, body_html, body_text, template_name, template_data, priority, send_at, status, created_at)
VALUES ($usr_id_val, '$to_email_safe', '$to_name_safe', '$subject_safe', '$body_html_safe', '$body_text_safe', '$template_safe', '$template_data', $priority, $send_at, 'pending', NOW())";
if (self::$db->execute($sql)) {
return self::$db->insert_id();
}
return false;
}
/**
* Process email queue
* @param int $limit Number of emails to process
* @return array Results
*/
public static function processQueue($limit = 50) {
self::init();
$limit = (int)$limit;
// Get pending emails
$sql = "SELECT * FROM db_email_queue
WHERE status = 'pending'
AND (send_at IS NULL OR send_at <= NOW())
ORDER BY priority ASC, created_at ASC
LIMIT $limit";
$result = self::$db->execute($sql);
if (!$result) {
return ['sent' => 0, 'failed' => 0];
}
$sent = 0;
$failed = 0;
while ($row = $result->FetchRow()) {
$email_id = (int)$row['email_id'];
// Mark as sending
self::$db->execute("UPDATE db_email_queue SET status = 'sending' WHERE email_id = $email_id");
// Send email
$success = self::sendEmail($row);
if ($success) {
self::$db->execute("UPDATE db_email_queue SET status = 'sent', sent_at = NOW() WHERE email_id = $email_id");
self::logEmail($email_id, $row, 'sent');
$sent++;
} else {
$attempts = (int)$row['attempts'] + 1;
$max_attempts = 3;
if ($attempts >= $max_attempts) {
self::$db->execute("UPDATE db_email_queue SET status = 'failed', attempts = $attempts WHERE email_id = $email_id");
self::logEmail($email_id, $row, 'failed');
$failed++;
} else {
// Retry later
self::$db->execute("UPDATE db_email_queue SET status = 'pending', attempts = $attempts WHERE email_id = $email_id");
}
}
}
return ['sent' => $sent, 'failed' => $failed];
}
/**
* Send individual email
* @param array $email_data Email data
* @return bool Success
*/
private static function sendEmail($email_data) {
if (self::$sendgrid_api_key) {
return self::sendViaSendGrid($email_data);
} else {
return self::sendViaPHPMailer($email_data);
}
}
/**
* Send via SendGrid
*/
private static function sendViaSendGrid($email_data) {
$url = 'https://api.sendgrid.com/v3/mail/send';
$data = [
'personalizations' => [[
'to' => [['email' => $email_data['to_email'], 'name' => $email_data['to_name']]]
]],
'from' => ['email' => self::$from_email, 'name' => self::$from_name],
'subject' => $email_data['subject'],
'content' => [
['type' => 'text/html', 'value' => $email_data['body_html']],
['type' => 'text/plain', 'value' => $email_data['body_text']]
]
];
$json = json_encode($data);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . self::$sendgrid_api_key,
'Content-Type: application/json'
]);
$result = curl_exec($ch);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $status_code == 202 || $status_code == 200;
}
/**
* Send via PHP mail (fallback)
*/
private static function sendViaPHPMailer($email_data) {
$to = $email_data['to_email'];
$subject = $email_data['subject'];
$message = $email_data['body_html'];
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=UTF-8\r\n";
$headers .= "From: " . self::$from_name . " <" . self::$from_email . ">\r\n";
return mail($to, $subject, $message, $headers);
}
/**
* Log email event
*/
private static function logEmail($email_id, $email_data, $status) {
$usr_id = $email_data['usr_id'] ?? 'NULL';
$to_email = VDatabase::escape($email_data['to_email']);
$subject = VDatabase::escape($email_data['subject']);
$status_safe = VDatabase::escape($status);
$sql = "INSERT INTO db_email_logs
(email_id, usr_id, to_email, subject, status, created_at)
VALUES ($email_id, $usr_id, '$to_email', '$subject', '$status_safe', NOW())";
self::$db->execute($sql);
}
/**
* Get user email preferences
* @param int $usr_id User ID
* @return array Preferences
*/
public static function getPreferences($usr_id) {
self::init();
$usr_id = (int)$usr_id;
$sql = "SELECT * FROM db_email_preferences WHERE usr_id = $usr_id";
$result = self::$db->execute($sql);
if ($result && $result->RecordCount() > 0) {
return $result->FetchRow();
}
// Return defaults
return [
'digest_frequency' => 'weekly',
'notify_comments' => 1,
'notify_replies' => 1,
'notify_likes' => 1,
'notify_subscribers' => 1,
'notify_uploads' => 1,
'notify_live_streams' => 1,
'notify_mentions' => 1,
'notify_milestones' => 1,
'marketing_emails' => 1
];
}
/**
* Update email preferences
* @param int $usr_id User ID
* @param array $preferences Preferences
* @return bool Success
*/
public static function updatePreferences($usr_id, $preferences) {
self::init();
$usr_id = (int)$usr_id;
// Build SET clause
$sets = [];
foreach ($preferences as $key => $value) {
$key_safe = VDatabase::escape($key);
$value_safe = VDatabase::escape($value);
$sets[] = "$key_safe = '$value_safe'";
}
$setClause = implode(', ', $sets);
$sql = "INSERT INTO db_email_preferences (usr_id, $setClause, updated_at)
VALUES ($usr_id, NOW())
ON DUPLICATE KEY UPDATE $setClause, updated_at = NOW()";
return self::$db->execute($sql);
}
/**
* Send templated email
* @param string $template_name Template name
* @param int $usr_id User ID
* @param string $to_email Email address
* @param array $variables Template variables
* @return int Email ID
*/
public static function sendTemplate($template_name, $usr_id, $to_email, $variables = []) {
self::init();
// Get template
$template_safe = VDatabase::escape($template_name);
$sql = "SELECT * FROM db_email_templates WHERE name = '$template_safe' AND is_active = 1";
$result = self::$db->execute($sql);
if (!$result || $result->RecordCount() == 0) {
return false;
}
$template = $result->FetchRow();
// Replace variables
$subject = $template['subject'];
$body_html = $template['body_html'];
$body_text = $template['body_text'];
foreach ($variables as $key => $value) {
$subject = str_replace('{' . $key . '}', $value, $subject);
$body_html = str_replace('{' . $key . '}', $value, $body_html);
$body_text = str_replace('{' . $key . '}', $value, $body_text);
}
return self::queueEmail($usr_id, $to_email, $subject, $body_html, [
'body_text' => $body_text,
'template_name' => $template_name,
'template_data' => $variables
]);
}
}