예제 #1
0
 /**
  * Check in DB for problem added to contest
  * 
  * @param array $problemData
  * @param array $contestData
  * @param Request $r
  */
 public static function assertProblemAddedToContest($problemData, $contestData, $r)
 {
     // Get problem and contest from DB
     $problem = ProblemsDAO::getByAlias($problemData["request"]["alias"]);
     $contest = ContestsDAO::getByAlias($contestData["request"]["alias"]);
     // Get problem-contest and verify it
     $contest_problems = ContestProblemsDAO::getByPK($contest->getContestId(), $problem->getProblemId());
     self::assertNotNull($contest_problems);
     self::assertEquals($r["points"], $contest_problems->getPoints());
     self::assertEquals($r["order_in_contest"], $contest_problems->getOrder());
 }
 /**
  * Checks the contest details response
  *
  * @param type $contestData
  * @param type $problems
  * @param type $response
  */
 private function assertContestDetails($contestData, $problems, $response)
 {
     // To validate, grab the contest object directly from the DB
     $contest = ContestsDAO::getByAlias($contestData['request']['alias']);
     // Assert we are getting correct data
     $this->assertEquals($contest->getDescription(), $response['description']);
     $this->assertEquals(Utils::GetPhpUnixTimestamp($contest->getStartTime()), $response['start_time']);
     $this->assertEquals(Utils::GetPhpUnixTimestamp($contest->getFinishTime()), $response['finish_time']);
     $this->assertEquals($contest->getWindowLength(), $response['window_length']);
     $this->assertEquals($contest->getAlias(), $response['alias']);
     $this->assertEquals($contest->getPointsDecayFactor(), $response['points_decay_factor']);
     $this->assertEquals($contest->getPartialScore(), $response['partial_score']);
     $this->assertEquals($contest->getSubmissionsGap(), $response['submissions_gap']);
     $this->assertEquals($contest->getFeedback(), $response['feedback']);
     $this->assertEquals($contest->getPenalty(), $response['penalty']);
     $this->assertEquals($contest->getScoreboard(), $response['scoreboard']);
     $this->assertEquals($contest->penalty_type, $response['penalty_type']);
     $this->assertEquals($contest->getPenaltyCalcPolicy(), $response['penalty_calc_policy']);
     // Assert we have our problems
     $numOfProblems = count($problems);
     $this->assertEquals($numOfProblems, count($response['problems']));
     // Assert problem data
     $i = 0;
     foreach ($response['problems'] as $problem_array) {
         // Get problem from DB
         $problem = ProblemsDAO::getByAlias($problems[$i]['request']['alias']);
         // Assert data in DB
         $this->assertEquals($problem->getTitle(), $problem_array['title']);
         $this->assertEquals($problem->getAlias(), $problem_array['alias']);
         $this->assertEquals($problem->getValidator(), $problem_array['validator']);
         $this->assertEquals($problem->getTimeLimit(), $problem_array['time_limit']);
         $this->assertEquals($problem->getMemoryLimit(), $problem_array['memory_limit']);
         $this->assertEquals($problem->getVisits(), $problem_array['visits']);
         $this->assertEquals($problem->getSubmissions(), $problem_array['submissions']);
         $this->assertEquals($problem->getAccepted(), $problem_array['accepted']);
         $this->assertEquals($problem->getOrder(), $problem_array['order']);
         // Get points of problem from Contest-Problem relationship
         $problemInContest = ContestProblemsDAO::getByPK($contest->getContestId(), $problem->getProblemId());
         $this->assertEquals($problemInContest->getPoints(), $problem_array['points']);
         $i++;
     }
 }
예제 #3
0
 /**
  * Validate the request of apiCreate
  * 
  * @param Request $r
  * @throws InvalidDatabaseOperationException
  * @throws NotFoundException
  */
 private static function validateCreate(Request $r)
 {
     Validators::isStringNonEmpty($r["contest_alias"], "contest_alias");
     Validators::isStringNonEmpty($r["problem_alias"], "problem_alias");
     Validators::isStringNonEmpty($r["message"], "message");
     try {
         $r["contest"] = ContestsDAO::getByAlias($r["contest_alias"]);
         $r["problem"] = ProblemsDAO::getByAlias($r["problem_alias"]);
     } catch (Exception $e) {
         throw new InvalidDatabaseOperationException($e);
     }
     if (is_null($r["contest"])) {
         throw new NotFoundException("contestNotFound");
     }
     if (is_null($r["problem"])) {
         throw new NotFoundException("problemNotFound");
     }
     // Is the combination contest_id and problem_id valid?
     if (is_null(ContestProblemsDAO::getByPK($r["contest"]->getContestId(), $r["problem"]->getProblemId()))) {
         throw new NotFoundException("problemNotFoundInContest");
     }
 }
예제 #4
0
 public static function RefreshScoreboardCache($contest_id)
 {
     try {
         $contest = ContestsDAO::getByPK($contest_id);
         $contest_runs = RunsDAO::GetContestRuns($contest_id);
         // Get all distinct contestants participating in the contest given contest_id
         $raw_contest_users = RunsDAO::GetAllRelevantUsers($contest_id, true, null);
         // Get all problems given contest_id
         $raw_contest_problems = ContestProblemsDAO::GetRelevantProblems($contest_id);
     } catch (Exception $e) {
         throw new InvalidDatabaseOperationException($e);
     }
     $problem_mapping = array();
     $order = 0;
     foreach ($raw_contest_problems as $problem) {
         $problem_mapping[$problem->problem_id] = array('order' => $order++, 'alias' => $problem->alias);
     }
     $scoreboardLimit = Scoreboard::getScoreboardTimeLimitUnixTimestamp($contest);
     // Cache scoreboard until the contest ends (or forever if it has already ended).
     $timeout = max(0, strtotime($contest->getFinishTime()) - time());
     $contestantScoreboardCache = new Cache(Cache::CONTESTANT_SCOREBOARD_PREFIX, $contest_id);
     $contestantScoreboard = Scoreboard::getScoreboardFromRuns($contest_runs, $raw_contest_users, $problem_mapping, $contest->getPenalty(), $scoreboardLimit, $contest, false, false);
     $contestantScoreboardCache->set($contestantScoreboard, $timeout);
     $adminScoreboardCache = new Cache(Cache::ADMIN_SCOREBOARD_PREFIX, $contest_id);
     $scoreboardLimit = Scoreboard::getScoreboardTimeLimitUnixTimestamp($contest, true);
     $adminScoreboard = Scoreboard::getScoreboardFromRuns($contest_runs, $raw_contest_users, $problem_mapping, $contest->getPenalty(), $scoreboardLimit, $contest, true, false);
     $adminScoreboardCache->set($adminScoreboard, $timeout);
     $contestantEventCache = new Cache(Cache::CONTESTANT_SCOREBOARD_EVENTS_PREFIX, $contest_id);
     $contestantEventCache->set(Scoreboard::calculateEvents($contest, $contest_runs, $raw_contest_users, $problem_mapping, false), $timeout);
     $adminEventCache = new Cache(Cache::ADMIN_SCOREBOARD_EVENTS_PREFIX, $contest_id);
     $adminEventCache->set(Scoreboard::calculateEvents($contest, $contest_runs, $raw_contest_users, $problem_mapping, true), $timeout);
     // Try to broadcast the updated scoreboards:
     $log = Logger::getLogger('Scoreboard');
     try {
         $grader = new Grader();
         $log->debug('Sending updated scoreboards');
         $grader->broadcast($contest->alias, json_encode(array('message' => '/scoreboard/update/', 'scoreboard' => $adminScoreboard)), false, -1, false);
         $grader->broadcast($contest->alias, json_encode(array('message' => '/scoreboard/update/', 'scoreboard' => $contestantScoreboard)), true, -1, true);
     } catch (Exception $e) {
         $log->error('Error broadcasting scoreboard: ' . $e);
     }
 }
예제 #5
0
 /**
  *
  * Validates Create Run request
  *
  * @param Request $r
  * @throws ApiException
  * @throws InvalidDatabaseOperationException
  * @throws NotAllowedToSubmitException
  * @throws InvalidParameterException
  * @throws ForbiddenAccessException
  */
 private static function validateCreateRequest(Request $r)
 {
     // https://github.com/omegaup/omegaup/issues/739
     if ($r['current_user']->username == 'omi') {
         throw new ForbiddenAccessException();
     }
     $allowedLanguages = array('kp', 'kj', 'c', 'cpp', 'cpp11', 'java', 'py', 'rb', 'pl', 'cs', 'pas', 'cat', 'hs');
     try {
         Validators::isStringNonEmpty($r['problem_alias'], 'problem_alias');
         // Check that problem exists
         $r['problem'] = ProblemsDAO::getByAlias($r['problem_alias']);
         if ($r['problem']->deprecated) {
             throw new PreconditionFailedException('problemDeprecated');
         }
         $allowedLanguages = array_intersect($allowedLanguages, explode(',', $r['problem']->languages));
         Validators::isInEnum($r['language'], 'language', $allowedLanguages);
         Validators::isStringNonEmpty($r['source'], 'source');
         // Check for practice or public problem, there is no contest info in this scenario
         if ($r['contest_alias'] == '') {
             if (Authorization::IsProblemAdmin($r['current_user_id'], $r['problem']) || time() > ProblemsDAO::getPracticeDeadline($r['problem']->getProblemId()) || $r['problem']->getPublic() == true) {
                 if (!RunsDAO::IsRunInsideSubmissionGap(null, $r['problem']->getProblemId(), $r['current_user_id']) && !Authorization::IsSystemAdmin($r['current_user_id'])) {
                     throw new NotAllowedToSubmitException('runWaitGap');
                 }
                 self::$practice = true;
                 return;
             } else {
                 throw new NotAllowedToSubmitException('problemIsNotPublic');
             }
         }
         // Validate contest
         Validators::isStringNonEmpty($r['contest_alias'], 'contest_alias');
         $r['contest'] = ContestsDAO::getByAlias($r['contest_alias']);
         if ($r['contest'] == null) {
             throw new InvalidParameterException('parameterNotFound', 'contest_alias');
         }
         if ($r['contest']->languages !== null) {
             $allowedLanguages = array_intersect($allowedLanguages, explode(',', $r['contest']->languages));
             Validators::isInEnum($r['language'], 'language', $allowedLanguages);
         }
         // Validate that the combination contest_id problem_id is valid
         if (!ContestProblemsDAO::getByPK($r['contest']->getContestId(), $r['problem']->getProblemId())) {
             throw new InvalidParameterException('parameterNotFound', 'problem_alias');
         }
         // Contest admins can skip following checks
         if (!Authorization::IsContestAdmin($r['current_user_id'], $r['contest'])) {
             // Before submit something, contestant had to open the problem/contest
             if (!ContestsUsersDAO::getByPK($r['current_user_id'], $r['contest']->getContestId())) {
                 throw new NotAllowedToSubmitException('runNotEvenOpened');
             }
             // Validate that the run is timely inside contest
             if (!ContestsDAO::isInsideContest($r['contest'], $r['current_user_id'])) {
                 throw new NotAllowedToSubmitException('runNotInsideContest');
             }
             // Validate if contest is private then the user should be registered
             if ($r['contest']->getPublic() == 0 && is_null(ContestsUsersDAO::getByPK($r['current_user_id'], $r['contest']->getContestId()))) {
                 throw new NotAllowedToSubmitException('runNotRegistered');
             }
             // Validate if the user is allowed to submit given the submissions_gap
             if (!RunsDAO::IsRunInsideSubmissionGap($r['contest']->getContestId(), $r['problem']->getProblemId(), $r['current_user_id'])) {
                 throw new NotAllowedToSubmitException('runWaitGap');
             }
         }
     } catch (ApiException $apiException) {
         // Propagate ApiException
         throw $apiException;
     } catch (Exception $e) {
         // Operation failed in the data layer
         throw new InvalidDatabaseOperationException($e);
     }
 }
예제 #6
0
 public static function apiDownload(Request $r)
 {
     self::authenticateRequest($r);
     self::validateStats($r);
     // Get our runs
     $relevant_columns = array("run_id", "guid", "language", "status", "verdict", "runtime", "penalty", "memory", "score", "contest_score", "time", "submit_delay", "Users.username", "Problems.alias");
     try {
         $runs = RunsDAO::search(new Runs(array("contest_id" => $r["contest"]->getContestId())), "time", "DESC", $relevant_columns);
     } catch (Exception $e) {
         // Operation failed in the data layer
         throw new InvalidDatabaseOperationException($e);
     }
     $zip = new ZipStream($r["contest_alias"] . '.zip');
     // Add runs to zip
     $table = "guid,user,problem,verdict,points\n";
     foreach ($runs as $run) {
         $zip->add_file_from_path("runs/" . $run->getGuid(), RunController::getSubmissionPath($run));
         $columns[0] = 'username';
         $columns[1] = 'alias';
         $usernameProblemData = $run->asFilteredArray($columns);
         $table .= $run->getGuid() . "," . $usernameProblemData['username'] . "," . $usernameProblemData['alias'] . "," . $run->getVerdict() . "," . $run->getContestScore();
         $table .= "\n";
     }
     $zip->add_file("summary.csv", $table);
     // Add problem cases to zip
     $contest_problems = ContestProblemsDAO::GetRelevantProblems($r["contest"]->getContestId());
     foreach ($contest_problems as $problem) {
         $zip->add_file_from_path($problem->getAlias() . "_cases.zip", PROBLEMS_PATH . "/" . $problem->getAlias() . "/cases.zip");
     }
     // Return zip
     $zip->finish();
     die;
 }
예제 #7
0
 public static function apiDownload(Request $r)
 {
     self::authenticateRequest($r);
     self::validateStats($r);
     // Get our runs
     $relevant_columns = array('run_id', 'guid', 'language', 'status', 'verdict', 'runtime', 'penalty', 'memory', 'score', 'contest_score', 'time', 'submit_delay', 'Users.username', 'Problems.alias');
     try {
         $runs = RunsDAO::search(new Runs(array('contest_id' => $r['contest']->getContestId())), 'time', 'DESC', $relevant_columns);
     } catch (Exception $e) {
         // Operation failed in the data layer
         throw new InvalidDatabaseOperationException($e);
     }
     $zip = new ZipStream($r['contest_alias'] . '.zip');
     // Add runs to zip
     $table = "guid,user,problem,verdict,points\n";
     foreach ($runs as $run) {
         $zip->add_file_from_path('runs/' . $run->getGuid(), RunController::getSubmissionPath($run));
         $columns[0] = 'username';
         $columns[1] = 'alias';
         $usernameProblemData = $run->asFilteredArray($columns);
         $table .= $run->getGuid() . ',' . $usernameProblemData['username'] . ',' . $usernameProblemData['alias'] . ',' . $run->getVerdict() . ',' . $run->getContestScore();
         $table .= "\n";
     }
     $zip->add_file('summary.csv', $table);
     // Add problem cases to zip
     $contest_problems = ContestProblemsDAO::GetRelevantProblems($r['contest']->getContestId());
     foreach ($contest_problems as $problem) {
         $zip->add_file_from_path($problem->getAlias() . '_cases.zip', PROBLEMS_PATH . '/' . $problem->getAlias() . '/cases.zip');
     }
     // Return zip
     $zip->finish();
     die;
 }
 /**
  * Validate problem Details API
  *
  * @param Request $r
  * @throws ApiException
  * @throws InvalidDatabaseOperationException
  * @throws NotFoundException
  * @throws ForbiddenAccessException
  */
 private static function validateDetails(Request $r)
 {
     Validators::isStringNonEmpty($r['contest_alias'], 'contest_alias', false);
     Validators::isStringNonEmpty($r['problem_alias'], 'problem_alias');
     // Lang is optional. Default is user's preferred.
     if (!is_null($r['lang'])) {
         Validators::isStringOfMaxLength($r['lang'], 'lang', 2);
     } else {
         $r['lang'] = UserController::getPreferredLanguage($r);
     }
     try {
         $r['problem'] = ProblemsDAO::getByAlias($r['problem_alias']);
     } catch (Exception $e) {
         throw new InvalidDatabaseOperationException($e);
     }
     if (is_null($r['problem'])) {
         throw new NotFoundException('problemNotFound');
     }
     if (isset($r['statement_type']) && !in_array($r['statement_type'], array('html', 'markdown'))) {
         throw new NotFoundException('invalidStatementType');
     }
     // If we request a problem inside a contest
     if (!is_null($r['contest_alias'])) {
         // Is the combination contest_id and problem_id valid?
         try {
             $r['contest'] = ContestsDAO::getByAlias($r['contest_alias']);
             if (is_null($r['contest'])) {
                 throw new NotFoundException('contestNotFound');
             }
             if (is_null(ContestProblemsDAO::getByPK($r['contest']->getContestId(), $r['problem']->getProblemId()))) {
                 throw new NotFoundException('problemNotFoundInContest');
             }
         } catch (ApiException $apiException) {
             throw $apiException;
         } catch (Exception $e) {
             throw new InvalidDatabaseOperationException($e);
         }
         // If the contest is private, verify that our user is invited
         $contest_admin = Authorization::IsContestAdmin($r['current_user_id'], $r['contest']);
         if ($r['contest']->public != '1') {
             if (is_null(ContestsUsersDAO::getByPK($r['current_user_id'], $r['contest']->contest_id)) && !$contest_admin) {
                 throw new ForbiddenAccessException();
             }
         }
         // If the contest has not started, user should not see it, unless
         // it is admin
         if (!ContestsDAO::hasStarted($r['contest']) && !$contest_admin) {
             throw new ForbiddenAccessException('contestNotStarted');
         }
     } else {
         if (!Authorization::CanEditProblem($r['current_user_id'], $r['problem'])) {
             // If the problem is requested outside a contest, we need to
             // check that it is not private
             if ($r['problem']->public != '1') {
                 throw new ForbiddenAccessException('problemIsPrivate');
             }
         }
     }
 }
예제 #9
0
 /**
  * Validate problem Details API
  * 
  * @param Request $r
  * @throws ApiException
  * @throws InvalidDatabaseOperationException
  * @throws NotFoundException
  * @throws ForbiddenAccessException
  */
 private static function validateDetails(Request $r)
 {
     Validators::isStringNonEmpty($r["contest_alias"], "contest_alias", false);
     Validators::isStringNonEmpty($r["problem_alias"], "problem_alias");
     // Lang is optional. Default is user's preferred.
     if (!is_null($r["lang"])) {
         Validators::isStringOfMaxLength($r["lang"], "lang", 2);
     } else {
         $r['lang'] = UserController::getPreferredLanguage($r);
     }
     try {
         $r["problem"] = ProblemsDAO::getByAlias($r["problem_alias"]);
     } catch (Exception $e) {
         throw new InvalidDatabaseOperationException($e);
     }
     if (is_null($r["problem"])) {
         throw new NotFoundException("problemNotFound");
     }
     if (isset($r["statement_type"]) && !in_array($r["statement_type"], array("html", "markdown"))) {
         throw new NotFoundException("invalidStatementType");
     }
     // If we request a problem inside a contest
     if (!is_null($r["contest_alias"])) {
         // Is the combination contest_id and problem_id valid?
         try {
             $r["contest"] = ContestsDAO::getByAlias($r["contest_alias"]);
             if (is_null($r["contest"])) {
                 throw new NotFoundException("contestNotFound");
             }
             if (is_null(ContestProblemsDAO::getByPK($r["contest"]->getContestId(), $r["problem"]->getProblemId()))) {
                 throw new NotFoundException("problemNotFoundInContest");
             }
         } catch (ApiException $apiException) {
             throw $apiException;
         } catch (Exception $e) {
             throw new InvalidDatabaseOperationException($e);
         }
         // If the contest is private, verify that our user is invited
         if ($r["contest"]->getPublic() === 0) {
             if (is_null(ContestsUsersDAO::getByPK($r["current_user_id"], $r["contest"]->getContestId())) && !Authorization::IsContestAdmin($r["current_user_id"], $r["contest"])) {
                 throw new ForbiddenAccessException();
             }
         }
         // If the contest has not started, user should not see it, unless it is admin
         if (!ContestsDAO::hasStarted($r["contest"]) && !Authorization::IsContestAdmin($r["current_user_id"], $r["contest"])) {
             throw new ForbiddenAccessException("contestNotStarted");
         }
     } else {
         if (!Authorization::CanEditProblem($r["current_user_id"], $r["problem"])) {
             // If the problem is requested outside a contest, we need to check that it is not private
             if ($r["problem"]->getPublic() == "0") {
                 throw new ForbiddenAccessException("problemIsPrivate");
             }
         }
     }
 }