/**
  * Returns a report with all user activity for a contest.
  *
  * @param Request $r
  * @return array
  * @throws InvalidDatabaseOperationException
  */
 public static function apiActivityReport(Request $r)
 {
     self::validateDetails($r);
     if (!$r['contest_admin']) {
         throw new ForbiddenAccessException();
     }
     $accesses = ContestAccessLogDAO::GetAccessForContest($r['contest']);
     $submissions = SubmissionLogDAO::GetSubmissionsForContest($r['contest']);
     // Merge both logs.
     $result['events'] = array();
     $lenAccesses = count($accesses);
     $lenSubmissions = count($submissions);
     $iAccesses = 0;
     $iSubmissions = 0;
     while ($iAccesses < $lenAccesses && $iSubmissions < $lenSubmissions) {
         if ($accesses[$iAccesses]['time'] < $submissions[$iSubmissions]['time']) {
             array_push($result['events'], ContestController::processAccess($accesses[$iAccesses++]));
         } else {
             array_push($result['events'], ContestController::processSubmission($submissions[$iSubmissions++]));
         }
     }
     while ($iAccesses < $lenAccesses) {
         array_push($result['events'], ContestController::processAccess($accesses[$iAccesses++]));
     }
     while ($iSubmissions < $lenSubmissions) {
         array_push($result['events'], ContestController::processSubmission($submissions[$iSubmissions++]));
     }
     // Anonimize data.
     $ipMapping = array();
     foreach ($result['events'] as &$entry) {
         if (!array_key_exists($entry['ip'], $ipMapping)) {
             $ipMapping[$entry['ip']] = count($ipMapping);
         }
         $entry['ip'] = $ipMapping[$entry['ip']];
     }
     $result['status'] = 'ok';
     return $result;
 }
 /**
  * Tests that user can get contest details with the scoreboard token
  */
 public function testDetailsUsingToken()
 {
     // Get a private contest
     $contestData = ContestsFactory::createContest(null, 0);
     // Create our user not added to the contest
     $externalUser = UserFactory::createUser();
     $originalContestAccessLog = ContestAccessLogDAO::getAll();
     // Get the scoreboard url by using the MyList api being the
     // contest director
     $response = ContestController::apiMyList(new Request(array('auth_token' => $this->login($contestData['director']))));
     // Look for our contest from the list and save the scoreboard tokens
     $scoreboard_url = null;
     $scoreboard_admin_url = null;
     foreach ($response['results'] as $c) {
         if ($c['alias'] === $contestData['request']['alias']) {
             $scoreboard_url = $c['scoreboard_url'];
             $scoreboard_admin_url = $c['scoreboard_url_admin'];
             break;
         }
     }
     $this->assertNotNull($scoreboard_url);
     $this->assertNotNull($scoreboard_admin_url);
     // Call details using token
     $detailsResponse = ContestController::apiDetails(new Request(array('auth_token' => $this->login($externalUser), 'contest_alias' => $contestData['request']['alias'], 'token' => $scoreboard_url)));
     $this->assertContestDetails($contestData, array(), $detailsResponse);
     // Call details using admin token
     $detailsResponse = ContestController::apiDetails(new Request(array('auth_token' => $this->login($externalUser), 'contest_alias' => $contestData['request']['alias'], 'token' => $scoreboard_admin_url)));
     $this->assertContestDetails($contestData, array(), $detailsResponse);
     // All requests were done using tokens, so the log must be identical.
     $contestAccessLog = ContestAccessLogDAO::getAll();
     $this->assertEquals($originalContestAccessLog, $contestAccessLog);
 }