g6
This commit is contained in:
1 parent
565c1b9911
commit
28490ce8b3
36 files changed
+586
-178
No files matched your search
@@ -0,0 +1,2 @@
|
||||
|
||||
data/couchdb.json
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="./auth.js"></script>
|
||||
<script src="./lib/basic.js"></script>
|
||||
<script src="./help/data_xample.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await createTemp();
|
||||
location.href = "./login.html";
|
||||
} catch(err) {
|
||||
alert("Ein Fehler ist aufgetreten: " + err);
|
||||
}
|
||||
})();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"sassy": {
|
||||
"users": {
|
||||
"turtle": {
|
||||
"password": "1234",
|
||||
"level": 3,
|
||||
"xp": 2,
|
||||
"avatar": null,
|
||||
"abilities": [],
|
||||
"enabled_abilities": [],
|
||||
"role": "student",
|
||||
"courses": ["weiche_ware", "bucket"]
|
||||
},
|
||||
"dumble-door": {
|
||||
"password": "bla",
|
||||
"level": 10,
|
||||
"xp": 0,
|
||||
"avatar": "https://static.turtle-coding-gbr.de/gmci/profile-pic.png",
|
||||
"abilities": [],
|
||||
"enabled_abilities": [],
|
||||
"role": "professor",
|
||||
"courses": ["weiche_ware", "algebra", "geometrie"]
|
||||
},
|
||||
"narrator": {
|
||||
"password": "stanley",
|
||||
"level": 10,
|
||||
"xp": 0,
|
||||
"avatar": "https://static.turtle-coding-gbr.de/gmci/st",
|
||||
"abilities": [
|
||||
"dark_mode",
|
||||
"accent_color",
|
||||
"pink_mode",
|
||||
"profile_pic",
|
||||
"simple_border",
|
||||
"gold_border",
|
||||
"epic_border",
|
||||
"title_of_honor"
|
||||
],
|
||||
"enabled_abilities": [],
|
||||
"role": "professor",
|
||||
"courses": ["bucket", "statistik"]
|
||||
}
|
||||
},
|
||||
"course:bucket": {
|
||||
"title": "Bucket",
|
||||
"description": "The end is never the end is never the end is never",
|
||||
"owner": "narrator",
|
||||
"questions": [
|
||||
{
|
||||
"title": "What is comedic timing?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "How does it work?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "How long should it last?",
|
||||
"type": "scala"
|
||||
},
|
||||
{
|
||||
"title": "How can it be used to effectively silence your political enemies?",
|
||||
"type": "emoji"
|
||||
}
|
||||
],
|
||||
"result": [
|
||||
["YES", "YES", 5, 2],
|
||||
["YES", "YES", 1, 3]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-27",
|
||||
"questions": [
|
||||
{ "title": "Wie war die Vorlesung?", "type": "text" },
|
||||
{ "title": "Wie war der Professor?", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-23",
|
||||
"expire_date": "2026-02-20"
|
||||
},
|
||||
"course:weiche_ware": {
|
||||
"title": "Weiche Ware",
|
||||
"description": "blabering",
|
||||
"owner": "dumble-door",
|
||||
"questions": [
|
||||
{
|
||||
"title": "Wie fanden Sie die Vorlesung?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "Finden Sie, dass man Zauberei an lebendigen Schülern praktizieren sollte?",
|
||||
"type": "scala"
|
||||
}
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1],
|
||||
["Lorem ipsum dolor sit amet", 2],
|
||||
["consetetur sadipscing elitr, sed diam ", 3],
|
||||
[" nonumy eirmod tempor invidunt ut labore ", 4],
|
||||
["et dolore magna aliquyam erat, sed diam", 5],
|
||||
[" voluptua. At vero eos et accusam et justo duo", 1],
|
||||
["the end", 5]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-27",
|
||||
"questions": [
|
||||
{ "title": "1", "type": "text" },
|
||||
{ "title": "2", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1],
|
||||
["Lorem ipsum dolor sit amet", 2],
|
||||
["consetetur sadipscing elitr, sed diam ", 3],
|
||||
[" nonumy eirmod tempor invidunt ut labore ", 4],
|
||||
["et dolore magna aliquyam erat, sed diam", 5],
|
||||
[" voluptua. At vero eos et accusam et justo duo", 1],
|
||||
["the end", 5]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-23",
|
||||
"expire_date": "2026-02-20"
|
||||
},
|
||||
"course:algebra": {
|
||||
"title": "Algebra",
|
||||
"description": "Grundlagen der algebraischen Konzepte.",
|
||||
"owner": "math-wizard",
|
||||
"questions": [
|
||||
{ "title": "Wie gut verstehen Sie die Grundlagen der Algebra?", "type": "text" },
|
||||
{ "title": "Bewerten Sie die Schwierigkeit algebraischer Aufgaben.", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-28",
|
||||
"questions": [
|
||||
{ "title": "1", "type": "text" },
|
||||
{ "title": "2", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-26",
|
||||
"expire_date": "2025-02-25"
|
||||
},
|
||||
"course:geometrie": {
|
||||
"title": "Geometrie",
|
||||
"description": "Erforschung geometrischer Figuren und Konzepte.",
|
||||
"owner": "geo-genius",
|
||||
"questions": [
|
||||
{ "title": "Wie sicher sind Sie im Umgang mit geometrischen Formen?", "type": "text" },
|
||||
{ "title": "Bewerten Sie die Komplexität geometrischer Aufgaben.", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-29",
|
||||
"questions": [
|
||||
{ "title": "1", "type": "text" },
|
||||
{ "title": "2", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-24",
|
||||
"expire_date": "2025-03-15"
|
||||
},
|
||||
"course:statistik": {
|
||||
"title": "Statistik",
|
||||
"description": "Grundlagen der statistischen Analyse und Interpretation.",
|
||||
"owner": "data-analyst",
|
||||
"questions": [
|
||||
{ "title": "Wie gut verstehen Sie statistische Methoden?", "type": "text" },
|
||||
{ "title": "Bewerten Sie die Schwierigkeit statistischer Analysen.", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-30",
|
||||
"questions": [
|
||||
{ "title": "1", "type": "text" },
|
||||
{ "title": "2", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Einfach, weil ...", 5],
|
||||
["Schwierig, weil ...", 1]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-25",
|
||||
"expire_date": "2025-04-10"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
location.href = "./login.html";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -50,12 +50,12 @@ async function main() {
|
||||
const data = await couchDB.get("xample");
|
||||
console.log(JSON.stringify(data));
|
||||
//Gibt { "my_data": 1, "more_data": "bla" } wieder
|
||||
|
||||
console.log(JSON.stringify(await couchDB.get("*")));
|
||||
//Gibt ["users","course:bucket","course:weiche_ware","course:algebra","course:geometrie","course:statistik","xample"] wieder
|
||||
}
|
||||
|
||||
main();
|
||||
createTemp().then((v) => {
|
||||
setUserData(couchDB);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
async function createTemp() {
|
||||
console.warn("createTemp is deprecated");
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -105,7 +105,7 @@ window.addEventListener("load", (event) => {
|
||||
|
||||
//http://127.0.0.1:5984/_utils/#_config/couchdb@127.0.0.1
|
||||
class CouchDB {
|
||||
static _default_url = "http://127.0.0.1:5984/";
|
||||
static _default_url = "/couchdb/";
|
||||
|
||||
constructor() {
|
||||
this._does_auth_exists_err();
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,148 +0,0 @@
|
||||
async function createTemp() {
|
||||
const couchDB = new CouchDB();
|
||||
await couchDB.set("users", {
|
||||
"turtle": {
|
||||
"password": "1234",
|
||||
"level": 3,
|
||||
"xp": 2,
|
||||
"avatar": null,
|
||||
"abilities": [],
|
||||
"enabled_abilities": [],
|
||||
"role": "student",
|
||||
"courses": [
|
||||
"weiche_ware",
|
||||
"bucket"
|
||||
]
|
||||
},
|
||||
"dumble-door": {
|
||||
"password": "bla",
|
||||
"level": 10,
|
||||
"xp": 0,
|
||||
"avatar": "https://static.turtle-coding-gbr.de/gmci/profile-pic.png",
|
||||
"abilities": [
|
||||
],
|
||||
"enabled_abilities": [
|
||||
],
|
||||
"role": "professor",
|
||||
"courses": [
|
||||
"weiche_ware", "algebra", "geometrie"
|
||||
]
|
||||
},
|
||||
"narrator": {
|
||||
"password": "stanley",
|
||||
"level": 10,
|
||||
"xp": 0,
|
||||
"avatar": "https://static.turtle-coding-gbr.de/gmci/st",
|
||||
"abilities": [
|
||||
"dark_mode",
|
||||
"accent_color",
|
||||
"pink_mode",
|
||||
"profile_pic",
|
||||
"simple_border",
|
||||
"gold_border",
|
||||
"epic_border",
|
||||
"title_of_honor"
|
||||
],
|
||||
"enabled_abilities": [
|
||||
],
|
||||
"role": "professor",
|
||||
"courses": [
|
||||
"bucket", "statistik"
|
||||
]
|
||||
}
|
||||
});
|
||||
await couchDB.set("course:bucket", {
|
||||
"title": "Bucket",
|
||||
"description": "The end is never the end is never the end is never",
|
||||
"owner": "narrator",
|
||||
"questions": [
|
||||
{
|
||||
"title": "What is comedic timing?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "How does it work?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "How long should it last?",
|
||||
"type": "scala"
|
||||
},
|
||||
{
|
||||
"title": "How can it be used to effectively silence your political enemies?",
|
||||
"type": "emoji"
|
||||
}
|
||||
],
|
||||
"result": [
|
||||
["YES", "YES", 5, 2],
|
||||
["YES", "YES", 1, 3]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-27",
|
||||
"questions": [
|
||||
{ "title": "Wie war die Vorlesung?", "type": "text" },
|
||||
{ "title": "Wie war der Professor?", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-23",
|
||||
"expire_date": "2026-02-20"
|
||||
});
|
||||
await couchDB.set("course:weiche_ware", {
|
||||
"title": "Weiche Ware",
|
||||
"description": "blabering",
|
||||
"owner": "dumble-door",
|
||||
"questions": [
|
||||
{
|
||||
"title": "Wie fanden Sie die Vorlesung?",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"title": "Finden Sie, dass man Zauberei an lebendigen Schülern praktizieren sollte?",
|
||||
"type": "scala"
|
||||
}
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1],
|
||||
["Lorem ipsum dolor sit amet", 2],
|
||||
["consetetur sadipscing elitr, sed diam ", 3],
|
||||
[" nonumy eirmod tempor invidunt ut labore ", 4],
|
||||
["et dolore magna aliquyam erat, sed diam", 5],
|
||||
[" voluptua. At vero eos et accusam et justo duo", 1],
|
||||
["the end", 5]
|
||||
],
|
||||
"result_history": [
|
||||
{
|
||||
"date": "2025-12-27",
|
||||
"questions": [
|
||||
{ "title": "1", "type": "text" },
|
||||
{ "title": "2", "type": "scala" }
|
||||
],
|
||||
"result": [
|
||||
["Gut, weil ...", 5],
|
||||
["Schlecht, weil ...", 1],
|
||||
["Lorem ipsum dolor sit amet", 2],
|
||||
["consetetur sadipscing elitr, sed diam ", 3],
|
||||
[" nonumy eirmod tempor invidunt ut labore ", 4],
|
||||
["et dolore magna aliquyam erat, sed diam", 5],
|
||||
[" voluptua. At vero eos et accusam et justo duo", 1],
|
||||
["the end", 5]
|
||||
]
|
||||
}
|
||||
],
|
||||
"start_date": "2025-12-23",
|
||||
"expire_date": "2026-02-20"
|
||||
});
|
||||
|
||||
|
||||
await couchDB.set("course:algebra", { "title": "Algebra", "description": "Grundlagen der algebraischen Konzepte.", "owner": "math-wizard", "questions": [ { "title": "Wie gut verstehen Sie die Grundlagen der Algebra?", "type": "text" }, { "title": "Bewerten Sie die Schwierigkeit algebraischer Aufgaben.", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ], "result_history": [ { "date": "2025-12-28", "questions": [ { "title": "1", "type": "text" }, { "title": "2", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ] } ], "start_date": "2025-12-26", "expire_date": "2025-02-25" });
|
||||
await couchDB.set("course:geometrie", { "title": "Geometrie", "description": "Erforschung geometrischer Figuren und Konzepte.", "owner": "geo-genius", "questions": [ { "title": "Wie sicher sind Sie im Umgang mit geometrischen Formen?", "type": "text" }, { "title": "Bewerten Sie die Komplexität geometrischer Aufgaben.", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ], "result_history": [ { "date": "2025-12-29", "questions": [ { "title": "1", "type": "text" }, { "title": "2", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ] } ], "start_date": "2025-12-24", "expire_date": "2025-03-15" });
|
||||
await couchDB.set("course:statistik", { "title": "Statistik", "description": "Grundlagen der statistischen Analyse und Interpretation.", "owner": "data-analyst", "questions": [ { "title": "Wie gut verstehen Sie statistische Methoden?", "type": "text" }, { "title": "Bewerten Sie die Schwierigkeit statistischer Analysen.", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ], "result_history": [ { "date": "2025-12-30", "questions": [ { "title": "1", "type": "text" }, { "title": "2", "type": "scala" } ], "result": [ ["Einfach, weil ...", 5], ["Schwierig, weil ...", 1] ] } ], "start_date": "2025-12-25", "expire_date": "2025-04-10" });
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
require_once './utils/url_handler.php';
|
||||
require_once './utils/couch.php';
|
||||
|
||||
|
||||
$path_info = new TurtlePathInfo();
|
||||
$path_info->content = "./files/";
|
||||
|
||||
$url_obj = TurtleURLObject::create_from_server(false, false);
|
||||
|
||||
if (str_starts_with($url_obj->url, "couchdb")) {
|
||||
$couchDB = new CouchDB("./data/couchdb.json", "./data/def_data.json", $url_obj);
|
||||
$couchDB->execute();
|
||||
} else {
|
||||
$url_obj->handle_request($path_info);
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
class CouchDB {
|
||||
public string $db_file;
|
||||
public string $def_db_file;
|
||||
public TurtleURLObject $url_obj;
|
||||
|
||||
public function __construct(string $db_file, string $def_db_file, TurtleURLObject $url_obj) {
|
||||
$this->db_file = $db_file;
|
||||
$this->def_db_file = $def_db_file;
|
||||
$this->url_obj = $url_obj;
|
||||
}
|
||||
|
||||
public function getFile(): object {
|
||||
if (file_exists($this->db_file)) {
|
||||
$content = json_decode(file_get_contents($this->db_file));
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($this->def_db_file)) {
|
||||
$content = json_decode(file_get_contents($this->def_db_file));
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
return (object) [];
|
||||
}
|
||||
|
||||
public function setFile(object $content): void {
|
||||
file_put_contents($this->db_file, str_replace(" ", "\t", json_encode($content, JSON_PRETTY_PRINT)));
|
||||
}
|
||||
|
||||
public function sendError(string $msg, int $code = 404) :bool {
|
||||
http_response_code($code);
|
||||
$this->url_obj->send_json(["ok" => false, "reason" => $msg]);
|
||||
return false;
|
||||
}
|
||||
public function sendData(object $data = new stdClass()) :bool {
|
||||
$data->ok = true;
|
||||
$this->url_obj->send_json($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function execute(): bool {
|
||||
$method = strtoupper($this->url_obj->method);
|
||||
$args = $this->url_obj->args;
|
||||
|
||||
//path
|
||||
$pathParts = explode("/", trim($this->url_obj->url ?? "", "/"));
|
||||
if (!empty($pathParts) && strtolower($pathParts[0]) == "couchdb") {
|
||||
array_splice($pathParts, 0, 1);
|
||||
}
|
||||
|
||||
if (empty($pathParts)) return $this->sendData();
|
||||
|
||||
$dbName = $pathParts[0] ?? null;
|
||||
$docId = null;
|
||||
if (sizeof($pathParts) > 1) $docId = $pathParts[1] ?? null;
|
||||
|
||||
if (!$dbName) return $this->sendError("wrong_usage");
|
||||
|
||||
//data
|
||||
$db_obj = $this->getFile();
|
||||
$jsonBody = null;
|
||||
$rawBody = $this->url_obj->get_body_text();
|
||||
if ($rawBody !== "") {
|
||||
$jsonBody = json_decode($rawBody, true);
|
||||
if (!is_array($jsonBody) && !is_object($jsonBody)) $jsonBody = null;
|
||||
else $jsonBody = (object) $jsonBody;
|
||||
}
|
||||
|
||||
//get data
|
||||
$obj = null;
|
||||
if (isset($db_obj->$dbName) && is_object($db_obj->$dbName)) {
|
||||
if ($docId && isset($db_obj->$dbName->$docId) && is_object($db_obj->$dbName->$docId)) {
|
||||
$obj = $db_obj->$dbName->$docId;
|
||||
} else if ($method != "PUT" && !($method == "GET" && $docId == "*")) {
|
||||
return $this->sendError("missing");
|
||||
}
|
||||
} else if ($method != "PUT") {
|
||||
if (!$dbName || !isset($db_obj->$dbName)) {
|
||||
return $this->sendError("no_db_file");
|
||||
}
|
||||
} else {
|
||||
$db_obj->$dbName = null;
|
||||
}
|
||||
|
||||
//execute
|
||||
switch ($method) {
|
||||
case "GET":
|
||||
if ($docId == "*") {
|
||||
$res_arr = [];
|
||||
foreach ($db_obj->$dbName as $key => $value) $res_arr[] = $key;
|
||||
$this->url_obj->send_json($res_arr);
|
||||
return true;
|
||||
}
|
||||
|
||||
$obj->_id = $docId;
|
||||
$obj->_rev = 0;
|
||||
$this->url_obj->send_json($obj);
|
||||
|
||||
return true;
|
||||
case "PUT":
|
||||
if ($db_obj->$dbName == null) {
|
||||
if ($docId == null) {
|
||||
$db_obj->$dbName = (object) [];
|
||||
$this->setFile($db_obj);
|
||||
return $this->sendData();
|
||||
} else {
|
||||
return $this->sendError("no_db_file");
|
||||
}
|
||||
}
|
||||
|
||||
$db_obj->$dbName->$docId ??= (object) [];
|
||||
|
||||
if ($jsonBody == null) return $this->sendError("missing_body");
|
||||
|
||||
unset($jsonBody->_id);
|
||||
unset($jsonBody->_rev);
|
||||
|
||||
$db_obj->$dbName->$docId = $jsonBody;
|
||||
$this->setFile($db_obj);
|
||||
|
||||
return $this->sendData((object) [
|
||||
"id" => $docId,
|
||||
"rev" => 0
|
||||
]);
|
||||
case "DELETE":
|
||||
unset($db_obj->$dbName->$docId);
|
||||
$this->setFile($db_obj);
|
||||
return $this->sendData((object) [ "id" => $docId ]);
|
||||
default:
|
||||
return $this->sendError("method_not_allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
function isFileExtImage(string $fileExt) :bool {
|
||||
switch ($fileExt) {
|
||||
case 'png':
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
case 'ico':
|
||||
case 'gif':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function res_mixed(bool $success, mixed $data = null, string $except = null) :object {
|
||||
return $success ? res_ok($data): res_err($data ?? $except);
|
||||
}
|
||||
function res_ok(mixed $data = null) :object {
|
||||
return (object) [
|
||||
"type" => "success",
|
||||
"data" => $data
|
||||
];
|
||||
}
|
||||
function res_err(string|null $message = null) :object {
|
||||
return (object) [
|
||||
"type" => "error",
|
||||
"message" => $message
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
require_once 'features.php';
|
||||
|
||||
///A collection of given paths
|
||||
class TurtlePathInfo {
|
||||
public string $content;
|
||||
}
|
||||
|
||||
///Parse url and execute it
|
||||
class TurtleURLObject {
|
||||
public static function create_from_server(bool $lowerCase = true, bool $alternativeURL = true) :TurtleURLObject {
|
||||
$urlParts = explode('?', trim($_SERVER['REQUEST_URI'], '/'));
|
||||
$urlMark = _parseUrlMark($urlParts);
|
||||
$request = str_replace("..", ".", $urlParts[0]);
|
||||
|
||||
if ($lowerCase) $request = strtolower($request);
|
||||
if ($alternativeURL) $request = str_replace("-", "/", $request);
|
||||
|
||||
$res = new TurtleURLObject($request, $urlMark);
|
||||
$res->method = $_SERVER['REQUEST_METHOD'];
|
||||
$res->method_type = explode(',', $_SERVER['HTTP_ACCEPT'] ?? '');
|
||||
return $res;
|
||||
}
|
||||
|
||||
public string $url;
|
||||
public object $args;
|
||||
public function __construct(string $url, object $args) {
|
||||
$this->url = $url;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
public string $method;
|
||||
public array $method_type;
|
||||
|
||||
public function get_body_text() :string {
|
||||
$bodyContent = file_get_contents("php://input");
|
||||
return $bodyContent;
|
||||
}
|
||||
public function get_body_json() :mixed {
|
||||
return json_decode($this->get_body_text());
|
||||
}
|
||||
|
||||
public function get_html_file(string $file_path): string {
|
||||
if (!file_exists($file_path)) {
|
||||
return "Not found!";
|
||||
} else {
|
||||
return file_get_contents($file_path);
|
||||
}
|
||||
}
|
||||
|
||||
public function send_text(string $text) :void {
|
||||
header('Content-Type: text/plain');
|
||||
echo $text;
|
||||
}
|
||||
public function send_json(mixed $data) :void {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
}
|
||||
public function send_image(string $path) :void {
|
||||
$fileExt = pathinfo($path, PATHINFO_EXTENSION);
|
||||
if ($fileExt === "ico") {
|
||||
header("Cache-Control: no-cache, must-revalidate, max-age=0");
|
||||
header("Content-Type: image/x-icon");
|
||||
} else {
|
||||
header("Content-Type: image/$fileExt");
|
||||
}
|
||||
readfile($path);
|
||||
}
|
||||
public function send_custom_file(string $path) :bool {
|
||||
$fileExt = pathinfo($path, PATHINFO_EXTENSION);
|
||||
if (isFileExtImage($fileExt)) {
|
||||
$this->send_image($path);
|
||||
} else if ($fileExt == "json") {
|
||||
$content = file_get_contents($path);
|
||||
if ($content == false) return false;
|
||||
header('Content-Type: application/json');
|
||||
echo $content;
|
||||
} else if ($fileExt == "txt") {
|
||||
$content = file_get_contents($path);
|
||||
if ($content == false) return false;
|
||||
$this->send_text($content);
|
||||
} else if ($fileExt == "js") {
|
||||
header('Content-Type: text/javascript; charset=utf-8');
|
||||
echo file_get_contents($path);
|
||||
return true;
|
||||
} else if ($fileExt == "css") {
|
||||
header("Content-Type: text/css");
|
||||
echo file_get_contents($path);
|
||||
} else if ($fileExt == "html") {
|
||||
echo $this->get_html_file($path);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function send_download_file(string $path) :bool {
|
||||
if (!file_exists($path)) return false;
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename="'.basename($path).'"');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: ' . filesize($path));
|
||||
|
||||
readfile($path);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function is_image_request() :bool {
|
||||
foreach ($this->method_type as $type) {
|
||||
if (!str_starts_with($type, "image/")) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handle_request(TurtlePathInfo $path_info): void {
|
||||
$referer = $_SERVER['HTTP_REFERER'] ?? '';
|
||||
|
||||
$filePath = $path_info->content . $this->url;
|
||||
|
||||
if (strlen($this->url) == 0) {
|
||||
$filePath = "{$path_info->content}START.html";
|
||||
}
|
||||
|
||||
//-------------Image-Pages-------------------//
|
||||
else if (
|
||||
!empty($referer) && $this->is_image_request()
|
||||
) {
|
||||
if (file_exists($filePath)) {
|
||||
$this->send_image($filePath);
|
||||
return;
|
||||
} else {
|
||||
$filePath = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------HTML-Pages-------------------//
|
||||
|
||||
if ($filePath === NULL || !file_exists($filePath)) {
|
||||
$filePath = "{$path_info->content}NOT-FOUND.html";
|
||||
http_response_code(404);
|
||||
}
|
||||
|
||||
$this->send_custom_file($filePath);
|
||||
}
|
||||
}
|
||||
|
||||
function _parseUrlMark($urlParts) :object {
|
||||
$res = (object) [];
|
||||
if (count($urlParts) == 1) return $res;
|
||||
foreach (explode('&', $urlParts[1]) as $part) {
|
||||
$arr = explode('=', $part, 2);
|
||||
$cnt = count($arr);
|
||||
switch ($cnt) {
|
||||
case 1:
|
||||
$res->{$arr[0]} = 1;
|
||||
break;
|
||||
case 2:
|
||||
$res->{$arr[0]} = $arr[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
Reference in new issue
Block a user