$group_data["groupname"], "description" => $group_data["description"], "games" => [] ]; $gameids = $group_data["games"]; foreach ($gameids as $gameid) { $game = get_game($gameid); $game_collection["games"][] = $game; } $games_by_groups[] = $game_collection; } $result = json_encode($games_by_groups); } break; case "start_or_continue_test": { $gameid = trim($_REQUEST["gameid"] ?: ""); $testid = create_or_continue_test($gameid, $nickname); $result = $testid; } break; case "get_results_overview": { $gameid = trim($_REQUEST["gameid"] ?: ""); $concluded_tests = get_concluded_tests($gameid, $nickname); $overviews = []; foreach ($concluded_tests as $ct) { $overview = [ "testid" => $ct["_id"], "start_time" => $ct["start_time"], "end_time" => $ct["end_time"], ...$ct["summary"] ]; $overviews[] = $overview; } $result = json_encode($overviews); } break; } // test-related queries if (isset($_REQUEST["testid"]) && (($testid = trim($_REQUEST["testid"])) !== "") && ((count($test_data = get_test($testid))) > 0) && (($test_data["nickname"] === $nickname) || $is_quizmaster)) { // update the test if timed update_timed_tests([$test_data]); switch ($action) { case "get_test": { $test_data_with_current_time = $test_data; $test_data_with_current_time["current_time"] = time(); $result = json_encode($test_data_with_current_time); } break; case "get_image": { $img_url = trim($_REQUEST["image_url"] ?: ""); if ($img_url !== "") { $gameid = $test_data["gameid"]; $game_dir = get_game_dir_by_gameid($gameid); $image_fetch_url = $game_dir . DIRECTORY_SEPARATOR . $img_url; $img_fp = fopen($image_fetch_url, "r"); fpassthru($img_fp); fclose($img_fp); } } break; } switch ($action) { case "save_answer": { $chidx = $_REQUEST["challenge_index"]; $answeridx = $_REQUEST["answer_index"]; save_answer($testid, $chidx, $answeridx); } break; case "submit_test": { conclude_test($testid); } break; } } // creator or quizmaster actions if (($privilege !== PRIVILEGE_CREATOR) && ($privilege !== PRIVILEGE_QUIZMASTER)) { goto print_result; } $requester_nickname = $is_quizmaster ? "*" : $nickname; // "*" means every game switch ($action) { case "create_game": case "update_game": { $update = $action === "update_game"; $data = json_decode($_REQUEST["data"], true) ?: []; if (($data === []) || (trim($data["name"] ?: "") === "")) { // no further processing goto print_result; // ~exit... } $gameid = $data["_id"]; $name = $data["name"]; $description = $data["description"]; $contributors = explode_list($data["contributors"] ?: ""); $owner = $update ? trim($data["owner"] ?: $nickname) : $nickname; $groups = explode_list($data["groups"] ?: ""); $properties = $data["properties"] ?: []; $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; } } // create or update if (!$update) { create_game($name, $owner, $description); } 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 $groupids_add = array_diff($new_groupids, $old_groupids); // groups this user needs to be added to $groupids_remove = array_diff($old_groupids, $new_groupids); // groups this user need to be removed from foreach ($groupids_add as $groupid) { // execute insertion and removal change_group_game_assignments($groupid, $gameid, null); } foreach ($groupids_remove as $groupid) { change_group_game_assignments($groupid, null, $gameid); } // re-fetch game data $game_data = get_game($gameid); // update game header data $game_data["name"] = $name; $game_data["description"] = $description; if (($game_data["owner"] === $nickname) || ($privilege === PRIVILEGE_QUIZMASTER)) { $game_data["owner"] = $owner; } $game_data["contributors"] = array_intersect($contributors, get_all_nicknames()); $game_data["properties"]["time_limit"] = $properties["time_limit"]; $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"]; } // update game data update_game($game_data); // update game file if supplied if (isset($_FILES["game_file"])) { // decide weather it's a package or a plain table $file = $_FILES["game_file"]; $file_type = $file["type"]; $challenge_import_status = []; if ($file_type === "application/zip") { // a package was uploaded $zip = new ZipArchive; 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 // remove former files recursively $dir_iter = new RecursiveDirectoryIterator($game_dir, FilesystemIterator::SKIP_DOTS); foreach ($dir_iter as $dir_item) { $item_path = $dir_item->getPathname(); $dir_item->isDir() ? rmdir($item_path) : unlink($item_path); } // extract package contents to the game directory $zip->extractTo($game_dir . DIRECTORY_SEPARATOR); // search for the CSV table file $csv_files = glob($game_dir . DIRECTORY_SEPARATOR . "*.csv") ?: []; if (count($csv_files)) { $challenge_import_status = import_challenges_from_csv($csv_files[0], $gameid); } } } else if ($file_type === "text/csv") { // a plain table was uploaded $challenge_import_status = import_challenges_from_csv($file["tmp_name"], $gameid); } $result = json_encode($challenge_import_status); } } } } break; case "get_all_game_headers": { $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); } break; case "get_challenges": { $gameid = ($_REQUEST["gameid"] ?: ""); $game_data = get_game($gameid); 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)); } } break; case "delete_games": { $gameids = explode_list(trim($_REQUEST["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); } } } break; case "export_game_file_csv": { $gameid = trim($_REQUEST["gameid"] ?: ""); if (($gameid !== "") && is_user_contributor_to_game($gameid, $nickname)) { $f = tmpfile(); header("Content-Type: text/csv"); header("Content-Disposition: attachment; filename=\"challenges_$gameid.csv\"\r\n"); export_challenges_to_csv($f, $gameid); fseek($f, 0); fpassthru($f); } } break; case "get_results_by_gameid": { $gameid = trim($_REQUEST["gameid"] ?: ""); $filter = trim($_REQUEST["filter"] ?: ""); $ordering = trim($_REQUEST["orderby"] ?: ""); 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); } } break; case "generate_detailed_stats": { $testids = json_decode(trim($_REQUEST["testids"] ?: "[]"), true); $gameid = trim($_REQUEST["gameid"] ?: ""); $stats = generate_detailed_stats($gameid, $testids); $result = json_encode($stats); } break; } // quizmaster actions if ($privilege !== PRIVILEGE_QUIZMASTER) { goto print_result; } switch ($action) { case "create_group": case "update_group": { $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"]); if ($owner === "") { $owner = $user_data["nickname"]; } if ($groupname != "") { switch ($action) { case "create_group": create_group($groupname, $owner, $description); break; case "update_group": { $gid = $_REQUEST["id"]; $group = get_group($gid); if (count($group) !== 0) { $group["unique"] = manage_unique_in_siblings($gid, $groupname); // manage unique flag in case of renaming $group["groupname"] = $groupname; $group["description"] = $description; $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); } } break; } } } break; case "delete_groups": { $groups = explode_list($_REQUEST["ids"] ?: ""); foreach ($groups as $g) { delete_group($g); } } break; case "get_all_groups": $result = json_encode(get_all_groups()); break; case "search_groups": { $needle = $_REQUEST["needle"] ?: ""; $result = json_encode(search_groups($needle)); } break; case "create_user": case "update_user": { $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); $groupids = get_groupids_by_compounds($groups); // convert group compounds to _ids if (($target_nickname !== "")) { if ((!$update) && ($password !== "")) { // CREATE add_user($target_nickname, $password, $realname, $groupids, $privilege); } else if ($update) { // UPDATE $user_data = get_user($target_nickname); // load user data // group management $old_groupids = $user_data["groups"]; // retain old groupids $new_groupids = $groupids; // get new groupids $groupids_add = array_diff($new_groupids, $old_groupids); // groups this user needs to be added to $groupids_remove = array_diff($old_groupids, $new_groupids); // groups this user need to be removed from foreach ($groupids_add as $groupid) { // execute insertion and removal change_group_user_assignments($groupid, $target_nickname, null); } foreach ($groupids_remove as $groupid) { change_group_user_assignments($groupid, null, $target_nickname); } // re-fetch user $user_data = get_user($target_nickname); // load user data // further field update $user_data["realname"] = $realname; $user_data["privilege"] = $privilege; // password replacement, if requested if ($password !== "") { $user_data["password"] = password_hash($password, PASSWORD_DEFAULT); } update_user($user_data); } } } break; case "delete_users": { $users = explode_list($_REQUEST["users"] ?: ""); foreach ($users as $g) { delete_user($g); } } break; case "get_all_users": { $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); } break; case "import_users_from_csv": { if (!isset($_FILES["users_table"])) { goto print_result; } } break; } // ---------- print_result: if ($result !== "") { echo $result; }