SpreadQuiz/interface.php
Epagris 89ac41a6e6 - report generation implemented
- recursive filtering fixed
- grouping added
2024-09-09 18:36:03 +02:00

475 lines
18 KiB
PHP

<?php
require_once "globals.php";
if (!file_exists(INSTALL_INDICATOR)) {
exit();
}
if (!isset($_REQUEST["action"])) {
exit();
}
require_once "common_func.php";
// load databases only if something meaningful have arrived
require_once "usermgr.php";
require_once "groupmgr.php";
require_once "gamemgr.php";
require_once "testmgr.php";
$action = $_REQUEST["action"];
$result = "";
// no-login accessible actions
switch ($action) {
case "login":
{
$nickname = $_REQUEST["nickname"];
$password = $_REQUEST["password"];
if (check_user_credentials($nickname, $password)) {
session_start();
$_SESSION["nickname"] = $nickname;
$result = "OK";
} else {
$result = "FAIL";
}
}
break;
}
// 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;
}
$user_data = get_user($_SESSION["nickname"]);
$nickname = $user_data["nickname"];
$privilege = $user_data["privilege"];
$is_quizmaster = $privilege === PRIVILEGE_QUIZMASTER;
// login-requiring actions
switch ($action) {
case "logout":
{
$_SESSION = []; // clean up session data
setcookie(SESSION_NAME, "", -1); // invalidate cookie
}
break;
case "get_user_info":
{
$user_data_filtered = $user_data;
unset($user_data_filtered["password"]);
$result = json_encode($user_data_filtered);
}
break;
case "get_available_games":
{
$games_by_groups = [];
$groupids = $user_data["groups"];
foreach ($groupids as $groupid) {
$group_data = get_group($groupid);
$game_collection = [
"groupname" => $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;
}