/**
  * Deletes the usertype specified by ID.
  * @return bool Was it successful?
  */
 protected function body()
 {
     if (!$this->userHasPrivileges(User::usersPrivPresets)) {
         return false;
     }
     if (!$this->isInputSet('id')) {
         return false;
     }
     $id = $this->getParams('id');
     if ($id == Repositories::StudentUserType) {
         return $this->death(StringID::CannotRemoveBasicStudentType);
     }
     /**
      * @var $deletedType \UserType
      */
     $deletedType = Repositories::findEntity(Repositories::UserType, $id);
     $users = Repositories::getRepository(Repositories::User)->findBy(['type' => $id]);
     /** @var \UserType $studentType */
     $studentType = Repositories::findEntity(Repositories::UserType, Repositories::StudentUserType);
     foreach ($users as $user) {
         /** @var $user \User */
         $user->setType($studentType);
         Repositories::persist($user);
     }
     Repositories::remove($deletedType);
     Repositories::flushAll();
     return true;
 }
 protected function body()
 {
     $plugins = Repositories::getRepository(Repositories::Plugin)->findAll();
     $errors = [];
     foreach ($plugins as $plugin) {
         /** @var $plugin \Plugin */
         $dbPhpFile = $plugin->getMainfile();
         $dbDescription = $plugin->getDescription();
         $dbIdentifier = $plugin->getIdentifier();
         $pluginDirectory = $this->getMainDirectory($dbPhpFile);
         if ($pluginDirectory === false) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_InvalidFolder);
             continue;
         }
         $manifestFile = Filesystem::combinePaths(Config::get('paths', 'plugins'), $pluginDirectory, "manifest.xml");
         $xml = new \DOMDocument();
         $success = $xml->load(realpath($manifestFile));
         if ($success === false) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_MalformedXmlOrFileMissing);
             continue;
         }
         $fileDescription = $xml->getElementsByTagName('description')->item(0);
         $fileArguments = $xml->getElementsByTagName('argument');
         $fileIdentifier = $xml->getElementsByTagName('identifier')->item(0);
         $fileArgumentsArray = [];
         for ($i = 0; $i < $fileArguments->length; $i++) {
             $fileArgumentsArray[] = trim($fileArguments->item($i)->nodeValue);
         }
         $fileArgumentsString = implode(';', $fileArgumentsArray);
         if ($dbDescription !== trim($fileDescription->nodeValue)) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_DescriptionMismatch);
             $plugin->setDescription(trim($fileDescription->nodeValue));
             Repositories::persist($plugin);
         }
         if ($dbIdentifier !== trim($fileIdentifier->nodeValue)) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_IdentifierMismatch);
             $plugin->setIdentifier(trim($fileIdentifier->nodeValue));
             Repositories::persist($plugin);
         }
         if ($plugin->getConfig() !== $fileArgumentsString) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_ArgumentsMismatch);
             $plugin->setConfig($fileArgumentsString);
             Repositories::persist($plugin);
         }
     }
     Repositories::flushAll();
     if (count($errors) === 0) {
         $this->addOutput("text", Language::get(StringID::ReloadManifests_DatabaseCorrespondsToManifests));
     } else {
         $this->addOutput("text", implode('<br>', $errors));
     }
     return true;
 }
 /**
  * Runs this script.
  * @return bool Is it successful?
  */
 protected function body()
 {
     if (!$this->isInputSet(array('id'))) {
         return false;
     }
     $id = $this->getParams('id');
     /**
      * @var $submission \Submission
      */
     $submission = Repositories::findEntity(Repositories::Submission, $id);
     if ($submission->getUser()->getId() !== User::instance()->getId()) {
         return $this->death(StringID::InsufficientPrivileges);
     }
     if ($submission->getStatus() === \Submission::STATUS_GRADED) {
         return $this->death(StringID::CannotDeleteGradedSubmissions);
     }
     if ($submission->getStatus() === \Submission::STATUS_REQUESTING_GRADING) {
         return $this->death(StringID::CannotDeleteHandsoffSubmissions);
     }
     $status = $submission->getStatus();
     $submission->setStatus(\Submission::STATUS_DELETED);
     Repositories::persist($submission);
     // Make something else latest
     if ($status === \Submission::STATUS_LATEST) {
         $latestSubmission = null;
         /**
          * @var $submissions \Submission[]
          * @var $latestSubmission \Submission
          */
         $submissions = Repositories::getRepository(Repositories::Submission)->findBy(['status' => \Submission::STATUS_NORMAL, 'assignment' => $submission->getAssignment()->getId(), 'user' => User::instance()->getId()]);
         foreach ($submissions as $olderSolution) {
             if ($latestSubmission === null || $olderSolution->getDate() > $latestSubmission->getDate()) {
                 $latestSubmission = $olderSolution;
             }
         }
         if ($latestSubmission !== null) {
             $latestSubmission->setStatus(\Submission::STATUS_LATEST);
             Repositories::persist($latestSubmission);
         }
     }
     Repositories::flushAll();
     return true;
 }
Exemple #4
0
 /**
  * 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;
     }
 }
 /**
  * Deletes plugin with supplied ID. This is a very destructive operation because all problems associated with this plugin will lose any reference to it and thus the submissions will lose reference and therefore we won't be able to use them for sooth.similarity comparison, for example.
  *
  * @param int $id plugin ID
  * @return array error properties provided by removalError() or retrievalError(),
  * or false in case of success
  */
 public static function deletePluginById($id)
 {
     /**
      * @var $plugin \Plugin
      * @var $tests \PluginTest[]
      * @var $problems \Problem[]
      */
     $plugin = Repositories::findEntity(Repositories::Plugin, $id);
     // Destroy plugin tests testing this plugin
     $tests = Repositories::getRepository(Repositories::PluginTest)->findBy(['plugin' => $id]);
     foreach ($tests as $test) {
         self::deleteTestById($test->getId());
     }
     // Problems that relied on this plugin are now without plugin
     $problems = Repositories::getRepository(Repositories::Problem)->findBy(['plugin' => $id]);
     foreach ($problems as $problem) {
         $problem->setPlugin(null);
         Repositories::persist($problem);
     }
     Repositories::flushAll();
     // Delete the plugin
     Repositories::remove($plugin);
     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);
        }
    }