From 4ace35b770c01986beb410a3a14e73cfc3260f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Tue, 19 Mar 2024 09:14:25 +0100 Subject: [PATCH] - challenge sequence numbers added - package uploading added - image support added - answer correctness indication added --- gamemgr.php | 31 +++++++++++++++++++++++++---- interface.php | 46 ++++++++++++++++++++++++++++++++++++++++++-- js/testground.js | 27 ++++++++++++++++++++++++++ style/spreadquiz.css | 31 +++++++++++++++++++++++++++++ testground.php | 9 +++++++-- 5 files changed, 136 insertions(+), 8 deletions(-) diff --git a/gamemgr.php b/gamemgr.php index d6e49bd..ec4ad6a 100644 --- a/gamemgr.php +++ b/gamemgr.php @@ -27,7 +27,7 @@ function create_game(string $name, string $owner, string $description = "", arra // prepare game context $id = $game_data["_id"]; - $current_game_media_dir = GAMEMEDIA_DIR . DIRECTORY_SEPARATOR . $id; + $current_game_media_dir = get_game_dir_by_gameid($id); mkdir($current_game_media_dir); save_challenges($id, []); return true; @@ -92,6 +92,7 @@ const CSV_ENCODINGS = ["Windows-1252", "UTF-8"]; function import_challenges_from_csv(string $csv_path, string $gameid): array { $game_data = get_game($gameid); + $game_dir = get_game_dir_by_gameid($gameid); if (count($game_data) === []) { return ["n" => 0, "encoding" => ""]; } @@ -125,14 +126,31 @@ function import_challenges_from_csv(string $csv_path, string $gameid): array continue; } if (count($csvline) >= 3) { + // construct challenge record $ch = [ - "question" => $csvline[0], - "image_url" => $csvline[1], - "correct_answer" => $csvline[2], + "question" => trim($csvline[0]), + "image_url" => trim($csvline[1]), + "correct_answer" => trim($csvline[2]), "answers" => array_filter(array_slice($csvline, 2), function ($v) { return trim($v) !== ""; }) ]; + + // if image is attached to the challenge, then give a random name to the image + if ($ch["image_url"] !== "") { + $old_img_name = $ch["image_url"]; + $ext = pathinfo($old_img_name, PATHINFO_EXTENSION); + $ext = ($ext !== "") ? ("." . $ext) : $ext; + $new_img_name = uniqid("img_", true) . $ext; + $ch["image_url"] = $new_img_name; + + // rename the actual file + $old_img_path = $game_dir . DIRECTORY_SEPARATOR . $old_img_name; + $new_img_path = $game_dir . DIRECTORY_SEPARATOR . $new_img_name; + rename($old_img_path, $new_img_path); + } + + // store the challenge $challenges[] = $ch; } } @@ -207,4 +225,9 @@ function get_contributors(string $gameid): array function get_game_file_by_gameid(string $gameid) { return GAMEMEDIA_DIR . DIRECTORY_SEPARATOR . $gameid . DIRECTORY_SEPARATOR . GAME_FILE; +} + +function get_game_dir_by_gameid(string $gameid) +{ + return GAMEMEDIA_DIR . DIRECTORY_SEPARATOR . $gameid; } \ No newline at end of file diff --git a/interface.php b/interface.php index 0076d14..2457a06 100644 --- a/interface.php +++ b/interface.php @@ -126,6 +126,20 @@ if ((($testid = trim($_REQUEST["testid"] ?: "")) !== "") && $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; case "save_answer": { $chidx = $_REQUEST["challenge_index"]; @@ -174,8 +188,8 @@ switch ($action) { $groupids_with_editor_access[] = $groupid; } } - $groupids_with_editor_access = $groupid; + // create or update if (!$update) { create_game($name, $owner, $description); } else if (is_user_contributor_to_game($gameid, $nickname)) { @@ -209,7 +223,35 @@ switch ($action) { // update game file if supplied if (isset($_FILES["game_file"])) { - $challenge_import_status = import_challenges_from_csv($_FILES["game_file"]["tmp_name"], $data["_id"]); + // 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); } } diff --git a/js/testground.js b/js/testground.js index 10182e3..be54e84 100644 --- a/js/testground.js +++ b/js/testground.js @@ -41,8 +41,19 @@ function populate_infobox(test_data) { INTERVAL_HANDLE = null; } }, 1000); + show("time-info"); + } else { + hide("time-info"); } + // fill further info + let further_info_box = document.getElementById("further-info"); + let further_info = ""; + if (!test_data["repeatable"]) { + further_info += "A teszt nem megismételhető!
"; + } + further_info_box.innerHTML = further_info; + show("ongoing-info"); hide("concluded-info"); } @@ -66,6 +77,18 @@ function populate_challenges(test_data) { answer_container.classList.add("answer-container"); challenge_box.append(question, answer_container); + if (challenge["image_url"] !== "") { + let qimg = document.createElement("img"); + qimg.src = `interface.php?action=get_image&testid=${test_data["_id"]}&image_url=${challenge["image_url"]}`; + qimg.classList.add("question-image") + challenge_box.insertBefore(qimg, answer_container); + } + + let seq_num_section = document.createElement("section"); + seq_num_section.innerText = String(challenge_N + 1) + "." + seq_num_section.classList.add("seq-num"); + challenge_box.append(seq_num_section); + let answer_N = 0; let player_answer = challenge["player_answer"]; player_answer = (player_answer !== "") ? Number(player_answer) : -1; @@ -90,6 +113,10 @@ function populate_challenges(test_data) { answer_text.setAttribute("for", answer_radio.id); if (test_concluded && (challenge["correct_answer"] === answer_N)) { answer_text.classList.add("correct-answer") + + if (player_answer !== challenge["correct_answer"]) { + challenge_box.classList.add("bad-answer"); + } } answer_section.append(answer_radio, answer_text); diff --git a/style/spreadquiz.css b/style/spreadquiz.css index fa1a37e..4e6cd08 100644 --- a/style/spreadquiz.css +++ b/style/spreadquiz.css @@ -229,6 +229,7 @@ section#test_area { section.challenge { display: block; + position: relative; margin: 0 auto; width: 40em; /*border: 1px solid black;*/ @@ -361,4 +362,34 @@ section.test-summary-record { code { font-family: 'Monaco', monospace; +} + +img.question-image { + display: block; + position: relative; + margin: 1em auto; + border-radius: 0.3em; + max-width: 100%; +} + +section.seq-num { + display: block; + position: absolute; + right: 0; + padding: 0.5em; + bottom: 0; + background-color: #176767; + color: whitesmoke; + border-bottom-right-radius: 0.3em; + border-top-left-radius: 0.3em; + width: 2em; +} + +section.bad-answer { + background-color: #e5d8d3; +} + +section#further-info { + font-size: 0.8em; + padding: 0.4em 0; } \ No newline at end of file diff --git a/testground.php b/testground.php index 176bcb7..eedc021 100644 --- a/testground.php +++ b/testground.php @@ -36,8 +36,13 @@ if ($testid === "") {
- Hátralevő idő: -
10:00:00
+
+ Hátralevő idő: +
10:00:00
+
+
+ +