diff --git a/web/app/cli.php b/web/app/cli.php index 056a3f9..131e1ff 100644 --- a/web/app/cli.php +++ b/web/app/cli.php @@ -8,6 +8,15 @@ requirePHPLib('luogu'); requirePHPLib('data'); // TODO: more beautiful argv parser +$my_args = array(); + +for ($i = 1; $i < count($argv); $i++) { + if (preg_match('/^--([^=]+)[=](.*)/', $argv[$i], $match)) { + $my_args[$match[1]] = $match[2]; + } else if (preg_match('/^--(.*)/', $argv[$i], $match)) { + $my_args[$match[1]] = $argv[++$i]; + } +} $handlers = [ 'upgrade:up' => function ($name) { @@ -64,18 +73,32 @@ $handlers = [ }); die("finished!\n"); }, - 'luogu:add-problem' => function () use ($argv) { - $rest_index = null; - $opts = getopt('', ['file::'], $rest_index); + 'luogu:add-problem' => function () use ($argv, $my_args) { + DB::init(); - if (!isset($opts['file'])) { + $db = array(); + + if (!isset($my_args['file'])) { echo "No database file specified, fetching online instead.\n\n"; + } else { + echo "Reading local database: {$my_args['file']}\n\n"; + + $file = file_get_contents($my_args['file']); + + foreach (explode("\n", $file) as $line) { + if (strlen($line) == 0) continue; + + $line_data = json_decode($line, true); + $db[$line_data['pid']] = $line_data; + } + + $db_count = count($db); + echo "Loaded {$db_count} items.\n\n"; } // TODO: read database from local file - $problems = array_slice($argv, $rest_index); - $problems = array_filter($problems, function ($id) { + $problems = array_filter($argv, function ($id) { if (!validateLuoguProblemId($id)) return false; return true; @@ -93,7 +116,16 @@ $handlers = [ foreach ($problems as $pid) { try { - $id = newLuoguRemoteProblem($pid); + if (!isset($db[$pid])) { + if (!empty($db)) { + echo "[WARN] $pid: fallback to fetch data online\n"; + } + + $id = newLuoguRemoteProblem($pid); + } else { + $parsed = parseLuoguProblemData($db[$pid]); + $id = newLuoguRemoteProblemFromData($parsed); + } echo "$pid: $id\n"; } catch (Exception $e) { diff --git a/web/app/cli.php.patch b/web/app/cli.php.patch index db68b5f..cf61687 100644 --- a/web/app/cli.php.patch +++ b/web/app/cli.php.patch @@ -1,6 +1,6 @@ --- UOJ-System/web/app/cli.php 2022-12-30 09:54:05.452022649 +0800 -+++ UOJ-Luogu-RemoteJudge/web/app/cli.php 2023-03-20 16:47:12.734169684 +0800 -@@ -4,6 +4,9 @@ ++++ UOJ-Luogu-RemoteJudge/web/app/cli.php 2023-03-20 18:30:46.336676319 +0800 +@@ -4,7 +4,19 @@ require $_SERVER['DOCUMENT_ROOT'] . '/app/libs/uoj-lib.php'; @@ -8,25 +8,49 @@ +requirePHPLib('data'); + // TODO: more beautiful argv parser ++$my_args = array(); ++ ++for ($i = 1; $i < count($argv); $i++) { ++ if (preg_match('/^--([^=]+)[=](.*)/', $argv[$i], $match)) { ++ $my_args[$match[1]] = $match[2]; ++ } else if (preg_match('/^--(.*)/', $argv[$i], $match)) { ++ $my_args[$match[1]] = $argv[++$i]; ++ } ++} $handlers = [ -@@ -61,7 +64,44 @@ + 'upgrade:up' => function ($name) { +@@ -61,7 +73,67 @@ }); die("finished!\n"); }, - 'help' => 'showHelp' -+ 'luogu:add-problem' => function () use ($argv) { -+ $rest_index = null; -+ $opts = getopt('', ['file::'], $rest_index); ++ 'luogu:add-problem' => function () use ($argv, $my_args) { ++ DB::init(); + -+ if (!isset($opts['file'])) { ++ $db = array(); ++ ++ if (!isset($my_args['file'])) { + echo "No database file specified, fetching online instead.\n\n"; ++ } else { ++ echo "Reading local database: {$my_args['file']}\n\n"; ++ ++ $file = file_get_contents($my_args['file']); ++ ++ foreach (explode("\n", $file) as $line) { ++ if (strlen($line) == 0) continue; ++ ++ $line_data = json_decode($line, true); ++ $db[$line_data['pid']] = $line_data; ++ } ++ ++ $db_count = count($db); ++ echo "Loaded {$db_count} items.\n\n"; + } + + // TODO: read database from local file + -+ $problems = array_slice($argv, $rest_index); -+ $problems = array_filter($problems, function ($id) { ++ $problems = array_filter($argv, function ($id) { + if (!validateLuoguProblemId($id)) return false; + + return true; @@ -44,7 +68,16 @@ + + foreach ($problems as $pid) { + try { -+ $id = newLuoguRemoteProblem($pid); ++ if (!isset($db[$pid])) { ++ if (!empty($db)) { ++ echo "[WARN] $pid: fallback to fetch data online\n"; ++ } ++ ++ $id = newLuoguRemoteProblem($pid); ++ } else { ++ $parsed = parseLuoguProblemData($db[$pid]); ++ $id = newLuoguRemoteProblemFromData($parsed); ++ } + + echo "$pid: $id\n"; + } catch (Exception $e) { diff --git a/web/app/libs/uoj-luogu-lib.php b/web/app/libs/uoj-luogu-lib.php index 820853d..11fac1c 100644 --- a/web/app/libs/uoj-luogu-lib.php +++ b/web/app/libs/uoj-luogu-lib.php @@ -77,11 +77,7 @@ function fetchLuoguProblemBasicInfo($pid) { return parseLuoguProblemData($data['currentData']['problem']); } -function newLuoguRemoteProblem($pid) { - // ensure validateLuoguProblemId($pid) is true - - $problem = fetchLuoguProblemBasicInfo($pid); - +function newLuoguRemoteProblemFromData($problem) { $esc_submission_requirements = json_encode(array( array( "name" => "answer", @@ -98,7 +94,7 @@ function newLuoguRemoteProblem($pid) { "view_details_type" => "ALL", )); - DB::insert("insert into problems (title, is_hidden, submission_requirement, extra_config, hackable, type) values ('" . DB::escape($problem['title']) . "', 1, '" . DB::escape($esc_submission_requirements) . "', '" . DB::escape($esc_extra_config) . "', 0, 'luogu')"); + DB::insert("insert into problems (title, is_hidden, submission_requirement, extra_config, hackable, type) values ('" . DB::escape($problem['title']) . "', 1, '" . DB::escape($esc_submission_requirements) . "', '" . DB::escape($esc_extra_config) . "', 0, 'luogu')") or die(mysqli_error($GLOBALS['uojMySQL']) . "\n"); $id = DB::insert_id(); @@ -109,6 +105,15 @@ function newLuoguRemoteProblem($pid) { return $id; } +function newLuoguRemoteProblem($pid) { + // ensure validateLuoguProblemId($pid) is true + + $problem = fetchLuoguProblemBasicInfo($pid); + $id = newLuoguRemoteProblemFromData($problem); + + return $id; +} + function refetchLuoguProblemInfo($id) { $problem = queryProblemBrief($id); $problem_extra_config = getProblemExtraConfig($problem);