diff --git a/web/app/controllers/new_remote_problem.php b/web/app/controllers/new_remote_problem.php index 6926ff0..02992bc 100644 --- a/web/app/controllers/new_remote_problem.php +++ b/web/app/controllers/new_remote_problem.php @@ -36,7 +36,15 @@ $new_remote_problem_form->addInput('remote_problem_id', [ $vdata['remote_problem_id'] = $id; return ''; - } elseif ($remote_oj === 'uoj') { + } else if ($remote_oj === 'uoj') { + if (!validateUInt($id)) { + return '不合法的题目 ID'; + } + + $vdata['remote_problem_id'] = $id; + + return ''; + } else if ($remote_oj === 'loj') { if (!validateUInt($id)) { return '不合法的题目 ID'; } @@ -123,8 +131,11 @@ $new_remote_problem_form->runAtServer();
  • 目前支持导入以下题库的题目作为远端评测题:

  • 在导入题目前请先搜索题库中是否已经存在相应题目,避免重复添加。
  • diff --git a/web/app/models/UOJRemoteProblem.php b/web/app/models/UOJRemoteProblem.php index c3cd1b4..c172efa 100644 --- a/web/app/models/UOJRemoteProblem.php +++ b/web/app/models/UOJRemoteProblem.php @@ -32,6 +32,12 @@ class UOJRemoteProblem { ], 'languages' => ['C', 'C++03', 'C++11', 'C++', 'C++17', 'C++20', 'Python3', 'Python2.7', 'Java8', 'Java11', 'Java17', 'Pascal'], ], + 'loj' => [ + 'name' => 'LibreOJ', + 'short_name' => 'LOJ', + 'url' => 'https://loj.ac', + 'languages' => ['C', 'C++03', 'C++11', 'C++', 'C++17', 'C++20', 'Python3', 'Python2.7', 'Java8', 'Java11', 'Java17', 'Pascal'], + ], ]; static function getCodeforcesProblemUrl($id) { @@ -58,6 +64,10 @@ class UOJRemoteProblem { return static::$providers['uoj']['url'] . '/problem/' . $id; } + static function getLojProblemUrl($id) { + return static::$providers['loj']['url'] . '/p/' . $id; + } + static function getCodeforcesProblemBasicInfoFromHtml($id, $html) { $remote_provider = static::$providers['codeforces']; @@ -332,6 +342,72 @@ class UOJRemoteProblem { ]; } + static function getLojProblemBasicInfo($id) { + $remote_provider = static::$providers['loj']; + $curl = new Curl(); + $curl->setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36 S2OJ/3.1.0'); + $curl->setHeader('Content-Type', 'application/json'); + + $res = retry_loop(function () use (&$curl, $id) { + $curl->post('https://api.loj.ac.cn/api/problem/getProblem', json_encode([ + 'displayId' => (int)$id, + 'localizedContentsOfLocale' => 'zh_CN', + 'samples' => true, + 'judgeInfo' => true, + ])); + + if ($curl->error) { + return false; + } + + return $curl->response; + }); + + if (!$res) return null; + + // Convert stdClass to array + $res = json_decode(json_encode($res), true); + + if (isset($res['error'])) return null; + + $localized_contents = $res['localizedContentsOfLocale']; + $statement = ''; + + foreach ($localized_contents['contentSections'] as $section) { + $statement .= "\n###" . $section['sectionTitle'] . "\n\n"; + + if ($section['type'] === 'Text') { + $statement .= $section['text'] . "\n"; + } else if ($section['type'] === 'Sample') { + // assert($res['samples'][$section['sampleId']]); + $display_sample_id = $section['sampleId'] + 1; + $sample = $res['samples'][$section['sampleId']]; + + $statement .= "\n#### 样例输入 #{$display_sample_id}\n\n"; + $statement .= "\n```text\n{$sample['inputData']}\n```\n\n"; + + $statement .= "\n#### 样例输出 #{$display_sample_id}\n\n"; + $statement .= "\n```text\n{$sample['outputData']}\n```\n\n"; + + if (trim($section['text'])) { + $statement .= "\n#### 样例解释 #{$display_sample_id}\n\n"; + $statement .= $section['text'] . "\n"; + } + } else { + // do nothing... + } + } + + return [ + 'type' => 'html', + 'title' => "【{$remote_provider['short_name']}{$id}】{$localized_contents['title']}", + 'time_limit' => (float)$res['judgeInfo']['timeLimit'] / 1000.0, + 'memory_limit' => $res['judgeInfo']['memoryLimit'], + 'difficulty' => -1, + 'statement' => HTML::purifier()->purify(HTML::parsedown()->text($statement)), + ]; + } + public static function getProblemRemoteUrl($oj, $id) { if ($oj === 'codeforces') { return static::getCodeforcesProblemUrl($id); @@ -339,6 +415,8 @@ class UOJRemoteProblem { return static::getAtcoderProblemUrl($id); } else if ($oj === 'uoj') { return static::getUojProblemUrl($id); + } else if ($oj === 'loj') { + return static::getLojProblemUrl($id); } return null; @@ -352,6 +430,8 @@ class UOJRemoteProblem { return static::getAtcoderProblemBasicInfo($id); } else if ($oj === 'uoj') { return static::getUojProblemBasicInfo($id); + } else if ($oj === 'loj') { + return static::getLojProblemBasicInfo($id); } return null;