protected function body() { if (!$this->userHasPrivileges(User::submissionsCorrect)) { return false; } $canViewAuthors = User::instance()->hasPrivileges(User::submissionsViewAuthors); $rated = $this->getParams('rated') ? true : false; $all = $this->getParams('all') ? true : false; $absolutelyAll = $this->getParams('absolutelyAll') ? true : false; $userId = User::instance()->getId(); if ($absolutelyAll) { if (!$this->userHasPrivileges(User::lecturesManageAll, User::groupsManageAll, User::otherAdministration)) { return false; } } /** * @var $submissions \Submission[] */ // group is a DQL reserved word, so we must use _group if ($absolutelyAll) { $submissions = Repositories::makeDqlQuery("SELECT submission, user, assignment, problem, _group FROM \\Submission submission JOIN submission.assignment assignment JOIN assignment.problem problem JOIN submission.user user JOIN assignment.group _group WHERE submission.status <> 'deleted'")->getResult(); } else { $submissions = Repositories::makeDqlQuery("SELECT submission, user, assignment, problem, _group FROM \\Submission submission JOIN submission.assignment assignment JOIN assignment.problem problem JOIN submission.user user JOIN assignment.group _group WHERE _group.owner = :submissionCorrector AND (submission.status = 'graded' OR submission.status = 'latest' OR submission.status = 'handsoff') AND _group.deleted = 0")->setParameter('submissionCorrector', $userId)->getResult(); } foreach ($submissions as $submission) { if (!$all && !$absolutelyAll) { if ($rated && $submission->getStatus() !== \Submission::STATUS_GRADED) { continue; } if (!$rated && $submission->getStatus() === \Submission::STATUS_GRADED) { continue; } } $descriptionForTeacher = $submission->getInfo(); if ($submission->getSimilarityStatus() == \Submission::SIMILARITY_STATUS_GUILTY) { $descriptionForTeacher = Language::get(StringID::ThisSubmissionIsPlagiarism) . "\n======\n" . $descriptionForTeacher; } if ($submission->getSimilarityStatus() == \Submission::SIMILARITY_STATUS_INNOCENT) { $descriptionForTeacher = $descriptionForTeacher . "\n======\n" . Language::get(StringID::ThisSubmissionIsInnocent); } if ($submission->getSimilarityStatus() == \Submission::SIMILARITY_STATUS_NEW) { $descriptionForTeacher = $descriptionForTeacher . "\n======\n" . Language::get(StringID::ThisHasYetToBeCheckedForPlagiarism); } if ($submission->getStatus() == \Submission::STATUS_REQUESTING_GRADING) { $descriptionForTeacher = Language::get(StringID::GradingRequested) . " " . $descriptionForTeacher; } $row = [$submission->getId(), $submission->getAssignment()->getProblem()->getName(), $submission->getAssignment()->getGroup()->getName(), $submission->getDate()->format("Y-m-d H:i:s"), $submission->getSuccess(), $descriptionForTeacher, $submission->getRating(), $submission->getExplanation(), $submission->getAssignment()->getReward(), $submission->getAssignment()->getDeadline()->format("Y-m-d H:i:s"), $canViewAuthors ? $submission->getUser()->getId() : 0, $canViewAuthors ? $submission->getUser()->getRealName() : Language::get(StringID::NotAuthorizedForName), $submission->getOutputfile() != '', $submission->getAssignment()->getId()]; if ($absolutelyAll) { $row[] = $canViewAuthors ? $submission->getUser()->getEmail() : Language::get(StringID::NotAuthorizedForName); $row[] = $submission->getStatus(); } $this->addRowToOutput($row); } return true; }
/** * Launches plugin and updates database with results. * @param string $pluginType one of 'php', 'java', or 'exe' * @param string $pluginFile plugin file path * @param string $inputFile input file path * @param boolean $isTest is this a plugin test or a submission? true if plugin test * @param int $rowId ID of row to be updated * @param array $arguments plugin arguments * @return bool true if no error occurred */ public static function launchPlugin($pluginType, $pluginFile, $inputFile, $isTest, $rowId, $arguments = array()) { try { $response = null; if (!is_file($pluginFile) || !is_file($inputFile)) { $error = "plugin file and/or input file don't exist"; } else { array_unshift($arguments, $inputFile); $cwd = getcwd(); chdir(dirname($pluginFile)); switch ($pluginType) { case 'php': $launcher = new PhpLauncher(); ob_start(); $error = $launcher->launch($pluginFile, $arguments, $response); ob_end_clean(); break; case 'java': $launcher = new JavaLauncher(); $error = $launcher->launch($pluginFile, $arguments, $responseString); break; case 'exe': $launcher = new ExeLauncher(); $error = $launcher->launch($pluginFile, $arguments, $responseString); break; default: $error = "unsupported plugin type '{$pluginType}'"; } chdir($cwd); } if (!$error) { if (isset($responseString)) { try { $response = PluginResponse::fromXmlString($responseString); } catch (Exception $ex) { $response = PluginResponse::createError('Internal error. Plugin did not supply valid response XML and this error occurred: ' . $ex->getMessage() . '. Plugin instead supplied this response string: ' . $responseString); } } } else { $response = PluginResponse::createError('Plugin cannot be launched (' . $error . ').'); } $outputFile = $response->getOutput(); if ($outputFile) { $outputFolder = Config::get('paths', 'output'); $newFile = $outputFolder . date('Y-m-d_H-i-s_') . StringUtils::randomString(10) . '.zip'; if (rename($outputFile, $newFile)) { $outputFile = $newFile; } else { $outputFile = 'tmp-file-rename-failed'; } } /** * @var $pluginTest \PluginTest * @var $submission \Submission * @var $previousSubmissions \Submission[] */ if ($isTest) { $pluginTest = Repositories::findEntity(Repositories::PluginTest, $rowId); $pluginTest->setStatus(\PluginTest::STATUS_COMPLETED); $pluginTest->setSuccess($response->getFulfillment()); $pluginTest->setInfo($response->getDetails()); $pluginTest->setOutput($outputFile); Repositories::persistAndFlush($pluginTest); } else { $submission = Repositories::findEntity(Repositories::Submission, $rowId); // There is a sort of a race condition in here. // It is, in theory, possible, that there will be two submissions with the "latest" status after all is done // This should not happen in practice, though, and even if it does, it will have negligible negative effects. $previousSubmissions = Repositories::makeDqlQuery("SELECT s FROM \\Submission s WHERE s.user = :sameUser AND s.assignment = :sameAssignment AND s.status != 'graded' AND s.status != 'deleted'")->setParameter('sameUser', $submission->getUser()->getId())->setParameter('sameAssignment', $submission->getAssignment()->getId())->getResult(); foreach ($previousSubmissions as $previousSubmission) { $previousSubmission->setStatus(\Submission::STATUS_NORMAL); Repositories::getEntityManager()->persist($previousSubmission); } $submission->setStatus(\Submission::STATUS_LATEST); $submission->setInfo($response->getDetails()); $submission->setSuccess($response->getFulfillment()); $submission->setOutputfile($outputFile); Repositories::getEntityManager()->persist($submission); Repositories::flushAll(); } return !$error; } catch (Exception $exception) { $errorInformation = "Internal error. Plugin launcher or plugin failed with an internal error. Exception information: " . $exception->getMessage() . " in " . $exception->getFile() . " at " . $exception->getLine(); if ($isTest) { $pluginTest = Repositories::findEntity(Repositories::PluginTest, $rowId); $pluginTest->setStatus(\PluginTest::STATUS_COMPLETED); $pluginTest->setSuccess(0); $pluginTest->setInfo($errorInformation); Repositories::persistAndFlush($pluginTest); } else { $submission = Repositories::findEntity(Repositories::Submission, $rowId); $submission->setStatus(\Submission::STATUS_NORMAL); $submission->setInfo($errorInformation); Repositories::persistAndFlush($submission); } return false; } }
/** * Performs the function of this script. */ protected function body() { if (!$this->userHasPrivileges(User::assignmentsSubmit)) { return; } if (!$this->isInputValid(array('assignmentId' => 'isIndex'))) { return; } $userId = User::instance()->getId(); $assignmentId = $this->getParams('assignmentId'); /** * @var $assignment \Assignment */ $assignment = Repositories::getEntityManager()->find('Assignment', $assignmentId); $query = "SELECT s, a FROM Subscription s, Assignment a WHERE s.group = a.group AND s.user = "******" AND a.id = " . $assignmentId; /** * @var $result \Subscription[] */ $result = Repositories::getEntityManager()->createQuery($query)->getResult(); if (count($result) === 0) { $this->stop(Language::get(StringID::HackerError)); return; } if ($result[0]->getStatus() == \Subscription::STATUS_REQUESTED) { $this->stop(Language::get(StringID::SubscriptionNotYetAccepted)); return; } $submissionsFolder = Config::get('paths', 'submissions'); $file = date('Y-m-d_H-i-s_') . $userId . '_' . StringUtils::randomString(10) . '.zip'; if (!$this->saveUploadedFile('submission', $submissionsFolder . $file)) { return; } // Create submission $newSubmission = new \Submission(); $newSubmission->setAssignment($assignment); $newSubmission->setSubmissionFile($file); $newSubmission->setUser(User::instance()->getEntity()); $newSubmission->setDate(new \DateTime()); // Put into database Repositories::persistAndFlush($newSubmission); // Launch plugin, or set full success if not connected to any plugin if ($assignment->getProblem()->getPlugin() === null) { $newSubmission->setSuccess(100); $newSubmission->setInfo(Language::get(StringID::NoPluginUsed)); $previousSubmissions = Repositories::makeDqlQuery("SELECT s FROM \\Submission s WHERE s.user = :sameUser AND s.assignment = :sameAssignment AND s.status != 'graded' AND s.status != 'deleted'")->setParameter('sameUser', User::instance()->getEntity()->getId())->setParameter('sameAssignment', $assignment->getId())->getResult(); foreach ($previousSubmissions as $previousSubmission) { $previousSubmission->setStatus(\Submission::STATUS_NORMAL); Repositories::getEntityManager()->persist($previousSubmission); } $newSubmission->setStatus(\Submission::STATUS_LATEST); Repositories::getEntityManager()->persist($newSubmission); Repositories::flushAll(); } else { Core::launchPlugin($assignment->getProblem()->getPlugin()->getType(), Config::get('paths', 'plugins') . $assignment->getProblem()->getPlugin()->getMainfile(), $submissionsFolder . $file, false, $newSubmission->getId(), explode(';', $assignment->getProblem()->getConfig())); } // Run checking for plagiarism $similarityJar = Config::get('paths', 'similarity'); if ($similarityJar != null && is_file($similarityJar)) { $arguments = "comparenew"; // Get config file and autoloader file $paths = Config::get('paths'); $vendorAutoload = $paths['composerAutoload']; $java = Config::get('bin', 'java'); $javaArguments = Config::get('bin', 'javaArguments'); $pathToCore = Config::get('paths', 'core'); // This code will be passed, shell-escaped to the PHP CLI $launchCode = <<<LAUNCH_CODE require_once '{$vendorAutoload}'; chdir("{$pathToCore}"); `"{$java}" {$javaArguments} -Dfile.encoding=UTF-8 -jar "{$similarityJar}" {$arguments}`; LAUNCH_CODE; ShellUtils::phpExecInBackground(Config::get('bin', 'phpCli'), $launchCode); } }