Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2b4ac2124 | ||
|
|
f7fd4ed183 | ||
|
|
a73b2ec13f | ||
|
|
dce0a0caed | ||
|
|
3d8c4291be | ||
|
|
a0afeabb27 | ||
|
|
96c27a8722 | ||
|
|
4478f7e82f | ||
|
|
c1f3c3ea4e | ||
|
|
2a8564d3bf | ||
|
|
14f4143207 | ||
|
|
53b4bd3423 | ||
|
|
386bef9094 | ||
|
|
4e52aa468f |
No files matched your search
@@ -3,3 +3,17 @@ RewriteEngine On
|
||||
RewriteRule ^(Commands|config_backups|controller|modules)($|/.*) - [F,L,NC]
|
||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
|
||||
|
||||
# -----------------------------------
|
||||
# .php entfernen
|
||||
# -----------------------------------
|
||||
|
||||
# browser requestet datei.php -> redirect zu /datei
|
||||
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
|
||||
RewriteRule ^ /%1 [R=301,L]
|
||||
|
||||
# /datei -> datei.php
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
|
||||
RewriteRule ^(.+)$ $1.php [L]
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
include_once '../controller/DatabaseController.php';
|
||||
include_once '../controller/DataController.php';
|
||||
include_once __DIR__ . '/../modules/Mail.php';
|
||||
include_once( __DIR__ . '/../../controller/DatabaseController.php');
|
||||
include_once( __DIR__ . '/../../controller/DataController.php');
|
||||
include_once( __DIR__ . '/../../controller/ApiController.php');
|
||||
include_once(__DIR__ . '/../../modules/Mail.php');
|
||||
|
||||
header("Content-Type: application/json");
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
@@ -13,9 +14,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
exit();
|
||||
}
|
||||
|
||||
$validTokens = [
|
||||
"15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e242",
|
||||
];
|
||||
$validTokens = DatabaseShow(
|
||||
"API_Credentials",
|
||||
"TOKEN"
|
||||
);
|
||||
|
||||
$validTokens = array_column($validTokens, 'TOKEN');
|
||||
|
||||
$headers = getallheaders();
|
||||
$token = $headers['Authorization'] ?? $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||||
@@ -28,18 +32,37 @@ if (!in_array($token, $validTokens)) {
|
||||
"debug_received_token" => $token,
|
||||
"debug_all_headers" => $headers
|
||||
]);
|
||||
|
||||
DatabaseInsert(
|
||||
"API_LOGS",
|
||||
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
|
||||
(new getSpecificData())->getClientIP(),
|
||||
$token,
|
||||
(new getSpecificData())->getRequestURL(),
|
||||
$function,
|
||||
$error
|
||||
);
|
||||
|
||||
errorMail(
|
||||
"API Login failed",
|
||||
$error,
|
||||
true,
|
||||
);
|
||||
echo $error;
|
||||
|
||||
echo json_encode(
|
||||
[
|
||||
"error" => "Unauthorized",
|
||||
"Contact" => "bruno.eckhardt07@gmail.com",
|
||||
]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = null;
|
||||
|
||||
if (in_array($token, $validTokens)) {
|
||||
DatabaseInsert(
|
||||
"API",
|
||||
"API_LOGS",
|
||||
"CLIENT_IP, TOKEN, API, FUNKTION",
|
||||
(new getSpecificData())->getClientIP(),
|
||||
$token,
|
||||
@@ -60,6 +83,13 @@ if (in_array($token, $validTokens)) {
|
||||
"MINUTEN"
|
||||
);
|
||||
}
|
||||
|
||||
if ($function === "Berichte") {
|
||||
$data = DatabaseShowWithFK(
|
||||
"Berufsschulberichte",
|
||||
$Berufsschulberichte,
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode(
|
||||
[
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
include_once '../controller/DatabaseController.php';
|
||||
include_once '../controller/DataController.php';
|
||||
include_once( __DIR__ . '/../../controller/DatabaseController.php' );
|
||||
include_once( __DIR__ . '/../../controller/DataController.php' );
|
||||
|
||||
header("Content-Type: application/json");
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
@@ -110,4 +110,4 @@ DatabaseInsert(
|
||||
$json
|
||||
);
|
||||
|
||||
echo $json;
|
||||
echo $json;
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
include_once(__DIR__ . '/../../controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/../../controller/DataController.php');
|
||||
include_once(__DIR__ . '/../../controller/ApiController.php');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$api = (new ApiController());
|
||||
|
||||
if ($api->urlAuth($_GET['token']) == true ) {
|
||||
|
||||
if (isset($_GET['day'])) {
|
||||
|
||||
$day = $_GET['day'];
|
||||
|
||||
$data = DatabaseShowWithFK(
|
||||
"Stundenplan",
|
||||
$Stundenplan,
|
||||
"ZEITEN, $day",
|
||||
"$day IS NOT NULL AND $day != '' AND $day != '(NULL)' ORDER BY ZEITEN ASC"
|
||||
);
|
||||
} else {
|
||||
$data = DatabaseShowWithFK(
|
||||
"Stundenplan",
|
||||
$Stundenplan,
|
||||
"ZEITEN, MO, DI, MO, DO, FR",
|
||||
);
|
||||
}
|
||||
echo $api->jsonSuccess($data);
|
||||
$api->requestSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* http://localhost:9000/api/v2/lessons.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
|
||||
* http://localhost:9000/api/v2/lessons.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&day=FR
|
||||
*/
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
include_once(__DIR__ . '/../../controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/../../controller/DataController.php');
|
||||
include_once(__DIR__ . '/../../controller/ApiController.php');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$api = (new ApiController());
|
||||
|
||||
if ($api->urlAuth($_GET['token']) == true ) {
|
||||
|
||||
if (isset($_GET['date'])) {
|
||||
|
||||
$date = $_GET['date'];
|
||||
|
||||
$data = DatabaseShowWithFK(
|
||||
"Berufsschulberichte",
|
||||
$Berufsschulberichte,
|
||||
"*",
|
||||
"DATUM = ?",
|
||||
$date
|
||||
);
|
||||
} else {
|
||||
$data = DatabaseShowWithFK(
|
||||
"Berufsschulberichte",
|
||||
$Berufsschulberichte,
|
||||
);
|
||||
}
|
||||
echo $api->jsonSuccess($data);
|
||||
$api->requestSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* http://localhost:9000/api/v2/schoolReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
|
||||
* http://localhost:9000/api/v2/schoolReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&date=2025-09-09
|
||||
*/
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
include_once(__DIR__ . '/../../controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/../../controller/DataController.php');
|
||||
include_once(__DIR__ . '/../../controller/ApiController.php');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$api = (new ApiController());
|
||||
|
||||
if ($api->urlAuth($_GET['token']) == true ) {
|
||||
|
||||
if (isset($_GET['date'])) {
|
||||
|
||||
$date = $_GET['date'];
|
||||
|
||||
$data = DatabaseShow(
|
||||
"Firmenberichte",
|
||||
"DATUM, PROZESS_1, PROZESS_2, PROZESS_3, PROZESS_4, BEGINN, ENDE_PUBLIC",
|
||||
"DATUM = ?",
|
||||
$date
|
||||
);
|
||||
} else {
|
||||
$data = DatabaseShow(
|
||||
"Firmenberichte",
|
||||
"DATUM, PROZESS_1, PROZESS_2, PROZESS_3, PROZESS_4, BEGINN, ENDE_PUBLIC",
|
||||
);
|
||||
}
|
||||
echo $api->jsonSuccess($data);
|
||||
$api->requestSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* http://localhost:9000/api/v2/workReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3
|
||||
* http://localhost:9000/api/v2/workReports.php?token=f3a50684d7f0cc2d9b21601798ea48242fab7481a0d0407a2b8683b0b74a79e3&date=2025-09-09
|
||||
*/
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
class ApiController {
|
||||
|
||||
/**
|
||||
* method for pretty jsonsuccess output
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function jsonSuccess($data) {
|
||||
return json_encode(
|
||||
[
|
||||
'status' => 'success',
|
||||
'data' => $data,
|
||||
],
|
||||
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* method for pretty jsonerror output
|
||||
*
|
||||
* @param array $error
|
||||
* @return string
|
||||
*/
|
||||
public function jsonError ($error) {
|
||||
echo json_encode(
|
||||
[
|
||||
'status' => 'failed',
|
||||
'data' => 'none',
|
||||
'error' => $error
|
||||
],
|
||||
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get authentication key out database
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAuthKey () {
|
||||
$validTokens = DatabaseShow(
|
||||
"API_Credentials",
|
||||
"TOKEN"
|
||||
);
|
||||
|
||||
return array_column($validTokens, 'TOKEN');
|
||||
}
|
||||
|
||||
/**
|
||||
* url authentication method via token and optional parameter function
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $function
|
||||
* @return void
|
||||
*/
|
||||
public function urlAuth ($token, $function = '') {
|
||||
|
||||
$validTokens = $this->getAuthKey();
|
||||
if (!in_array($token, $validTokens)) {
|
||||
http_response_code(401);
|
||||
$error = json_encode([
|
||||
"error" => "Unauthorized",
|
||||
"debug_received_token" => $token,
|
||||
]);
|
||||
|
||||
echo $this->jsonError($error);
|
||||
|
||||
DatabaseInsert(
|
||||
"API_LOGS",
|
||||
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
|
||||
(new getSpecificData())->getClientIP(),
|
||||
$token,
|
||||
(new getSpecificData())->getRequestURL(),
|
||||
$function,
|
||||
$error
|
||||
);
|
||||
|
||||
errorMail(
|
||||
"API Login failed",
|
||||
$error,
|
||||
true,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requestSave($function = '') {
|
||||
DatabaseInsert(
|
||||
"API_LOGS",
|
||||
"CLIENT_IP, TOKEN, API, FUNKTION, JSON",
|
||||
(new getSpecificData())->getClientIP(),
|
||||
$_GET['token'],
|
||||
(new getSpecificData())->getRequestURL(),
|
||||
$function,
|
||||
'{"status": "success"}',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
class getSpecificData {
|
||||
|
||||
public function getWeather() {
|
||||
$url = "https://api.openweathermap.org/data/2.5/weather?q=Berlin,DE&APPID=5bc3e1a438c58fca444c4370ac0517b2&units=metric";
|
||||
$url = "https://api.openweathermap.org/data/2.5/weather?q=Jena,DE&APPID=5bc3e1a438c58fca444c4370ac0517b2&units=metric";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
|
||||
@@ -147,10 +147,37 @@ function DatabaseUpdate($table, $set, $where, ...$values) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getFKValue($conn, $table, $key, $value, $id, &$cache) {
|
||||
if ($id === null) return null;
|
||||
|
||||
$cacheKey = $table . "_" . $id;
|
||||
|
||||
if (isset($cache[$cacheKey])) {
|
||||
return $cache[$cacheKey];
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("SELECT `$value` FROM `$table` WHERE `$key` = ? LIMIT 1");
|
||||
if (!$stmt) {
|
||||
die("FK Prepare Fehler: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param("i", $id);
|
||||
$stmt->execute();
|
||||
|
||||
$result = $stmt->get_result()->fetch_assoc();
|
||||
$valueResult = $result[$value] ?? null;
|
||||
|
||||
$cache[$cacheKey] = $valueResult;
|
||||
|
||||
return $valueResult;
|
||||
}
|
||||
|
||||
function DatabaseShowWithFK($table, $fkMap = [], $columns = "*", $where = "", ...$values) {
|
||||
include_once 'DatabaseConnect.php';
|
||||
$conn = db_connect();
|
||||
|
||||
$cache = [];
|
||||
|
||||
$select = is_array($columns) ? implode(", ", $columns) : $columns;
|
||||
|
||||
$sql = "SELECT $select FROM `$table`";
|
||||
@@ -161,33 +188,32 @@ function DatabaseShowWithFK($table, $fkMap = [], $columns = "*", $where = "", ..
|
||||
$stmt = $conn->prepare($sql);
|
||||
if (!$stmt) die("Fehler beim Prepare: " . $conn->error);
|
||||
|
||||
if (!$stmt->execute($values)) die("Fehler beim Execute: " . $stmt->error);
|
||||
if (!empty($values)) {
|
||||
$stmt->execute($values);
|
||||
} else {
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$result = $stmt->get_result();
|
||||
if (!$result) die("Fehler beim get_result: " . $stmt->error);
|
||||
|
||||
$columnsResult = [];
|
||||
while ($fieldinfo = $result->fetch_field()) {
|
||||
$columnsResult[] = $fieldinfo->name;
|
||||
}
|
||||
if (!$result) die("Fehler beim get_result: " . $conn->error);
|
||||
|
||||
$rows = $result->fetch_all(MYSQLI_ASSOC);
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
foreach ($fkMap as $fkColumn => $fkInfo) {
|
||||
if (isset($row[$fkColumn]) && $row[$fkColumn] !== null) {
|
||||
$fkStmt = $conn->prepare(
|
||||
"SELECT {$fkInfo['value']} FROM `{$fkInfo['table']}` WHERE {$fkInfo['key']} = ?"
|
||||
);
|
||||
if (!$fkStmt) die("Fehler beim Prepare FK: " . $conn->error);
|
||||
|
||||
$fkStmt->bind_param("i", $row[$fkColumn]);
|
||||
$fkStmt->execute();
|
||||
$fkResult = $fkStmt->get_result();
|
||||
$fkRow = $fkResult->fetch_assoc();
|
||||
|
||||
$row[$fkColumn] = $fkRow ? $fkRow[$fkInfo['value']] : null;
|
||||
if (!isset($row[$fkColumn]) || $row[$fkColumn] === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row[$fkColumn] = getFKValue(
|
||||
$conn,
|
||||
$fkInfo['table'],
|
||||
$fkInfo['key'],
|
||||
$fkInfo['value'],
|
||||
$row[$fkColumn],
|
||||
$cache
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+437
-112
@@ -1,29 +1,69 @@
|
||||
<?php
|
||||
// API Tester Service - Als Modul für index.php
|
||||
// Dieser Service dient zum manuellen Testen der API-Endpunkte.
|
||||
// ======================================================
|
||||
// API TESTER
|
||||
// Modul für index.php
|
||||
// ======================================================
|
||||
|
||||
// Basis-Verzeichnisse scannen (Pfad relativ zur index.php)
|
||||
$apiDir = __DIR__ . '/../api/';
|
||||
$apiFiles = glob($apiDir . '*.php');
|
||||
// API Basis-Verzeichnis
|
||||
$apiDir = realpath(__DIR__ . '/../api');
|
||||
|
||||
// Alle PHP APIs rekursiv finden
|
||||
$apiOptions = [];
|
||||
foreach ($apiFiles as $file) {
|
||||
$apiOptions[] = 'api/' . basename($file);
|
||||
|
||||
if ($apiDir !== false) {
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator(
|
||||
$apiDir,
|
||||
RecursiveDirectoryIterator::SKIP_DOTS
|
||||
)
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
|
||||
if (!$file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($file->getExtension() !== 'php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// relativen Pfad erzeugen
|
||||
$relativePath = str_replace(
|
||||
$apiDir . DIRECTORY_SEPARATOR,
|
||||
'',
|
||||
$file->getPathname()
|
||||
);
|
||||
|
||||
// Windows kompatibel
|
||||
$relativePath = str_replace('\\', '/', $relativePath);
|
||||
|
||||
$apiOptions[] = 'api/' . $relativePath;
|
||||
}
|
||||
}
|
||||
|
||||
// Token aus deiner get.php entnommen
|
||||
// sortieren
|
||||
sort($apiOptions);
|
||||
|
||||
// Standard Token
|
||||
$defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e242";
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* Spezifische Styles für den API Tester innerhalb des Content-Bereichs */
|
||||
/* ======================================================
|
||||
API TESTER STYLES
|
||||
====================================================== */
|
||||
|
||||
.api-tester-container {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background-color: var(--card-bg);
|
||||
padding: 25px;
|
||||
border-radius: 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--card-border);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.api-tester-container h2 {
|
||||
@@ -31,83 +71,8 @@ $defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e24
|
||||
margin-bottom: 20px;
|
||||
color: var(--btn-bg);
|
||||
border-bottom: 1px solid var(--card-border);
|
||||
padding-bottom: 10px;
|
||||
padding-bottom: 12px;
|
||||
display: block;
|
||||
/* style.css h2 hat flex, wir wollen hier einfaches block */
|
||||
}
|
||||
|
||||
.tester-form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.tester-form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tester-input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: var(--input-bg);
|
||||
border: 1px solid var(--input-border);
|
||||
color: var(--input-text);
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tester-btn-send {
|
||||
background-color: var(--btn-bg);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.tester-btn-send:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
#tester-response-container {
|
||||
margin-top: 25px;
|
||||
background-color: var(--input-bg);
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--card-border);
|
||||
min-height: 80px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#tester-output-content {
|
||||
white-space: pre-wrap;
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tester-badge {
|
||||
display: inline-block;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tester-status-200 {
|
||||
background-color: var(--status-bg);
|
||||
color: var(--status-text);
|
||||
}
|
||||
|
||||
.tester-status-error {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tester-grid {
|
||||
@@ -116,140 +81,500 @@ $defaultToken = "15a437d128c918633e57dc7d18118a073b807644f21731ed5a7ebcf3eca9e24
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.tester-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.tester-form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.tester-form-group label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tester-input,
|
||||
.tester-textarea,
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: var(--input-bg);
|
||||
border: 1px solid var(--input-border);
|
||||
color: var(--input-text);
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tester-textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
|
||||
.tester-btn-send {
|
||||
width: 100%;
|
||||
background-color: var(--btn-bg);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 13px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: 0.2s;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tester-btn-send:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
#tester-response-container {
|
||||
margin-top: 25px;
|
||||
background-color: var(--input-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
min-height: 100px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#tester-output-content {
|
||||
white-space: pre-wrap;
|
||||
font-family: Consolas, monospace;
|
||||
font-size: 0.85rem;
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tester-badge {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.tester-status-200 {
|
||||
background-color: #198754;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tester-status-error {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tester-status-warning {
|
||||
background-color: #ffc107;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.tester-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tester-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.tester-small-btn {
|
||||
background: transparent;
|
||||
border: 1px solid var(--input-border);
|
||||
color: var(--text);
|
||||
padding: 6px 10px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tester-small-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.tester-response-info {
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
|
||||
.tester-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tester-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="api-tester-container">
|
||||
|
||||
<h2>🛠️ API Tester</h2>
|
||||
|
||||
<!-- API Auswahl -->
|
||||
<div class="tester-form-group">
|
||||
<label for="endpoint">API Endpunkt</label>
|
||||
|
||||
<select id="endpoint" class="tester-input" onchange="checkEndpoint()">
|
||||
|
||||
<?php foreach ($apiOptions as $opt): ?>
|
||||
<option value="<?= $opt ?>"><?= $opt ?></option>
|
||||
|
||||
<option value="<?= htmlspecialchars($opt) ?>">
|
||||
<?= htmlspecialchars($opt) ?>
|
||||
</option>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Methode + Function -->
|
||||
<div class="tester-grid">
|
||||
|
||||
<div class="tester-form-group">
|
||||
<label for="method">HTTP Methode</label>
|
||||
|
||||
<select id="method" class="tester-input">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
<option value="OPTIONS">OPTIONS</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="tester-form-group" id="function-group">
|
||||
<label for="function-header">Function Header</label>
|
||||
|
||||
<input type="text" id="function-header" class="tester-input" placeholder="z.B. IPs, Ueberstunden">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Token -->
|
||||
<div class="tester-form-group">
|
||||
|
||||
<label for="token">Authorization Token</label>
|
||||
<input type="text" id="token" class="tester-input" value="<?= $defaultToken ?>">
|
||||
|
||||
<div class="tester-row">
|
||||
|
||||
<input type="text" id="token" class="tester-input" value="<?= htmlspecialchars($defaultToken) ?>">
|
||||
|
||||
<label class="tester-checkbox">
|
||||
<input type="checkbox" id="send-token" checked>
|
||||
Mitsenden
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Eigene Header -->
|
||||
<div class="tester-form-group">
|
||||
|
||||
<label for="custom-headers">
|
||||
Zusätzliche Header (JSON)
|
||||
</label>
|
||||
|
||||
<textarea id="custom-headers" class="tester-textarea" placeholder='{
|
||||
"X-Test": "123",
|
||||
"Client": "Frontend"
|
||||
}'></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- JSON Body -->
|
||||
<div class="tester-form-group" id="json-body-group">
|
||||
|
||||
<label for="json-body">
|
||||
JSON Body
|
||||
</label>
|
||||
|
||||
<textarea id="json-body" class="tester-textarea" placeholder='{
|
||||
"test": true
|
||||
}'></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Datei Upload -->
|
||||
<div class="tester-form-group hidden" id="file-group">
|
||||
<label for="files">Dateien (files)</label>
|
||||
|
||||
<label for="files">Dateien Upload</label>
|
||||
|
||||
<input type="file" id="files" class="tester-input" multiple>
|
||||
|
||||
</div>
|
||||
|
||||
<button class="tester-btn-send" onclick="sendApiRequest()">Anfrage senden 🚀</button>
|
||||
<!-- Buttons -->
|
||||
<div class="tester-grid">
|
||||
|
||||
<button class="tester-btn-send" onclick="sendApiRequest()">
|
||||
Anfrage senden 🚀
|
||||
</button>
|
||||
|
||||
<button class="tester-btn-send" onclick="clearResponse()">
|
||||
Ausgabe leeren 🧹
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Ausgabe -->
|
||||
<div id="tester-response-container">
|
||||
<div style="text-align: center; color: #888; padding: 10px;">Bereit für Anfragen.</div>
|
||||
|
||||
<div style="text-align:center; opacity:0.7; padding:15px;">
|
||||
Bereit für Anfragen.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ======================================================
|
||||
// CHECK ENDPOINT
|
||||
// ======================================================
|
||||
|
||||
function checkEndpoint() {
|
||||
|
||||
const endpoint = document.getElementById('endpoint').value;
|
||||
|
||||
const fileGroup = document.getElementById('file-group');
|
||||
const functionGroup = document.getElementById('function-group');
|
||||
const jsonBodyGroup = document.getElementById('json-body-group');
|
||||
const methodSelect = document.getElementById('method');
|
||||
|
||||
// Standard: alles ausblenden
|
||||
// reset
|
||||
fileGroup.classList.add('hidden');
|
||||
functionGroup.classList.remove('hidden');
|
||||
jsonBodyGroup.classList.remove('hidden');
|
||||
|
||||
// upload api
|
||||
if (endpoint.includes('upload.php')) {
|
||||
|
||||
if (endpoint === 'api/upload.php') {
|
||||
// Nur bei exakt api/upload.php Dateien anzeigen
|
||||
fileGroup.classList.remove('hidden');
|
||||
functionGroup.classList.add('hidden');
|
||||
jsonBodyGroup.classList.add('hidden');
|
||||
|
||||
methodSelect.value = 'POST';
|
||||
}
|
||||
|
||||
if (endpoint === 'api/get.php') {
|
||||
// get api
|
||||
if (endpoint.includes('get.php')) {
|
||||
methodSelect.value = 'GET';
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// CLEAR RESPONSE
|
||||
// ======================================================
|
||||
|
||||
function clearResponse() {
|
||||
|
||||
document.getElementById('tester-response-container').innerHTML = `
|
||||
<div style="text-align:center; opacity:0.7; padding:15px;">
|
||||
Ausgabe geleert.
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// SEND REQUEST
|
||||
// ======================================================
|
||||
|
||||
async function sendApiRequest() {
|
||||
|
||||
const endpoint = document.getElementById('endpoint').value;
|
||||
const method = document.getElementById('method').value;
|
||||
const token = document.getElementById('token').value;
|
||||
const functionHeader = document.getElementById('function-header').value;
|
||||
const customHeadersInput = document.getElementById('custom-headers').value;
|
||||
const jsonBodyInput = document.getElementById('json-body').value;
|
||||
const fileInput = document.getElementById('files');
|
||||
const sendToken = document.getElementById('send-token').checked;
|
||||
|
||||
const responseContainer = document.getElementById('tester-response-container');
|
||||
|
||||
responseContainer.innerHTML = '<div style="text-align: center; padding: 10px;">Lade...</div>';
|
||||
responseContainer.innerHTML = `
|
||||
<div style="text-align:center; padding:15px;">
|
||||
Anfrage läuft...
|
||||
</div>
|
||||
`;
|
||||
|
||||
let headers = {
|
||||
'Authorization': token
|
||||
};
|
||||
let headers = {};
|
||||
|
||||
if (endpoint.includes('get.php') && functionHeader) {
|
||||
// Token
|
||||
if (sendToken && token.trim() !== '') {
|
||||
headers['Authorization'] = token;
|
||||
}
|
||||
|
||||
// Function Header
|
||||
if (functionHeader.trim() !== '') {
|
||||
headers['Function'] = functionHeader;
|
||||
}
|
||||
|
||||
// Custom Headers
|
||||
if (customHeadersInput.trim() !== '') {
|
||||
|
||||
try {
|
||||
|
||||
const customHeaders = JSON.parse(customHeadersInput);
|
||||
|
||||
headers = {
|
||||
...headers,
|
||||
...customHeaders
|
||||
};
|
||||
|
||||
} catch (e) {
|
||||
|
||||
responseContainer.innerHTML = `
|
||||
<div style="color:#dc3545; padding:15px;">
|
||||
Fehlerhafte Header JSON Struktur.
|
||||
</div>
|
||||
`;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let options = {
|
||||
method: method,
|
||||
headers: headers
|
||||
};
|
||||
|
||||
// Upload
|
||||
if (endpoint.includes('upload.php') && fileInput.files.length > 0) {
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
for (let i = 0; i < fileInput.files.length; i++) {
|
||||
formData.append('files[]', fileInput.files[i]);
|
||||
}
|
||||
|
||||
options.body = formData;
|
||||
|
||||
} else {
|
||||
|
||||
// JSON Body
|
||||
if (
|
||||
['POST', 'PUT', 'PATCH', 'DELETE']
|
||||
.includes(method) &&
|
||||
jsonBodyInput.trim() !== ''
|
||||
) {
|
||||
|
||||
try {
|
||||
|
||||
JSON.parse(jsonBodyInput);
|
||||
|
||||
headers['Content-Type'] = 'application/json';
|
||||
|
||||
options.body = jsonBodyInput;
|
||||
|
||||
} catch (e) {
|
||||
|
||||
responseContainer.innerHTML = `
|
||||
<div style="color:#dc3545; padding:15px;">
|
||||
Fehlerhafte JSON Body Struktur.
|
||||
</div>
|
||||
`;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const startedAt = performance.now();
|
||||
|
||||
try {
|
||||
|
||||
const response = await fetch(endpoint, options);
|
||||
|
||||
const duration = (performance.now() - startedAt).toFixed(0);
|
||||
|
||||
const status = response.status;
|
||||
|
||||
const rawText = await response.text();
|
||||
|
||||
let resultText = rawText;
|
||||
|
||||
// JSON hübsch formatieren
|
||||
try {
|
||||
|
||||
const json = JSON.parse(rawText);
|
||||
|
||||
resultText = JSON.stringify(json, null, 2);
|
||||
|
||||
} catch (e) {}
|
||||
|
||||
const badgeClass = status >= 200 && status < 300 ? 'tester-status-200' : 'tester-status-error';
|
||||
let badgeClass = 'tester-status-error';
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
badgeClass = 'tester-status-200';
|
||||
} else if (status >= 300 && status < 400) {
|
||||
badgeClass = 'tester-status-warning';
|
||||
}
|
||||
|
||||
responseContainer.innerHTML = `
|
||||
<div class="tester-badge ${badgeClass}">Status: ${status}</div>
|
||||
<pre id="tester-output-content"></pre>
|
||||
`;
|
||||
<div class="tester-badge ${badgeClass}">
|
||||
Status: ${status}
|
||||
</div>
|
||||
|
||||
<div class="tester-response-info">
|
||||
⏱️ ${duration} ms
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="tester-small-btn"
|
||||
onclick="copyResponse()"
|
||||
>
|
||||
Antwort kopieren
|
||||
</button>
|
||||
|
||||
<pre id="tester-output-content"></pre>
|
||||
`;
|
||||
|
||||
document.getElementById('tester-output-content').textContent = resultText;
|
||||
|
||||
} catch (error) {
|
||||
responseContainer.innerHTML = `<div style="color:#dc3545; padding: 10px;">Fehler: ${error.message}</div>`;
|
||||
|
||||
responseContainer.innerHTML = `
|
||||
<div style="color:#dc3545; padding:15px;">
|
||||
Fehler: ${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial check
|
||||
// ======================================================
|
||||
// COPY RESPONSE
|
||||
// ======================================================
|
||||
|
||||
function copyResponse() {
|
||||
|
||||
const content = document.getElementById('tester-output-content');
|
||||
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(content.textContent);
|
||||
|
||||
alert('Antwort kopiert.');
|
||||
}
|
||||
|
||||
// Initial
|
||||
checkEndpoint();
|
||||
</script>
|
||||
@@ -42,7 +42,7 @@ $conn->close();
|
||||
data: <?php echo json_encode($data); ?>,
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
fill: true,
|
||||
fill: false,
|
||||
tension: 0
|
||||
}]
|
||||
},
|
||||
@@ -82,7 +82,7 @@ $conn->close();
|
||||
}
|
||||
},
|
||||
y: {
|
||||
min: 0,
|
||||
min: -10,
|
||||
max: 40,
|
||||
title: {
|
||||
display: true,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
include_once __DIR__ . '/../controller/DatabaseController.php';
|
||||
include_once __DIR__ . '/../controller/RoutesController.php';
|
||||
|
||||
$conn = db_connect();
|
||||
$view = $_GET['view'] ?? 'show';
|
||||
$selectedService = $_GET['service'];
|
||||
@@ -8,8 +11,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_overtime'])) {
|
||||
$datum = $_POST['ot_date'];
|
||||
$minuten = intval($_POST['ot_minutes']);
|
||||
$grund = $conn->real_escape_string($_POST['ot_reason']);
|
||||
$insert_sql = "INSERT INTO Ueberstunden (DATUM, MINUTEN, GRUND) VALUES ('$datum', $minuten, '$grund')";
|
||||
$conn->query($insert_sql);
|
||||
|
||||
DatabaseInsert(
|
||||
"Ueberstunden",
|
||||
"DATUM, MINUTEN, GRUND",
|
||||
$datum,
|
||||
$minuten,
|
||||
$grund
|
||||
);
|
||||
|
||||
redirectToWebsite((new getSpecificData())->getReferer());
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- Gesamtsumme berechnen ---
|
||||
@@ -59,6 +71,7 @@ $gesamt_minuten = $minuten_berichte - $minuten_abbau + $minuten_aufbau;
|
||||
<option value="">Bitte wählen</option>
|
||||
<option value="Abbau">Abbau</option>
|
||||
<option value="Aufbau">Aufbau</option>
|
||||
<option value="Anderes">Anderes</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit"
|
||||
|
||||
Reference in new issue
Block a user