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
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'] ?? '';
$b = body();
function find_user($name) {
function find_user($name){
$st=db()->prepare("SELECT user_id FROM users WHERE username=?");
$st->execute([$name]);
$st->execute([trim($name)]);
$r=$st->fetch();
return $r ? $r["user_id"] : 0;
return $r? (int)$r["user_id"] : 0;
}
if ($a==="create") {
$u=trim($b["username"]??"");
$c=trim($b["name"]??"");
if($u==""||$c=="") out(false,"invalid",[],400);
$uid=find_user($u);
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()]);
try {
if ($a === "create") {
$uid = isset($b['user_id']) ? (int)$b['user_id'] : 0;
if ($uid<=0){
$u = trim($b["username"] ?? "");
if ($u==="") out(false,"username or user_id required",[],400);
$uid = find_user($u);
if (!$uid) out(false,"user not found",[],404);
}
$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") {
$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()]);
}
// --- delete ---
if ($a === "delete") {
$u = trim($_GET['username'] ?? '');
$n = trim($_GET['name'] ?? '');
if ($u===''||$n==='') out(false,'username/name required',[],400);
$uid = find_user($u);
if (!$uid) out(false,"user not found",[],404);
$del = db()->prepare("DELETE FROM characters WHERE user_id=? AND name=?");
$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);
} catch (Throwable $e) {
bad("server error: ".$e->getMessage(),500);
}
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");
out(true,"ok",["items"=>$st->fetchAll()]);
}
if ($a==="delete") {
$u=$_GET["username"]??""; $c=$_GET["name"]??"";
$uid=find_user($u);
if(!$uid) out(false,"user not found",[],404);
$d=db()->prepare("DELETE FROM characters WHERE user_id=? AND name=?");
$d->execute([$uid,$c]);
out(true,"deleted",["count"=>$d->rowCount()]);
}
out(false,"unknown action",[],404);

View File

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

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
//Felix
require "db.php";$action=$_GET['action']??'';$b=body();
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";

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
//Lucas
require "db.php";
$action=$_GET['action']??'';$b=body();
if($action==="create"){

View File

@ -1,30 +1,55 @@
CREATE DATABASE IF NOT EXISTS vprmini_simple DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE vprmini_simple;
--jakob
CREATE DATABASE IF NOT EXISTS vpr DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE vpr;
--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 sessions;
DROP TABLE IF EXISTS users;
-- user für login
-- User
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40) NOT NULL UNIQUE,
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40) NOT NULL UNIQUE,
pass_hash VARCHAR(255) NOT NULL
);
-- charaktere sind unique und gehören zu einem user
CREATE TABLE characters (
character_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
name VARCHAR(50) NOT NULL,
CONSTRAINT fk_char_user FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
CONSTRAINT ux_user_char UNIQUE(user_id, name)
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 (
character_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
campaign_id INT NULL,
name VARCHAR(50) NOT NULL,
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)
);
-- session
CREATE TABLE sessions (
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
require "db.php";
$a = $_GET['action'] ?? '';
//Gabriel,Jakob
$action = $_GET['action'] ?? '';
$b = body();
if ($a==="register") {
$u = trim($b["username"]??"");
$p = trim($b["password"]??"");
if ($u==""||$p=="") out(false,"username/password required",[],400);
$st=db()->prepare("SELECT 1 FROM users WHERE username=?");
function out_ok($arr = []) { echo json_encode(['ok'=>true] + $arr, JSON_UNESCAPED_UNICODE); exit; }
function out_err($msg, $code=400) { http_response_code($code); echo json_encode(['ok'=>false,'error'=>$msg], JSON_UNESCAPED_UNICODE); exit; }
if ($action === 'register') {
$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]);
if ($st->fetch()) out(false,"exists",[],409);
$hash=password_hash($p,PASSWORD_DEFAULT);
db()->prepare("INSERT INTO users(username,pass_hash) VALUES(?,?)")->execute([$u,$hash]);
out(true,"registered",["user_id"=>db()->lastInsertId()]);
if ($st->fetch()) out_err('username exists', 409);
$hash = password_hash($p, PASSWORD_DEFAULT);
$ins = db()->prepare("INSERT INTO users(username, pass_hash) VALUES(?, ?)");
$ins->execute([$u, $hash]);
out_ok(['user_id' => (int)db()->lastInsertId(), 'username' => $u]);
}
if ($a==="login") {
$u = trim($b["username"]??"");
$p = trim($b["password"]??"");
$st=db()->prepare("SELECT * FROM users WHERE username=?");
if ($action === 'login') {
$u = trim($b['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]);
$r=$st->fetch();
if(!$r || !password_verify($p,$r["pass_hash"])) out(false,"invalid",[],401);
out(true,"ok",["user_id"=>$r["user_id"],"username"=>$u]);
$row = $st->fetch();
if (!$row) out_err('invalid credentials', 401);
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);