/** * Alrighty, now we get fancy! This examines the contents of the `rows` property, which is an array of data type * rows. Most Data Type has its own settings schema which we need to validate against. All this function does * is return whatever errors occurred; if everything checks out, it returns nothing. * @param $json * @return array */ private function validateDataTypeSettings($json) { $dataTypes = DataTypePluginHelper::getDataTypeList(Core::$dataTypePlugins); $schemaFiles = DataTypePluginHelper::getSchemaFiles($dataTypes); $dataTypeFolders = DataTypePluginHelper::getDataTypeFolders(Core::$dataTypePlugins); $rows = $json->rows; $numRows = count($rows); for ($i = 0; $i < $numRows; $i++) { $dataType = $rows[$i]->type; // check the Data Type folder name is valid. Note: we just compare against the list of all possible // Data Types, not those that have schemas. Not all Data Types have a schema: some, like Email, are simple // and have no settings if (!in_array($dataType, $dataTypeFolders)) { return array("error" => ErrorCodes::API_UNKNOWN_DATA_TYPE, "error_details" => "invalid `type` attribute: `{$dataType}`", "location" => "index {$i} of the `rows` array"); } // check the Data Type has a title if (!property_exists($rows[$i], "title")) { return array("error" => ErrorCodes::API_MISSING_DATA_TYPE_TITLE, "error_details" => "Missing `title` attribute", "location" => "index {$i} of the `rows` array"); } // if the schema file exists for the Data Type, validate against it if (array_key_exists($dataType, $schemaFiles)) { $schema = json_decode($schemaFiles[$dataType]); $json = property_exists($rows[$i], "settings") ? $rows[$i]->settings : json_decode("{}"); // verify the settings for this data type $result = Jsv4::validate($json, $schema); if ($result->valid) { continue; } // ladies and gentleman, we have an error! Return as much user friendly information to the user // to help them locate the problem return array("error" => ErrorCodes::API_INVALID_DATA_TYPE_JSON, "error_details" => "Invalid Data Type JSON `settings` content passed", "validation_error" => $result->errors[0]->message, "location" => "index {$i} of the `rows` array", "data_type" => $dataType); } } }
/** * This is used on the generate page to output raw markup into the page for use by the generator. * * @param array $params * @param object $smarty */ function smarty_function_data_type_options($params, &$smarty) { $resources = DataTypePluginHelper::getDataTypeResources(); for ($i = 0; $i < count($resources); $i++) { $currDataTypeResource = $resources[$i]; echo "<div id=\"gdDataTypeOptions_data-type-{$currDataTypeResource["folder"]}\">{$currDataTypeResource["options"]}</div>"; } }
/** * This is used on the generate page to output raw markup into the page for use by the generator. * * @param array $params * @param object $smarty */ function smarty_function_data_type_help($params, &$smarty) { $resources = DataTypePluginHelper::getDataTypeResources(); for ($i = 0; $i < count($resources); $i++) { $currDataTypeResource = $resources[$i]; echo "<div id=\"gdDataTypeHelp_data-type-{$currDataTypeResource["folder"]}\" class=\"hidden\">{$currDataTypeResource["help"]}</div>"; } }
/** * @param $environment "POST" or "API" * @param $data Either the contents of POST sent from the main data generator UI, or the contents of a JSON * POST sent to the API. */ public function __construct($environment, $data) { $this->genEnvironment = $environment; $this->dataTypes = DataTypePluginHelper::getDataTypeHash(Core::$dataTypePlugins); if ($environment === GEN_ENVIRONMENT_POST) { $this->initUIGenerator($data); } else if ($environment === GEN_ENVIRONMENT_API) { $this->initAPIGenerator($data); } }
/** * @param $postData array everything from the form post. The Generator is used in 3 different * contexts: for in-page generation, new tab/window or for prompting download of the data. */ public function __construct($postData) { $this->exportTarget = $postData["gdExportTarget"]; // inPage, newTab or promptDownload if ($this->exportTarget == "inPage") { $this->batchSize = $postData["gdBatchSize"]; $this->batchNum = $postData["gdCurrentBatchNum"]; } else { $this->batchSize = $postData["gdNumRowsToGenerate"]; $this->batchNum = 1; } $this->numResults = $postData["gdNumRowsToGenerate"]; if (Core::checkDemoMode() && !Core::checkIsLoggedIn()) { $maxDemoModeRows = Core::getMaxDemoModeRows(); if ($this->numResults > $maxDemoModeRows) { $this->numResults = $maxDemoModeRows; } } // always apply the max generated rows limitation. Technically this value could be lower than // the $maxDemoModeRows value above, but it's extremely unlikely & an acceptable restriction $maxGeneratedRows = Core::getMaxGeneratedRows(); if ($this->numResults > $maxGeneratedRows) { $this->numResults = $maxGeneratedRows; } $this->countries = isset($postData["gdCountries"]) ? $postData["gdCountries"] : array(); $this->dataTypes = DataTypePluginHelper::getDataTypeHash(Core::$dataTypePlugins); $this->postData = $postData; if (isset($postData["configurationID"])) { $this->configurationID = $postData["configurationID"]; } // make a note of whether this batch is the first / last. This is useful information for the // Export Types to know whether to output special content at the top or bottom $this->isFirstBatch = $this->batchNum == 1; $this->isLastBatch = $this->batchNum * $this->batchSize >= $this->numResults; $this->currentBatchFirstRow = ($this->batchNum - 1) * $this->batchSize + 1; $this->currentBatchLastRow = $this->currentBatchFirstRow + $this->batchSize > $this->numResults ? $this->numResults : $this->currentBatchFirstRow + $this->batchSize - 1; // figure out what we're going to need to generate $this->createDataSetTemplate($postData); // now we farm out the work of data generation to the selected Export Type $exportTypes = Core::$exportTypePlugins; $selectedExportType = null; foreach ($exportTypes as $currExportType) { if ($currExportType->getFolder() != $postData["gdExportType"]) { continue; } $this->exportType = $currExportType; break; } // set the value of isCompressionRequired if ($postData["gdExportTarget"] == "promptDownload" && $postData["gdExportTarget_promptDownload_zip"] == "doZip") { $this->isCompressionRequired = true; } }
/** * create a /cache/appStart-unminified.js file. Grunt will handle the renaming of the file and the generation * of the /cache/minifiedResourcePaths.php file. */ public static function createAppStartFile() { $exportTypes = Core::$exportTypePlugins; $exportTypeJSModules = ExportTypePluginHelper::getExportTypeJSResources($exportTypes, "string"); $dataTypes = DataTypePluginHelper::getDataTypeList(Core::$dataTypePlugins); $dataTypeJSModules = DataTypePluginHelper::getDataTypeJSResources($dataTypes, "string"); $js = 'require(["manager","generator","accountManager",' . $exportTypeJSModules . "," . $dataTypeJSModules . ',"pageInit"], function(manager) {manager.start(); });'; $file = realpath(__DIR__ . "/../../cache/") . "/appStartGenerated.js"; if (is_file($file)) { unlink($file); } if (file_put_contents($file, $js)) { return true; } else { return false; } }
/** * Used in lang.php to return the current language strings for the Core, data types and * export types. */ public function getLanguageStringsJS() { $lines = array(); while (list($key, $value) = each($this->currentLanguageStrings)) { if (is_string($value)) { $lines[] = "\"{$key}\":\"" . addslashes($value) . "\""; } } // Export Types $exportTypeLines = array(); $exportTypes = Core::$exportTypePlugins; if (is_array($exportTypes)) { foreach ($exportTypes as $exportType) { $moduleFolder = $exportType->folder; if (!isset($exportType->L)) { continue; } $currModuleLines = array(); while (list($key, $value) = each($exportType->L)) { $currModuleLines[] = "\"{$key}\":\"" . addslashes($value) . "\""; } $exportTypeLines[] = " \"{$moduleFolder}\": {" . implode(",\n", $currModuleLines) . "}"; } $lines[] = "\"exportTypePlugins\": {\n" . implode(",\n", $exportTypeLines) . "\n}"; } // Data Types $dataTypeLines = array(); $dataTypesByGroup = Core::$dataTypePlugins; if (is_array($dataTypesByGroup)) { $dataTypes = DataTypePluginHelper::getDataTypeList($dataTypesByGroup); foreach ($dataTypes as $dataType) { $moduleFolder = $dataType->folder; if (!isset($dataType->L)) { continue; } $currModuleLines = array(); while (list($key, $value) = each($dataType->L)) { $currModuleLines[] = "\"{$key}\":\"" . addslashes($value) . "\""; } $dataTypeLines[] = " \"{$moduleFolder}\": {" . implode(",\n", $currModuleLines) . "}"; } $lines[] = "\"dataTypePlugins\": {\n" . implode(",\n", $dataTypeLines) . "\n}"; } return "var L={\n" . implode(",\n", $lines) . "}"; }
/** * @param array $postdata everything from the form post. The Generator is used in 3 different * contexts: for in-page generation, new tab/window or for prompting download of the data. */ public function __construct($postData) { $this->exportTarget = $postData["gdExportTarget"]; // inPage, newTab or promptDownload if ($this->exportTarget == "inPage") { $this->batchSize = $postData["gdBatchSize"]; $this->batchNum = $postData["gdCurrentBatchNum"]; } else { $this->batchSize = $postData["gdNumRowsToGenerate"]; $this->batchNum = 1; } $this->numResults = $postData["gdNumRowsToGenerate"]; if (Core::checkDemoMode()) { if ($this->numResults > 500) { $this->numResults = 500; } } $this->countries = isset($postData["gdCountries"]) ? $postData["gdCountries"] : array(); $this->dataTypes = DataTypePluginHelper::getDataTypeHash(Core::$dataTypePlugins); $this->postData = $postData; if (isset($postData["configurationID"])) { $this->configurationID = $postData["configurationID"]; } // make a note of whether this batch is the first / last. This is useful information for the // Export Types to know whether to output special content at the top or bottom $this->isFirstBatch = $this->batchNum == 1; $this->isLastBatch = $this->batchNum * $this->batchSize >= $this->numResults; $this->currentBatchFirstRow = ($this->batchNum - 1) * $this->batchSize + 1; $this->currentBatchLastRow = $this->currentBatchFirstRow + $this->batchSize > $this->numResults ? $this->numResults : $this->currentBatchFirstRow + $this->batchSize - 1; // figure out what we're going to need to generate $this->createDataSetTemplate($postData); // now we farm out the work of data generation to the selected Export Type $exportTypes = Core::$exportTypePlugins; $selectedExportType = null; foreach ($exportTypes as $currExportType) { if ($currExportType->getFolder() != $postData["gdExportType"]) { continue; } $this->exportType = $currExportType; break; } }
/** * Called by Core::init(), this initializes Core::$dataTypePlugins. * @access private */ private static function initDataTypes($runtimeContext) { if (!Core::$settingsFileExists) { return; } // parse the Data Types folder and identify those plugins that are available self::$dataTypePlugins = DataTypePluginHelper::getDataTypePlugins($runtimeContext); }
private function setDataTypes() { $index = $this->post["index"]; $groupedDataTypes = DataTypePluginHelper::getDataTypePlugins("installationDatabaseReady", false); $dataTypes = DataTypePluginHelper::getDataTypeList($groupedDataTypes); if ($index >= count($dataTypes)) { $this->response["success"] = 1; $this->response["content"] = ""; $this->response["isComplete"] = true; } else { // attempt to install this data type $currDataType = $dataTypes[$index]; $this->response["dataTypeName"] = $currDataType->getName(); $this->response["dataTypeFolder"] = $currDataType->folder; $this->response["isComplete"] = false; try { list($success, $content) = $currDataType->install(); $this->response["success"] = $success; $this->response["content"] = $content; } catch (Exception $e) { $this->response["success"] = false; $this->response["content"] = "Unknown error."; } } }
// if need be, redirect to the install instructions page Utils::maybeShowInstallationPage(); if (!Core::checkIsLoggedIn() && !Core::checkAllowMultiUserAnonymousUse()) { header("location: login.php#t1"); exit; } // start piecing together all the various info we need to pass to the page $pageParams = array(); $settings = Settings::getSettings(); $exportTypes = Core::$exportTypePlugins; $exportTypeAdditionalSettings = ExportTypePluginHelper::getExportTypeAdditionalSettingsHTML($exportTypes); $dataTypes = DataTypePluginHelper::getDataTypeList(Core::$dataTypePlugins); $exportTypeJSModules = ExportTypePluginHelper::getExportTypeJSResources($exportTypes, "string"); $exportTypeCssIncludes = ExportTypePluginHelper::getExportTypeCSSIncludes($exportTypes); $dataTypeJSModules = DataTypePluginHelper::getDataTypeJSResources($dataTypes, "string"); $dataTypeCssIncludes = DataTypePluginHelper::getDataTypeCSSIncludes($dataTypes); $cssIncludes = $exportTypeCssIncludes . "\n" . $dataTypeCssIncludes; // used in the settings page $pageParams["allCountryPlugins"] = Core::$countryPlugins; $pageParams["allExportTypes"] = $exportTypes; $pageParams["groupedDataTypes"] = Core::$dataTypePlugins; $pageParams["allDataTypes"] = $dataTypes; $pageParams["allTranslations"] = Core::$translations->getList(); $useMinifiedResources = Core::isUsingMinifiedResources(); $pageParams["useMinifiedResources"] = $useMinifiedResources; if ($useMinifiedResources) { $pageParams["minifiedResourcePaths"] = Minification::getMinifiedResourcePaths(); } $pageParams["dataTypeJSModules"] = $dataTypeJSModules; $pageParams["exportTypeJSModules"] = $exportTypeJSModules; $pageParams["exportTypeAdditionalSettings"] = $exportTypeAdditionalSettings;
/** * AjaxRequest objects are automatically processed when they are created, based on the unique $action * value. The result of the call is stored in $response to be handled however you need (e.g. output * as JSON, XML etc) - or an Exception is thrown if something went wrong. Exceptions are used SOLELY for * program errors: not for user-entry errors. */ public function __construct($action, $post = array()) { if (empty($action)) { throw new Exception("no_action_specified"); return; } $this->action = $action; $post = Utils::sanitize($post); switch ($this->action) { // ------------------------------------------------------------------------------------ // INSTALLATION // ------------------------------------------------------------------------------------ // a fresh install assumes it's a blank slate: no database tables, no settings file case "installationTestDbSettings": Core::init("installation"); list($success, $content) = Database::testDbSettings($post["dbHostname"], $post["dbName"], $post["dbUsername"], $post["dbPassword"]); $this->response["success"] = $success; $this->response["content"] = $content; break; case "installationCreateSettingsFile": Core::init("installation"); if (Core::checkSettingsFileExists()) { $this->response["success"] = 0; $this->response["content"] = "Your settings.php file already exists."; return; } else { list($success, $content) = Installation::createSettingsFile($post["dbHostname"], $post["dbName"], $post["dbUsername"], $post["dbPassword"], $post["dbTablePrefix"]); $this->response["success"] = $success; $this->response["content"] = $content; } break; case "installationCreateDatabase": Core::init("installation_db_ready"); list($success, $content) = Installation::createDatabase(); if (!$success) { $this->response["success"] = 0; $this->response["content"] = $content; return; } // always create the administrator account. If the user chose the anonymous setup, all values // will be blank and all configurations will be associated with this (anonymous) user $adminAccount = array("accountType" => "admin", "firstName" => $post["firstName"], "lastName" => $post["lastName"], "email" => $post["email"], "password" => $post["password"]); Account::createAccount($adminAccount); // make note of the fact that we've passed this installation step Settings::setSetting("userAccountSetup", $post["userAccountSetup"]); Settings::setSetting("installationStepComplete_Core", "yes"); $this->response["success"] = 1; $this->response["content"] = ""; break; case "installationDataTypes": Core::init("installation_db_ready"); $index = $post["index"]; $groupedDataTypes = DataTypePluginHelper::getDataTypePlugins("installion_db_ready", false); $dataTypes = DataTypePluginHelper::getDataTypeList($groupedDataTypes); if ($index >= count($dataTypes)) { $this->response["success"] = 1; $this->response["content"] = ""; $this->response["isComplete"] = true; } else { // attempt to install this data type $currDataType = $dataTypes[$index]; $this->response["dataTypeName"] = $currDataType->getName(); $this->response["dataTypeFolder"] = $currDataType->folder; $this->response["isComplete"] = false; try { list($success, $content) = $currDataType->install(); $this->response["success"] = $success; $this->response["content"] = $content; } catch (Exception $e) { $this->response["success"] = false; $this->response["content"] = "Unknown error."; } } break; case "installationSaveDataTypes": Core::init("installation_db_ready"); $folders = $post["folders"]; $response = Settings::setSetting("installedDataTypes", $folders); $this->response["success"] = $response["success"]; $this->response["content"] = $response["errorMessage"]; break; case "installationExportTypes": Core::init("installation_db_ready"); $index = $post["index"]; $exportTypes = ExportTypePluginHelper::getExportTypePlugins("installation_db_ready", false); if ($index >= count($exportTypes)) { $this->response["success"] = 1; $this->response["content"] = ""; $this->response["isComplete"] = true; } else { // attempt to install this data type $currExportType = $exportTypes[$index]; $this->response["exportTypeName"] = $currExportType->getName(); $this->response["exportTypeFolder"] = $currExportType->folder; $this->response["isComplete"] = false; try { list($success, $content) = $currExportType->install(); $this->response["success"] = $success; $this->response["content"] = $content; } catch (Exception $e) { $this->response["success"] = false; $this->response["content"] = "Unknown error."; } } break; case "installationSaveExportTypes": Core::init("installation_db_ready"); $folders = $post["folders"]; $response = Settings::setSetting("installedExportTypes", $folders); $this->response["success"] = $response["success"]; $this->response["content"] = $response["errorMessage"]; break; case "installationCountries": Core::init("installation_db_ready"); $index = $post["index"]; $countryPlugins = CountryPluginHelper::getCountryPlugins(false); if ($index >= count($countryPlugins)) { $this->response["success"] = 1; $this->response["content"] = ""; $this->response["isComplete"] = true; } else { // attempt to install this data type $currCountryPlugin = $countryPlugins[$index]; $this->response["countryName"] = $currCountryPlugin->getName(); $this->response["countryFolder"] = $currCountryPlugin->folder; $this->response["isComplete"] = false; try { // always run the uninstallation function first to ensure any old data is all cleared out $currCountryPlugin->uninstall(); list($success, $content) = $currCountryPlugin->install(); $this->response["success"] = $success; $this->response["content"] = $content; } catch (Exception $e) { $this->response["success"] = false; $this->response["content"] = "Unknown error."; } } break; case "installationSaveCountries": Core::init("installation_db_ready"); $folders = $post["folders"]; $response = Settings::setSetting("installedCountries", $folders); $response = Settings::setSetting("installationComplete", "yes"); $this->response["success"] = $response["success"]; $this->response["content"] = $response["errorMessage"]; break; case "generateInPage": Core::init("generation"); $gen = new Generator($_POST); $response = $gen->generate(); $this->response["success"] = $response["success"]; $this->response["content"] = $response["content"]; $this->response["isComplete"] = $response["isComplete"]; break; // ------------------------------------------------------------------------------------ // USER ACCOUNTS // ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------ // USER ACCOUNTS // ------------------------------------------------------------------------------------ case "getAccount": Core::init(); $response = Core::$user->getAccount(); $this->response["success"] = true; $this->response["content"] = $response; break; case "getUsers": Core::init(); $response = Core::$user->getUsers(); $this->response["success"] = $response["success"]; if (isset($response["accounts"])) { $this->response["content"] = $response["accounts"]; } break; case "createAccount": Core::init(); if (!Core::checkIsLoggedIn()) { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::NOT_LOGGED_IN; } else { if (Core::$user->getAccountType() != "admin") { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::NON_ADMIN; } else { $accountInfo = $post; $accountInfo["accountType"] = "user"; $response = Account::createAccount($accountInfo); $this->response["success"] = true; } } break; case "deleteAccount": Core::init(); if (!Core::checkIsLoggedIn()) { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::NOT_LOGGED_IN; } else { if (Core::$user->getAccountType() != "admin") { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::NON_ADMIN; } else { $accountID = $post["accountID"]; $response = Core::$user->deleteAccount($accountID); $this->response["success"] = true; } } break; // updates the current logged in user's info // updates the current logged in user's info case "updateAccount": Core::init(); if (!Core::checkIsLoggedIn()) { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::NOT_LOGGED_IN; } else { if (Core::$user->isAnonymous()) { $this->response["success"] = false; $this->response["errorCode"] = ErrorCodes::INVALID_REQUEST; } else { $accountID = $post["accountID"]; $this->response = Core::$user->updateAccount($accountID, $post); } } break; case "saveConfiguration": Core::init(); $response = Core::$user->saveConfiguration($post); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; if (isset($response["lastUpdated"])) { $this->response["lastUpdated"] = $response["lastUpdated"]; } break; case "deleteDataSets": Core::init(); $configurationIDs = $post["configurationIDs"]; $response = Core::$user->deleteConfigurations($configurationIDs); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; break; case "saveDataSetVisibilityStatus": Core::init(); $configurationID = $post["configurationID"]; $status = $post["status"]; $time = $post["time"]; $response = Core::$user->saveDataSetVisibilityStatus($configurationID, $status, $time); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; if (isset($response["newStatus"])) { $this->response["newStatus"] = $response["newStatus"]; } break; case "getPublicDataSet": Core::init(); $configurationID = $post["dataSetID"]; $response = Core::$user->getPublicDataSet($configurationID); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; break; case "login": Core::init(); $email = $post["email"]; $password = $post["password"]; $response = Account::login($email, $password); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; break; // for single // for single case "logout": Core::init(); if (!Core::checkIsLoggedIn()) { $this->response["success"] = true; } else { if (!Core::$user->isAnonymous()) { Core::$user->logout(); $this->response["success"] = true; } } break; case "resetPassword": Core::init(); $email = $post["email"]; $response = Account::resetPassword($email); $this->response["success"] = $response["success"]; $this->response["content"] = $response["message"]; break; } }
private function installDataTypes() { $groupedDataTypes = DataTypePluginHelper::getDataTypePlugins("installationDatabaseReady", false); $L = Core::$language->getCurrentLanguageStrings(); $hasError = false; $response = array(); $count = 0; $folders = array(); while (list($group_name, $dataTypes) = each($groupedDataTypes)) { $data = array(); foreach ($dataTypes as $currDataType) { try { list($success, $content) = $currDataType->install(); if (!$success) { $hasError = true; break; } $folder = $currDataType->getFolder(); $data[] = array("name" => $currDataType->getName(), "folder" => $folder, "desc" => $currDataType->getDesc()); $folders[] = $folder; $count++; } catch (Exception $e) { $hasError = true; break; } } // organized in this data structure because objects lose their order $response[] = array("group_name" => $L[$group_name], "data_types" => $data); } // need error handling here Settings::setSetting("installedDataTypes", implode(",", $folders)); $this->response["success"] = !$hasError; $this->response["content"] = array("total" => $count, "results" => $response); }