middleware/dashboard.php

396 lines
15 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
error_reporting(E_ALL);
ini_set('display_errors', 1);
// dashboard.php
// Zentrale Zugangsdaten einbinden
require_once 'secrets.php';
// Datenbank-Verbindungsparameter
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET;
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
} catch (PDOException $e) {
header('Content-Type: application/json');
echo json_encode(['error' => 'Database connection failed: ' . $e->getMessage()]);
exit;
}
// Bearer Token für Mastodon-API (falls benötigt)
$bearerToken = 'your_bearer_token_here';
// -----------------------
// AJAX-Anfragen (POST)
// -----------------------
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
header('Content-Type: application/json');
if ($action === 'save_config') {
// Erwartet: from_date, to_date, refresh_interval
$from_date = $_POST['from_date']; // z.B. "2025-03-17T14:00"
$to_date = $_POST['to_date'];
$refresh_interval = $_POST['refresh_interval'];
// Aktualisieren wir gehen davon aus, dass die Config-Tabelle eine einzelne Zeile mit id=1 hat.
$stmt = $pdo->prepare("UPDATE config SET from_date = :from_date, to_date = :to_date, refresh_interval = :refresh_interval WHERE id = 1");
$stmt->execute([
'from_date' => date('Y-m-d H:i:s', strtotime($from_date)),
'to_date' => date('Y-m-d H:i:s', strtotime($to_date)),
'refresh_interval' => $refresh_interval
]);
echo json_encode(['status' => 'ok']);
exit;
} elseif ($action === 'save_hashtags') {
// Erwartet ein Array "hashtags" mit den Feldern: hashtag_id, hashtag, active
$hashtags = isset($_POST['hashtags']) ? $_POST['hashtags'] : [];
$response = ['saved' => 0, 'updated' => 0];
foreach ($hashtags as $row) {
if (isset($row['hashtag_id']) && !empty($row['hashtag_id'])) {
// Update
$stmt = $pdo->prepare("UPDATE hashtags SET hashtag = :hashtag, active = :active WHERE hashtag_id = :hashtag_id");
$stmt->execute([
'hashtag' => $row['hashtag'],
'active' => !empty($row['active']) ? 1 : 0,
'hashtag_id' => $row['hashtag_id']
]);
$response['updated']++;
} else {
// Insert neuer Eintrag
$stmt = $pdo->prepare("INSERT INTO hashtags (hashtag, active) VALUES (:hashtag, :active)");
$stmt->execute([
'hashtag' => $row['hashtag'],
'active' => !empty($row['active']) ? 1 : 0
]);
$response['saved']++;
}
}
echo json_encode($response);
exit;
} elseif ($action === 'save_accounts') {
// Erwartet ein Array "accounts" (Felder: acc_id, active)
$accounts = isset($_POST['accounts']) ? $_POST['accounts'] : [];
$response = ['updated' => 0];
foreach ($accounts as $row) {
// Anpassen: WHERE user_id = :acc_id
$stmt = $pdo->prepare("UPDATE users SET active = :active WHERE user_id = :acc_id");
$stmt->execute([
'active' => !empty($row['active']) ? 1 : 0,
'acc_id' => $row['acc_id']
]);
$response['updated']++;
}
echo json_encode($response);
exit;
} elseif ($action === 'sync_accounts') {
// Synchronisation: Aus der findings-Tabelle werden alle getrackten Accounts (acc_id, username) ermittelt
// Für jeden Account, der noch nicht in der "users"-Tabelle existiert, erfolgt ein Insert mit active=0
$stmt = $pdo->query("SELECT DISTINCT f.acc_id, f.username FROM findings f LEFT JOIN users u ON f.acc_id = u.user_id WHERE u.user_id IS NULL");
$newAccounts = $stmt->fetchAll();
foreach ($newAccounts as $acc) {
// Neuer Account unaktiv in die Tabelle schreiben
$insertStmt = $pdo->prepare("INSERT INTO users (user_id, username, active) VALUES (:acc_id, :username, 0)");
$insertStmt->execute([
'acc_id' => $acc['acc_id'],
'username' => $acc['username']
]);
}
// Nun alle Accounts aus der users-Tabelle abrufen
$stmt = $pdo->query("SELECT user_id as acc_id, username, active FROM users ORDER BY username ASC");
$accountsList = $stmt->fetchAll();
echo json_encode($accountsList);
exit;
} elseif ($action === 'get_dashboard_data') {
// Lese den Zeitraum und Refresh-Intervall aus der config-Tabelle (id=1)
$configStmt = $pdo->query("SELECT from_date, to_date, refresh_interval FROM config WHERE id = 1");
$config = $configStmt->fetch();
if (!$config) {
$config = ['from_date' => date('Y-m-d H:i:s', strtotime('-1 day')), 'to_date' => date('Y-m-d H:i:s'), 'refresh_interval' => 20];
}
// Aggregation: Nur Beiträge innerhalb des Zeitraums, zu aktiven Hashtags und von aktiven Usern
$query = "SELECT f.username, h.hashtag,
SUM(f.replies_count) AS total_replies,
SUM(f.reblogs_count) AS total_reblogs,
SUM(f.favorites_count) AS total_favorites
FROM findings f
JOIN hashtags h ON f.hashtag_id = h.hashtag_id
JOIN users u ON f.acc_id = u.user_id
WHERE f.created_at BETWEEN :from_date AND :to_date
AND h.active = 1
AND u.active = 1
GROUP BY h.hashtag, f.username
ORDER BY h.hashtag, f.username";
$stmt = $pdo->prepare($query);
$stmt->execute([
'from_date' => $config['from_date'],
'to_date' => $config['to_date']
]);
$data = $stmt->fetchAll();
// Bestimme globale Maximalwerte für jeden Metrik, um die Balkenhöhen zu skalieren
$maxReplies = $maxReblogs = $maxFavorites = 0;
foreach ($data as $row) {
if ($row['total_replies'] > $maxReplies) { $maxReplies = $row['total_replies']; }
if ($row['total_reblogs'] > $maxReblogs) { $maxReblogs = $row['total_reblogs']; }
if ($row['total_favorites'] > $maxFavorites) { $maxFavorites = $row['total_favorites']; }
}
echo json_encode([
'data' => $data,
'max' => ['replies' => $maxReplies, 'reblogs' => $maxReblogs, 'favorites' => $maxFavorites]
]);
exit;
}
exit;
}
// -----------------------
// GET-Anfragen: Anzeige der Seite
// -----------------------
// Wenn action=setup in der URL übergeben wurde, wird der Konfigurationsbereich angezeigt.
if (isset($_GET['action']) && $_GET['action'] == 'setup') {
// Lese Konfiguration aus der config-Tabelle (angenommen, es gibt eine einzelne Zeile mit id=1)
$configStmt = $pdo->query("SELECT from_date, to_date, refresh_interval FROM config WHERE id = 1");
$config = $configStmt->fetch();
if (!$config) {
$config = ['from_date' => date('Y-m-d\TH:i'), 'to_date' => date('Y-m-d\TH:i'), 'refresh_interval' => 20];
} else {
// Für datetime-local Eingabefelder im Format "YYYY-MM-DDTHH:MM"
$config['from_date'] = date('Y-m-d\TH:i', strtotime($config['from_date']));
$config['to_date'] = date('Y-m-d\TH:i', strtotime($config['to_date']));
}
// Lade Hashtag-Konfiguration
$hashtagStmt = $pdo->query("SELECT hashtag_id, hashtag, active FROM hashtags ORDER BY hashtag ASC");
$hashtags = $hashtagStmt->fetchAll();
// Lade getrackte User: Alle unterschiedlichen User aus findings, verknüpft mit der users-Tabelle
$userStmt = $pdo->query("SELECT DISTINCT f.acc_id, f.username, IFNULL(u.active, 0) as active
FROM findings f
LEFT JOIN users u ON f.acc_id = u.user_id
ORDER BY f.username ASC");
$users = $userStmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Dashboard Konfiguration</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }
th, td { border: 1px solid #ccc; padding: 5px; text-align: left; }
.error { color: red; }
.config-section { margin-bottom: 2em; padding: 1em; border: 1px solid #ddd; }
</style>
</head>
<body>
<h1>Dashboard Konfiguration</h1>
<!-- Zeitraum-Konfiguration -->
<div class="config-section">
<h2>Zeitraum</h2>
<form id="config-form">
<label for="from_date">Von:</label>
<input type="datetime-local" id="from_date" name="from_date" value="<?php echo $config['from_date']; ?>">
<label for="to_date">Bis:</label>
<input type="datetime-local" id="to_date" name="to_date" value="<?php echo $config['to_date']; ?>">
<label for="refresh_interval">Refresh Intervall (Sekunden):</label>
<input type="text" id="refresh_interval" name="refresh_interval" value="<?php echo $config['refresh_interval']; ?>" size="3">
<button type="button" id="save-config">Speichern</button>
</form>
</div>
<!-- Hashtag-Konfiguration -->
<div class="config-section">
<h2>Hashtags</h2>
<table id="hashtag-config-table">
<thead>
<tr>
<th>Hashtag</th>
<th>Aktiv</th>
</tr>
</thead>
<tbody>
<?php foreach($hashtags as $h): ?>
<tr data-id="<?php echo $h['hashtag_id']; ?>">
<td><input type="text" class="hashtag-text" value="<?php echo htmlspecialchars($h['hashtag']); ?>"></td>
<td><input type="checkbox" class="hashtag-active" <?php echo ($h['active'] == 1) ? 'checked' : ''; ?>></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<button id="add-hashtag">+1</button>
<button id="save-hashtags">Speichern</button>
</div>
<!-- User-Konfiguration -->
<div class="config-section">
<h2>Getrackte User</h2>
<table id="user-config-table">
<thead>
<tr>
<th>Acc_ID</th>
<th>Username</th>
<th>Aktiv</th>
</tr>
</thead>
<tbody>
<?php foreach($users as $u): ?>
<tr data-id="<?php echo $u['acc_id']; ?>">
<td><?php echo $u['acc_id']; ?></td>
<td><?php echo htmlspecialchars($u['username']); ?></td>
<td><input type="checkbox" class="user-active" <?php echo ($u['active'] == 1) ? 'checked' : ''; ?>></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<button id="save-users">Speichern</button>
</div>
<script>
$(document).ready(function(){
// Konfigurationsspeicherung für Zeitraum
$('#save-config').click(function(){
$.ajax({
url: 'dashboard.php',
type: 'POST',
dataType: 'json',
data: {
action: 'save_config',
from_date: $('#from_date').val(),
to_date: $('#to_date').val(),
refresh_interval: $('#refresh_interval').val()
},
success: function(resp) {
alert('Konfiguration gespeichert.');
}
});
});
// Hashtag-Konfiguration speichern
$('#save-hashtags').click(function(){
var hashtags = [];
$('#hashtag-config-table tbody tr').each(function(){
var id = $(this).data('id');
var text = $(this).find('.hashtag-text').val().trim();
var active = $(this).find('.hashtag-active').is(':checked') ? 1 : 0;
if(text !== ""){
hashtags.push({hashtag_id: id, hashtag: text, active: active});
}
});
$.ajax({
url: 'dashboard.php',
type: 'POST',
dataType: 'json',
data: { action: 'save_hashtags', hashtags: hashtags },
success: function(resp){
alert('Hashtags gespeichert.');
location.reload();
}
});
});
// User-Konfiguration speichern
$('#save-users').click(function(){
var accounts = [];
$('#user-config-table tbody tr').each(function(){
var acc_id = $(this).data('id');
var active = $(this).find('.user-active').is(':checked') ? 1 : 0;
accounts.push({acc_id: acc_id, active: active});
});
$.ajax({
url: 'dashboard.php',
type: 'POST',
dataType: 'json',
data: { action: 'save_accounts', accounts: accounts },
success: function(resp){
alert('User gespeichert.');
}
});
});
});
</script>
</body>
</html>
<?php
exit;
} else {
// Dashboard-Übersicht: Wenn kein action=setup übergeben wird, wird die aggregierte Ansicht angezeigt.
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Dashboard Übersicht</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
.tile { border: 1px solid #ccc; padding: 10px; margin: 10px; display: inline-block; vertical-align: top; width: 200px; }
.bar-container { height: 100px; width: 30px; display: inline-block; margin-right: 5px; background: #eee; position: relative; }
.bar { position: absolute; bottom: 0; width: 100%; background: #3b82f6; }
.label { text-align: center; font-size: 12px; }
</style>
</head>
<body>
<h1>Dashboard Übersicht</h1>
<div id="tiles-container">
<!-- Hier werden die Kacheln angezeigt -->
</div>
<script>
function loadDashboard(){
$.ajax({
url: 'dashboard.php',
type: 'POST',
dataType: 'json',
data: { action: 'get_dashboard_data' },
success: function(resp){
var data = resp.data;
var maxReplies = resp.max.replies;
var maxReblogs = resp.max.reblogs;
var maxFavorites = resp.max.favorites;
var container = $('#tiles-container');
container.empty();
// Sortierung nach Hashtag und dann Username
data.sort(function(a, b){
if(a.hashtag === b.hashtag) {
return a.username.localeCompare(b.username);
}
return a.hashtag.localeCompare(b.hashtag);
});
$.each(data, function(i, row){
var repliesHeight = maxReplies > 0 ? (row.total_replies / maxReplies) * 100 : 0;
var reblogsHeight = maxReblogs > 0 ? (row.total_reblogs / maxReblogs) * 100 : 0;
var favoritesHeight = maxFavorites > 0 ? (row.total_favorites / maxFavorites) * 100 : 0;
var tile = $('<div class="tile"></div>');
tile.append('<h3>' + row.hashtag + '</h3>');
tile.append('<p>' + row.username + '</p>');
var bars = $('<div></div>');
bars.append('<div class="bar-container"><div class="bar" style="height:'+repliesHeight+'%"></div><div class="label">Replies ('+row.total_replies+')</div></div>');
bars.append('<div class="bar-container"><div class="bar" style="height:'+reblogsHeight+'%"></div><div class="label">Reblogs ('+row.total_reblogs+')</div></div>');
bars.append('<div class="bar-container"><div class="bar" style="height:'+favoritesHeight+'%"></div><div class="label">Likes ('+row.total_favorites+')</div></div>');
tile.append(bars);
container.append(tile);
});
}
});
}
// Initiales Laden
loadDashboard();
// Aktualisierung im Hintergrund Intervall aus der Config (Standard 20 Sek.)
setInterval(loadDashboard, 20000);
</script>
</body>
</html>
<?php
}
?>