- ReqHandler added
- interface reworked
This commit is contained in:
		
							parent
							
								
									356615c70b
								
							
						
					
					
						commit
						e6aadf0a5c
					
				
							
								
								
									
										139
									
								
								class/ReqHandler.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								class/ReqHandler.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// response types
 | 
			
		||||
const RESP_NONE = "none";
 | 
			
		||||
const RESP_PLAIN = "plain";
 | 
			
		||||
const RESP_JSON = "json";
 | 
			
		||||
 | 
			
		||||
// Request Handler Assignment class
 | 
			
		||||
// Members get populated when instantiated by ReqHandler;
 | 
			
		||||
// should not be used outside ReqHandler
 | 
			
		||||
class ReqHandlerAssignment
 | 
			
		||||
{
 | 
			
		||||
    // members
 | 
			
		||||
    public string $action; // action string
 | 
			
		||||
    public array $params; // request parameters
 | 
			
		||||
    public string $handler; // handler function
 | 
			
		||||
    public string $hint; // human-readable hint about what this action performs
 | 
			
		||||
    public string $level; // required command authentication level
 | 
			
		||||
    public string $resp_type; // response type
 | 
			
		||||
    public ReqHandler $rh; // reference to request handler
 | 
			
		||||
 | 
			
		||||
    function __construct(string $action, array $params, string $level, string $handler, string $resp_type, string $hint, ReqHandler &$rh)
 | 
			
		||||
    {
 | 
			
		||||
        $this->action = $action;
 | 
			
		||||
        $this->params = $params;
 | 
			
		||||
        $this->level = $level;
 | 
			
		||||
        $this->handler = $handler;
 | 
			
		||||
        $this->resp_type = $resp_type;
 | 
			
		||||
        $this->hint = $hint;
 | 
			
		||||
        $this->rh = &$rh; // assign be reference
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Request Handler class
 | 
			
		||||
class ReqHandler
 | 
			
		||||
{
 | 
			
		||||
    private array $mapping; // action-handler mapping
 | 
			
		||||
    private array $request; // reference to $_REQUEST
 | 
			
		||||
    private array $files; // reference to $_FILES
 | 
			
		||||
    private string $level; // max privilege level
 | 
			
		||||
 | 
			
		||||
    // Constructor
 | 
			
		||||
    function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        // create reference bindings
 | 
			
		||||
        $this->request = &$_REQUEST;
 | 
			
		||||
        $this->files = &$_FILES;
 | 
			
		||||
 | 
			
		||||
        $this->mapping = [PRIVILEGE_NONE => [], PRIVILEGE_PLAYER => [], PRIVILEGE_CREATOR => [], PRIVILEGE_QUIZMASTER => []]; // create assignment categories
 | 
			
		||||
        $this->level = PRIVILEGE_NONE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add new handler
 | 
			
		||||
    function add(string|array $actions, array $params, string $level, string $handler, string $resp_type, string $hint): bool
 | 
			
		||||
    {
 | 
			
		||||
        // convert single actions to array
 | 
			
		||||
        $actions = is_string($actions) ? [$actions] : $actions;
 | 
			
		||||
 | 
			
		||||
        // cannot assign more than one handler to the same action
 | 
			
		||||
        foreach ($actions as $action) {
 | 
			
		||||
            if (in_array($action, $this->mapping[$level])) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // create the assignment object
 | 
			
		||||
            $assignment = new ReqHandlerAssignment($action, $params, $level, $handler, $resp_type, $hint, $this);
 | 
			
		||||
            $this->mapping[$level][$action] = $assignment;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ACTION_KEY = "action";
 | 
			
		||||
 | 
			
		||||
    // Process possible pending request. Also check access privilege.
 | 
			
		||||
    function process(string $level = null, string $action_key = self::ACTION_KEY) : array {
 | 
			
		||||
        // get action
 | 
			
		||||
        $action = $this->request[$action_key] ?? "";
 | 
			
		||||
 | 
			
		||||
        // don't process empty actions
 | 
			
		||||
        if (trim($action) === "") {
 | 
			
		||||
            return ["", false];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // if privilege level is specified, then store
 | 
			
		||||
        $this->level = $level ?? $this->level;
 | 
			
		||||
 | 
			
		||||
        $resp = "";
 | 
			
		||||
        $success = false;
 | 
			
		||||
 | 
			
		||||
        // look up action
 | 
			
		||||
        $categories = array_keys($this->mapping);
 | 
			
		||||
        $highest_category_index = array_search($this->level, $categories);
 | 
			
		||||
        for ($i = 0; ($i < count($categories)) && ($i <= $highest_category_index); $i++) {
 | 
			
		||||
            // get category
 | 
			
		||||
            $category = &$this->mapping[$categories[$i]];
 | 
			
		||||
 | 
			
		||||
            // find the command level category that includes this action
 | 
			
		||||
            if (array_key_exists($action, $category)) {
 | 
			
		||||
                // get assignment
 | 
			
		||||
                $assignment = &$category[$action];
 | 
			
		||||
 | 
			
		||||
                // check that all required parameters were passed
 | 
			
		||||
                $all_params_passed = true;
 | 
			
		||||
                foreach ($assignment->params as $param) {
 | 
			
		||||
                    $all_params_passed &= array_key_exists($param, $this->request);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // if params were provided, then invoke the callback
 | 
			
		||||
                if ($all_params_passed) {
 | 
			
		||||
                    $handler = $assignment->handler;
 | 
			
		||||
                    $raw_resp = $handler($this, $this->request);
 | 
			
		||||
 | 
			
		||||
                    // convert response to preset response type
 | 
			
		||||
                    if ($assignment->resp_type !== RESP_NONE) { // if command returns with anything at all
 | 
			
		||||
                        if ($assignment->resp_type === RESP_JSON) { // JSON
 | 
			
		||||
                            $resp = json_encode($raw_resp);
 | 
			
		||||
                        } else if ($assignment->resp_type === RESP_PLAIN) { // PLAIN
 | 
			
		||||
                            $resp = $raw_resp;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // processing successful
 | 
			
		||||
                    $success = true;
 | 
			
		||||
 | 
			
		||||
                    break; // break the loop
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [$resp, $success];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set access privilege level
 | 
			
		||||
    function set_privilege_level(string $level) {
 | 
			
		||||
        $this->level = $level;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										442
									
								
								interface.php
									
									
									
									
									
								
							
							
						
						
									
										442
									
								
								interface.php
									
									
									
									
									
								
							@ -22,6 +22,9 @@ require_once "testmgr.php";
 | 
			
		||||
 | 
			
		||||
require_once "controller.php";
 | 
			
		||||
 | 
			
		||||
require_once "class/ReqHandler.php";
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
function patch_through_image(string $gameid, string $img_url)
 | 
			
		||||
{
 | 
			
		||||
    $game_dir = get_game_dir_by_gameid($gameid);
 | 
			
		||||
@ -35,16 +38,24 @@ function patch_through_image(string $gameid, string $img_url)
 | 
			
		||||
    fclose($img_fp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
$action = $_REQUEST["action"];
 | 
			
		||||
 | 
			
		||||
$result = "";
 | 
			
		||||
$success = false;
 | 
			
		||||
$privilege = PRIVILEGE_NONE;
 | 
			
		||||
 | 
			
		||||
// no-login accessible actions
 | 
			
		||||
switch ($action) {
 | 
			
		||||
    case "login":
 | 
			
		||||
// create request handler
 | 
			
		||||
$rh = new ReqHandler();
 | 
			
		||||
 | 
			
		||||
/* ------------ ACTIONS AVAILABLE WITHOUT LOGGING IN ---------- */
 | 
			
		||||
 | 
			
		||||
// login the user
 | 
			
		||||
function login(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $nickname = $_REQUEST["nickname"];
 | 
			
		||||
            $password = $_REQUEST["password"];
 | 
			
		||||
    $nickname = $params["nickname"];
 | 
			
		||||
    $password = $params["password"];
 | 
			
		||||
    if (check_user_credentials($nickname, $password)) {
 | 
			
		||||
        session_start();
 | 
			
		||||
        $_SESSION["nickname"] = $nickname;
 | 
			
		||||
@ -52,13 +63,15 @@ switch ($action) {
 | 
			
		||||
    } else {
 | 
			
		||||
        $result = "FAIL";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$rh->add("login", ["nickname", "password"], PRIVILEGE_NONE, "login", RESP_PLAIN, "Log in the user.");
 | 
			
		||||
 | 
			
		||||
// exit script if there's no live session or nickname is missing or the referenced user is non-existent
 | 
			
		||||
if ((session_status() != PHP_SESSION_ACTIVE) || (!isset($_SESSION["nickname"])) || (count(get_user($_SESSION["nickname"])) == 0)) {
 | 
			
		||||
    goto print_result;
 | 
			
		||||
    goto process_and_print;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$user_data = get_user($_SESSION["nickname"]);
 | 
			
		||||
@ -66,23 +79,26 @@ $nickname = $user_data["nickname"];
 | 
			
		||||
$privilege = $user_data["privilege"];
 | 
			
		||||
$is_quizmaster = $privilege === PRIVILEGE_QUIZMASTER;
 | 
			
		||||
 | 
			
		||||
// login-requiring actions
 | 
			
		||||
switch ($action) {
 | 
			
		||||
    case "logout":
 | 
			
		||||
/* ---------- ACTIONS REQUIRING BEING LOGGED IN ------------ */
 | 
			
		||||
 | 
			
		||||
function logout(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
    $_SESSION = []; // clean up session data
 | 
			
		||||
    setcookie(SESSION_NAME, "", -1); // invalidate cookie
 | 
			
		||||
    return "OK";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_user_info":
 | 
			
		||||
 | 
			
		||||
function get_user_info(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
    global $user_data;
 | 
			
		||||
    $user_data_filtered = $user_data;
 | 
			
		||||
    unset($user_data_filtered["password"]);
 | 
			
		||||
            $result = json_encode($user_data_filtered);
 | 
			
		||||
    return $user_data_filtered;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_available_games":
 | 
			
		||||
 | 
			
		||||
function get_available_games(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
    global $user_data;
 | 
			
		||||
    $games_by_groups = [];
 | 
			
		||||
    $groupids = $user_data["groups"];
 | 
			
		||||
    foreach ($groupids as $groupid) {
 | 
			
		||||
@ -99,20 +115,21 @@ switch ($action) {
 | 
			
		||||
        }
 | 
			
		||||
        $games_by_groups[] = $game_collection;
 | 
			
		||||
    }
 | 
			
		||||
            $result = json_encode($games_by_groups);
 | 
			
		||||
 | 
			
		||||
    return $games_by_groups;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "start_or_continue_test":
 | 
			
		||||
 | 
			
		||||
function start_or_continue_test(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
            $testid = create_or_continue_test($gameid, $nickname);
 | 
			
		||||
            $result = $testid;
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    $testid = create_or_continue_test($params["gameid"], $nickname);
 | 
			
		||||
    return $testid;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_results_overview":
 | 
			
		||||
 | 
			
		||||
function get_results_overview(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
            $concluded_tests = get_concluded_tests($gameid, $nickname);
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    $concluded_tests = get_concluded_tests($params["gameid"], $nickname);
 | 
			
		||||
    $overviews = [];
 | 
			
		||||
    foreach ($concluded_tests as $ct) {
 | 
			
		||||
        $overview = [
 | 
			
		||||
@ -123,80 +140,124 @@ switch ($action) {
 | 
			
		||||
        ];
 | 
			
		||||
        $overviews[] = $overview;
 | 
			
		||||
    }
 | 
			
		||||
            $result = json_encode($overviews);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    return $overviews;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$rh->add("logout", [], PRIVILEGE_PLAYER, "logout", RESP_PLAIN, "Log out the user.");
 | 
			
		||||
$rh->add("get_user_info", [], PRIVILEGE_PLAYER, "get_user_info", RESP_JSON, "Get user information.");
 | 
			
		||||
$rh->add("get_available_games", [], PRIVILEGE_PLAYER, "get_available_games", RESP_JSON, "Get available games to the player.");
 | 
			
		||||
$rh->add("start_or_continue_test", ["gameid"], PRIVILEGE_PLAYER, "start_or_continue_test", RESP_PLAIN, "Start new or continue an ongoing test.");
 | 
			
		||||
$rh->add("get_results_overview", ["gameid"], PRIVILEGE_PLAYER, "get_results_overview", RESP_JSON, "Get a quick overview of player's results of a single game.");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// test-related queries
 | 
			
		||||
const TEST_RELATED_ACTIONS = ["get_test", "save_answer", "submit_test"];
 | 
			
		||||
if (in_array($action, TEST_RELATED_ACTIONS)) {
 | 
			
		||||
function does_test_belong_to_user(array $test_data): bool
 | 
			
		||||
{
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    return $test_data["nickname"] === $nickname;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    $testid = trim($_REQUEST["testid"] ?? "");
 | 
			
		||||
    $test_data = ($testid !== "") ? get_test($testid) : [];
 | 
			
		||||
    $is_a_default_test_with_access = ($testid !== "") && ((count($test_data)) > 0) && (($test_data["nickname"] === $nickname));
 | 
			
		||||
function is_test_access_approved(array $test_data): bool
 | 
			
		||||
{
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    global $is_quizmaster;
 | 
			
		||||
 | 
			
		||||
    $user_is_contributor_or_quizmaster = $is_quizmaster || is_user_contributor_to_game($test_data["gameid"], $nickname);
 | 
			
		||||
    return does_test_belong_to_user($test_data) || is_user_contributor_to_game($test_data["gameid"], $nickname) || $is_quizmaster;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if ($is_a_default_test_with_access || $user_is_contributor_or_quizmaster) {
 | 
			
		||||
function access_test_data(string $testid): array|null
 | 
			
		||||
{
 | 
			
		||||
    $testid = trim($testid);
 | 
			
		||||
    $test_data = ($testid !== "") ? get_test($testid) : null;
 | 
			
		||||
 | 
			
		||||
    // fetch test data
 | 
			
		||||
    if ($test_data === null) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // check if access is approved to the specific test
 | 
			
		||||
    if (!is_test_access_approved($test_data)) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // update the test if timed
 | 
			
		||||
    update_timed_tests([$test_data]);
 | 
			
		||||
 | 
			
		||||
        switch ($action) {
 | 
			
		||||
            case "get_test":
 | 
			
		||||
    return $test_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function get_player_test(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
    $result = [];
 | 
			
		||||
    $test_data = access_test_data($params["testid"]);
 | 
			
		||||
 | 
			
		||||
    if ($test_data !== null) {
 | 
			
		||||
        $test_data_with_current_time = $test_data;
 | 
			
		||||
        $test_data_with_current_time["current_time"] = time();
 | 
			
		||||
                    $result = json_encode($test_data_with_current_time);
 | 
			
		||||
        $result = $test_data_with_current_time;
 | 
			
		||||
    }
 | 
			
		||||
                break;
 | 
			
		||||
            case "save_answer":
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function save_player_answer(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
                    $chidx = $_REQUEST["challenge_index"];
 | 
			
		||||
                    $answeridx = $_REQUEST["answer_index"];
 | 
			
		||||
                    save_answer($testid, $chidx, $answeridx);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case "submit_test":
 | 
			
		||||
                {
 | 
			
		||||
                    conclude_test($testid);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
    if (access_test_data($params["testid"] !== null)) {
 | 
			
		||||
        save_answer($params["testid"], $params["challenge_index"], $params["answer_index"]);
 | 
			
		||||
        return "OK";
 | 
			
		||||
    } else {
 | 
			
		||||
        return "FAIL";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    // $user_has_access_to_game = does_user_access_game($nickname, $gameid);
 | 
			
		||||
function submit_test(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
    if (access_test_data($params["testid"] !== null)) {
 | 
			
		||||
        conclude_test($params["testid"]);
 | 
			
		||||
        return "OK";
 | 
			
		||||
    } else {
 | 
			
		||||
        return "FAIL";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    // get_image needs special treatment
 | 
			
		||||
    if ($action === "get_image") {
 | 
			
		||||
        if ($is_a_default_test_with_access || $user_is_contributor_or_quizmaster) { // default case
 | 
			
		||||
            $img_url = trim($_REQUEST["img_url"] ?? "");
 | 
			
		||||
function get_image(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
    $img_url = trim($params["img_url"] ?? "");
 | 
			
		||||
    if ($img_url !== "") {
 | 
			
		||||
                $gameid = $_REQUEST["gameid"];
 | 
			
		||||
        $gameid = $params["gameid"];
 | 
			
		||||
        patch_through_image($gameid, $img_url);
 | 
			
		||||
    }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$rh->add("get_test", ["testid"], PRIVILEGE_PLAYER, "get_player_test", RESP_JSON, "Get player's test by ID.");
 | 
			
		||||
$rh->add("save_answer", ["testid", "challenge_index", "answer_index"], PRIVILEGE_PLAYER, "save_player_answer", RESP_PLAIN, "Store player's answer.");
 | 
			
		||||
$rh->add("submit_test", ["testid"], PRIVILEGE_PLAYER, "submit_test", RESP_PLAIN, "Finish player's test.");
 | 
			
		||||
$rh->add("get_image", ["gameid", "img_url"], PRIVILEGE_PLAYER, "get_image", RESP_NONE, "Get image per game.");
 | 
			
		||||
 | 
			
		||||
// execute query if user has the player privilege level
 | 
			
		||||
if ($privilege === PRIVILEGE_PLAYER) {
 | 
			
		||||
    goto process_and_print;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// creator or quizmaster actions
 | 
			
		||||
if (($privilege !== PRIVILEGE_CREATOR) && ($privilege !== PRIVILEGE_QUIZMASTER)) {
 | 
			
		||||
    goto print_result;
 | 
			
		||||
}
 | 
			
		||||
/* --------------- CREATOR LEVEL ACTIONS ---------------- */
 | 
			
		||||
 | 
			
		||||
$requester_nickname = $is_quizmaster ? "*" : $nickname; // "*" means every game
 | 
			
		||||
 | 
			
		||||
switch ($action) {
 | 
			
		||||
    case "create_game":
 | 
			
		||||
    case "update_game":
 | 
			
		||||
function create_update_game(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $update = $action === "update_game";
 | 
			
		||||
            $data = json_decode($_REQUEST["data"], true) ?? [];
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    global $is_quizmaster;
 | 
			
		||||
 | 
			
		||||
    $update = $params[ReqHandler::ACTION_KEY] === "update_game";
 | 
			
		||||
    $data = json_decode($params["data"], true) ?? [];
 | 
			
		||||
    if (($data === []) || (trim($data["name"] ?? "") === "")) { // no further processing
 | 
			
		||||
                goto print_result; // ~exit...
 | 
			
		||||
        return []; // ~exit...
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // fetch fields
 | 
			
		||||
    $gameid = $data["_id"];
 | 
			
		||||
    $name = $data["name"];
 | 
			
		||||
    $description = $data["description"];
 | 
			
		||||
@ -205,15 +266,19 @@ switch ($action) {
 | 
			
		||||
    $groups = explode_list($data["groups"] ?? "");
 | 
			
		||||
    $properties = $data["properties"] ?? [];
 | 
			
		||||
 | 
			
		||||
    // convert group compounds to group IDs
 | 
			
		||||
    $groupids = get_groupids_by_compounds($groups); // convert group compounds to _ids
 | 
			
		||||
 | 
			
		||||
    // remove group ID's this user cannot edit
 | 
			
		||||
            $groupids_with_editor_access = [];
 | 
			
		||||
            foreach ($groupids as $groupid) {
 | 
			
		||||
                if (is_user_editor_to_group($groupid, $nickname) || $is_quizmaster) {
 | 
			
		||||
                    $groupids_with_editor_access[] = $groupid;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
//    $groupids_with_editor_access = [];
 | 
			
		||||
//    foreach ($groupids as $groupid) {
 | 
			
		||||
//        if (is_user_editor_to_group($groupid, $nickname) || $is_quizmaster) {
 | 
			
		||||
//            $groupids_with_editor_access[] = $groupid;
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    // result
 | 
			
		||||
    $result = [];
 | 
			
		||||
 | 
			
		||||
    // create or update
 | 
			
		||||
    if (!$update) {
 | 
			
		||||
@ -221,6 +286,7 @@ switch ($action) {
 | 
			
		||||
    } else if (is_user_contributor_to_game($gameid, $nickname) || $is_quizmaster) {
 | 
			
		||||
        $game_data = get_game($gameid);
 | 
			
		||||
        if (count($game_data) !== 0) {
 | 
			
		||||
 | 
			
		||||
            // group management
 | 
			
		||||
            $old_groupids = $game_data["groups"]; // retain old groupids
 | 
			
		||||
            $new_groupids = $groupids; // get new groupids
 | 
			
		||||
@ -239,7 +305,7 @@ switch ($action) {
 | 
			
		||||
            // update game header data
 | 
			
		||||
            $game_data["name"] = $name;
 | 
			
		||||
            $game_data["description"] = $description;
 | 
			
		||||
                    if (($game_data["owner"] === $nickname) || ($privilege === PRIVILEGE_QUIZMASTER)) {
 | 
			
		||||
            if (($game_data["owner"] === $nickname) || $is_quizmaster) {
 | 
			
		||||
                $game_data["owner"] = $owner;
 | 
			
		||||
            }
 | 
			
		||||
            $game_data["contributors"] = array_intersect($contributors, get_all_nicknames());
 | 
			
		||||
@ -247,11 +313,7 @@ switch ($action) {
 | 
			
		||||
            $game_data["properties"]["repeatable"] = $properties["repeatable"];
 | 
			
		||||
 | 
			
		||||
            // process game public flag: a game might be only public if not being time-constrained and is allowed to be taken multiple times
 | 
			
		||||
                    if (($properties["time_limit"] !== 0) || (!$properties["repeatable"])) {
 | 
			
		||||
                        $game_data["public"] = false;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $game_data["public"] = $data["public"];
 | 
			
		||||
                    }
 | 
			
		||||
            $game_data["public"] = ($properties["time_limit"] !== 0) || (!$properties["repeatable"]) ? false : $data["public"];
 | 
			
		||||
 | 
			
		||||
            // update game data
 | 
			
		||||
            update_game($game_data);
 | 
			
		||||
@ -270,7 +332,7 @@ switch ($action) {
 | 
			
		||||
                    if ($zip->open($file["tmp_name"])) {
 | 
			
		||||
 | 
			
		||||
                        $game_dir = get_game_dir_by_gameid($gameid); // get game directory
 | 
			
		||||
                                $game_files = glob($game_dir); // get list of existing game files
 | 
			
		||||
                        //$game_files = glob($game_dir); // get list of existing game files
 | 
			
		||||
                        // remove former files recursively
 | 
			
		||||
                        $dir_iter = new RecursiveDirectoryIterator($game_dir, FilesystemIterator::SKIP_DOTS);
 | 
			
		||||
                        foreach ($dir_iter as $dir_item) {
 | 
			
		||||
@ -290,43 +352,56 @@ switch ($action) {
 | 
			
		||||
                } else if ($file_type === "csv") { // a plain table was uploaded
 | 
			
		||||
                    $challenge_import_status = import_challenges_from_csv($file["tmp_name"], $gameid);
 | 
			
		||||
                }
 | 
			
		||||
                        $result = json_encode($challenge_import_status);
 | 
			
		||||
                $result = $challenge_import_status;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_all_game_headers":
 | 
			
		||||
 | 
			
		||||
function get_all_game_headers(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
    global $requester_nickname;
 | 
			
		||||
    $game_headers = get_all_game_data_by_contributor_nickname($requester_nickname);
 | 
			
		||||
    foreach ($game_headers as &$game_header) {
 | 
			
		||||
        resolve_groupids($game_header["groups"]);
 | 
			
		||||
    }
 | 
			
		||||
            $result = json_encode($game_headers);
 | 
			
		||||
    return $game_headers;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_challenges":
 | 
			
		||||
 | 
			
		||||
function get_challenges(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $gameid = ($_REQUEST["gameid"] ?? "");
 | 
			
		||||
    global $is_quizmaster;
 | 
			
		||||
    global $requester_nickname;
 | 
			
		||||
    $gameid = $params["gameid"];
 | 
			
		||||
    $game_data = get_game($gameid);
 | 
			
		||||
    $result = "";
 | 
			
		||||
    if ((count($game_data) > 0) && ($is_quizmaster || (is_user_contributor_to_game($gameid, $requester_nickname)))) {
 | 
			
		||||
        $result = file_get_contents(get_game_file_by_gameid($gameid));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "delete_games":
 | 
			
		||||
 | 
			
		||||
function delete_games(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $gameids = explode_list(trim($_REQUEST["ids"] ?? ""));
 | 
			
		||||
    global $nickname;
 | 
			
		||||
 | 
			
		||||
    $gameids = explode_list(trim($params["ids"]));
 | 
			
		||||
    foreach ($gameids as $gameid) {
 | 
			
		||||
        if (($gameid !== "") && (is_user_owner_of_the_game($gameid, $nickname))) { // only the owner may delete a game
 | 
			
		||||
            delete_game($gameid);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return "OK";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "export_game_file_csv":
 | 
			
		||||
 | 
			
		||||
function export_game_file_csv(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    $gameid = trim($params["gameid"]);
 | 
			
		||||
    if (($gameid !== "") && is_user_contributor_to_game($gameid, $nickname)) {
 | 
			
		||||
        $f = tmpfile();
 | 
			
		||||
        header("Content-Type: text/csv");
 | 
			
		||||
@ -335,62 +410,71 @@ switch ($action) {
 | 
			
		||||
        fseek($f, 0);
 | 
			
		||||
        fpassthru($f);
 | 
			
		||||
    }
 | 
			
		||||
    return "";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_results_by_gameid":
 | 
			
		||||
 | 
			
		||||
function get_player_results_by_gameid(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
            $filter = trim($_REQUEST["filter"] ?? "");
 | 
			
		||||
            $ordering = trim($_REQUEST["orderby"] ?? "");
 | 
			
		||||
    global $nickname;
 | 
			
		||||
    global $is_quizmaster;
 | 
			
		||||
 | 
			
		||||
    $gameid = trim($params["gameid"]);
 | 
			
		||||
    $filter = trim($params["filter"] ?? "");
 | 
			
		||||
    $ordering = trim($params["orderby"] ?? "");
 | 
			
		||||
 | 
			
		||||
    $result = [];
 | 
			
		||||
    if (($gameid !== "") && (is_user_contributor_to_game($gameid, $nickname) || $is_quizmaster)) {
 | 
			
		||||
        $game_results = get_results_by_gameid($gameid, $filter, $ordering, true);
 | 
			
		||||
                $result = json_encode($game_results);
 | 
			
		||||
        $result = $game_results;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "generate_detailed_stats":
 | 
			
		||||
 | 
			
		||||
function generate_detailed_game_stats(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $testids = json_decode(trim($_REQUEST["testids"] ?? "[]"), true);
 | 
			
		||||
            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
    $testids = json_decode(trim($params["testids"]), true);
 | 
			
		||||
    $gameid = trim($params["gameid"]);
 | 
			
		||||
    $stats = generate_detailed_stats($gameid, $testids);
 | 
			
		||||
            $result = json_encode($stats);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
//    case "get_image":
 | 
			
		||||
//        {
 | 
			
		||||
//            $gameid = trim($_REQUEST["gameid"] ?? "");
 | 
			
		||||
//            $img_url = trim($_REQUEST["img_url"] ?? "");
 | 
			
		||||
//            patch_through_image($gameid, $img_url);
 | 
			
		||||
//        }
 | 
			
		||||
//        break;
 | 
			
		||||
    return $stats;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// quizmaster actions
 | 
			
		||||
if ($privilege !== PRIVILEGE_QUIZMASTER) {
 | 
			
		||||
    goto print_result;
 | 
			
		||||
$rh->add(["create_game", "update_game"], ["data"], PRIVILEGE_CREATOR, "create_update_game", RESP_JSON, "Create or update game.");
 | 
			
		||||
$rh->add("get_all_game_headers", [], PRIVILEGE_CREATOR, "get_all_game_headers", RESP_JSON, "Get all game headers.");
 | 
			
		||||
$rh->add("get_challenges", [], PRIVILEGE_CREATOR, "get_challenges", RESP_PLAIN, "Get game challenges.");
 | 
			
		||||
$rh->add("delete_games", ["ids"], PRIVILEGE_CREATOR, "delete_games", RESP_PLAIN, "Delete games.");
 | 
			
		||||
$rh->add("export_game_file_csv", ["gameid"], PRIVILEGE_CREATOR, "export_game_file_csv", RESP_NONE, "Export game CSV file.");
 | 
			
		||||
$rh->add("get_results_by_gameid", ["gameid"], PRIVILEGE_CREATOR, "get_player_results_by_gameid", RESP_JSON, "Get game results.");
 | 
			
		||||
$rh->add("generate_detailed_stats", ["gameid", "testids"], PRIVILEGE_CREATOR, "generate_detailed_game_stats", RESP_JSON, "Generate detailed game stats.");
 | 
			
		||||
 | 
			
		||||
// execute processing if user is a creator
 | 
			
		||||
if ($privilege === PRIVILEGE_CREATOR) {
 | 
			
		||||
    goto process_and_print;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
switch ($action) {
 | 
			
		||||
    case "create_group":
 | 
			
		||||
    case "update_group":
 | 
			
		||||
 | 
			
		||||
/* ------------------------ QUIZMASTER ACTIONS --------------------- */
 | 
			
		||||
 | 
			
		||||
function create_update_group(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $update = $action === "update_group";
 | 
			
		||||
            $groupname = trim($_REQUEST["groupname"] ?? "");
 | 
			
		||||
            $description = trim($_REQUEST["description"] ?? "");
 | 
			
		||||
            $editors = explode_list(trim($_REQUEST["editors"] ?? ""));
 | 
			
		||||
            $owner = (!$update) ? $user_data["nickname"] : trim($_REQUEST["owner"]);
 | 
			
		||||
    global $user_data;
 | 
			
		||||
 | 
			
		||||
    $update = $params[ReqHandler::ACTION_KEY] === "update_group";
 | 
			
		||||
    $groupname = trim($params["groupname"]);
 | 
			
		||||
    $description = trim($params["description"]);
 | 
			
		||||
    $editors = (!$update) ? [] : explode_list(trim($params["editors"]));
 | 
			
		||||
    $owner = (!$update) ? $user_data["nickname"] : trim($params["owner"]);
 | 
			
		||||
 | 
			
		||||
    $result = "FAIL";
 | 
			
		||||
    if ($owner === "") {
 | 
			
		||||
        $owner = $user_data["nickname"];
 | 
			
		||||
    }
 | 
			
		||||
    if ($groupname != "") {
 | 
			
		||||
                switch ($action) {
 | 
			
		||||
                    case "create_group":
 | 
			
		||||
        if (!$update) {
 | 
			
		||||
            create_group($groupname, $owner, $description);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case "update_group":
 | 
			
		||||
                        {
 | 
			
		||||
                            $gid = $_REQUEST["id"];
 | 
			
		||||
            $result = "OK";
 | 
			
		||||
        } else {
 | 
			
		||||
            $gid = $params["id"];
 | 
			
		||||
            $group = get_group($gid);
 | 
			
		||||
            if (count($group) !== 0) {
 | 
			
		||||
                $group["unique"] = manage_unique_in_siblings($gid, $groupname); // manage unique flag in case of renaming
 | 
			
		||||
@ -399,48 +483,50 @@ switch ($action) {
 | 
			
		||||
                $group["editors"] = array_intersect($editors, $group["users"]); // a user cannot be an editor if not part of the group
 | 
			
		||||
                $group["owner"] = $owner;
 | 
			
		||||
                update_group($group);
 | 
			
		||||
                $result = "OK";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
                        break;
 | 
			
		||||
    }
 | 
			
		||||
    return $result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case "delete_groups":
 | 
			
		||||
function delete_groups(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
            $groups = explode_list($_REQUEST["ids"] ?? "");
 | 
			
		||||
    $groups = explode_list($params["ids"] ?? "");
 | 
			
		||||
    foreach ($groups as $g) {
 | 
			
		||||
        delete_group($g);
 | 
			
		||||
    }
 | 
			
		||||
    return "OK";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_all_groups":
 | 
			
		||||
        $result = json_encode(get_all_groups());
 | 
			
		||||
        break;
 | 
			
		||||
    case "search_groups":
 | 
			
		||||
 | 
			
		||||
function get_all_player_groups(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $needle = $_REQUEST["needle"] ?? "";
 | 
			
		||||
            $result = json_encode(search_groups($needle));
 | 
			
		||||
    return get_all_groups();
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "create_user":
 | 
			
		||||
    case "update_user":
 | 
			
		||||
 | 
			
		||||
function search_player_groups(ReqHandler &$rh, array $params): array
 | 
			
		||||
{
 | 
			
		||||
            $update = $action === "update_user";
 | 
			
		||||
            $target_nickname = trim($_REQUEST["nickname"] ?? "");
 | 
			
		||||
            $password = trim($_REQUEST["password"] ?? "");
 | 
			
		||||
            $groups = explode_list($_REQUEST["groups"] ?? "");
 | 
			
		||||
            $realname = trim($_REQUEST["realname"] ?? "");
 | 
			
		||||
            $privilege = trim($_REQUEST["privilege"] ?? PRIVILEGE_PLAYER);
 | 
			
		||||
    return search_groups($params["needle"]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function create_update_user(ReqHandler &$rh, array $params): string
 | 
			
		||||
{
 | 
			
		||||
    $update = $params[ReqHandler::ACTION_KEY] === "update_user";
 | 
			
		||||
    $target_nickname = trim($params["nickname"]);
 | 
			
		||||
    $password = trim($params["password"]);
 | 
			
		||||
    $groups = explode_list($params["groups"]);
 | 
			
		||||
    $realname = trim($params["realname"]);
 | 
			
		||||
    $privilege = trim($params["privilege"]);
 | 
			
		||||
 | 
			
		||||
    $groupids = get_groupids_by_compounds($groups); // convert group compounds to _ids
 | 
			
		||||
 | 
			
		||||
    $success = false;
 | 
			
		||||
    if (($target_nickname !== "")) {
 | 
			
		||||
        if ((!$update) && ($password !== "")) { // CREATE
 | 
			
		||||
                    add_user($target_nickname, $password, $realname, $groupids, $privilege);
 | 
			
		||||
            $success = add_user($target_nickname, $password, $realname, $groupids, $privilege);
 | 
			
		||||
        } else if ($update) { // UPDATE
 | 
			
		||||
            $user_data = get_user($target_nickname); // load user data
 | 
			
		||||
            if (count ($user_data) > 0) {
 | 
			
		||||
 | 
			
		||||
                // group management
 | 
			
		||||
                $old_groupids = $user_data["groups"]; // retain old groupids
 | 
			
		||||
@ -466,43 +552,55 @@ switch ($action) {
 | 
			
		||||
                    $user_data["password"] = password_hash($password, PASSWORD_DEFAULT);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    update_user($user_data);
 | 
			
		||||
                $success = update_user($user_data);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $success ? "OK" : "FAIL";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "delete_users":
 | 
			
		||||
        {
 | 
			
		||||
            $users = explode_list($_REQUEST["users"] ?? "");
 | 
			
		||||
 | 
			
		||||
function delete_users(ReqHandler &$rh, array $params): string {
 | 
			
		||||
    $users = explode_list($params["users"]);
 | 
			
		||||
    foreach ($users as $g) {
 | 
			
		||||
        delete_user($g);
 | 
			
		||||
    }
 | 
			
		||||
    return "OK";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "get_all_users":
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
function get_all_game_users(ReqHandler &$rh, array $params): array {
 | 
			
		||||
    $user_data_filtered = get_all_users();
 | 
			
		||||
    for ($i = 0; $i < count($user_data_filtered); $i++) {
 | 
			
		||||
        unset($user_data_filtered[$i]["password"]); // remove password from records
 | 
			
		||||
        resolve_groupids($user_data_filtered[$i]["groups"]);  // resolve group IDs
 | 
			
		||||
    }
 | 
			
		||||
            $result = json_encode($user_data_filtered);
 | 
			
		||||
    return $user_data_filtered;
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
    case "import_users_from_csv":
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
function import_users_from_csv(ReqHandler &$rh, array $params): string {
 | 
			
		||||
    if (!isset($_FILES["users_table"])) {
 | 
			
		||||
                goto print_result;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    return "OK";
 | 
			
		||||
}
 | 
			
		||||
        break;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$rh->add("create_group", ["groupname", "description"], PRIVILEGE_QUIZMASTER, "create_update_group", RESP_PLAIN, "Create group.");
 | 
			
		||||
$rh->add("update_group", ["groupname", "description", "owner", "editors", "id"], PRIVILEGE_QUIZMASTER, "create_update_group", RESP_PLAIN, "Update group.");
 | 
			
		||||
$rh->add("delete_group", ["ids"], PRIVILEGE_QUIZMASTER, "delete_group", RESP_PLAIN, "Delete group.");
 | 
			
		||||
$rh->add("get_all_groups", [], PRIVILEGE_QUIZMASTER, "get_all_player_groups", RESP_JSON, "Get all player groups.");
 | 
			
		||||
$rh->add("search_groups", ["needle"], PRIVILEGE_QUIZMASTER, "search_player_groups", RESP_JSON, "Serach and fetch player groups.");
 | 
			
		||||
 | 
			
		||||
$rh->add(["create_user", "update_user"], ["nickname", "password", "groups", "realname", "privilege"], PRIVILEGE_QUIZMASTER, "create_update_user", RESP_PLAIN, "Create or update user.");
 | 
			
		||||
$rh->add("delete_users", ["users"], PRIVILEGE_QUIZMASTER, "delete_users", RESP_PLAIN, "Delete users.");
 | 
			
		||||
$rh->add("get_all_game_users", [], PRIVILEGE_QUIZMASTER, "get_all_users", RESP_JSON, "Get all users.");
 | 
			
		||||
$rh->add("import_users_from_csv", [], PRIVILEGE_QUIZMASTER, "import_", RESP_JSON, "Get all users.");
 | 
			
		||||
 | 
			
		||||
// ----------
 | 
			
		||||
 | 
			
		||||
print_result:
 | 
			
		||||
process_and_print:
 | 
			
		||||
 | 
			
		||||
if ($result !== "") {
 | 
			
		||||
[$result, $success] = $rh->process($privilege);
 | 
			
		||||
 | 
			
		||||
if ($success && ($result !== "")) {
 | 
			
		||||
    echo $result;
 | 
			
		||||
}
 | 
			
		||||
@ -38,6 +38,10 @@
 | 
			
		||||
        width: calc(100vw - 3em);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    section.answer label {
 | 
			
		||||
        max-width: 80%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    section#infobox {
 | 
			
		||||
        top: unset;
 | 
			
		||||
        left: 0;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ require_once "controller.php";
 | 
			
		||||
 | 
			
		||||
$userdb = new \SleekDB\Store(USERDB, DATADIR, ["timeout" => false]);
 | 
			
		||||
 | 
			
		||||
const PRIVILEGE_NONE = "none";
 | 
			
		||||
const PRIVILEGE_PLAYER = "player";
 | 
			
		||||
const PRIVILEGE_CREATOR = "creator";
 | 
			
		||||
const PRIVILEGE_QUIZMASTER = "admin"; // TODO: refactor!
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user