This commit is contained in:
Felix Brabender 2025-09-12 09:58:27 +02:00
parent b7caa9be78
commit aa789dd5a7
9 changed files with 352 additions and 78 deletions

70
Backend/campaigns.php Normal file
View File

@ -0,0 +1,70 @@
<?php
require "db.php";
//Felix
function user_id_from_username($u){
$st=db()->prepare("SELECT user_id FROM users WHERE username=?");
$st->execute([$u]);
$r=$st->fetch();
return $r ? (int)$r['user_id'] : 0;
}
$action = $_GET['action'] ?? '';
if ($action==='get_for_owner') {
$uname = $_GET['owner_username'] ?? '';
if ($uname==='') bad('owner_username required');
$st = db()->prepare("SELECT c.campaign_id, c.title, c.description
FROM campaigns c
JOIN users u ON u.user_id=c.owner_user_id
WHERE u.username=? LIMIT 1");
$st->execute([$uname]);
$row = $st->fetch();
if (!$row) bad('not_found',404);
ok($row);
}
if ($action==='ensure_for_owner') {
$b = body(); $uname = $b['owner_username'] ?? '';
if ($uname==='') bad('owner_username required');
$uid = user_id_from_username($uname);
if ($uid<=0) bad('user_not_found',404);
$st = db()->prepare("SELECT campaign_id, title, description FROM campaigns WHERE owner_user_id=? LIMIT 1");
$st->execute([$uid]);
$row = $st->fetch();
if ($row) ok($row);
$ins = db()->prepare("INSERT INTO campaigns(owner_user_id,title,description) VALUES(?,?,?)");
$ins->execute([$uid,'Meine Kampagne',null]);
ok(['campaign_id'=>(int)db()->lastInsertId(),'title'=>'Meine Kampagne','description'=>null]);
}
if ($action==='update_for_owner') {
$b = body();
$uname = $b['owner_username'] ?? '';
$title = trim($b['title'] ?? '');
$desc = $b['description'] ?? null;
if ($uname==='') bad('owner_username required');
if ($title==='') bad('title required');
$uid = user_id_from_username($uname);
if ($uid<=0) bad('user_not_found',404);
$st = db()->prepare("SELECT campaign_id FROM campaigns WHERE owner_user_id=? LIMIT 1");
$st->execute([$uid]);
$row = $st->fetch();
if ($row) {
$upd = db()->prepare("UPDATE campaigns SET title=?, description=? WHERE campaign_id=?");
$upd->execute([$title,$desc,(int)$row['campaign_id']]);
ok(['campaign_id'=>(int)$row['campaign_id']]);
} else {
$ins = db()->prepare("INSERT INTO campaigns(owner_user_id,title,description) VALUES(?,?,?)");
$ins->execute([$uid,$title,$desc]);
ok(['campaign_id'=>(int)db()->lastInsertId()]);
}
}
http_response_code(404); echo json_encode(['ok'=>false,'error'=>'unknown action']);

View File

@ -1,34 +1,98 @@
<?php <?php
require "db.php"; require "db.php";
//Paul,Jakob
function out($ok, $msg='ok', $arr=[], $code=200){ if($ok) ok(['msg'=>$msg]+$arr); else bad($msg,$code); }
$a = $_GET['action'] ?? ''; $a = $_GET['action'] ?? '';
$b = body(); $b = body();
function find_user($name){ function find_user($name){
$st=db()->prepare("SELECT user_id FROM users WHERE username=?"); $st=db()->prepare("SELECT user_id FROM users WHERE username=?");
$st->execute([$name]); $st->execute([trim($name)]);
$r=$st->fetch(); $r=$st->fetch();
return $r ? $r["user_id"] : 0; return $r? (int)$r["user_id"] : 0;
} }
try {
if ($a === "create") { if ($a === "create") {
$uid = isset($b['user_id']) ? (int)$b['user_id'] : 0;
if ($uid<=0){
$u = trim($b["username"] ?? ""); $u = trim($b["username"] ?? "");
$c=trim($b["name"]??""); if ($u==="") out(false,"username or user_id required",[],400);
if($u==""||$c=="") out(false,"invalid",[],400);
$uid = find_user($u); $uid = find_user($u);
if (!$uid) out(false,"user not found",[],404); if (!$uid) out(false,"user not found",[],404);
db()->prepare("INSERT INTO characters(user_id,name) VALUES(?,?)")->execute([$uid,$c]);
out(true,"created",["character_id"=>db()->lastInsertId()]);
} }
$c = trim($b["name"] ?? "");
if ($c==="") out(false,"invalid",[],400);
$ins = db()->prepare("INSERT INTO characters(user_id,name) VALUES(?,?)");
try { $ins->execute([$uid,$c]); }
catch(PDOException $e){ if($e->errorInfo[1]==1062) out(false,"character exists for this user",[],409); throw $e; }
out(true,"created",["character_id"=>(int)db()->lastInsertId()]);
}
if ($a === "list") { if ($a === "list") {
$st=db()->query("SELECT c.character_id,c.name,u.username FROM characters c JOIN users u ON u.user_id=c.user_id"); $camp = (int)($_GET['campaign_id'] ?? 0);
if ($camp>0){
$st = db()->prepare("
SELECT c.character_id, c.user_id, c.name, u.username,
EXISTS(SELECT 1 FROM campaign_characters cc
WHERE cc.campaign_id=? AND cc.character_id=c.character_id) AS assigned
FROM characters c
JOIN users u ON u.user_id=c.user_id
ORDER BY u.username ASC, c.name ASC
");
$st->execute([$camp]);
} else {
$st = db()->query("
SELECT c.character_id, c.user_id, c.name, u.username, 0 AS assigned
FROM characters c
JOIN users u ON u.user_id=c.user_id
ORDER BY u.username ASC, c.name ASC
");
}
out(true,"ok",["items"=>$st->fetchAll()]); out(true,"ok",["items"=>$st->fetchAll()]);
} }
// --- delete ---
if ($a === "delete") { if ($a === "delete") {
$u=$_GET["username"]??""; $c=$_GET["name"]??""; $u = trim($_GET['username'] ?? '');
$n = trim($_GET['name'] ?? '');
if ($u===''||$n==='') out(false,'username/name required',[],400);
$uid = find_user($u); $uid = find_user($u);
if (!$uid) out(false,"user not found",[],404); if (!$uid) out(false,"user not found",[],404);
$d=db()->prepare("DELETE FROM characters WHERE user_id=? AND name=?");
$d->execute([$uid,$c]); $del = db()->prepare("DELETE FROM characters WHERE user_id=? AND name=?");
out(true,"deleted",["count"=>$d->rowCount()]); $del->execute([$uid,$n]);
out(true,"deleted",["count"=>$del->rowCount()]);
} }
if ($a === "assign") {
$cid = (int)($b['character_id'] ?? 0);
$camp = $b['campaign_id'] ?? null;
if ($cid<=0) out(false,'character_id required',[],400);
if ($camp===null || $camp===''){
$st = db()->prepare("DELETE FROM campaign_characters WHERE character_id=?");
$st->execute([$cid]);
out(true,'unassigned',[]);
} else {
$camp = (int)$camp;
$st = db()->prepare("INSERT IGNORE INTO campaign_characters(campaign_id,character_id) VALUES(?,?)");
$st->execute([$camp,$cid]);
out(true,'assigned',[]);
}
}
out(false,"unknown action",[],404); out(false,"unknown action",[],404);
} catch (Throwable $e) {
bad("server error: ".$e->getMessage(),500);
}

View File

@ -1,27 +1,37 @@
<?php <?php
header('Content-Type: application/json; charset=utf-8');
function db() {
function db()
{
static $pdo = null; static $pdo = null;
if ($pdo) if ($pdo) return $pdo;
return $pdo;
$pdo = new PDO("mysql:host=127.0.0.1;dbname=vprmini_simple;charset=utf8mb4", "root", "root", [ $dbName = "vpr"; //Datenbankname
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, $linkName = "localhost"; //Datenbank-Server
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC $user = "root"; //Benutzername
]); $pw = ""; //Passwort
$pdo = new \PDO("mysql:dbname=$dbName;host=$linkName"
, $user
, $pw
, array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
return $pdo; return $pdo;
} }
function body()
{ function body() {
$raw = file_get_contents("php://input"); $raw = file_get_contents('php://input');
$j = json_decode($raw, true); $b = json_decode($raw, true);
return is_array($j) ? $j : $_POST; return is_array($b) ? $b : [];
} }
function out($ok, $msg, $data = [], $status = 200)
{ const JSON_FLAGS = JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE;
http_response_code($status);
header("Content-Type: application/json"); function bad($m, $code = 400) {
echo json_encode(["ok" => $ok, "msg" => $msg] + $data); http_response_code($code);
echo json_encode(['ok' => false, 'error' => $m], JSON_FLAGS);
exit;
}
function ok($arr = []) {
echo json_encode(['ok' => true] + $arr, JSON_FLAGS);
exit; exit;
} }

24
Backend/notes.php Normal file
View File

@ -0,0 +1,24 @@
<?php
//Lucas
require "db.php";
$action = $_GET['action'] ?? '';
if ($action==='list') {
$camp = isset($_GET['campaign_id']) ? (int)$_GET['campaign_id'] : 0;
if ($camp<=0) bad('campaign_id required');
$st=db()->prepare("SELECT id, campaign_id, user_id, text FROM campaign_notes WHERE campaign_id=? ORDER BY id DESC");
$st->execute([$camp]);
ok(['items'=>$st->fetchAll()]);
}
if ($action==='add') {
$b = body();
$camp=(int)($b['campaign_id']??0); $uid=(int)($b['user_id']??0); $txt=trim($b['text']??'');
if ($camp<=0||$uid<=0||$txt==='') bad('invalid');
$st=db()->prepare("INSERT INTO campaign_notes(campaign_id,user_id,text) VALUES(?,?,?)");
$st->execute([$camp,$uid,$txt]);
ok(['id'=>db()->lastInsertId()]);
}
http_response_code(404); echo json_encode(['ok'=>false,'error'=>'unknown action']);

View File

@ -1,4 +1,5 @@
<?php <?php
//Felix
require "db.php";$action=$_GET['action']??'';$b=body(); require "db.php";$action=$_GET['action']??'';$b=body();
if($action==="join"){ if($action==="join"){
$sid=(int)($b["session_id"]??0);$uid=(int)($b["user_id"]??0);$role=$b["role"]??"Player";if(!in_array($role,["DM","Player"]))$role="Player"; $sid=(int)($b["session_id"]??0);$uid=(int)($b["user_id"]??0);$role=$b["role"]??"Player";if(!in_array($role,["DM","Player"]))$role="Player";

62
Backend/restAPI.php Normal file
View File

@ -0,0 +1,62 @@
<?php
session_start();
spl_autoload_register(function ($className) {
if (substr($className, 0, 4) !== 'ppb\\') { return; }
$fileName = __DIR__.'/'.str_replace('\\', DIRECTORY_SEPARATOR, substr($className, 4)).'.php';
if (file_exists($fileName)) { include $fileName; }
});
$endpoint = explode('/', trim($_SERVER['PATH_INFO'],'/'));
$data = json_decode(file_get_contents('php://input'), true);
$controllerName = $endpoint[0];
$id = false;
$alias = false;
if (isset($endpoint[1])) {
if (preg_match('/\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/', $$endpoint[1])) {
$id = $$endpoint[1];
} else {
$alias = $$endpoint[1];
}
}
$controllerClassName = 'ppb\\Controller\\'.ucfirst($controllerName). 'Controller';
if ($_SERVER['REQUEST_METHOD'] == "DELETE") {
$methodName = "delete" . ucfirst($controllerName);
} else if ($_SERVER['REQUEST_METHOD'] == "PUT") {
$methodName = "update" . ucfirst($controllerName);
} else if ($_SERVER['REQUEST_METHOD'] == "POST") {
$methodName = "write" . ucfirst($controllerName);
} else if ($_SERVER['REQUEST_METHOD'] == "GET") {
if ($alias) {
$methodName = $alias;
} else {
$methodName = "get" . ucfirst($controllerName);
}
}
if (method_exists($controllerClassName, $methodName)) {
$controller = new $controllerClassName();
if ($_SERVER['REQUEST_METHOD'] == "GET") {
if ($id) {
$controller->$methodName($id);
} else {
$controller->$methodName();
}
} else if ($_SERVER['REQUEST_METHOD'] == "POST"){
$controller->$methodName($data);
} else if ($_SERVER['REQUEST_METHOD'] == "DELETE"){
$controller->$methodName($id);
} else {
$controller->$methodName($id, $data);
}
} else {
}
?>

View File

@ -1,4 +1,5 @@
<?php <?php
//Lucas
require "db.php"; require "db.php";
$action=$_GET['action']??'';$b=body(); $action=$_GET['action']??'';$b=body();
if($action==="create"){ if($action==="create"){

View File

@ -1,30 +1,55 @@
CREATE DATABASE IF NOT EXISTS vprmini_simple DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS vpr DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE vprmini_simple; USE vpr;
--jakob
--Jakob
DROP TABLE IF EXISTS campaign_notes;
DROP TABLE IF EXISTS campaign_characters;
DROP TABLE IF EXISTS campaigns;
DROP TABLE IF EXISTS characters; DROP TABLE IF EXISTS characters;
DROP TABLE IF EXISTS sessions; DROP TABLE IF EXISTS sessions;
DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS users;
-- user für login -- User
CREATE TABLE users ( CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY, user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40) NOT NULL UNIQUE, username VARCHAR(40) NOT NULL UNIQUE,
pass_hash VARCHAR(255) NOT NULL pass_hash VARCHAR(255) NOT NULL
); );
-- charaktere sind unique und gehören zu einem user CREATE TABLE campaigns (
campaign_id INT AUTO_INCREMENT PRIMARY KEY,
owner_user_id INT NOT NULL,
title VARCHAR(100) NOT NULL DEFAULT 'Meine Kampagne',
description TEXT NULL,
UNIQUE KEY ux_owner_one_campaign (owner_user_id),
CONSTRAINT fk_campaign_owner FOREIGN KEY (owner_user_id)
REFERENCES users(user_id) ON DELETE CASCADE
);
CREATE TABLE characters ( CREATE TABLE characters (
character_id INT AUTO_INCREMENT PRIMARY KEY, character_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL, user_id INT NOT NULL,
campaign_id INT NULL,
name VARCHAR(50) NOT NULL, name VARCHAR(50) NOT NULL,
CONSTRAINT fk_char_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE, CONSTRAINT fk_char_user FOREIGN KEY (user_id)
REFERENCES users(user_id) ON DELETE CASCADE,
CONSTRAINT fk_char_campaign FOREIGN KEY (campaign_id)
REFERENCES campaigns(campaign_id) ON DELETE SET NULL,
CONSTRAINT ux_user_char UNIQUE (user_id, name) CONSTRAINT ux_user_char UNIQUE (user_id, name)
); );
-- session
CREATE TABLE sessions ( CREATE TABLE sessions (
session_id INT AUTO_INCREMENT PRIMARY KEY, session_id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL title VARCHAR(100) NOT NULL
); );
CREATE TABLE campaign_notes (
note_id INT AUTO_INCREMENT PRIMARY KEY,
campaign_id INT NOT NULL,
user_id INT NOT NULL,
text TEXT NOT NULL,
CONSTRAINT fk_note_campaign FOREIGN KEY (campaign_id)
REFERENCES campaigns(campaign_id) ON DELETE CASCADE,
CONSTRAINT fk_note_user FOREIGN KEY (user_id)
REFERENCES users(user_id) ON DELETE CASCADE
);

View File

@ -1,26 +1,43 @@
<?php <?php
require "db.php"; require "db.php";
$a = $_GET['action'] ?? '';
//Gabriel,Jakob
$action = $_GET['action'] ?? '';
$b = body(); $b = body();
if ($a==="register") { function out_ok($arr = []) { echo json_encode(['ok'=>true] + $arr, JSON_UNESCAPED_UNICODE); exit; }
$u = trim($b["username"]??""); function out_err($msg, $code=400) { http_response_code($code); echo json_encode(['ok'=>false,'error'=>$msg], JSON_UNESCAPED_UNICODE); exit; }
$p = trim($b["password"]??"");
if ($u==""||$p=="") out(false,"username/password required",[],400); if ($action === 'register') {
$st=db()->prepare("SELECT 1 FROM users WHERE username=?"); $u = trim($b['username'] ?? '');
$p = (string)($b['password'] ?? '');
if ($u === '' || $p === '') out_err('username/password required');
$st = db()->prepare("SELECT user_id FROM users WHERE username=?");
$st->execute([$u]); $st->execute([$u]);
if ($st->fetch()) out(false,"exists",[],409); if ($st->fetch()) out_err('username exists', 409);
$hash = password_hash($p, PASSWORD_DEFAULT); $hash = password_hash($p, PASSWORD_DEFAULT);
db()->prepare("INSERT INTO users(username,pass_hash) VALUES(?,?)")->execute([$u,$hash]); $ins = db()->prepare("INSERT INTO users(username, pass_hash) VALUES(?, ?)");
out(true,"registered",["user_id"=>db()->lastInsertId()]); $ins->execute([$u, $hash]);
out_ok(['user_id' => (int)db()->lastInsertId(), 'username' => $u]);
} }
if ($a==="login") {
$u = trim($b["username"]??""); if ($action === 'login') {
$p = trim($b["password"]??""); $u = trim($b['username'] ?? '');
$st=db()->prepare("SELECT * FROM users WHERE username=?"); $p = (string)($b['password'] ?? '');
if ($u === '' || $p === '') out_err('username/password required');
$st = db()->prepare("SELECT user_id, pass_hash FROM users WHERE username=?");
$st->execute([$u]); $st->execute([$u]);
$r=$st->fetch(); $row = $st->fetch();
if(!$r || !password_verify($p,$r["pass_hash"])) out(false,"invalid",[],401); if (!$row) out_err('invalid credentials', 401);
out(true,"ok",["user_id"=>$r["user_id"],"username"=>$u]);
if (!password_verify($p, $row['pass_hash'])) out_err('invalid credentials', 401);
out_ok(['user_id' => (int)$row['user_id'], 'username' => $u]);
} }
out(false,"unknown action",[],404);
out_err('unknown action', 404);