403Webshell
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/clients/client2/web20/web/wp-content/plugins/dgt-verkehrsmonitor/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/clients/client2/web20/web/wp-content/plugins/dgt-verkehrsmonitor/includes/admin.php
<?php
/**
 * Admin-Bereich: Dashboard-Widget, Menü, Quellen-Verwaltung.
 *
 * @package dgt-verkehrsmonitor
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/* ─── Admin-Menü ───────────────────────────────────────── */

function dgt_vm_admin_menu() {
	add_menu_page(
		'Verkehrsmonitor',
		'Verkehrsmonitor',
		'manage_options',
		'dgt-vm',
		'dgt_vm_admin_dashboard',
		'dashicons-chart-line',
		30
	);

	add_submenu_page(
		'dgt-vm',
		'Meldungen',
		'Meldungen',
		'manage_options',
		'dgt-vm',
		'dgt_vm_admin_dashboard'
	);

	add_submenu_page(
		'dgt-vm',
		'Quellen',
		'Quellen',
		'manage_options',
		'dgt-vm-sources',
		'dgt_vm_admin_sources'
	);

	add_submenu_page(
		'dgt-vm',
		'Statistiken',
		'Statistiken',
		'manage_options',
		'dgt-vm-stats',
		'dgt_vm_admin_stats'
	);

	add_submenu_page(
		'dgt-vm',
		'Einstellungen',
		'Einstellungen',
		'manage_options',
		'dgt-vm-settings',
		'dgt_vm_admin_settings'
	);
}
add_action( 'admin_menu', 'dgt_vm_admin_menu' );

/* ─── Dashboard (Meldungen-Übersicht) ──────────────────── */

function dgt_vm_admin_dashboard() {
	global $wpdb;
	$t = dgt_vm_table( 'incidents' );

	$counts = $wpdb->get_row(
		"SELECT
			COUNT(*)                                   AS total,
			SUM(status = 'publiziert')                 AS publiziert,
			SUM(status = 'entwurf')                    AS entwurf,
			SUM(status = 'abgelehnt')                  AS abgelehnt,
			SUM(source_date = CURDATE())               AS heute
		 FROM {$t}"
	);

	$per_page = 25;
	$paged    = max( 1, (int) ( $_GET['paged'] ?? 1 ) );
	$offset   = ( $paged - 1 ) * $per_page;

	$search     = sanitize_text_field( $_GET['s'] ?? '' );
	$fil_status = sanitize_text_field( $_GET['vm_status'] ?? '' );
	$fil_bl     = sanitize_text_field( $_GET['vm_bl'] ?? '' );
	$fil_delikt = sanitize_text_field( $_GET['vm_delikt'] ?? '' );

	$where  = array();
	$values = array();

	if ( $search ) {
		$like     = '%' . $wpdb->esc_like( $search ) . '%';
		$where[]  = '(ai_headline LIKE %s OR stadt LIKE %s OR original_titel LIKE %s)';
		$values[] = $like;
		$values[] = $like;
		$values[] = $like;
	}
	if ( $fil_status ) {
		$where[]  = 'status = %s';
		$values[] = $fil_status;
	}
	if ( $fil_bl ) {
		$where[]  = 'bundesland = %s';
		$values[] = $fil_bl;
	}
	if ( $fil_delikt ) {
		$where[]  = 'delikt = %s';
		$values[] = $fil_delikt;
	}

	$where_sql = $where ? 'WHERE ' . implode( ' AND ', $where ) : '';

	$total_q = "SELECT COUNT(*) FROM {$t} {$where_sql}";
	$total   = $values ? (int) $wpdb->get_var( $wpdb->prepare( $total_q, $values ) ) : (int) $wpdb->get_var( $total_q );

	$pages = max( 1, (int) ceil( $total / $per_page ) );
	if ( $paged > $pages ) {
		$paged  = $pages;
		$offset = ( $paged - 1 ) * $per_page;
	}

	$query = "SELECT id, ai_headline, ai_slug, bundesland, stadt, delikt, source_date, status
		 FROM {$t} {$where_sql}
		 ORDER BY created_at DESC
		 LIMIT %d OFFSET %d";
	$qvals = array_merge( $values, array( $per_page, $offset ) );
	$rows  = $wpdb->get_results( $wpdb->prepare( $query, $qvals ) );

	$base_url = admin_url( 'admin.php?page=dgt-vm' );

	?>
	<div class="wrap">
		<h1>Verkehrsmonitor – Meldungen</h1>

		<div style="display:flex;gap:1rem;margin:1.5rem 0;">
			<div class="card" style="flex:1;padding:1rem;text-align:center;">
				<h2 style="margin:0;font-size:2rem;"><?php echo (int) $counts->total; ?></h2>
				<p>Gesamt</p>
			</div>
			<div class="card" style="flex:1;padding:1rem;text-align:center;">
				<h2 style="margin:0;font-size:2rem;color:#46b450;"><?php echo (int) $counts->publiziert; ?></h2>
				<p>Publiziert</p>
			</div>
			<div class="card" style="flex:1;padding:1rem;text-align:center;">
				<h2 style="margin:0;font-size:2rem;color:#f0b849;"><?php echo (int) $counts->entwurf; ?></h2>
				<p>Entwurf</p>
			</div>
			<div class="card" style="flex:1;padding:1rem;text-align:center;">
				<h2 style="margin:0;font-size:2rem;color:#dc3232;"><?php echo (int) $counts->abgelehnt; ?></h2>
				<p>Abgelehnt</p>
			</div>
			<div class="card" style="flex:1;padding:1rem;text-align:center;">
				<h2 style="margin:0;font-size:2rem;"><?php echo (int) $counts->heute; ?></h2>
				<p>Heute</p>
			</div>
		</div>

		<form method="get" action="<?php echo esc_url( $base_url ); ?>" style="margin:1rem 0;display:flex;gap:.5rem;flex-wrap:wrap;align-items:end;">
			<input type="hidden" name="page" value="dgt-vm">
			<div>
				<input type="search" name="s" value="<?php echo esc_attr( $search ); ?>" placeholder="Headline, Stadt, Titel …" style="width:260px;">
			</div>
			<div>
				<select name="vm_status">
					<option value="">– Status –</option>
					<?php foreach ( array( 'publiziert', 'entwurf', 'abgelehnt' ) as $st ) : ?>
						<option value="<?php echo esc_attr( $st ); ?>" <?php selected( $fil_status, $st ); ?>><?php echo esc_html( ucfirst( $st ) ); ?></option>
					<?php endforeach; ?>
				</select>
			</div>
			<div>
				<select name="vm_bl">
					<option value="">– Bundesland –</option>
					<?php foreach ( dgt_vm_bundeslaender() as $slug => $name ) : ?>
						<option value="<?php echo esc_attr( $slug ); ?>" <?php selected( $fil_bl, $slug ); ?>><?php echo esc_html( $name ); ?></option>
					<?php endforeach; ?>
				</select>
			</div>
			<div>
				<select name="vm_delikt">
					<option value="">– Delikt –</option>
					<?php foreach ( array( 'alkohol' => 'Alkohol', 'drogen' => 'Drogen', 'beides' => 'Beides', 'sonstiges' => 'Sonstiges' ) as $dk => $dl ) : ?>
						<option value="<?php echo esc_attr( $dk ); ?>" <?php selected( $fil_delikt, $dk ); ?>><?php echo esc_html( $dl ); ?></option>
					<?php endforeach; ?>
				</select>
			</div>
			<?php submit_button( 'Suchen', 'primary', 'submit', false ); ?>
			<?php if ( $search || $fil_status || $fil_bl || $fil_delikt ) : ?>
				<a href="<?php echo esc_url( $base_url ); ?>" class="button">Zurücksetzen</a>
			<?php endif; ?>
		</form>

		<?php if ( $search || $fil_status || $fil_bl || $fil_delikt ) : ?>
			<p><?php printf( '<strong>%d</strong> Ergebnis(se) gefunden.', $total ); ?></p>
		<?php endif; ?>

		<table class="widefat striped">
			<thead>
				<tr>
					<th>ID</th>
					<th>Headline</th>
					<th>Bundesland</th>
					<th>Stadt</th>
					<th>Delikt</th>
					<th>Datum</th>
					<th>Status</th>
					<th>Frontend</th>
				</tr>
			</thead>
			<tbody>
				<?php if ( $rows ) : foreach ( $rows as $r ) : ?>
					<tr>
						<td><?php echo (int) $r->id; ?></td>
						<td><?php echo esc_html( $r->ai_headline ?: '(kein Titel)' ); ?></td>
						<td><?php echo esc_html( dgt_vm_bundesland_name( $r->bundesland ) ?: $r->bundesland ); ?></td>
						<td><?php echo esc_html( $r->stadt ); ?></td>
						<td><?php echo esc_html( $r->delikt ); ?></td>
						<td><?php echo esc_html( $r->source_date ); ?></td>
						<td><?php echo esc_html( $r->status ); ?></td>
						<td>
							<?php if ( 'publiziert' === $r->status && $r->ai_slug ) : ?>
								<a href="<?php echo esc_url( dgt_vm_incident_url( $r ) ); ?>" target="_blank" class="button button-small">Ansehen ↗</a>
							<?php else : ?>
								<span style="color:#999;">–</span>
							<?php endif; ?>
						</td>
					</tr>
				<?php endforeach; else : ?>
					<tr><td colspan="8">Keine Meldungen gefunden.</td></tr>
				<?php endif; ?>
			</tbody>
		</table>

		<?php if ( $pages > 1 ) : ?>
			<div class="tablenav" style="margin-top:1rem;">
				<div class="tablenav-pages">
					<span class="displaying-num"><?php printf( '%d Einträge', $total ); ?></span>
					<?php
					$pag_args = array(
						's'         => $search,
						'vm_status' => $fil_status,
						'vm_bl'     => $fil_bl,
						'vm_delikt' => $fil_delikt,
					);
					$pag_args = array_filter( $pag_args );

					if ( $paged > 1 ) :
						$prev_url = add_query_arg( array_merge( $pag_args, array( 'page' => 'dgt-vm', 'paged' => $paged - 1 ) ), $base_url );
						?>
						<a class="prev-page button" href="<?php echo esc_url( $prev_url ); ?>">‹</a>
					<?php endif; ?>

					<span class="paging-input">
						<strong><?php echo $paged; ?></strong> von <strong><?php echo $pages; ?></strong>
					</span>

					<?php if ( $paged < $pages ) :
						$next_url = add_query_arg( array_merge( $pag_args, array( 'page' => 'dgt-vm', 'paged' => $paged + 1 ) ), $base_url );
						?>
						<a class="next-page button" href="<?php echo esc_url( $next_url ); ?>">›</a>
					<?php endif; ?>
				</div>
			</div>
		<?php endif; ?>
	</div>
	<?php
}

/* ─── Quellen-Verwaltung ──────────────────────────────── */

function dgt_vm_admin_sources() {
	global $wpdb;
	$t = dgt_vm_table( 'sources' );

	// Neue Quelle speichern.
	if ( isset( $_POST['dgt_vm_source_nonce'] ) && wp_verify_nonce( $_POST['dgt_vm_source_nonce'], 'dgt_vm_add_source' ) ) {
		$wpdb->insert( $t, array(
			'name'       => sanitize_text_field( $_POST['name'] ),
			'bundesland' => sanitize_title( $_POST['bundesland'] ),
			'feed_url'   => esc_url_raw( $_POST['feed_url'] ),
			'feed_type'  => sanitize_text_field( $_POST['feed_type'] ),
			'aktiv'      => 1,
			'created_at' => current_time( 'mysql' ),
		) );
		echo '<div class="updated"><p>Quelle hinzugefügt.</p></div>';
	}

	$sources = $wpdb->get_results( "SELECT * FROM {$t} ORDER BY bundesland, name" );

	?>
	<div class="wrap">
		<h1>Verkehrsmonitor – Quellen</h1>

		<h2>Neue Quelle hinzufügen</h2>
		<form method="post" style="max-width:600px;">
			<?php wp_nonce_field( 'dgt_vm_add_source', 'dgt_vm_source_nonce' ); ?>
			<table class="form-table">
				<tr>
					<th><label for="name">Name</label></th>
					<td><input type="text" id="name" name="name" class="regular-text" required></td>
				</tr>
				<tr>
					<th><label for="bundesland">Bundesland</label></th>
					<td>
						<select id="bundesland" name="bundesland" required>
							<?php foreach ( dgt_vm_bundeslaender() as $slug => $label ) : ?>
								<option value="<?php echo esc_attr( $slug ); ?>"><?php echo esc_html( $label ); ?></option>
							<?php endforeach; ?>
						</select>
					</td>
				</tr>
				<tr>
					<th><label for="feed_url">Feed-URL</label></th>
					<td><input type="url" id="feed_url" name="feed_url" class="regular-text" required></td>
				</tr>
				<tr>
					<th><label for="feed_type">Typ</label></th>
					<td>
						<select id="feed_type" name="feed_type">
							<option value="rss">RSS</option>
							<option value="html">HTML</option>
							<option value="api">API</option>
						</select>
					</td>
				</tr>
			</table>
			<?php submit_button( 'Quelle hinzufügen' ); ?>
		</form>

		<h2>Aktive Quellen (<?php echo count( $sources ); ?>)</h2>
		<table class="widefat striped">
			<thead>
				<tr>
					<th>Name</th>
					<th>Bundesland</th>
					<th>Feed-URL</th>
					<th>Typ</th>
					<th>Letzter Fetch</th>
					<th>Letzte Anzahl</th>
					<th>Aktiv</th>
				</tr>
			</thead>
			<tbody>
				<?php if ( $sources ) : foreach ( $sources as $s ) : ?>
					<tr>
						<td><?php echo esc_html( $s->name ); ?></td>
						<td><?php echo esc_html( dgt_vm_bundesland_name( $s->bundesland ) ); ?></td>
						<td><code style="font-size:11px;"><?php echo esc_html( $s->feed_url ); ?></code></td>
						<td><?php echo esc_html( $s->feed_type ); ?></td>
						<td><?php echo $s->last_fetch ? esc_html( dgt_vm_format_datetime( $s->last_fetch ) ) : '–'; ?></td>
						<td><?php echo (int) $s->last_count; ?></td>
						<td><?php echo $s->aktiv ? '✓' : '✗'; ?></td>
					</tr>
				<?php endforeach; else : ?>
					<tr><td colspan="7">Noch keine Quellen konfiguriert.</td></tr>
				<?php endif; ?>
			</tbody>
		</table>
	</div>
	<?php
}

/* ─── Statistik-Seite ──────────────────────────────────── */

function dgt_vm_admin_stats() {
	global $wpdb;
	$t = dgt_vm_table( 'daily_stats' );

	$stats = $wpdb->get_results(
		"SELECT * FROM {$t} WHERE bundesland = '_all' ORDER BY stat_date DESC LIMIT 30"
	);

	?>
	<div class="wrap">
		<h1>Verkehrsmonitor – Tagesstatistiken</h1>

		<table class="widefat striped">
			<thead>
				<tr>
					<th>Datum</th>
					<th>Gesamt</th>
					<th>Alkohol</th>
					<th>Drogen</th>
					<th>Beides</th>
					<th>Unfälle</th>
					<th>FS entzogen</th>
					<th>∅ BAK</th>
					<th>Max BAK</th>
				</tr>
			</thead>
			<tbody>
				<?php if ( $stats ) : foreach ( $stats as $s ) : ?>
					<tr>
						<td><?php echo esc_html( $s->stat_date ); ?></td>
						<td><strong><?php echo (int) $s->total; ?></strong></td>
						<td><?php echo (int) $s->alkohol; ?></td>
						<td><?php echo (int) $s->drogen; ?></td>
						<td><?php echo (int) $s->beides; ?></td>
						<td><?php echo (int) $s->unfaelle; ?></td>
						<td><?php echo (int) $s->fs_entzogen; ?></td>
						<td><?php echo $s->avg_bak ? number_format_i18n( $s->avg_bak, 2 ) : '–'; ?></td>
						<td><?php echo $s->max_bak ? number_format_i18n( $s->max_bak, 2 ) : '–'; ?></td>
					</tr>
				<?php endforeach; else : ?>
					<tr><td colspan="9">Noch keine Statistiken vorhanden.</td></tr>
				<?php endif; ?>
			</tbody>
		</table>
	</div>
	<?php
}

/* ─── Einstellungen ────────────────────────────────────── */

function dgt_vm_admin_settings() {
	if ( isset( $_POST['dgt_vm_settings_nonce'] ) && wp_verify_nonce( $_POST['dgt_vm_settings_nonce'], 'dgt_vm_save_settings' ) ) {
		update_option( 'dgt_vm_api_key', sanitize_text_field( $_POST['dgt_vm_api_key'] ) );
		update_option( 'dgt_vm_ai_model', sanitize_text_field( $_POST['dgt_vm_ai_model'] ) );
		echo '<div class="updated"><p>Einstellungen gespeichert.</p></div>';
	}

	if ( isset( $_POST['dgt_vm_action_nonce'] ) && wp_verify_nonce( $_POST['dgt_vm_action_nonce'], 'dgt_vm_manual_action' ) ) {
		$action = sanitize_text_field( $_POST['dgt_vm_action'] );
		if ( 'fetch' === $action ) {
			dgt_vm_do_fetch_sources();
			$count = get_option( 'dgt_vm_last_fetch_count', 0 );
			echo '<div class="updated"><p>Fetch abgeschlossen: ' . (int) $count . ' neue Meldungen.</p></div>';
		} elseif ( 'analyze' === $action ) {
			dgt_vm_do_analyze_pending();
			$count = get_option( 'dgt_vm_last_analyze_count', 0 );
			echo '<div class="updated"><p>Analyse abgeschlossen: ' . (int) $count . ' Meldungen analysiert.</p></div>';
		} elseif ( 'aggregate' === $action ) {
			dgt_vm_do_aggregate_daily();
			echo '<div class="updated"><p>Tagesstatistik für gestern aggregiert.</p></div>';
		} elseif ( 'scrape' === $action ) {
			$count = dgt_vm_do_scrape_listings( 5 );
			$count2 = dgt_vm_do_scrape_categories( 3 );
			echo '<div class="updated"><p>Scrape abgeschlossen: ' . ( (int) $count + (int) $count2 ) . ' neue Meldungen.</p></div>';
		} elseif ( 'refetch' === $action ) {
			$count = dgt_vm_refetch_fulltext( 50 );
			echo '<div class="updated"><p>Volltext aktualisiert: ' . (int) $count . ' Einträge.</p></div>';
		} elseif ( 'seed' === $action ) {
			dgt_vm_seed_sources();
			echo '<div class="updated"><p>Seed-Quellen eingefügt.</p></div>';
		}
	}

	$api_key = get_option( 'dgt_vm_api_key', '' );
	$model   = get_option( 'dgt_vm_ai_model', 'claude-haiku-4-5-20251001' );

	$last_fetch     = get_option( 'dgt_vm_last_fetch', '–' );
	$last_analyze   = get_option( 'dgt_vm_last_analyze', '–' );
	$last_aggregate = get_option( 'dgt_vm_last_aggregate', '–' );

	global $wpdb;
	$pending = (int) $wpdb->get_var( "SELECT COUNT(*) FROM " . dgt_vm_table( 'incidents' ) . " WHERE status = 'entwurf'" );
	?>
	<div class="wrap">
		<h1>Verkehrsmonitor – Einstellungen</h1>

		<h2>API-Konfiguration</h2>
		<form method="post" style="max-width:600px;">
			<?php wp_nonce_field( 'dgt_vm_save_settings', 'dgt_vm_settings_nonce' ); ?>
			<table class="form-table">
				<tr>
					<th><label for="dgt_vm_api_key">Claude API-Key</label></th>
					<td>
						<input type="password" id="dgt_vm_api_key" name="dgt_vm_api_key" class="regular-text" value="<?php echo esc_attr( $api_key ); ?>">
						<p class="description">Anthropic API-Key für die KI-Analyse.</p>
					</td>
				</tr>
				<tr>
					<th><label for="dgt_vm_ai_model">KI-Modell</label></th>
					<td>
						<select id="dgt_vm_ai_model" name="dgt_vm_ai_model">
							<option value="claude-haiku-4-5-20251001" <?php selected( $model, 'claude-haiku-4-5-20251001' ); ?>>Claude Haiku 4.5 (günstig)</option>
							<option value="claude-sonnet-4-6" <?php selected( $model, 'claude-sonnet-4-6' ); ?>>Claude Sonnet 4.6 (mittel)</option>
							<option value="claude-opus-4-6" <?php selected( $model, 'claude-opus-4-6' ); ?>>Claude Opus 4.6 (beste Qualität)</option>
						</select>
					</td>
				</tr>
			</table>
			<?php submit_button( 'Speichern' ); ?>
		</form>

		<hr>

		<h2>Status</h2>
		<table class="widefat" style="max-width:600px;">
			<tr><th>Letzter Fetch</th><td><?php echo esc_html( $last_fetch ); ?></td></tr>
			<tr><th>Letzte Analyse</th><td><?php echo esc_html( $last_analyze ); ?></td></tr>
			<tr><th>Letzte Aggregation</th><td><?php echo esc_html( $last_aggregate ); ?></td></tr>
			<tr><th>Ausstehende Entwürfe</th><td><strong><?php echo $pending; ?></strong></td></tr>
		</table>

		<hr>

		<h2>Manuelle Aktionen</h2>
		<p>Aktionen werden normalerweise automatisch per System-Crontab ausgeführt.</p>
		<div style="display:flex;gap:1rem;flex-wrap:wrap;">
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="fetch">
				<?php submit_button( 'Quellen jetzt fetchen', 'secondary', 'submit', false ); ?>
			</form>
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="analyze">
				<?php submit_button( 'Entwürfe analysieren (' . $pending . ')', 'secondary', 'submit', false ); ?>
			</form>
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="aggregate">
				<?php submit_button( 'Statistik aggregieren', 'secondary', 'submit', false ); ?>
			</form>
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="scrape">
				<?php submit_button( 'Listings scrapen', 'secondary', 'submit', false ); ?>
			</form>
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="refetch">
				<?php submit_button( 'Volltext nachladen', 'secondary', 'submit', false ); ?>
			</form>
			<form method="post" style="display:inline;">
				<?php wp_nonce_field( 'dgt_vm_manual_action', 'dgt_vm_action_nonce' ); ?>
				<input type="hidden" name="dgt_vm_action" value="seed">
				<?php submit_button( 'Seed-Quellen einfügen', 'secondary', 'submit', false ); ?>
			</form>
		</div>
	</div>
	<?php
}

Youez - 2016 - github.com/yon3zu
LinuXploit