ob_end_flush(); echo "<p>\n"; while ($row = $res->next()) { echo "s" . specialchars($row['submitid']) . ", "; $DB->q('START TRANSACTION'); // first invalidate old judging, maybe different from prevjudgingid! $DB->q('UPDATE judging SET valid=0 WHERE submitid=%i', $row['submitid']); // then set judging to valid $DB->q('UPDATE judging SET valid=1 WHERE submitid=%i AND rejudgingid=%i', $row['submitid'], $id); // remove relation from submission to rejudge $DB->q('UPDATE submission SET rejudgingid=NULL WHERE submitid=%i', $row['submitid']); // last update cache calcScoreRow($row['cid'], $row['teamid'], $row['probid']); $DB->q('COMMIT'); } echo "\n</p>\n"; $DB->q('UPDATE rejudging SET endtime=%s, userid_finish=%i WHERE rejudgingid=%i', now(), $userdata['userid'], $id); auditlog('rejudging', $id, 'applying rejudge', '(end)'); $time_end = microtime(TRUE); echo "<p>Rejudging <a href=\"rejudging.php?id=" . urlencode($id) . "\">r{$id}</a> applied in " . round($time_end - $time_start, 2) . " seconds.</p>\n\n"; require LIBWWWDIR . '/footer.php'; return; } else { if (isset($_REQUEST['cancel'])) { if (isset($rejdata['endtime'])) { error("Rejudging already " . ($rejdata['valid'] ? 'applied.' : 'canceled.'));
/** * Change the valid status of a given submission. * * Part of the DOMjudge Programming Contest Jury System and licenced * under the GNU GPL. See README and COPYING for details. */ require 'init.php'; if (!IS_ADMIN) { error("Admin privileges are required for this operation."); } $id = @$_POST['id']; $val = @$_POST['val']; if (empty($id)) { error("No submission ID passed to mark as (in)valid."); } $cnt = $DB->q('RETURNAFFECTED UPDATE submission s SET s.valid = %i WHERE s.submitid = %i', $val, $id); auditlog('submission', $id, 'marked ' . ($val ? 'valid' : 'invalid')); if ($cnt == 0) { error("Submission s{$id} not found."); } else { if ($cnt > 1) { error("Ignored more than one submission."); } } $sdata = $DB->q('TUPLE SELECT submitid, cid, teamid, probid FROM submission WHERE submitid = %i', $id); calcScoreRow($sdata['cid'], $sdata['teamid'], $sdata['probid']); /* redirect back. */ header('Location: submission.php?id=' . urlencode($sdata['submitid']));
/** * Judging_Runs */ function judging_runs_POST($args) { global $DB, $api; checkargs($args, array('judgingid', 'testcaseid', 'runresult', 'runtime', 'output_run', 'output_diff', 'output_error', 'output_system', 'judgehost')); $results_remap = dbconfig_get('results_remap'); $results_prio = dbconfig_get('results_prio'); if (array_key_exists($args['runresult'], $results_remap)) { logmsg(LOG_INFO, "Testcase {$args['testcaseid']} remapping result " . $args['runresult'] . " -> " . $results_remap[$args['runresult']]); $args['runresult'] = $results_remap[$args['runresult']]; } $DB->q('INSERT INTO judging_run (judgingid, testcaseid, runresult, runtime, output_run, output_diff, output_error, output_system) VALUES (%i, %i, %s, %f, %s, %s, %s, %s)', $args['judgingid'], $args['testcaseid'], $args['runresult'], $args['runtime'], base64_decode($args['output_run']), base64_decode($args['output_diff']), base64_decode($args['output_error']), base64_decode($args['output_system'])); // result of this judging_run has been stored. now check whether // we're done or if more testcases need to be judged. $probid = $DB->q('VALUE SELECT probid FROM testcase WHERE testcaseid = %i', $args['testcaseid']); $runresults = $DB->q('COLUMN SELECT runresult FROM judging_run LEFT JOIN testcase USING(testcaseid) WHERE judgingid = %i ORDER BY rank', $args['judgingid']); $numtestcases = $DB->q('VALUE SELECT count(*) FROM testcase WHERE probid = %i', $probid); $allresults = array_pad($runresults, $numtestcases, null); $before = $DB->q('VALUE SELECT result FROM judging WHERE judgingid = %i', $args['judgingid']); if (($result = getFinalResult($allresults, $results_prio)) !== NULL) { // Lookup global lazy evaluation of results setting and // possible problem specific override. $lazy_eval = dbconfig_get('lazy_eval_results', true); $prob_lazy = $DB->q('MAYBEVALUE SELECT cp.lazy_eval_results FROM judging j LEFT JOIN submission s USING(submitid) LEFT JOIN contestproblem cp ON (cp.cid=j.cid AND cp.probid=s.probid) WHERE judgingid = %i', $args['judgingid']); if (isset($prob_lazy)) { $lazy_eval = (bool) $prob_lazy; } if (count($runresults) == $numtestcases || $lazy_eval) { // NOTE: setting endtime here determines in testcases_GET // whether a next testcase will be handed out. $DB->q('UPDATE judging SET result = %s, endtime = %s WHERE judgingid = %i', $result, now(), $args['judgingid']); } else { $DB->q('UPDATE judging SET result = %s WHERE judgingid = %i', $result, $args['judgingid']); } // Only update if the current result is different from what we // had before. This should only happen when the old result was // NULL. if ($before !== $result) { if ($before !== NULL) { error('internal bug: the evaluated result changed during judging'); } $row = $DB->q('TUPLE SELECT s.cid, s.teamid, s.probid, s.langid, s.submitid FROM judging LEFT JOIN submission s USING(submitid) WHERE judgingid = %i', $args['judgingid']); calcScoreRow($row['cid'], $row['teamid'], $row['probid']); // We call alert here before possible validation. Note // that this means that these alert messages should be // treated as confidential information. alert($result === 'correct' ? 'accept' : 'reject', "submission {$row['submitid']}, judging {$args['judgingid']}: {$result}"); // log to event table if no verification required // (case of verification required is handled in www/jury/verify.php) if (!dbconfig_get('verification_required', 0)) { $DB->q('INSERT INTO event (eventtime, cid, teamid, langid, probid, submitid, judgingid, description) VALUES(%s, %i, %i, %s, %i, %i, %i, "problem judged")', now(), $row['cid'], $row['teamid'], $row['langid'], $row['probid'], $row['submitid'], $args['judgingid']); if ($result == 'correct') { // prevent duplicate balloons in case of multiple correct submissions $numcorrect = $DB->q('VALUE SELECT count(submitid) FROM balloon LEFT JOIN submission USING(submitid) WHERE valid = 1 AND probid = %i AND teamid = %i AND cid = %i', $row['probid'], $row['teamid'], $row['cid']); if ($numcorrect == 0) { $balloons_enabled = (bool) $DB->q("VALUE SELECT process_balloons\n\t\t\t\t\t\t FROM contest WHERE cid = %i", $row['cid']); if ($balloons_enabled) { $DB->q('INSERT INTO balloon (submitid) VALUES(%i)', $row['submitid']); } } } } auditlog('judging', $args['judgingid'], 'judged', $result, $args['judgehost']); } } $DB->q('UPDATE judgehost SET polltime = %s WHERE hostname = %s', now(), $args['judgehost']); return ''; }
/** * This function takes a (set of) temporary file(s) of a submission, * validates it and puts it into the database. Additionally it * moves it to a backup storage. */ function submit_solution($team, $prob, $contest, $lang, $files, $filenames, $origsubmitid = NULL) { global $DB; if (empty($team)) { error("No value for Team."); } if (empty($prob)) { error("No value for Problem."); } if (empty($contest)) { error("No value for Contest."); } if (empty($lang)) { error("No value for Language."); } if (!is_array($files) || count($files) == 0) { error("No files specified."); } if (count($files) > dbconfig_get('sourcefiles_limit', 100)) { error("Tried to submit more than the allowed number of source files."); } if (!is_array($filenames) || count($filenames) != count($files)) { error("Nonmatching (number of) filenames specified."); } if (count($filenames) != count(array_unique($filenames))) { error("Duplicate filenames detected."); } $sourcesize = dbconfig_get('sourcesize_limit'); // If no contest has started yet, refuse submissions. $now = now(); $contestdata = $DB->q('MAYBETUPLE SELECT starttime,endtime FROM contest WHERE cid = %i', $contest); if (!isset($contestdata)) { error("Contest c{$contest} not found."); } if (difftime($contestdata['starttime'], $now) > 0) { error("The contest is closed, no submissions accepted. [c{$contest}]"); } // Check 2: valid parameters? if (!($langid = $DB->q('MAYBEVALUE SELECT langid FROM language WHERE langid = %s AND allow_submit = 1', $lang))) { error("Language '{$lang}' not found in database or not submittable."); } if (!($teamid = $DB->q('MAYBEVALUE SELECT teamid FROM team WHERE teamid = %i AND enabled = 1', $team))) { error("Team '{$team}' not found in database or not enabled."); } $probdata = $DB->q('MAYBETUPLE SELECT probid, points FROM problem INNER JOIN contestproblem USING (probid) WHERE probid = %s AND cid = %i AND allow_submit = 1', $prob, $contest); if (empty($probdata)) { error("Problem p{$prob} not found in database or not submittable [c{$contest}]."); } else { $points = $probdata['points']; $probid = $probdata['probid']; } // Reindex arrays numerically to allow simultaneously iterating // over both $files and $filenames. $files = array_values($files); $filenames = array_values($filenames); $totalsize = 0; for ($i = 0; $i < count($files); $i++) { if (!is_readable($files[$i])) { error("File '" . $files[$i] . "' not found (or not readable)."); } if (!preg_match(FILENAME_REGEX, $filenames[$i])) { error("Illegal filename '" . $filenames[$i] . "'."); } $totalsize += filesize($files[$i]); } if ($totalsize > $sourcesize * 1024) { error("Submission file(s) are larger than {$sourcesize} kB."); } logmsg(LOG_INFO, "input verified"); // Insert submission into the database $id = $DB->q('RETURNID INSERT INTO submission (cid, teamid, probid, langid, submittime, origsubmitid) VALUES (%i, %i, %i, %s, %s, %i)', $contest, $teamid, $probid, $langid, $now, $origsubmitid); for ($rank = 0; $rank < count($files); $rank++) { $DB->q('INSERT INTO submission_file (submitid, filename, rank, sourcecode) VALUES (%i, %s, %i, %s)', $id, $filenames[$rank], $rank, getFileContents($files[$rank], false)); } // Recalculate scoreboard cache for pending submissions calcScoreRow($contest, $teamid, $probid); // Log to event table $DB->q('INSERT INTO event (eventtime, cid, teamid, langid, probid, submitid, description) VALUES(%s, %i, %i, %s, %i, %i, "problem submitted")', now(), $contest, $teamid, $langid, $probid, $id); if (is_writable(SUBMITDIR)) { // Copy the submission to SUBMITDIR for safe-keeping for ($rank = 0; $rank < count($files); $rank++) { $fdata = array('cid' => $contest, 'submitid' => $id, 'teamid' => $teamid, 'probid' => $probid, 'langid' => $langid, 'rank' => $rank, 'filename' => $filenames[$rank]); $tofile = SUBMITDIR . '/' . getSourceFilename($fdata); if (!@copy($files[$rank], $tofile)) { warning("Could not copy '" . $files[$rank] . "' to '" . $tofile . "'"); } } } else { logmsg(LOG_DEBUG, "SUBMITDIR not writable, skipping"); } if (difftime($contestdata['endtime'], $now) <= 0) { logmsg(LOG_INFO, "The contest is closed, submission stored but not processed. [c{$contest}]"); } return $id; }
error('submission is already part of rejudging r' . specialchars($jud['rejudgingid'])); } else { // silently skip that submission continue; } } $DB->q('START TRANSACTION'); if (!$full_rejudge) { $DB->q('UPDATE judging SET valid = 0 WHERE judgingid = %i', $jud['judgingid']); } $DB->q('UPDATE submission SET judgehost = NULL' . ($full_rejudge ? ', rejudgingid=%i ' : '%_ ') . 'WHERE submitid = %i AND rejudgingid IS NULL', @$rejudgingid, $jud['submitid']); // Prioritize single submission rejudgings if ($table == 'submission') { $DB->q('UPDATE team SET judging_last_started = NULL WHERE teamid IN (SELECT teamid FROM submission WHERE submitid = %i)', $jud['submitid']); } if (!$full_rejudge) { calcScoreRow($jud['cid'], $jud['teamid'], $jud['probid']); } $DB->q('COMMIT'); if (!$full_rejudge) { auditlog('judging', $jud['judgingid'], 'mark invalid', '(rejudge)'); } } /** redirect back. */ if ($full_rejudge) { header('Location: rejudging.php?id=' . urlencode($rejudgingid)); } else { header('Location: ' . $table . '.php?id=' . urlencode($id)); }
echo "<p>Recalculating all values for the scoreboard cache for contest c{$contest} (" . count($teams) . " teams, " . count($probs) . " problems)...</p>\n\n<pre>\n"; if (count($teams) == 0) { echo "No teams defined, doing nothing.</pre>\n\n"; continue; } if (count($probs) == 0) { echo "No problems defined, doing nothing.</pre>\n\n"; continue; } // for each team, fetch the status of each problem foreach ($teams as $team) { echo "Team t" . specialchars($team['teamid']) . ":"; // for each problem fetch the result foreach ($probs as $pr) { echo " p" . specialchars($pr['probid']); calcScoreRow($pr['cid'], $team['teamid'], $pr['probid']); } // Now recompute the rank echo " rankcache"; updateRankCache($contest, $team['teamid']); echo "\n"; ob_flush(); } echo "</pre>\n\n"; } echo "<p>Deleting irrelevant data...</p>\n\n"; // Drop all teams and problems that do not exist in each contest foreach ($contests as $contest) { $probids = $DB->q('COLUMN SELECT probid FROM problem INNER JOIN contestproblem USING (probid) WHERE cid = %i ORDER BY shortname', $contest);