- test-related request block redesigned - elvis operator replaced with the more adequate null coalescing one
267 lines
7.5 KiB
PHP
267 lines
7.5 KiB
PHP
<?php
|
|
|
|
require_once "globals.php";
|
|
require_once "common_func.php";
|
|
|
|
$gamedb = new \SleekDB\Store(GAMEDB, DATADIR, ["timeout" => false]);
|
|
|
|
const DEFAULT_GAME_PROPERTIES = [
|
|
"forward_only" => false, // player may traverse back and forth between challenges
|
|
"time_limit" => 0, // no time limit; otherwise, this field indicates time limit in seconds
|
|
"repeatable" => false // this test can be taken multiple times
|
|
];
|
|
|
|
const CURRENT_GAME_VERSION = 2; // MUST BE INCREMENTED!!
|
|
|
|
function generate_public_id(): string
|
|
{
|
|
return uniqid("p");
|
|
}
|
|
|
|
function create_game(string $name, string $owner, string $description = "", array $properties = DEFAULT_GAME_PROPERTIES, array $contributors = [], array $challenges = []): bool
|
|
{
|
|
global $gamedb;
|
|
$game_data = [
|
|
"name" => $name,
|
|
"owner" => $owner,
|
|
"contributors" => $contributors,
|
|
"description" => $description,
|
|
"game_file_present" => false,
|
|
"properties" => $properties,
|
|
"groups" => [],
|
|
"public" => false,
|
|
"public_id" => generate_public_id(),
|
|
"version" => CURRENT_GAME_VERSION
|
|
];
|
|
$game_data = $gamedb->insert($game_data);
|
|
|
|
// prepare game context
|
|
$id = $game_data["_id"];
|
|
$current_game_media_dir = get_game_dir_by_gameid($id);
|
|
mkdir($current_game_media_dir);
|
|
save_challenges($id, []);
|
|
return true;
|
|
}
|
|
|
|
function get_game(string $gameid): array
|
|
{
|
|
global $gamedb;
|
|
return $gamedb->findById($gameid);
|
|
}
|
|
|
|
function get_public_game(string $public_id): array
|
|
{
|
|
global $gamedb;
|
|
return $gamedb->findBy([["public", "=", "true"], "AND", ["public_id", "=", $public_id]]);
|
|
}
|
|
|
|
function update_game(array $game_data)
|
|
{
|
|
global $gamedb;
|
|
$gamedb->update($game_data);
|
|
}
|
|
|
|
function delete_game(string $gameid)
|
|
{
|
|
global $gamedb;
|
|
$game_data = get_game($gameid);
|
|
if (count($game_data) != 0) {
|
|
foreach ($game_data["groups"] as $groupid) {
|
|
change_group_game_assignments($groupid, null, $gameid);
|
|
}
|
|
$gamedb->deleteById($gameid);
|
|
}
|
|
}
|
|
|
|
function change_game_group_assignments(string $gid, $groupname_add, $groupname_remove)
|
|
{
|
|
$game_data = get_game($gid);
|
|
if (count($game_data) != 0) {
|
|
alter_array_contents($game_data["groups"], $groupname_add, $groupname_remove);
|
|
update_game($game_data); // update user
|
|
}
|
|
}
|
|
|
|
function get_all_games()
|
|
{
|
|
global $gamedb;
|
|
return $gamedb->findAll();
|
|
}
|
|
|
|
function patch_up_game_data(array &$game_data)
|
|
{
|
|
$game_version = $game_data["version"] ?? 0;
|
|
if ($game_version < 2) { // update to game version 2
|
|
if (!key_exists("public_id", $game_data)) {
|
|
$game_data["public"] = false;
|
|
$game_data["public_id"] = generate_public_id();
|
|
}
|
|
|
|
$game_data["version"] = 2;
|
|
}
|
|
|
|
return $game_version < CURRENT_GAME_VERSION;
|
|
}
|
|
|
|
function get_all_game_data_by_contributor_nickname(string $nickname): array
|
|
{
|
|
global $gamedb;
|
|
$game_headers = [];
|
|
if ($nickname !== "*") {
|
|
$game_data_array = $gamedb->findBy([["owner", "=", $nickname], "OR", ["contributors", "CONTAINS", $nickname]]);
|
|
} else {
|
|
$game_data_array = $gamedb->findAll();
|
|
}
|
|
foreach ($game_data_array as $game_data) {
|
|
if (patch_up_game_data($game_data)) {
|
|
update_game($game_data);
|
|
}
|
|
$game_headers[] = $game_data;
|
|
}
|
|
return $game_headers;
|
|
}
|
|
|
|
const CSV_ENCODINGS = ["UTF-8", "Windows-1252"];
|
|
|
|
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" => ""];
|
|
}
|
|
|
|
// convert text encoding into UTF-8
|
|
$data = file_get_contents($csv_path);
|
|
$encoding = "UNKNOWN";
|
|
foreach (CSV_ENCODINGS as $enc) { // detect encoding
|
|
if (mb_check_encoding($data, $enc)) {
|
|
$encoding = $enc;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($encoding !== "UNKNOWN") { // if encoding has been detected successfully
|
|
$data = mb_convert_encoding($data, "UTF-8", $encoding);
|
|
file_put_contents($csv_path, $data);
|
|
}
|
|
|
|
// load challenges
|
|
$challenges = [];
|
|
|
|
// load filled CSV file
|
|
$f = fopen($csv_path, "r");
|
|
if (!$f) { // failed to open file
|
|
return ["n" => 0, "encoding" => $encoding];
|
|
}
|
|
while ($csvline = fgetcsv($f)) {
|
|
// skip empty lines
|
|
if (trim(implode("", $csvline)) === "") {
|
|
continue;
|
|
}
|
|
if (count($csvline) >= 3) {
|
|
// construct challenge record
|
|
$ch = [
|
|
"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;
|
|
}
|
|
}
|
|
fclose($f);
|
|
|
|
// save challenges
|
|
save_challenges($gameid, $challenges);
|
|
|
|
// update game with game file present
|
|
$game_data["game_file_present"] = true;
|
|
update_game($game_data);
|
|
|
|
return ["n" => count($challenges), "encoding" => $encoding];
|
|
}
|
|
|
|
function is_user_contributor_to_game(string $gameid, string $nickname): bool
|
|
{
|
|
$game_data = get_game($gameid);
|
|
if (count($game_data) === 0) {
|
|
return false;
|
|
}
|
|
|
|
return in_array($nickname, $game_data["contributors"]) || ($game_data["owner"] === $nickname);
|
|
}
|
|
|
|
function is_user_owner_of_the_game(string $gameid, string $nickname): bool
|
|
{
|
|
$game_data = get_game($gameid);
|
|
if (count($game_data) === 0) {
|
|
return false;
|
|
}
|
|
return $game_data["owner"] === $nickname;
|
|
}
|
|
|
|
function save_challenges(string $gameid, array $challenges)
|
|
{
|
|
file_put_contents(get_game_file_by_gameid($gameid), json_encode($challenges)); // store challenges in JSON-format
|
|
}
|
|
|
|
function load_challenges(string $gameid)
|
|
{
|
|
return json_decode(file_get_contents(get_game_file_by_gameid($gameid)), true);
|
|
}
|
|
|
|
function export_challenges_to_csv($f, string $gameid)
|
|
{
|
|
$game_data = get_game($gameid);
|
|
if ((count($game_data) === []) || (!$game_data["game_file_present"])) {
|
|
return;
|
|
}
|
|
|
|
// load challenges
|
|
$challenges = load_challenges($gameid);
|
|
|
|
// populate CSV file
|
|
foreach ($challenges as $ch) {
|
|
$csvline = [
|
|
$ch["question"],
|
|
$ch["image_url"],
|
|
];
|
|
$csvline = array_merge($csvline, $ch["answers"]);
|
|
fputcsv($f, $csvline);
|
|
}
|
|
}
|
|
|
|
function get_contributors(string $gameid): array
|
|
{
|
|
$game_data = get_game($gameid);
|
|
return $game_data["contributors"];
|
|
}
|
|
|
|
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;
|
|
} |