public function run($userId, $mode = 'test') { $testMode = $mode != 'run'; $message = "Fix Lexicon View Settings to default to visible\n\n"; $projectlist = new ProjectListModel(); $projectlist->read(); foreach ($projectlist->entries as $projectParams) { // foreach existing project $projectId = $projectParams['id']; $project = new ProjectModel($projectId); if ($project->appName == 'lexicon') { $project = new LexiconProjectModel($projectId); $message .= "Inspecting project {$project->projectName}.\n"; $showFieldUpdated = 0; $roleShowFieldUpdated = 0; foreach ($project->config->roleViews as $role => $roleView) { foreach ($roleView->fields as $fieldName => $field) { if (!$field->show) { $field->show = true; $showFieldUpdated++; $roleShowFieldUpdated++; } } } $userShowFieldUpdated = 0; foreach ($project->config->userViews as $userId => $userView) { foreach ($userView->fields as $fieldName => $field) { if (!$field->show) { $field->show = true; $showFieldUpdated++; $userShowFieldUpdated++; } } } if ($showFieldUpdated > 0) { $message .= " Changed {$showFieldUpdated} View Settings fields to be visible. This comprised: \n"; $message .= " - Changed {$roleShowFieldUpdated} role-based View Settings fields to be visible.\n"; $message .= " - Changed {$userShowFieldUpdated} user-based View Settings fields to be visible.\n\n"; if (!$testMode) { $message .= " Saving changes to project {$project->projectName}.\n\n"; $project->write(); } } else { $message .= " No invisible View Settings fields found/changed.\n\n"; } } } return $message; }
/** * Create or update project * @param string $projectId * @param string $userId * @param array<projectModel> $object * @throws UserUnauthorizedException * @throws \Exception * @return string projectId */ public static function updateProject($projectId, $userId, $object) { $project = new LexiconProjectModel($projectId); if (!$project->hasRight($userId, Domain::USERS + Operation::EDIT)) { throw new UserUnauthorizedException("Insufficient privileges to update project in method 'updateProject'"); } $oldDBName = $project->databaseName(); $object['id'] = $projectId; JsonDecoder::decode($project, $object); $newDBName = $project->databaseName(); if ($oldDBName != '' && $oldDBName != $newDBName) { if (MongoStore::hasDB($newDBName)) { throw new \Exception("Cannot rename '{$oldDBName}' to ' {$newDBName}' . New project name {$newDBName} already exists. Not renaming."); } MongoStore::renameDB($oldDBName, $newDBName); } $projectId = $project->write(); return $projectId; }
/** * Reads a MultiText from the XmlNode $sxeNode given by the element 'gloss' * * @param SimpleXMLElement $sxeNode * @param MultiText $multiText * @param ArrayOf $inputSystems * @return MultiText */ public function readMultiTextGloss($sxeNode, $multiText, $inputSystems = null) { CodeGuard::checkTypeAndThrow($multiText, 'Api\\Model\\Languageforge\\Lexicon\\MultiText'); if ($sxeNode->getName() != 'gloss') { throw new \Exception("'" . $sxeNode->getName() . "' is not a gloss"); } $inputSystemTag = (string) $sxeNode['lang']; $multiText->form($inputSystemTag, (string) $sxeNode->text); $this->projectModel->addInputSystem($inputSystemTag); // TODO InputSystems should extend ArrayOf (or Map) and become more useful. CP 2014-10 if (isset($inputSystems)) { // i.e. $inputSystems->ensureFieldHasInputSystem($inputSystemTag); $inputSystems->value($inputSystemTag); } }
/** * Import a LIFT file * * @param string $projectId * @param string $mediaType * @param string $tmpFilePath * @throws \Exception * @return \Api\Model\Shared\Command\UploadResponse */ public static function importLiftFile($projectId, $mediaType, $tmpFilePath) { if ($mediaType != 'import-lift') { throw new \Exception("Unsupported upload type."); } if (!$tmpFilePath) { throw new \Exception("Upload controller did not move the uploaded file."); } $file = $_FILES['file']; $fileName = $file['name']; $mergeRule = $_POST['mergeRule']; $skipSameModTime = $_POST['skipSameModTime']; $deleteMatchingEntry = $_POST['deleteMatchingEntry']; $finfo = finfo_open(FILEINFO_MIME_TYPE); $fileType = finfo_file($finfo, $tmpFilePath); finfo_close($finfo); $fileName = FileUtilities::replaceSpecialCharacters($fileName); $fileExt = false === ($pos = strrpos($fileName, '.')) ? '' : substr($fileName, $pos); $allowedTypes = array("text/xml", "application/xml"); $response = new UploadResponse(); if (in_array(strtolower($fileType), $allowedTypes) && in_array(strtolower($fileExt), self::$allowedLiftExtensions)) { // make the folders if they don't exist $project = new LexiconProjectModel($projectId); $folderPath = $project->getAssetsFolderPath(); FileUtilities::createAllFolders($folderPath); $importer = LiftImport::get()->merge($tmpFilePath, $project, $mergeRule, $skipSameModTime, $deleteMatchingEntry); $project->write(); $moveOk = true; if (!$project->liftFilePath || $mergeRule != LiftMergeRule::IMPORT_LOSES) { // cleanup previous files of any allowed extension $cleanupFiles = glob($folderPath . '/*[' . implode(', ', self::$allowedLiftExtensions) . ']'); foreach ($cleanupFiles as $cleanupFile) { @unlink($cleanupFile); } // move uploaded LIFT file from tmp location to assets $filePath = $folderPath . '/' . $fileName; $project->liftFilePath = $filePath; $project->write(); $moveOk = copy($tmpFilePath, $filePath); @unlink($tmpFilePath); } // construct server response if ($moveOk && $tmpFilePath) { $data = new ImportResult(); $data->path = $project->getAssetsRelativePath(); $data->fileName = $fileName; $data->stats = $importer->stats; $data->importErrors = $importer->getReport()->toFormattedString(); $response->result = true; } else { $data = new ErrorResult(); $data->errorType = 'UserMessage'; $data->errorMessage = "{$fileName} could not be saved to the right location. Contact your Site Administrator."; $response->result = false; } } else { $allowedExtensionsStr = implode(", ", self::$allowedLiftExtensions); $data = new ErrorResult(); $data->errorType = 'UserMessage'; if (count(self::$allowedLiftExtensions) < 1) { $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. No LIFT file formats are currently enabled, contact your Site Administrator."; } elseif (count(self::$allowedLiftExtensions) == 1) { $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. Ensure the file is a {$allowedExtensionsStr}."; } else { $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. Ensure the file is one of the following types: {$allowedExtensionsStr}."; } $response->result = false; } $response->data = $data; return $response; }
/** * * @param string $zipFilePath * @param LexiconProjectModel $projectModel * @param LiftMergeRule $mergeRule * @param boolean $skipSameModTime * @param boolean $deleteMatchingEntry * @throws \Exception * @return \Api\Model\Languageforge\Lexicon\LiftImport */ public function importZip($zipFilePath, $projectModel, $mergeRule = LiftMergeRule::IMPORT_WINS, $skipSameModTime = false, $deleteMatchingEntry = false) { $assetsFolderPath = $projectModel->getAssetsFolderPath(); $extractFolderPath = $assetsFolderPath . '/initialUpload_' . mt_rand(); $this->report = new ImportErrorReport(); $zipNodeError = new ZipImportNodeError(ZipImportNodeError::FILE, basename($zipFilePath)); try { self::extractZip($zipFilePath, $extractFolderPath); // Now find the .lift file in the uploaded zip $dirIter = new \RecursiveDirectoryIterator($extractFolderPath); $iterIter = new \RecursiveIteratorIterator($dirIter); $liftIter = new \RegexIterator($iterIter, '/\\.lift$/', \RegexIterator::MATCH); $liftFilePaths = array(); foreach ($liftIter as $file) { $liftFilePaths[] = $file->getPathname(); } if (empty($liftFilePaths)) { throw new \Exception("Uploaded file does not contain any LIFT data"); } if (count($liftFilePaths) > 1) { foreach (array_slice($liftFilePaths, 1) as $filename) { $zipNodeError->addUnhandledLiftFile(basename($filename)); } } // Import subfolders foreach (glob($extractFolderPath . '/*', GLOB_ONLYDIR) as $folderPath) { $folderName = basename($folderPath); switch ($folderName) { case 'pictures': case 'audio': case 'others': case 'WritingSystems': $assetsPath = $assetsFolderPath . "/" . $folderName; if (file_exists($folderPath) && is_dir($folderPath)) { FileUtilities::copyDirTree($folderPath, $assetsPath); } break; default: $zipNodeError->addUnhandledSubfolder($folderName); } } // Import first .lift file (only). $this->liftFilePath = $liftFilePaths[0]; $this->merge($this->liftFilePath, $projectModel, $mergeRule, $skipSameModTime, $deleteMatchingEntry); if ($zipNodeError->hasError()) { error_log($zipNodeError->toString() . "\n"); } foreach ($this->report->nodeErrors as $subnodeError) { $zipNodeError->addSubnodeError($subnodeError); } $this->report = new ImportErrorReport(); $this->report->nodeErrors[] = $zipNodeError; } catch (Exception $e) { if ($zipNodeError->hasError()) { error_log($zipNodeError->toString() . "\n"); } foreach ($this->report->nodeErrors as $subnodeError) { $zipNodeError->addSubnodeError($subnodeError); } $this->report = new ImportErrorReport(); $this->report->nodeErrors[] = $zipNodeError; throw new \Exception($e); } return $this; }
if ($site == 'scriptureforge') { $text1 = TextCommands::updateText($testProject, array('id' => '', 'title' => $constants['testText1Title'], 'content' => $constants['testText1Content'])); $text2 = TextCommands::updateText($testProject, array('id' => '', 'title' => $constants['testText2Title'], 'content' => $constants['testText2Content'])); $question1 = QuestionCommands::updateQuestion($testProject, array('id' => '', 'textRef' => $text1, 'title' => $constants['testText1Question1Title'], 'description' => $constants['testText1Question1Content'])); $question2 = QuestionCommands::updateQuestion($testProject, array('id' => '', 'textRef' => $text1, 'title' => $constants['testText1Question2Title'], 'description' => $constants['testText1Question2Content'])); $template1 = QuestionTemplateCommands::updateTemplate($testProject, array('id' => '', 'title' => 'first template', 'description' => 'not particularly interesting')); $template2 = QuestionTemplateCommands::updateTemplate($testProject, array('id' => '', 'title' => 'second template', 'description' => 'not entirely interesting')); $answer1 = QuestionCommands::updateAnswer($testProject, $question1, array('id' => '', 'content' => $constants['testText1Question1Answer']), $managerUserId); $answer1Id = array_keys($answer1)[0]; $answer2 = QuestionCommands::updateAnswer($testProject, $question2, array('id' => '', 'content' => $constants['testText1Question2Answer']), $managerUserId); $answer2Id = array_keys($answer2)[0]; $comment1 = QuestionCommands::updateComment($testProject, $question1, $answer1Id, array('id' => '', 'content' => $constants['testText1Question1Answer1Comment']), $managerUserId); $comment2 = QuestionCommands::updateComment($testProject, $question2, $answer2Id, array('id' => '', 'content' => $constants['testText1Question2Answer2Comment']), $managerUserId); } elseif ($site == 'languageforge') { // Set up LanguageForge E2E test envrionment here $testProjectModel = new LexiconProjectModel($testProject); $testProjectModel->addInputSystem("th-fonipa", "tipa", "Thai"); $testProjectModel->config->entry->fields[LexiconConfigObj::LEXEME]->inputSystems[] = 'th-fonipa'; $testProjectId = $testProjectModel->write(); // setup to mimic file upload $fileName = $constants['testEntry1']['senses'][0]['pictures'][0]['fileName']; $file = array(); $file['name'] = $fileName; $_FILES['file'] = $file; // put a copy of the test file in tmp $tmpFilePath = sys_get_temp_dir() . "/CopyOf{$fileName}"; copy(dirname(TestPath) . "/php/common/{$fileName}", $tmpFilePath); $response = LexUploadCommands::uploadImageFile($testProjectId, 'sense-image', $tmpFilePath); // cleanup tmp file if it still exists if (file_exists($tmpFilePath) and !is_dir($tmpFilePath)) { @unlink($tmpFilePath);