/** * Check stats are ok for WA, AC, PA and total counts * Also validates the max wait time guid */ public function testGetStats() { // Get a problem $problemData = ProblemsFactory::createProblem(); // Get a contest $contestData = ContestsFactory::createContest(); // Add the problem to the contest ContestsFactory::addProblemToContest($problemData, $contestData); // Create our contestant $contestant = UserFactory::createUser(); // Create some runs to be pending $pendingRunsCount = 5; $pendingRunsData = array(); for ($i = 0; $i < $pendingRunsCount; $i++) { $pendingRunsData[$i] = RunsFactory::createRun($problemData, $contestData, $contestant); } $ACRunsCount = 2; $ACRunsData = array(); for ($i = 0; $i < $ACRunsCount; $i++) { $ACRunsData[$i] = RunsFactory::createRun($problemData, $contestData, $contestant); // Grade the run RunsFactory::gradeRun($ACRunsData[$i]); } $WARunsCount = 1; $WARunsData = array(); for ($i = 0; $i < $WARunsCount; $i++) { $WARunsData[$i] = RunsFactory::createRun($problemData, $contestData, $contestant); // Grade the run with WA RunsFactory::gradeRun($WARunsData[$i], 0, "WA"); } // Create request $r = new Request(); $r["problem_alias"] = $problemData["request"]["alias"]; $r["auth_token"] = $this->login($problemData["author"]); // Call API $response = ProblemController::apiStats($r); // Check number of pending runs $this->assertEquals(count($pendingRunsData), count($response["pending_runs"])); $this->assertEquals(count($ACRunsData), $response["verdict_counts"]["AC"]); $this->assertEquals(count($WARunsData), $response["verdict_counts"]["WA"]); $this->assertEquals($pendingRunsCount + $ACRunsCount + $WARunsCount, $response["total_runs"]); }
/** * Generates a CSV for contest report * * @param Request $r * @return array */ public static function apiCsvReport(Request $r) { self::authenticateRequest($r); self::validateStats($r); // Get full Report API of the contest $reportRequest = new Request(array("contest_alias" => $r["contest_alias"], "auth_token" => $r["auth_token"])); $contestReport = self::apiReport($reportRequest); // Get problem stats for each contest problem so we can // have the full list of cases $problemStats = array(); $i = 0; foreach ($contestReport["problems"] as $entry) { $problem_alias = $entry["alias"]; $problemStatsRequest = new Request(array("problem_alias" => $problem_alias, "auth_token" => $r["auth_token"])); $problemStats[$i] = ProblemController::apiStats($problemStatsRequest); $problemStats[$problem_alias] = $problemStats[$i]; $i++; } // Build a csv $csvData = array(); // Build titles $csvRow = array(); $csvRow[] = "username"; foreach ($contestReport["problems"] as $entry) { foreach ($problemStats[$entry["alias"]]["cases_stats"] as $caseName => $counts) { $csvRow[] = $caseName; } $csvRow[] = $entry["alias"] . " total"; } $csvRow[] = "total"; $csvData[] = $csvRow; foreach ($contestReport["ranking"] as $userData) { if ($userData === "ok") { continue; } $csvRow = array(); $csvRow[] = $userData["username"]; foreach ($userData["problems"] as $key => $problemData) { // If the user don't have these details then he didn't submit, // we need to fill the report with 0s for completeness if (!isset($problemData["run_details"]["cases"]) || count($problemData["run_details"]["cases"]) === 0) { for ($i = 0; $i < count($problemStats[$key]["cases_stats"]); $i++) { $csvRow[] = '0'; } // And adding the total for this problem $csvRow[] = '0'; } else { // for each case foreach ($problemData["run_details"]["cases"] as $caseData) { // If case is correct if (strcmp($caseData["meta"]["status"], "OK") === 0 && strcmp($caseData["out_diff"], "") === 0) { $csvRow[] = '1'; } else { $csvRow[] = '0'; } } $csvRow[] = $problemData["points"]; } } $csvRow[] = $userData["total"]["points"]; $csvData[] = $csvRow; } // Set headers to auto-download file header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Content-Type: application/force-download"); header("Content-Type: application/octet-stream"); header("Content-Type: application/download"); header("Content-Disposition: attachment;filename=" . $r["contest_alias"] . "_report.csv"); header("Content-Transfer-Encoding: binary"); // Write contents to a csv raw string // TODO(https://github.com/omegaup/omegaup/issues/628): Escape = to prevent applications from inadvertently executing code // http://contextis.co.uk/blog/comma-separated-vulnerabilities/ $out = fopen('php://output', 'w'); foreach ($csvData as $csvRow) { fputcsv($out, ContestController::escapeCsv($csvRow)); } fclose($out); // X_X die; }