/** * Stats of a problem * * @param Request $r * @return array * @throws ForbiddenAccessException * @throws InvalidDatabaseOperationException */ public static function apiStats(Request $r) { // Get user self::authenticateRequest($r); // Validate request self::validateRuns($r); // We need to check that the user has priviledges on the problem if (!Authorization::CanEditProblem($r['current_user_id'], $r['problem'])) { throw new ForbiddenAccessException(); } try { // Array of GUIDs of pending runs $pendingRunsGuids = RunsDAO::GetPendingRunsOfProblem($r['problem']->getProblemId()); // Count of pending runs (int) $totalRunsCount = RunsDAO::CountTotalRunsOfProblem($r['problem']->getProblemId()); // List of verdicts $verdict_counts = array(); foreach (self::$verdicts as $verdict) { $verdict_counts[$verdict] = RunsDAO::CountTotalRunsOfProblemByVerdict($r['problem']->getProblemId(), $verdict); } // Array to count AC stats per case. // Let's try to get the last snapshot from cache. $problemStatsCache = new Cache(Cache::PROBLEM_STATS, $r['problem']->getAlias()); $cases_stats = $problemStatsCache->get(); if (is_null($cases_stats)) { // Initialize the array at counts = 0 $cases_stats = array(); $cases_stats['counts'] = array(); // We need to save the last_id that we processed, so next time we do not repeat this $cases_stats['last_id'] = 0; // Build problem dir $problem_dir = PROBLEMS_PATH . '/' . $r['problem']->getAlias() . '/cases/'; // Get list of cases $dir = opendir($problem_dir); if (is_dir($problem_dir)) { while (($file = readdir($dir)) !== false) { // If we have an input if (strstr($file, '.in')) { // Initialize it to 0 $cases_stats['counts'][str_replace('.in', '', $file)] = 0; } } closedir($dir); } } // Get all runs of this problem after the last id we had $runs = RunsDAO::searchRunIdGreaterThan(new Runs(array('problem_id' => $r['problem']->getProblemId())), $cases_stats['last_id'], 'run_id'); // For each run we got foreach ($runs as $run) { // Build grade dir $grade_dir = RunController::getGradePath($run); // Skip it if it failed to compile. if (file_exists("{$grade_dir}/compile_error.log")) { continue; } // Try to open the details file. if (file_exists("{$grade_dir}/details.json")) { $details = json_decode(file_get_contents("{$grade_dir}/details.json")); foreach ($details as $group) { foreach ($group->cases as $case) { if ($case->score > 0) { $cases_stats['counts'][$case->name]++; } } } } } } catch (Exception $e) { throw new InvalidDatabaseOperationException($e); } // Save the last id we saw in case we saw something if (!is_null($runs) && count($runs) > 0) { $cases_stats['last_id'] = $runs[count($runs) - 1]->getRunId(); } // Save in cache what we got $problemStatsCache->set($cases_stats, APC_USER_CACHE_PROBLEM_STATS_TIMEOUT); return array('total_runs' => $totalRunsCount, 'pending_runs' => $pendingRunsGuids, 'verdict_counts' => $verdict_counts, 'cases_stats' => $cases_stats['counts'], 'status' => 'ok'); }