Files
thetool/scripts/pipework/run-weekly-email.php
2025-04-14 10:58:52 +02:00

279 lines
13 KiB
PHP

#!/usr/bin/php
<?php
// Configuration and Setup
require_once(__DIR__ . "/../../config/config.php"); // Use __DIR__ for reliability
define('FRONKDB_SQLDEBUG', false);
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
// Ensure necessary classes are loaded (adjust paths if needed)
require_once(LIBDIR . "/mvcfronk/mfRouter/mfRouter.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseModel.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseController.php");
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
// --- User Context (Keep if required by Models/Controllers) ---
$me = new User(1); // Assuming User class is loaded via autoloader or included elsewhere
define("INTERNAL_USER_ID", $me->id);
define("INTERNAL_USER_USERNAME", $me->username);
// --- Controller Instantiation (Keep if required) ---
$pipeworkController = new PipeworkController(false); // Assuming PipeworkController class is loaded
// --- Data Fetching ---
$networkIDs = [41, 90, 22, 2, 25, 24, 7, 15, 6, 12, 13];
$allNetworkData = [];
$from = strtotime("-1 week"); // Simpler timestamp generation
$to = time();
foreach ($networkIDs as $networkID) {
try {
$network = new Network($networkID); // Assuming Network class is loaded
if ($network->id) { // Basic check if network loaded successfully
$history = BuildingModel::getHistory($from, $to, $networkID, ''); // Assuming BuildingModel is loaded
$allNetworkData[$network->name] = $history;
} else {
// Optional: Log or handle cases where a Network object couldn't be created
error_log("Could not load Network with ID: " . $networkID);
}
} catch (Exception $e) {
// Optional: Log or handle exceptions during data fetching for a specific network
error_log("Error fetching data for Network ID " . $networkID . ": " . $e->getMessage());
}
}
// --- HTML Email Generation ---
// Logo paths - Ensure these are correct relative to the script location or absolute paths
$logoToolPath = LIBDIR . '/../public/assets/images/the-tool-logo.png';
$logoXinonPath = LIBDIR . '/../public/assets/images/xinon-full.png';
// Check if logo files exist
$logoToolExists = file_exists($logoToolPath);
$logoXinonExists = file_exists($logoXinonPath);
// --- Start HTML ---
$html = <<<HTML
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tiefbau Report</title>
<style>
/* Basic Resets (some email clients support limited styles here) */
body { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; line-height: 1.5; }
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px; text-align: left; }
/* Add other minimal base styles if needed */
</style>
</head>
<body style="margin: 0; padding: 0; background-color: #f3f4f6;">
<table role="presentation" style="width: 100%; border-collapse: collapse; background-color: #f3f4f6;">
<tr>
<td align="center" style="padding: 20px 0;">
<table role="presentation" style="width: 90%; max-width: 600px; border-collapse: collapse; background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);">
<tr>
<td style="padding: 20px; background-color: #ffffff; text-align: center; border-bottom: 1px solid #e5e7eb;">
<table role="presentation" style="width: 100%; border-collapse: collapse;">
<tr>
<td style="width: 50%; text-align: right; padding-right: 10px;">
HTML;
if ($logoToolExists) {
$html .= '<img src="cid:logo_thetool" alt="The Tool Logo" style="max-height: 40px; display: inline-block; vertical-align: middle;">';
} else {
$html .= '<span style="color: #dc2626; font-size: 12px;">The Tool Logo not found</span>';
}
$html .= <<<HTML
</td>
<td style="width: 50%; text-align: left; padding-left: 10px;">
HTML;
if ($logoXinonExists) {
$html .= '<img src="cid:logo_xinon" alt="Xinon Logo" style="max-height: 40px; display: inline-block; vertical-align: middle;">';
} else {
$html .= '<span style="color: #dc2626; font-size: 12px;">Xinon Logo not found</span>';
}
$html .= <<<HTML
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding: 24px 20px;">
<h1 style="font-size: 1.5rem; font-weight: 600; color: #111827; margin: 0 0 16px 0; text-align: center;">Tiefbau Report</h1>
<p style="font-size: 0.875rem; color: #4b5563; margin: 0; text-align: center;">Änderungen der letzten Woche</p>
</td>
</tr>
HTML;
if (empty($allNetworkData)) {
$html .= <<<HTML
<tr>
<td style="padding: 20px;">
<p style="color: #4b5563; text-align: center;">Keine Netzwerkdaten zum Anzeigen vorhanden.</p>
</td>
</tr>
HTML;
} else {
foreach ($allNetworkData as $networkName => $networkData) {
$networkNameHtml = htmlspecialchars($networkName);
$html .= <<<HTML
<tr>
<td style="padding: 20px; border-top: 1px solid #e5e7eb;">
<h2 style="font-size: 1.25rem; font-weight: 600; color: #00558c; margin: 0 0 16px 0;">Netzwerk: {$networkNameHtml}</h2>
HTML;
if (empty($networkData)) {
$noChangesMsg = htmlspecialchars("Keine Änderungen im Tiefbau für diesen Zeitraum.");
$html .= <<<HTML
<p style="background-color: #fef3c7; color: #92400e; padding: 10px 15px; border-radius: 6px; font-size: 0.875rem; margin: 0;">{$noChangesMsg}</p>
HTML;
} else {
$html .= <<<HTML
<table role="presentation" style="width: 100%; border-collapse: collapse; font-size: 0.875rem;">
<thead>
<tr style="background-color: #f3f4f6;">
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Straße</th>
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Ort</th>
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Feld</th>
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Wert</th>
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Editiert</th>
<th style="padding: 10px; border-bottom: 1px solid #d1d5db; color: #374151; font-weight: 600;">Von</th>
</tr>
</thead>
<tbody>
HTML;
foreach ($networkData as $item) {
// Determine the value to display
$valueDisplay = '';
if (!empty($item->value_string)) {
$valueDisplay = htmlspecialchars($item->value_string);
} elseif (!empty($item->value_int)) {
$valueDisplay = htmlspecialchars($item->value_int);
} elseif (!empty($item->value_text)) {
$valueDisplay = nl2br(htmlspecialchars($item->value_text));
} else {
// Optionally skip rows with no displayable value, or show N/A
// continue; // Uncomment to skip
$valueDisplay = '<span style="color: #9ca3af;">N/A</span>';
}
// Skip fully empty rows based on original logic if needed (though the check above is usually sufficient)
if (empty($item->value_string) && empty($item->value_int) && empty($item->value_text) && $valueDisplay === '<span style="color: #9ca3af;">N/A</span>') {
continue;
}
$userName = 'Unbekannt'; // Default username
try {
$user = UserModel::getOne($item->last_edited_by_user_id); // Assuming UserModel is loaded
if ($user && $user->username) {
$userName = htmlspecialchars($user->username);
}
} catch (Exception $e) {
error_log("Error fetching user ID " . $item->last_edited_by_user_id . ": " . $e->getMessage());
}
$street = htmlspecialchars($item->building_street ?? 'N/A');
$city = htmlspecialchars($item->building_city ?? 'N/A');
$label = htmlspecialchars($item->item_label ?? 'N/A');
$editedAt = date("d.m.Y H:i", $item->last_edited_at); // Shortened format for space
$html .= <<<HTML
<tr style="border-bottom: 1px solid #e5e7eb;">
<td style="padding: 10px; color: #4b5563;">{$street}</td>
<td style="padding: 10px; color: #4b5563;">{$city}</td>
<td style="padding: 10px; color: #4b5563;">{$label}</td>
<td style="padding: 10px; color: #111827; max-width: 200px; word-wrap: break-word;">{$valueDisplay}</td>
<td style="padding: 10px; color: #4b5563; white-space: nowrap;">{$editedAt}</td>
<td style="padding: 10px; color: #4b5563;">{$userName}</td>
</tr>
HTML;
} // End foreach item
$html .= <<<HTML
</tbody>
</table>
HTML;
} // End if empty networkData
$html .= <<<HTML
</td>
</tr>
HTML;
} // End foreach network
} // End if empty allNetworkData
// --- Footer ---
$html .= <<<HTML
<tr>
<td style="padding: 20px; text-align: center; font-size: 0.75rem; color: #6b7280; border-top: 1px solid #e5e7eb;">
Automatisch generierter Report von XINON TheTool | &copy;
HTML;
$html .= date("Y");
$html .= <<<HTML
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
HTML;
// --- Email Sending ---
$mail = new PHPMailer(true);
try {
// Server settings - Ensure these constants are defined in config.php
$mail->isSMTP();
$mail->Host = TT_PIPEWORK_SMTP_HOST;
$mail->SMTPAuth = true;
$mail->Username = TT_PIPEWORK_SMTP_USER;
$mail->Password = TT_PIPEWORK_SMTP_PASS;
$mail->CharSet = PHPMailer::CHARSET_UTF8; // Use PHPMailer constant
$mail->Encoding = 'base64';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// Embed Logos - Do this *before* setting the body
if ($logoToolExists) {
$mail->addEmbeddedImage($logoToolPath, 'logo_thetool');
}
if ($logoXinonExists) {
$mail->addEmbeddedImage($logoXinonPath, 'logo_xinon');
}
// Recipients
$mail->setFrom('thetool@xinon.at', 'XINON TheTool'); // Use sender address from config if available
$mail->addAddress('mark.zaff@xinon.eu', 'Mark Zaff');
$mail->addAddress('luca.haid@xinon.eu', 'Luca Haid');
// Content
$mail->isHTML(true);
$mail->Subject = 'Tiefbau Report - ' . date('d.m.Y'); // Use PHP date function for dynamic date
$mail->Body = $html;
// Create a plain text version (simple approach)
$plainTextBody = strip_tags(str_replace('<br>', "\n", $html)); // Basic conversion
$plainTextBody = html_entity_decode($plainTextBody); // Decode HTML entities
$mail->AltBody = $plainTextBody;
$mail->send();
echo 'Nachricht wurde erfolgreich gesendet.' . PHP_EOL; // German output
} catch (Exception $e) {
// Log the detailed error
error_log("E-Mail konnte nicht gesendet werden. Mailer Error: {$mail->ErrorInfo}");
// Output a user-friendly message
echo "E-Mail konnte nicht gesendet werden. Fehlerdetails wurden protokolliert. Mailer Error: {$mail->ErrorInfo}" . PHP_EOL; // German output
}
?>