/** * Update problem contents * * @param Request $r * @throws ApiException * @throws InvalidDatabaseOperationException */ public static function apiUpdate(Request $r) { self::authenticateRequest($r); self::validateCreateOrUpdate($r, true); // Validate commit message. Validators::isStringNonEmpty($r['message'], 'message'); // Update the Problem object $valueProperties = array('public', 'title', 'validator' => array('important' => true), 'time_limit' => array('important' => true), 'validator_time_limit' => array('important' => true), 'overall_wall_time_limit' => array('important' => true), 'extra_wall_time' => array('important' => true), 'memory_limit' => array('important' => true), 'output_limit' => array('important' => true), 'stack_limit' => array('important' => true), 'email_clarifications', 'source', 'order', 'languages'); $problem = $r['problem']; $requiresRejudge = self::updateValueProperties($r, $problem, $valueProperties); $r['problem'] = $problem; $response = array('rejudged' => false); $problemDeployer = new ProblemDeployer($problem->alias, ProblemDeployer::UPDATE_CASES); // Insert new problem try { //Begin transaction ProblemsDAO::transBegin(); if (isset($_FILES['problem_contents']) && FileHandler::GetFileUploader()->IsUploadedFile($_FILES['problem_contents']['tmp_name'])) { // DeployProblemZip requires alias => problem_alias $r['alias'] = $r['problem_alias']; $problemDeployer->deploy(); if ($problemDeployer->hasValidator) { $problem->validator = 'custom'; } elseif ($problem->validator == 'custom') { throw new ProblemDeploymentFailedException('problemDeployerValidatorRequired'); } // This must come before the commit in case isSlow throws an exception. $problem->slow = $problemDeployer->isSlow($problem); // Calculate output limit. $output_limit = $problemDeployer->getOutputLimit(); if ($output_limit != -1) { $r['problem']->setOutputLimit($output_limit); } $response['uploaded_files'] = $problemDeployer->filesToUnzip; $problemDeployer->commit($r['message'], $r['current_user']); $requiresRejudge |= $problemDeployer->requiresRejudge; } else { $problem->slow = $problemDeployer->isSlow($problem); } // Save the contest object with data sent by user to the database ProblemsDAO::save($problem); //End transaction ProblemsDAO::transEnd(); } catch (ApiException $e) { // Operation failed in the data layer, rollback transaction ProblemsDAO::transRollback(); throw $e; } catch (Exception $e) { // Operation failed in the data layer, rollback transaction ProblemsDAO::transRollback(); self::$log->error('Failed to update problem'); self::$log->error($e); throw new InvalidDatabaseOperationException($e); } finally { $problemDeployer->cleanup(); } if ($requiresRejudge == true && OMEGAUP_ENABLE_REJUDGE_ON_PROBLEM_UPDATE == true) { self::$log->info('Calling ProblemController::apiRejudge'); try { self::apiRejudge($r); $response['rejudged'] = true; } catch (Exception $e) { self::$log->error('Best efort ProblemController::apiRejudge failed', $e); } } if ($r['redirect'] === true) { header('Location: ' . $_SERVER['HTTP_REFERER']); } // All clear $response['status'] = 'ok'; // Invalidar problem statement cache @todo invalidar todos los lenguajes foreach ($problemDeployer->getUpdatedLanguages() as $lang) { Cache::deleteFromCache(Cache::PROBLEM_STATEMENT, $r['problem']->getAlias() . '-' . $lang . 'html'); Cache::deleteFromCache(Cache::PROBLEM_STATEMENT, $r['problem']->getAlias() . '-' . $lang . 'markdown'); } Cache::deleteFromCache(Cache::PROBLEM_SAMPLE, $r['problem']->getAlias() . '-sample.in'); return $response; }
/** * Entry point for zip validation * Determines the type of problem we are deploying * * @return boolean * @throws InvalidParameterException */ private function validateZip() { $this->log->info('Validating zip...'); if (!array_key_exists('problem_contents', $_FILES)) { $this->log->error('\\$_FILES global does not contain problem_contents.'); throw new InvalidParameterException('parameterEmpty', 'problem_contents'); } if (isset($_FILES['problem_contents']) && !FileHandler::GetFileUploader()->IsUploadedFile($_FILES['problem_contents']['tmp_name'])) { $this->log->error("GetFileUploader()->IsUploadedFile() check failed for \$_FILES['problem_contents']['tmp_name']."); throw new InvalidParameterException('parameterEmpty', 'problem_contents'); } $this->filesToUnzip = array(); $this->imageHashes = array(); $this->casesFiles = array(); $this->zipPath = $_FILES['problem_contents']['tmp_name']; $this->log->info("Opening {$this->zipPath}..."); $zip = new ZipArchive(); $resource = $zip->open($this->zipPath); $size = 0; if ($resource !== true) { $this->log->error('Unable to open zip file: ' . ZipHandler::ErrorMessage($resource)); throw new InvalidParameterException('problemDeployerCorruptZip'); } // Get list of files for ($i = 0; $i < $zip->numFiles; $i++) { $this->log->info("Found inside zip: '" . $zip->getNameIndex($i) . "'"); $zipFilesArray[] = $zip->getNameIndex($i); // Sum up the size $statI = $zip->statIndex($i); $size += $statI['size']; // If the file is THE validator for custom outputs... if (stripos($zip->getNameIndex($i), 'validator.') === 0) { $this->hasValidator = true; $this->filesToUnzip[] = $zip->getNameIndex($i); $this->log->info('Validator found: ' . $zip->getNameIndex($i)); } // Interactive problems. if (stripos($zip->getNameIndex($i), 'interactive/') === 0) { $this->filesToUnzip[] = $zip->getNameIndex($i); $this->isInteractive = true; if (ProblemDeployer::endsWith($zip->getNameIndex($i), '.idl', true)) { $this->log->info('.idl file found: ' . $zip->getNameIndex($i)); $this->idlFile = $zip->getNameIndex($i); } } // Example inputs. if (stripos($zip->getNameIndex($i), 'examples/') === 0 && ProblemDeployer::endsWith($zip->getNameIndex($i), '.in', true)) { $this->filesToUnzip[] = $zip->getNameIndex($i); } } $this->checkedForInteractive = true; if ($this->isInteractive) { if ($this->idlFile == null) { throw new InvalidParameterException('problemDeployerIdlMissing'); } elseif (!in_array('interactive/examples/sample.in', $this->filesToUnzip)) { throw new InvalidParameterException('problemDeployerInteractiveSampleMissing'); } } if ($this->isInteractive && $size > ProblemDeployer::MAX_INTERACTIVE_ZIP_FILESIZE) { throw new InvalidParameterException('problemDeployerExceededZipSizeLimit', null, array('size' => $size, 'max_size' => ProblemDeployer::MAX_INTERACTIVE_ZIP_FILESIZE)); } elseif ($size > ProblemDeployer::MAX_ZIP_FILESIZE) { throw new InvalidParameterException('problemDeployerExceededZipSizeLimit', null, array('size' => $size, 'max_size' => ProblemDeployer::MAX_ZIP_FILESIZE)); } try { // Look for testplan if (in_array('testplan', $zipFilesArray)) { $returnValue = $this->checkCasesWithTestplan($zip, $zipFilesArray); $this->log->info('testplan found, checkCasesWithTestPlan=' . $returnValue); $this->filesToUnzip[] = 'testplan'; } else { $this->log->info('testplan not found'); $this->checkCases($zip, $zipFilesArray); } // Log files to unzip $this->log->info('Files to unzip: '); foreach ($this->filesToUnzip as $file) { $this->log->info($file); } // Look for statements $returnValue = $this->checkProblemStatements($zipFilesArray, $zip); $this->log->info('checkProblemStatements=' . $returnValue . '.'); } finally { // Close zip $this->log->info('closing zip'); $zip->close(); } return $returnValue; }