Example #1
0
 public static function isInsideContest(Contests $contest, $user_id)
 {
     if (time() > strtotime($contest->finish_time) || time() < strtotime($contest->start_time)) {
         return false;
     }
     if (is_null($contest->window_length)) {
         return true;
     }
     $contest_user = ContestsUsersDAO::getByPK($user_id, $contest->contest_id);
     $first_access_time = $contest_user->access_time;
     return time() <= strtotime($first_access_time) + $contest->window_length * 60;
 }
Example #2
0
 public static function CheckAndSaveFirstTimeAccess($user_id, $contest_id)
 {
     $contest_user = self::getByPK($user_id, $contest_id);
     // If is null, add our contest_user relationship
     if (is_null($contest_user)) {
         $contest_user = new ContestsUsers();
         $contest_user->setUserId($user_id);
         $contest_user->setContestId($contest_id);
         $contest_user->setAccessTime(date("Y-m-d H:i:s"));
         $contest_user->setScore(0);
         $contest_user->setTime(0);
         ContestsUsersDAO::save($contest_user);
     } else {
         if ($contest_user->getAccessTime() === "0000-00-00 00:00:00") {
             // If its set to default time, update it
             $contest_user->setAccessTime(date("Y-m-d H:i:s"));
             ContestsUsersDAO::save($contest_user);
         }
     }
     return $contest_user;
 }
 public static function CheckAndSaveFirstTimeAccess($user_id, $contest_id, $grant_access = false)
 {
     $contest_user = self::getByPK($user_id, $contest_id);
     if (is_null($contest_user)) {
         if (!$grant_access) {
             // User was not authorized to do this.
             throw new ForbiddenAccessException();
         }
         $contest_user = new ContestsUsers();
         $contest_user->setUserId($user_id);
         $contest_user->setContestId($contest_id);
         $contest_user->setAccessTime(date('Y-m-d H:i:s'));
         $contest_user->setScore(0);
         $contest_user->setTime(0);
         ContestsUsersDAO::save($contest_user);
     } elseif ($contest_user->getAccessTime() === '0000-00-00 00:00:00') {
         // If its set to default time, update it
         $contest_user->setAccessTime(date('Y-m-d H:i:s'));
         ContestsUsersDAO::save($contest_user);
     }
     return $contest_user;
 }
 /**
  * Create a new run
  *
  * @param Request $r
  * @return array
  * @throws Exception
  * @throws InvalidDatabaseOperationException
  * @throws InvalidFilesystemOperationException
  */
 public static function apiCreate(Request $r)
 {
     // Init
     self::initializeGrader();
     // Authenticate user
     self::authenticateRequest($r);
     // Validate request
     self::validateCreateRequest($r);
     self::$log->info('New run being submitted!!');
     $response = array();
     if (self::$practice) {
         if (OMEGAUP_LOCKDOWN) {
             throw new ForbiddenAccessException('lockdown');
         }
         $submit_delay = 0;
         $contest_id = null;
         $test = 0;
     } else {
         //check the kind of penalty_type for this contest
         $penalty_type = $r['contest']->penalty_type;
         switch ($penalty_type) {
             case 'contest_start':
                 // submit_delay is calculated from the start
                 // of the contest
                 $start = $r['contest']->getStartTime();
                 break;
             case 'problem_open':
                 // submit delay is calculated from the
                 // time the user opened the problem
                 $opened = ContestProblemOpenedDAO::getByPK($r['contest']->getContestId(), $r['problem']->getProblemId(), $r['current_user_id']);
                 if (is_null($opened)) {
                     //holy moly, he is submitting a run
                     //and he hasnt even opened the problem
                     //what should be done here?
                     throw new NotAllowedToSubmitException('runEvenOpened');
                 }
                 $start = $opened->getOpenTime();
                 break;
             case 'none':
             case 'runtime':
                 //we dont care
                 $start = null;
                 break;
             default:
                 self::$log->error('penalty_type for this contests is not a valid option, asuming `none`.');
                 $start = null;
         }
         if (!is_null($start)) {
             //ok, what time is it now?
             $c_time = time();
             $start = strtotime($start);
             //asuming submit_delay is in minutes
             $submit_delay = (int) (($c_time - $start) / 60);
         } else {
             $submit_delay = 0;
         }
         $contest_id = $r['contest']->getContestId();
         $test = Authorization::IsContestAdmin($r['current_user_id'], $r['contest']) ? 1 : 0;
     }
     // Populate new run object
     $run = new Runs(array('user_id' => $r['current_user_id'], 'problem_id' => $r['problem']->getProblemId(), 'contest_id' => $contest_id, 'language' => $r['language'], 'source' => $r['source'], 'status' => 'new', 'runtime' => 0, 'penalty' => $submit_delay, 'memory' => 0, 'score' => 0, 'contest_score' => $contest_id != null ? 0 : null, 'submit_delay' => $submit_delay, 'guid' => md5(uniqid(rand(), true)), 'verdict' => 'JE', 'test' => $test));
     try {
         // Push run into DB
         RunsDAO::save($run);
         SubmissionLogDAO::save(new SubmissionLog(array('user_id' => $run->user_id, 'run_id' => $run->run_id, 'contest_id' => $run->contest_id, 'ip' => ip2long($_SERVER['REMOTE_ADDR']))));
         // Update submissions counter++
         $r['problem']->setSubmissions($r['problem']->getSubmissions() + 1);
         ProblemsDAO::save($r['problem']);
     } catch (Exception $e) {
         // Operation failed in the data layer
         throw new InvalidDatabaseOperationException($e);
     }
     try {
         // Create file for the run
         $filepath = RunController::getSubmissionPath($run);
         FileHandler::CreateFile($filepath, $r['source']);
     } catch (Exception $e) {
         throw new InvalidFilesystemOperationException($e);
     }
     // Call Grader
     try {
         self::$grader->Grade([$run->guid], false, false);
     } catch (Exception $e) {
         self::$log->error('Call to Grader::grade() failed:');
         self::$log->error($e);
     }
     if (self::$practice) {
         $response['submission_deadline'] = 0;
     } else {
         // Add remaining time to the response
         try {
             $contest_user = ContestsUsersDAO::getByPK($r['current_user_id'], $r['contest']->getContestId());
             if ($r['contest']->getWindowLength() === null) {
                 $response['submission_deadline'] = strtotime($r['contest']->getFinishTime());
             } else {
                 $response['submission_deadline'] = min(strtotime($r['contest']->getFinishTime()), strtotime($contest_user->getAccessTime()) + $r['contest']->getWindowLength() * 60);
             }
         } catch (Exception $e) {
             // Operation failed in the data layer
             throw new InvalidDatabaseOperationException($e);
         }
     }
     // Happy ending
     $response['guid'] = $run->getGuid();
     $response['status'] = 'ok';
     // Expire rank cache
     UserController::deleteProblemsSolvedRankCacheList();
     return $response;
 }
Example #5
0
 /**
  * Update a Contest
  *
  * @param Request $r
  * @return array
  * @throws InvalidDatabaseOperationException
  */
 public static function apiUpdate(Request $r)
 {
     if (OMEGAUP_LOCKDOWN) {
         throw new ForbiddenAccessException("lockdown");
     }
     // Authenticate request
     self::authenticateRequest($r);
     // Validate request
     self::validateCreateOrUpdate($r, true);
     // Update contest DAO
     if (!is_null($r["public"])) {
         // If going public
         if ($r["public"] == 1) {
             self::validateContestCanBePublic($r["contest"]);
         }
         $r["contest"]->setPublic($r["public"]);
     }
     $valueProperties = array("title", "description", "start_time" => array("transform" => function ($value) {
         return gmdate('Y-m-d H:i:s', $value);
     }), "finish_time" => array("transform" => function ($value) {
         return gmdate('Y-m-d H:i:s', $value);
     }), "window_length" => array("transform" => function ($value) {
         return $value == "NULL" ? NULL : $value;
     }), "scoreboard", "points_decay_factor", "partial_score", "submissions_gap", "feedback", "penalty" => array("transform" => function ($value) {
         return max(0, intval($value));
     }), "penalty_type", "penalty_calc_policy", "show_scoreboard_after", "contestant_must_register");
     self::updateValueProperties($r, $r["contest"], $valueProperties);
     // Push changes
     try {
         // Begin a new transaction
         ContestsDAO::transBegin();
         // Save the contest object with data sent by user to the database
         ContestsDAO::save($r["contest"]);
         // If the contest is private, add the list of allowed users
         if (!is_null($r["public"]) && $r["public"] != 1 && $r["hasPrivateUsers"]) {
             // Get current users
             $cu_key = new ContestsUsers(array("contest_id" => $r["contest"]->getContestId()));
             $current_users = ContestsUsersDAO::search($cu_key);
             $current_users_id = array();
             foreach ($current_users as $cu) {
                 array_push($current_users_id, $current_users->getUserId());
             }
             // Check who needs to be deleted and who needs to be added
             $to_delete = array_diff($current_users_id, $r["private_users_list"]);
             $to_add = array_diff($r["private_users_list"], $current_users_id);
             // Add users in the request
             foreach ($to_add as $userkey) {
                 // Create a temp DAO for the relationship
                 $temp_user_contest = new ContestsUsers(array("contest_id" => $r["contest"]->getContestId(), "user_id" => $userkey, "access_time" => "0000-00-00 00:00:00", "score" => 0, "time" => 0));
                 // Save the relationship in the DB
                 ContestsUsersDAO::save($temp_user_contest);
             }
             // Delete users
             foreach ($to_delete as $userkey) {
                 // Create a temp DAO for the relationship
                 $temp_user_contest = new ContestsUsers(array("contest_id" => $r["contest"]->getContestId(), "user_id" => $userkey));
                 // Delete the relationship in the DB
                 ContestsUsersDAO::delete(ContestProblemsDAO::search($temp_user_contest));
             }
         }
         if (!is_null($r['problems'])) {
             // Get current problems
             $p_key = new Problems(array("contest_id" => $r["contest"]->getContestId()));
             $current_problems = ProblemsDAO::search($p_key);
             $current_problems_id = array();
             foreach ($current_problems as $p) {
                 array_push($current_problems_id, $p->getProblemId());
             }
             // Check who needs to be deleted and who needs to be added
             $to_delete = array_diff($current_problems_id, self::$problems_id);
             $to_add = array_diff(self::$problems_id, $current_problems_id);
             foreach ($to_add as $problem) {
                 $contest_problem = new ContestProblems(array('contest_id' => $r["contest"]->getContestId(), 'problem_id' => $problem, 'points' => $r["problems"][$problem]['points']));
                 ContestProblemsDAO::save($contest_problem);
             }
             foreach ($to_delete as $problem) {
                 $contest_problem = new ContestProblems(array('contest_id' => $r["contest"]->getContestId(), 'problem_id' => $problem));
                 ContestProblemsDAO::delete(ContestProblemsDAO::search($contest_problem));
             }
         }
         // End transaction
         ContestsDAO::transEnd();
     } catch (Exception $e) {
         // Operation failed in the data layer, rollback transaction
         ContestsDAO::transRollback();
         throw new InvalidDatabaseOperationException($e);
     }
     // Expire contest-info cache
     Cache::deleteFromCache(Cache::CONTEST_INFO, $r["contest_alias"]);
     // Expire contest scoreboard cache
     Scoreboard::InvalidateScoreboardCache($r["contest"]->getContestId());
     // Happy ending
     $response = array();
     $response["status"] = 'ok';
     self::$log->info("Contest updated (alias): " . $r['contest_alias']);
     return $response;
 }
 /**
  * Entry point for Problem Details API
  *
  * @param Request $r
  * @throws InvalidFilesystemOperationException
  * @throws InvalidDatabaseOperationException
  */
 public static function apiDetails(Request $r)
 {
     // Get user.
     // Allow unauthenticated requests if we are not openning a problem
     // inside a contest.
     try {
         self::authenticateRequest($r);
     } catch (UnauthorizedException $e) {
         if (!is_null($r['contest_alias'])) {
             throw $e;
         }
     }
     // Validate request
     self::validateDetails($r);
     $response = array();
     // Create array of relevant columns
     $relevant_columns = array('title', 'alias', 'validator', 'time_limit', 'validator_time_limit', 'overall_wall_time_limit', 'extra_wall_time', 'memory_limit', 'output_limit', 'visits', 'submissions', 'accepted', 'difficulty', 'creation_date', 'source', 'order', 'points', 'public', 'languages', 'slow', 'stack_limit', 'email_clarifications');
     // Read the file that contains the source
     if (!ProblemController::isLanguageSupportedForProblem($r)) {
         // If there is no language file for the problem, return the spanish version.
         $r['lang'] = 'es';
     }
     $statement_type = ProblemController::getStatementType($r);
     Cache::getFromCacheOrSet(Cache::PROBLEM_STATEMENT, $r['problem']->getAlias() . '-' . $r['lang'] . '-' . $statement_type, $r, 'ProblemController::getProblemStatement', $file_content, APC_USER_CACHE_PROBLEM_STATEMENT_TIMEOUT);
     // Add problem statement to source
     $response['problem_statement'] = $file_content;
     $response['problem_statement_language'] = $r['lang'];
     // Add the example input.
     $sample_input = null;
     Cache::getFromCacheOrSet(Cache::PROBLEM_SAMPLE, $r['problem']->getAlias() . '-sample.in', $r, 'ProblemController::getSampleInput', $sample_input, APC_USER_CACHE_PROBLEM_STATEMENT_TIMEOUT);
     if (!empty($sample_input)) {
         $response['sample_input'] = $sample_input;
     }
     // Add the problem the response
     $response = array_merge($response, $r['problem']->asFilteredArray($relevant_columns));
     // If the problem is public or if the user has admin privileges, show the
     // problem source and alias of owner.
     if ($r['problem']->public || Authorization::IsProblemAdmin($r['current_user_id'], $r['problem'])) {
         $problemsetter = UsersDAO::getByPK($r['problem']->author_id);
         if (!is_null($problemsetter)) {
             $response['problemsetter'] = array('username' => $problemsetter->username, 'name' => is_null($problemsetter->name) ? $problemsetter->username : $problemsetter->name);
         }
     } else {
         unset($response['source']);
     }
     if (!is_null($r['current_user_id'])) {
         // Create array of relevant columns for list of runs
         $relevant_columns = array('guid', 'language', 'status', 'verdict', 'runtime', 'penalty', 'memory', 'score', 'contest_score', 'time', 'submit_delay');
         // Search the relevant runs from the DB
         $contest = ContestsDAO::getByAlias($r['contest_alias']);
         $keyrun = new Runs(array('user_id' => $r['current_user_id'], 'problem_id' => $r['problem']->getProblemId(), 'contest_id' => is_null($r['contest']) ? null : $r['contest']->getContestId()));
         // Get all the available runs done by the current_user
         try {
             $runs_array = RunsDAO::search($keyrun);
         } catch (Exception $e) {
             // Operation failed in the data layer
             throw new InvalidDatabaseOperationException($e);
         }
         // Add each filtered run to an array
         if (count($runs_array) >= 0) {
             $runs_filtered_array = array();
             foreach ($runs_array as $run) {
                 $filtered = $run->asFilteredArray($relevant_columns);
                 $filtered['alias'] = $r['problem']->alias;
                 $filtered['username'] = $r['current_user']->username;
                 $filtered['time'] = strtotime($filtered['time']);
                 array_push($runs_filtered_array, $filtered);
             }
         }
         $response['runs'] = $runs_filtered_array;
     }
     if (!is_null($r['contest'])) {
         // At this point, contestant_user relationship should be established.
         try {
             ContestsUsersDAO::CheckAndSaveFirstTimeAccess($r['current_user_id'], $r['contest']->contest_id);
         } catch (ApiException $e) {
             throw $e;
         } catch (Exception $e) {
             // Operation failed in the data layer
             throw new InvalidDatabaseOperationException($e);
         }
         // As last step, register the problem as opened
         if (!ContestProblemOpenedDAO::getByPK($r['contest']->getContestId(), $r['problem']->getProblemId(), $r['current_user_id'])) {
             //Create temp object
             $keyContestProblemOpened = new ContestProblemOpened(array('contest_id' => $r['contest']->getContestId(), 'problem_id' => $r['problem']->getProblemId(), 'user_id' => $r['current_user_id']));
             try {
                 // Save object in the DB
                 ContestProblemOpenedDAO::save($keyContestProblemOpened);
             } catch (Exception $e) {
                 // Operation failed in the data layer
                 throw new InvalidDatabaseOperationException($e);
             }
         }
     } elseif (isset($r['show_solvers']) && $r['show_solvers']) {
         $response['solvers'] = RunsDAO::GetBestSolvingRunsForProblem($r['problem']->problem_id);
     }
     if (!is_null($r['current_user_id'])) {
         ProblemViewedDAO::MarkProblemViewed($r['current_user_id'], $r['problem']->problem_id);
     }
     $response['score'] = self::bestScore($r);
     $response['status'] = 'ok';
     return $response;
 }
 /**
  * First access time should not change
  */
 public function testAccessTimeIsAlwaysFirstAccessForPrivate()
 {
     // Get a contest
     $contestData = ContestsFactory::createContest(null, 0);
     // Get a user for our scenario
     $contestant = UserFactory::createUser();
     // Add user to our private contest
     ContestsFactory::addUser($contestData, $contestant);
     // Prepare our request
     $r = new Request();
     $r['contest_alias'] = $contestData['request']['alias'];
     // Log in the user
     $r['auth_token'] = $this->login($contestant);
     // Call api
     $response = ContestController::apiDetails($r);
     // We need to grab the access time from the ContestUsers table
     $contest = ContestsDAO::getByAlias($contestData['request']['alias']);
     $contest_user = ContestsUsersDAO::getByPK($contestant->getUserId(), $contest->getContestId());
     $firstAccessTime = $contest_user->getAccessTime();
     // Call API again, access time should not change
     $response = ContestController::apiDetails($r);
     $contest_user = ContestsUsersDAO::getByPK($contestant->getUserId(), $contest->getContestId());
     $this->assertEquals($firstAccessTime, $contest_user->getAccessTime());
 }
Example #8
0
 /**
  * Test sending runs after the window length expired
  *
  * @expectedException NotAllowedToSubmitException
  */
 public function testNewRunOutWindowLengthPublicContest()
 {
     // Set the context for the first contest
     $r = $this->setValidRequest();
     // Alter Contest window length to 20
     // This means: once I started the contest, I have 20 more mins
     // to finish it.
     $contest = ContestsDAO::getByAlias($r["contest_alias"]);
     $contest->setWindowLength(20);
     ContestsDAO::save($contest);
     // Alter first access time of our contestant such that he started
     // 21 minutes ago, this is, window length has expired by 1 minute
     $contest_user = ContestsUsersDAO::getByPK($this->contestant->getUserId(), $contest->getContestId());
     $contest_user->setAccessTime(date("Y-m-d H:i:s", time() - 21 * 60));
     //Window length is in minutes
     ContestsUsersDAO::save($contest_user);
     // Call API
     RunController::apiCreate($r);
 }
Example #9
0
 /**
  * Entry point for Problem Details API
  * 
  * @param Request $r
  * @throws InvalidFilesystemOperationException
  * @throws InvalidDatabaseOperationException
  */
 public static function apiDetails(Request $r)
 {
     // Get user.
     // Allow unauthenticated requests if we are not openning a problem
     // inside a contest.
     try {
         self::authenticateRequest($r);
     } catch (ForbiddenAccessException $e) {
         if (!is_null($r["contest_alias"])) {
             throw $e;
         }
     }
     // Validate request
     self::validateDetails($r);
     $response = array();
     // Create array of relevant columns
     $relevant_columns = array("title", "author_id", "alias", "validator", "time_limit", "validator_time_limit", "overall_wall_time_limit", "extra_wall_time", "memory_limit", "output_limit", "visits", "submissions", "accepted", "difficulty", "creation_date", "source", "order", "points", "public", "languages", "slow", "stack_limit", "email_clarifications");
     // Read the file that contains the source
     if (!ProblemController::isLanguageSupportedForProblem($r)) {
         // If there is no language file for the problem, return the spanish version.
         $r['lang'] = 'es';
     }
     $statement_type = ProblemController::getStatementType($r);
     Cache::getFromCacheOrSet(Cache::PROBLEM_STATEMENT, $r["problem"]->getAlias() . "-" . $r["lang"] . "-" . $statement_type, $r, 'ProblemController::getProblemStatement', $file_content, APC_USER_CACHE_PROBLEM_STATEMENT_TIMEOUT);
     // Add problem statement to source
     $response["problem_statement"] = $file_content;
     $response["problem_statement_language"] = $r['lang'];
     // Add the example input.
     $sample_input = null;
     Cache::getFromCacheOrSet(Cache::PROBLEM_SAMPLE, $r["problem"]->getAlias() . "-sample.in", $r, 'ProblemController::getSampleInput', $sample_input, APC_USER_CACHE_PROBLEM_STATEMENT_TIMEOUT);
     if (!empty($sample_input)) {
         $response['sample_input'] = $sample_input;
     }
     // Add the problem the response
     $response = array_merge($response, $r["problem"]->asFilteredArray($relevant_columns));
     if (!is_null($r['current_user_id'])) {
         // Create array of relevant columns for list of runs
         $relevant_columns = array("guid", "language", "status", "verdict", "runtime", "penalty", "memory", "score", "contest_score", "time", "submit_delay");
         // Search the relevant runs from the DB
         $contest = ContestsDAO::getByAlias($r["contest_alias"]);
         $keyrun = new Runs(array("user_id" => $r["current_user_id"], "problem_id" => $r["problem"]->getProblemId(), "contest_id" => is_null($r["contest"]) ? null : $r["contest"]->getContestId()));
         // Get all the available runs done by the current_user
         try {
             $runs_array = RunsDAO::search($keyrun);
         } catch (Exception $e) {
             // Operation failed in the data layer
             throw new InvalidDatabaseOperationException($e);
         }
         // Add each filtered run to an array
         if (count($runs_array) >= 0) {
             $runs_filtered_array = array();
             foreach ($runs_array as $run) {
                 $filtered = $run->asFilteredArray($relevant_columns);
                 $filtered['time'] = strtotime($filtered['time']);
                 array_push($runs_filtered_array, $filtered);
             }
         }
         $response["runs"] = $runs_filtered_array;
     }
     if (!is_null($r["contest"])) {
         // At this point, contestant_user relationship should be established.
         try {
             $contest_user = ContestsUsersDAO::CheckAndSaveFirstTimeAccess($r["current_user_id"], $r["contest"]->getContestId());
         } catch (Exception $e) {
             // Operation failed in the data layer
             throw new InvalidDatabaseOperationException($e);
         }
         // As last step, register the problem as opened
         if (!ContestProblemOpenedDAO::getByPK($r["contest"]->getContestId(), $r["problem"]->getProblemId(), $r["current_user_id"])) {
             //Create temp object
             $keyContestProblemOpened = new ContestProblemOpened(array("contest_id" => $r["contest"]->getContestId(), "problem_id" => $r["problem"]->getProblemId(), "user_id" => $r["current_user_id"]));
             try {
                 // Save object in the DB
                 ContestProblemOpenedDAO::save($keyContestProblemOpened);
             } catch (Exception $e) {
                 // Operation failed in the data layer
                 throw new InvalidDatabaseOperationException($e);
             }
         }
     } else {
         if (isset($r['show_solvers']) && $r['show_solvers']) {
             $response['solvers'] = RunsDAO::GetBestSolvingRunsForProblem($r['problem']->problem_id);
         }
     }
     if (!is_null($r['current_user_id'])) {
         ProblemViewedDAO::MarkProblemViewed($r['current_user_id'], $r['problem']->problem_id);
     }
     $response["score"] = self::bestScore($r);
     $response["status"] = "ok";
     return $response;
 }