| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/seaside.pacim.de/web/ |
Upload File : |
<?php
/**
* pushover-day.php – Pushover-Kurzinfos zur Tagesansicht (tasks/day) an den eigenen Account.
*
* Aktionen (action):
* preview GET/POST -> { ok, title, message, count, monospace:true } (nur Vorschau, kein Versand)
* send POST -> legt die Nachricht in die Pushover-Queue (Cron versendet im Hintergrund)
*
* Empfänger ist IMMER der eingeloggte Mitarbeiter (persönlicher Pushover-Key aus pacim_user_notify).
* Nachricht im Monospace-Stil (ausgerichtete Spalten), ohne Emoji.
*/
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start();
function pdy_json( $a ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $a ); exit(); }
function pdy_fail( $m ) { pdy_json( array( 'ok' => false, 'error' => $m ) ); }
if ( ! function_exists( 'is_admin' ) || ! is_admin() ) { http_response_code( 403 ); pdy_json( array( 'ok' => false, 'error' => 'forbidden' ) ); }
$action = $_GET['action'] ?? ( $_POST['action'] ?? '' );
$date = substr( (string) ( $_REQUEST['date'] ?? '' ), 0, 10 );
if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date ) ) pdy_fail( 'Ungültiges Datum.' );
$uid = function_exists( 'current_user_id' ) ? current_user_id() : 0;
$key = class_exists( 'pushnotify' ) ? pushnotify::userKey( $uid ) : '';
if ( $key === '' ) pdy_fail( 'Kein persönlicher Pushover-Key hinterlegt (Einstellungen → Benutzer → Benachrichtigungen).' );
if ( ! pushnotify::configured() ) pdy_fail( 'Es ist kein systemweiter Pushover App-Token hinterlegt.' );
/* ---------------- Eingaben / Filter ---------------- */
$format = ( ( $_REQUEST['format'] ?? 'summary' ) === 'list' ) ? 'list' : 'summary';
$parkRaw = (string) ( $_REQUEST['parking'] ?? 'halle,aussen' );
$parking = array_values( array_intersect( array( 'halle', 'aussen', 'valet' ), array_map( 'trim', explode( ',', $parkRaw ) ) ) );
if ( ! $parking ) $parking = array( 'halle', 'aussen' );
$status = (string) ( $_REQUEST['status'] ?? 'all' ); // all | open | arrived
if ( ! in_array( $status, array( 'all', 'open', 'arrived' ), true ) ) $status = 'all';
$timeFrom = trim( (string) ( $_REQUEST['from'] ?? '' ) );
$timeTo = trim( (string) ( $_REQUEST['to'] ?? '' ) );
if ( ! preg_match( '/^([01]\d|2[0-3]):[0-5]\d$/', $timeFrom ) ) $timeFrom = '';
if ( ! preg_match( '/^([01]\d|2[0-3]):[0-5]\d$/', $timeTo ) ) $timeTo = '';
$ship = trim( (string) ( $_REQUEST['ship'] ?? '' ) );
$trip = isset( $_REQUEST['trip'] ) && $_REQUEST['trip'] !== '' ? (int) $_REQUEST['trip'] : 0;
// Spalten der Liste (Kennzeichen IMMER dabei). Optional: name, type, time.
$colsRaw = (string) ( $_REQUEST['columns'] ?? 'name,type' );
$cols = array_values( array_intersect( array( 'name', 'type', 'time', 'dur' ), array_map( 'trim', explode( ',', $colsRaw ) ) ) );
$db = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
/* ---------------- Tagesanreisen laden + filtern (geteilte Logik) ---------------- */
require_once( __DIR__ . '/includes/day-arrivals.php' );
$da = pacim_day_arrivals( $db, $date, array(
'parking' => $parking, 'status' => $status, 'from' => $timeFrom, 'to' => $timeTo, 'ship' => $ship, 'trip' => $trip,
) );
$items = $da['items']; $buckets = $da['buckets']; $total = $da['total'];
/* ---------------- Nachricht bauen (Monospace) ---------------- */
function pdy_pad( $s, $w, $right = false ) {
$s = (string) $s; $len = mb_strlen( $s, 'UTF-8' );
if ( $len > $w ) return mb_substr( $s, 0, $w, 'UTF-8' );
$pad = str_repeat( ' ', $w - $len );
return $right ? $pad . $s : $s . $pad;
}
$wdays = array( 1 => 'Mo', 2 => 'Di', 3 => 'Mi', 4 => 'Do', 5 => 'Fr', 6 => 'Sa', 7 => 'So' );
$wd = $wdays[ (int) date( 'N', strtotime( $date ) ) ];
$dDE = date( 'd.m.Y', strtotime( $date ) );
// Kompakte Filterzeile (nur wenn etwas einschränkt)
$flt = array();
if ( $status === 'open' ) $flt[] = 'nur offen';
if ( $status === 'arrived' ) $flt[] = 'nur angereist';
if ( $timeFrom !== '' || $timeTo !== '' ) $flt[] = trim( ( $timeFrom !== '' ? 'ab ' . $timeFrom : '' ) . ( $timeTo !== '' ? ' bis ' . $timeTo : '' ) );
if ( $ship !== '' ) $flt[] = $ship;
if ( $trip > 0 ) $flt[] = $trip . ' Tage';
$parkLabels = array( 'halle' => 'Halle', 'aussen' => 'Außen', 'valet' => 'Valet' );
if ( count( $parking ) < 3 ) $flt[] = implode( '+', array_map( function ( $p ) use ( $parkLabels ) { return $parkLabels[ $p ]; }, $parking ) );
$fltLine = $flt ? ( '[' . implode( ' · ', $flt ) . ']' ) : '';
$isHtml = false; // Pushover bleibt Monospace (ausgerichtete Tabelle); Links via verlinkter Web-Liste.
$chunks = array(); // vollständige Übermittlung -> ggf. mehrere Pushover-Nachrichten (Monospace ist kompakt)
if ( $format === 'list' ) {
$title = 'Anreise ' . $wd . ' ' . $dDE . ' (' . $total . ')';
// Ausgerichtete Monospace-Tabelle; Kennzeichen immer erste Spalte.
$spec = array(
'plate' => array( 'h' => 'KENNZ.', 'w' => 12 ),
'name' => array( 'h' => 'NAME', 'w' => 15 ),
'type' => array( 'h' => 'TYP', 'w' => 3 ),
'time' => array( 'h' => 'ZEIT', 'w' => 5 ),
'dur' => array( 'h' => 'TAGE', 'w' => 4 ),
);
$useCols = array_merge( array( 'plate' ), $cols );
$cell = function ( $key, $it ) use ( $spec ) {
switch ( $key ) {
case 'name': $v = $it['name']; break;
case 'type': $v = $it['letter']; break;
case 'time': $v = ( $it['time'] !== '' ) ? $it['time'] : '—'; break;
case 'dur': $v = ( $it['dur'] > 0 ) ? (string) $it['dur'] : '—'; break;
default: $v = $it['plate'];
}
return pdy_pad( $v, $spec[ $key ]['w'] );
};
$hdr = array(); foreach ( $useCols as $k ) $hdr[] = pdy_pad( $spec[ $k ]['h'], $spec[ $k ]['w'] );
$headLine = rtrim( implode( ' ', $hdr ) );
$allLines = array();
foreach ( $items as $it ) {
$cells = array(); foreach ( $useCols as $k ) $cells[] = $cell( $k, $it );
$allLines[] = rtrim( implode( ' ', $cells ) );
}
$message = ( $fltLine !== '' ? $fltLine . "\n" : '' ) . $headLine . "\n"
. ( $allLines ? implode( "\n", $allLines ) : '— keine Einträge —' );
// In Pushover-taugliche Blöcke (< 1024 Zeichen) aufteilen – vollständig, nichts wird weggelassen.
$cap = 950; $cur = '';
foreach ( $allLines as $ln ) {
$cand = ( $cur === '' ) ? $ln : ( $cur . "\n" . $ln );
if ( $cur !== '' && mb_strlen( $cand, 'UTF-8' ) > $cap ) { $chunks[] = $cur; $cur = $ln; }
else $cur = $cand;
}
if ( $cur !== '' ) $chunks[] = $cur;
if ( ! $chunks ) $chunks[] = '— keine Einträge —';
// Kopf (Filter + Spaltenüberschrift) auf jeden Block setzen, damit jede Nachricht lesbar bleibt.
$head = ( $fltLine !== '' ? $fltLine . "\n" : '' ) . $headLine . "\n";
foreach ( $chunks as $i => $c ) $chunks[ $i ] = $head . $c;
} else {
$title = 'Anreise ' . $wd . ' ' . $dDE;
$sumExp = $sumArr = $sumOpen = 0;
$lines = array();
if ( $fltLine !== '' ) $lines[] = $fltLine;
$lines[] = pdy_pad( '', 8 ) . pdy_pad( 'Erw', 5, true ) . pdy_pad( 'Ang', 5, true ) . pdy_pad( 'Off', 5, true );
foreach ( $parking as $p ) {
$b = $buckets[ $p ];
$lines[] = pdy_pad( $b['label'], 8 ) . pdy_pad( $b['exp'], 5, true ) . pdy_pad( $b['arr'], 5, true ) . pdy_pad( $b['open'], 5, true );
$sumExp += $b['exp']; $sumArr += $b['arr']; $sumOpen += $b['open'];
}
$lines[] = str_repeat( '─', 23 );
$lines[] = pdy_pad( 'Gesamt', 8 ) . pdy_pad( $sumExp, 5, true ) . pdy_pad( $sumArr, 5, true ) . pdy_pad( $sumOpen, 5, true );
$message = implode( "\n", $lines );
$chunks = array( $message );
}
// Notification verlinkt auf die hash-gesicherte Web-Liste (klickbare Kennzeichen -> Check-in/Zahlung).
$url = SITE_URL . '/day-list.php?' . http_build_query( array(
'date' => $date, 'from' => $timeFrom, 'to' => $timeTo, 'status' => $status,
'parking' => implode( ',', $parking ), 'ship' => $ship, 'trip' => $trip,
'columns' => implode( ',', $cols ), 'h' => pacim_sign( 'daylist:' . $date ),
) );
$urlTitle = 'Liste öffnen & einchecken';
$parts = max( 1, count( $chunks ) );
if ( $action === 'preview' ) {
pdy_json( array( 'ok' => true, 'title' => $title, 'message' => $message, 'count' => $total,
'monospace' => ! $isHtml, 'html' => $isHtml, 'parts' => $parts ) );
}
if ( $action === 'send' ) {
if ( $_SERVER['REQUEST_METHOD'] !== 'POST' ) pdy_fail( 'POST erforderlich.' );
$sent = 0;
foreach ( $chunks as $i => $chunk ) {
$t = $title . ( $parts > 1 ? ' (' . ( $i + 1 ) . '/' . $parts . ')' : '' );
$id = pushnotify::enqueue( $key, $t, $chunk, $url, $urlTitle, 'daypush', ! $isHtml, $isHtml );
if ( $id ) $sent++;
}
if ( ! $sent ) pdy_fail( 'Konnte nicht in die Queue gelegt werden.' );
$msg = $parts > 1
? ( 'In ' . $parts . ' Pushover-Nachrichten eingereiht (vollständige Liste) – werden im Hintergrund versendet.' )
: 'Pushover-Nachricht eingereiht – wird im Hintergrund versendet.';
pdy_json( array( 'ok' => true, 'queued' => true, 'count' => $total, 'parts' => $parts, 'message' => $msg ) );
}
pdy_fail( 'unknown_action' );