Files
namaste/utilities/migrateData.php
gramps 373ebc8c93 Archive: Namaste PHP AMQP framework v1.0 (2017-2020)
952 days continuous production uptime, 40k+ tp/s single node.
Original corpo Bitbucket history not included — clean archive commit.
2026-04-05 09:49:30 -07:00

1591 lines
81 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* DB-43: HTML-based Migration
*
*
*/
$errorList = [];
const REMOTE_COLLECTION_NAME = 'remoteCollectionName';
const REMOTE_START_DATE = 'remoteStartDate';
const REMOTE_END_DATE = 'remoteEndDate';
const REMOTE_AUTH_SOURCE = 'remoteAuthDB';
const NA = 'N/A';
const REMOTE_RECORD_COUNT = 'remoteRecordCount';
const SOURCE_USER = 'User';
const SOURCE_NAMASTE = 'Namaste';
const NAMASTE_HOST = 'namasteHost';
const NAMASTE_PORT = 'namastePort';
const NAMASTE_SCHEMA = 'namasteSchema';
const NAMASTE_USER = 'namasteUser';
const NAMASTE_PASS = 'namastePass';
const NAMASTE_DB = 'namasteDB';
const NAMASTE_TABLE = 'namasteTable';
const NAMASTE_CHARSET = 'namasteCharset';
const NAMASTE_AUTH_SOURCE = 'namasteAuthSource';
const NAMASTE_REPL_SET_NAME = 'namasteReplSetName';
const NAMASTE_REPL_SET_LIST = 'namasteReplSetList';
const NAMASTE_INSTANCE_TYPE = 'namasteInstanceType';
const NAMASTE_SHARD_SERVER = 'namasteShardServer';
const REMOTE_SCHEMA = 'remoteSchema';
const REMOTE_SHARD_SERVER = 'shardServer';
// load the light-version of the framework
try {
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc');
} catch (ParseError | Throwable $p) {
$errorList[] = ERROR_TYPE_EXCEPTION_PARSE . $p->getMessage();
}
/**
* remoteMongoConnect() -- file method
*
* This method will attempt to make a connection to a remote mongo service, and ping the admin db, to validate the
* resource's connection parameters.
*
* There are four input parameters to the method:
*
* $mongoDSN - string value containing the mongo Data Source Name
* $remoteMongoAuthSource - string value containing the db name the user will authenticate against
* $migErrors - call-by-reference array parameter, container for error messages
* $mongoOptions - optional array parameter for mongo resource-connection options
*
* The method will connect to the resource, authenticating against the named collection, and ping the admin service
* to verify that the remote connection is valid an accepting connection requests.
*
* The method returns a boolean value to indicate success or failure.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $mongoDSN
* @param string $remoteMongoAuthSource
* @param array $migErrors
* @param array|null $mongoOptions
* @return bool
*
*
* HISTORY:
* ========
* 10-01-18 mks DB-43: original coding
*
*/
function remoteMongoConnect(string $mongoDSN, string $remoteMongoAuthSource, array &$migErrors, array $mongoOptions = null): bool
{
$remoteMongoConnection = false;
// now that we have the DSN built, test the connection by connecting and pinging the authDB service
try {
if (isset($mongoOptions) and is_array($mongoOptions))
$manager = new MongoDB\Driver\Manager($mongoDSN, $mongoOptions);
else
$manager = new MongoDB\Driver\Manager($mongoDSN);
$command = new MongoDB\Driver\Command(['ping' => 1]);
$results = $manager->executeCommand($remoteMongoAuthSource, $command);
$results = $results->toArray();
$remoteMongoConnection = ($results[0]->ok == 1);
} catch (MongoDB\Driver\Exception\ConnectionException |
MongoDB\Driver\Exception\InvalidArgumentException |
MongoDB\Driver\Exception\RuntimeException |
MongoDB\Driver\Exception\Exception $e) {
$migErrors[] = ERROR_MONGO_CONNECT;
$migErrors[] = $e->getMessage();
}
return $remoteMongoConnection;
}
/**
* remoteMysqlConnect() - file method
*
* This method attempts to make a connection to a remote mysql resource and, if the connection is successful, then
* submits a simple query to validate that resource.
*
* There are seven input parameters passed to this method:
*
* $PDOConnectString - string value that has the PDO connect string... self-documenting, yo
* $user - string value containing the authenticating user's account name
* $pass - string value containing the authenticating user's password
* $tableName - string value containing the table we'll pull from/test
* $pdoAttributes - array value containing PDO specific attributes passed to the resource constructor
* $migErrors - array, call-by-reference value, that will implicitly return any error messages to the calling client
* $rowCount - integer, call-by-reference value, that will implicitly return the row count of the named table
*
* The method returns a boolean value indicating if the remote connection was successful *and* if we were able a
* row count from the targeted table.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $PDOConnectString
* @param string $user
* @param string $pass
* @param string $tableName
* @param array $pdoAttributes
* @param array $migErrors
* @param int $rowCount
* @return bool
*
*
* HISTORY:
* ========
* 10-01-18 mks DB-43: original coding
*
*/
function remoteMysqlConnect(string $PDOConnectString, string $user, string $pass, string $tableName, array $pdoAttributes, array &$migErrors, int &$rowCount): bool
{
$resRemote = null;
$queryResults = null;
try {
$resRemote = new PDO($PDOConnectString, $user, $pass, $pdoAttributes);
$query = 'SELECT COUNT(1) AS numRecs FROM ' . $tableName;
foreach ($resRemote->query($query) as $results)
$queryResults = $results;
if (is_array($queryResults) and isset($queryResults[STRING_NUM_RECS])) $rowCount = $queryResults[STRING_NUM_RECS];
return true;
} catch (PDOException | Throwable $e) {
$msg = basename(__FILE__) . COLON_NS . __LINE__ . COLON . ERROR_PDO_CONNECT;
$migErrors[] = $msg;
$migErrors[] = $e->getMessage();
}
return false;
}
/**
* validateMigrationDate() -- file method
*
* This method validates a date string, passed as the first input parameter, retrieved from the datePicker widget. The
* second input parameter is an optional date-format string.
*
* The method returns a boolean indicating if the date is valid. If you change the date format in date-picker, then
* you'll need to update how this method is called by using the optional second parameter.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $date - string containing the date string returned by the date-picker widget
* @param string $dateFormat - format of the date string returned by the date-picker widget
* @return bool
*
*
* HISTORY:
* ========
* 10-02-18 mks DB-43: original coding
*
*/
function validateMigrationDate(string $date, $dateFormat = 'j F, Y'): bool
{
$d = DateTime::createFromFormat($dateFormat, $date);
return $d && $d->format($dateFormat) === $date;
}
// lvar initialization
$rc = 0;
$savedData = [];
$templateName = STRING_UNKNOWN;
$cfgRemote = [];
$cfgNamaste = null;
$cfgMig = null;
$disableNamasteSchema = false;
$haveTemplateNameError = false;
$g2g = false;
// squelch IDE warnings
$defaultRemoteMysql = $defaultRemoteMongo = $defaultNamasteMongo = $defaultNamasteMysql = null;
$remoteMongoAuthSource = $remoteMongoURI = $remoteMongoPort = $remoteMongoCollection = $remoteMongoPassword = null;
$remoteMysqlURI = $remoteMysqlPort = $remoteMysqlLogin = $remoteMysqlPassword = null;
$remoteMysqlTableName = $remoteMysqlStartDate = $remoteMysqlEndDate = null;
$importDeletes = $importPartials = $testMode = $validateRemoteSource = 0;
$submitLTO = 0;
$startMigration = 0;
$beginMigration = 0;
$remoteMongoDatabase = $remoteMysqlDBName = '';
$haveValidTemplate = false;
$haveValidSource = false;
$haveValidDestination = false;
$haveLogin = false;
$havePassword = false;
$haveAuthDB = false;
$haveValidSource = false;
$haveValidDestination = false;
$migErrors = [];
$mongoOptions = [];
$remoteSchema = '';
$namasteSchema = '';
$patternUriPort = '/(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])(:[0-9]+)?$/';
// load the migration defaults from the Namaste XML structure
if (!empty(gasConfig::$settings[CONFIG_MIGRATION])) {
$cfgMig = gasConfig::$settings[CONFIG_MIGRATION];
} else {
// fatal error -- rudely die
exit (CONFIG_XML_LOAD);
}
// production check: are Login and Password required?
$lpRequired = (gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] == ENV_PRODUCTION);
// load list of valid template names
try {
$templateNames = gasStatic::loadValidTemplateNames();
} catch (TypeError $t) {
exit ($t->getMessage());
}
/*
* This is a critical section - when the form self-posts, it saves all variables into a single associative array
* that's keyed by the variable name. This variable is stored as a base64-encoded json string as a hidden field.
*
* New variables will override the variables in this array but, once processing is complete, this array becomes
* the "authority" for all form-control variables in the HTML.
*
*/
if (!empty($_POST)) {
// first - pull and remove the savedData from the $_POST if available
if (!empty($_POST['savedData'])) {
// radio buttons are handled separately
$rbs = ['defaultNamasteMongo', 'defaultNamasteMysql', 'defaultRemoteMongo', 'defaultRemoteMysql'];
$savedData = json_decode(base64_decode(htmlspecialchars(stripslashes($_POST['savedData']))), true);
unset($_POST['savedData']);
}
// next, loop through the rest of the $_POST and extract into identically-named PHP vars
foreach ($_POST as $key => $value) {
if (in_array($key, $rbs)) { // if the post var is a radio-button
$$key = boolval($value); // convert to a boolean value
$savedData[$key] = boolval($value);
} else {
$savedData[$key] = htmlspecialchars(strip_tags($value)); // stash in saved-var container
$$key = htmlspecialchars(strip_tags($value)); // otherwise, everything else is a string
}
}
}
/*
* once the form variables, and the POST vars, are loaded and saved, we need to determine which event triggered
* the post and take the action appropriate to the event...
*/
// logically, the first event that should be fired on a new page load is the template selection modal...
// The template has to be validated (contains a migration section) and the information in the valid template
// subsequently also populates the destination (Namaste) configuration...
// Also, do NOT process the template name if we clicked the validate-remote-source button...
if (isset($_POST['templateName']) and $validateRemoteSource != 1) {
$templateName = htmlspecialchars(stripslashes($_POST['templateName']));
$tName = STRING_CLASS_GAT . htmlspecialchars(stripslashes($_POST['templateName'])) . STRING_CLASS_FILE_EXT;
$tObjName = STRING_CLASS_GAT . htmlspecialchars(stripslashes($_POST['templateName']));
$tFile = $templateDir . SLASH . $tName;
// validate that the template file exists
if (!file_exists($tFile)) {
$errorList[] = ERROR_TEMPLATE_FILE_404 . $templateName;
$templateName = $errorList;
$haveTemplateNameError = true;
} else {
// we have a template file - set the Namaste (destination) and source schema data based on the selected-template
try {
/** @var gatProdRegistrations $tObj */
$tObj = new $tObjName();
// ensure that the template has a valid migration section
if (!isset($tObj->migrationMap) or !is_array($tObj->migrationMap)) {
$errorList[] = ERROR_MIGRATION_MAP_404;
$templateName = STRING_UNKNOWN;
} else {
$savedData['templateName'] = $templateName;
$pdoConfig = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO][CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_MASTER];
$mdbConfig = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB][CONFIG_DATABASE_MONGODB_APPSERVER];
// load the destination configuration
switch ($tObj->schema) {
case TEMPLATE_DB_PDO :
$defaultNamasteMysql = true;
$savedData[NAMASTE_HOST] = $pdoConfig[CONFIG_DATABASE_PDO_HOSTNAME];
$savedData[NAMASTE_PORT] = $pdoConfig[CONFIG_DATABASE_PDO_PORT];
$savedData[NAMASTE_SCHEMA] = STRING_MYSQL;
$savedData[NAMASTE_USER] = $pdoConfig[CONFIG_DATABASE_PDO_USERNAME];
$savedData[NAMASTE_PASS] = $pdoConfig[CONFIG_DATABASE_PDO_PASSWORD];
$savedData[NAMASTE_DB] = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . $pdoConfig[CONFIG_DATABASE_PDO_DB];
$savedData[NAMASTE_TABLE] = $tObj->collection;
$savedData[NAMASTE_CHARSET] = $pdoConfig[CONFIG_DATABASE_PDO_CHARSET];
break;
case TEMPLATE_DB_MONGO :
$defaultNamasteMongo = true;
$savedData[NAMASTE_HOST] = $mdbConfig[CONFIG_DATABASE_MONGODB_HOST];
$savedData[NAMASTE_PORT] = $mdbConfig[CONFIG_DATABASE_MONGODB_PORT];
$savedData[NAMASTE_SCHEMA] = STRING_MONGO;
$savedData[NAMASTE_USER] = $mdbConfig[CONFIG_DATABASE_MONGODB_USER];
$savedData[NAMASTE_PASS] = $mdbConfig[CONFIG_DATABASE_MONGODB_PASSWORD];
$savedData[NAMASTE_DB] = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $mdbConfig[CONFIG_DATABASE_MONGODB_DB_NAME];
$savedData[NAMASTE_TABLE] = $tObj->collection;
$savedData[NAMASTE_AUTH_SOURCE] = $mdbConfig[CONFIG_DATABASE_MONGODB_AUTH_SOURCE];
if ($mdbConfig[NAMASTE_INSTANCE_TYPE] == CONFIG_INSTANCE_TYPE_SHARD) {
$savedData[NAMASTE_SHARD_SERVER] = $mdbConfig[CONFIG_DATABASE_MONGODB_SHARDING_MONGOS_NODES];
} elseif ($mdbConfig[NAMASTE_INSTANCE_TYPE] == CONFIG_INSTANCE_TYPE_REPL) {
$savedData[NAMASTE_REPL_SET_NAME] = $mdbConfig[CONFIG_DATABASE_MONGODB_REPLSET_NAME];
foreach ($mdbConfig[CONFIG_DATABASE_MONGODB_ADMIN_REPLSET_SET] as $node)
$savedData[MONGO_REPL_SET_LIST][] = $node;
}
break;
case TEMPLATE_DB_DDB :
$errorList[] = sprintf(ERROR_SCHEMA_NOT_SUPPORTED, TEMPLATE_DB_DDB);
break;
default :
$errorList[] = sprintf(ERROR_MIGRATION_SCHEMA_UNKNOWN, $tObj->schema);
break;
}
// load the source configuration
if (!isset($tObj->migrationSourceSchema) or empty($tObj->migrationSourceSchema)) {
$errorList[] = ERROR_WF_MIG_TEMPLATE_SCHEMA_404;
} else {
switch ($tObj->migrationSourceSchema) {
case STRING_MYSQL :
$defaultRemoteMysql = true;
$haveValidTemplate = true;
$cfgRemote = gasConfig::$settings[CONFIG_MIGRATION][CONFIG_SCHEMA_MYSQL];
$savedData[STRING_HOST] = $cfgRemote[STRING_HOST];
$savedData[STRING_PORT] = $cfgRemote[STRING_PORT];
$savedData[REMOTE_SCHEMA] = STRING_MYSQL;
$savedData[STRING_USER] = $cfgRemote[STRING_USER];
$savedData[STRING_PASS] = $cfgRemote[STRING_PASS];
$savedData[CONFIG_DATABASE] = $cfgRemote[CONFIG_DATABASE];
$savedData[CONFIG_DATABASE_PDO_CHARSET] = $cfgRemote[CONFIG_DATABASE_PDO_CHARSET];
break;
case STRING_MONGO :
$defaultRemoteMongo = true;
$haveValidTemplate = true;
$cfgRemote = gasConfig::$settings[CONFIG_MIGRATION][CONFIG_SCHEMA_MONGO];
$savedData[STRING_HOST] = $cfgRemote[STRING_HOST];
$savedData[STRING_PORT] = $cfgRemote[STRING_PORT];
$savedData[REMOTE_SCHEMA] = STRING_MONGO;
$savedData[STRING_USER] = $cfgRemote[STRING_USER];
$savedData[STRING_PASS] = $cfgRemote[STRING_PASS];
$savedData[STRING_AUTH_SRC] = $cfgRemote[CONFIG_DATABASE_MONGODB_AUTH_SOURCE];
$savedData[CONFIG_DATABASE] = $cfgRemote[CONFIG_DATABASE];
if ($cfgRemote[CONFIG_INSTANCE_TYPE] == CONFIG_INSTANCE_TYPE_SHARD) {
$savedData[REMOTE_SHARD_SERVER] = $cfgRemote[CONFIG_DATABASE_MONGODB_SHARDING_MONGOS_NODES];
} elseif ($cfgRemote[CONFIG_INSTANCE_TYPE] == CONFIG_INSTANCE_TYPE_REPL) {
$savedData[MONGO_REPL_SET] = $cfgRemote[CONFIG_DATABASE_MONGODB_REPLSET_NAME];
foreach ($cfgRemote[CONFIG_DATABASE_MONGODB_REPLSET_DSN] as $value)
$savedData[MONGO_REPL_SET_LIST][] = $value;
}
break;
default :
$errorList[] = ERROR_WF_MIG_REMOTE_SCHEMA;
break;
}
}
}
if (is_object($tObj)) $tObj->__destruct();
unset($tObj);
} catch (Throwable $t) {
$templateName = STRING_UNKNOWN;
$errorList[] = $t->getMessage();
}
}
}
// next - see if any of the default (Namaste XML) configurations have been selected and validate...
if ($defaultRemoteMysql and $defaultRemoteMysql === $defaultRemoteMongo)
$errorList[] = ERROR_HTML_MIG_FORM_ERROR . ' Remote RBs are the same';
if ($defaultNamasteMysql and $defaultNamasteMysql === $defaultNamasteMongo)
$errorList[] = ERROR_HTML_MIG_FORM_ERROR . ' Namaste RBs are the same';
// if one of the RBs was clicked, assign the default (XML) configuration
if ($defaultRemoteMysql) {
$cfgRemote = $cfgMig[STRING_MYSQL];
$savedData['defaultRemoteMysql'] = $cfgRemote;
if (isset($savedData['defaultRemoteMongo'])) unset($savedData['defaultRemoteMongo']);
$haveValidSource = true;
$remoteSchema = STRING_MYSQL;
}
if ($defaultRemoteMongo) {
$cfgRemote = $cfgMig[STRING_MONGO];
$savedData['defaultRemoteMongo'] = $cfgRemote;
if (isset($savedData['defaultRemoteMysql'])) unset($savedData['defaultRemoteMysql']);
$haveValidSource = true;
$remoteSchema = STRING_MONGO;
}
// we need to validate the remote table
if ($validateRemoteSource == 1) {
if (empty($remoteTableName))
$migErrors[] = ERROR_WF_MIG_TABLE_404;
else
$savedData['remoteTableName'] = $remoteTableName;
if (!empty($remoteXMLStartDate)) {
if (!validateMigrationDate($remoteXMLStartDate)) {
$migErrors[] = sprintf(ERROR_WF_MIG_DATE_BAD, 'Start', $remoteXMLStartDate);
}
}
if (!empty($remoteXMLEndDate)) {
if (!validateMigrationDate($remoteXMLEndDate)) {
$migErrors[] = sprintf(ERROR_WF_MIG_DATE_BAD, 'End', $remoteMysqlEndDate);
}
}
}
// if we're overriding the default Source XML, process that data...
$validRemoteMongoConfig = false;
// remote source is mongo schema
if (isset($changeDefaultMongo) and $changeDefaultMongo == 1) {
// validate that we have the minimum data -- either we need a remote URI and Port, or a replSet name and node list
if ((!isset($remoteMongoURI) or empty($remoteMongoURI)
and (!isset($remoteMongoPort)) or empty($remoteMongoPort))
and ((!isset($remoteMongoReplSet) or empty($remoteMongoReplSet))
and (!isset($remoteMongoReplSetList) or empty($remoteMongoReplSetList)))
or (isset($remoteMongoURI) and isset($remoteMongoReplSet))) {
// neither the URI, Port, ReplSetName, or ReplSetList have been set
$migErrors[] = ERROR_WF_MIG_REMOTE_MONGO_404;
} elseif (isset($remoteMongoURI) and !isset($remoteMongoReplSet)) {
// remoteMongoURI is set -- validate
if (isset($remoteMongoReplSet) and !empty($remoteMongoReplSet)) {
$migErrors[] = ERROR_WF_MIG_REMOTE_MONGO_404;
} elseif (empty($remoteMongoPort)) {
$migErrors[] = ERROR_WF_MIG_PORT_404;
} else {
$cfgRemote[STRING_HOST] = $remoteMongoURI;
$cfgRemote[STRING_PORT] = $remoteMongoPort;
}
} elseif (isset($remoteMongoPort) and !isset($remoteMongoURI)) {
$migErrors[] = ERROR_WF_MIG_URI_404;
} elseif (isset($remoteMongoReplSet) and !isset($remoteMongoReplSetList)) {
$migErrors[] = ERROR_WF_MIG_REPL_500;
} elseif (isset($remoteMongoReplSet) and isset($remoteMongoReplSetList)) {
$cfgRemote[MONGO_REPL_SET_LIST] = $remoteMongoReplSetList;
$savedData[MONGO_REPL_SET_LIST] = $remoteMongoReplSetList;
// if we have a replication set, we need a replSet name and at least three members of the repl set,
// each of which must consist of a domainName/IP-Address:PortNumber
$replSetErrors = false;
if (false == ($rmr = preg_split("/[\s,]+/", $remoteMongoReplSetList))) {
$migErrors[] = ERROR_WF_MIG_REPL_BAD;
$replSetErrors = true;
} else {
$remoteMongoReplSetList = null;
$validPatterns = true;
foreach ($rmr as $hp) {
if (!empty($hp) and 1 !== preg_match($patternUriPort, $hp)) {
$migErrors[] = sprintf(ERROR_WF_MIG_REPL_URL, $hp);
$validPatterns = false;
$replSetErrors = true;
} elseif (!empty($hp)) {
$remoteMongoReplSetList[] = $hp;
}
}
if (count($rmr) < 3) {
$migErrors[] = ERROR_WF_MIG_REPL_NUM;
$replSetErrors = true;
}
}
}
// todo -- date validation
// if production then ensure we have requisite login data
if ($lpRequired) {
if (!isset($remoteMongoLogin)) $migErrors[] = ERROR_WF_MIG_LOGIN_404;
if (!isset($remoteMongoPassword)) $migErrors[] = ERROR_WF_MIG_PWD_404;
if (!isset($remoteMongoAuthSource)) $migErrors[] = ERROR_WF_MIG_ADB_404;
}
// if we have a login, then we also have to have a password and an authDB (regardless if production)
if (isset($remoteMongoLogin) and !empty($remoteMongoLogin)) {
$cfgRemote[STRING_USER] = $remoteMongoLogin;
$haveLogin = true;
}
if (isset($remoteMongoPassword) and !empty($remoteMongoPassword))
if (!$haveLogin)
$migErrors[] = ERROR_WF_MIG_LOGIN_MISSING;
else {
$cfgRemote[STRING_PASS] = $remoteMongoPassword;
$havePassword = true;
}
elseif ($haveLogin)
$migErrors[] = ERROR_WF_MIG_PWD_MISSING;
if (isset($remoteMongoAuthSource) and !empty($remoteMongoAuthSource)) {
if (!$haveLogin) $migErrors[] = ERROR_WF_MIG_LOGIN_MISSING;
if (!$havePassword) $migErrors[] = ERROR_WF_MIG_PWD_MISSING;
$cfgRemote[REMOTE_AUTH_SOURCE] = $remoteMongoAuthSource;
} elseif ($haveLogin or $havePassword)
$migErrors[] = ERROR_WF_MIG_ADB_MISSING;
if (!isset($remoteMongoDatabase) or empty($remoteMongoDatabase))
$migErrors[] = ERROR_WF_MIG_DB_404;
else
$cfgRemote[CONFIG_DATABASE] = $remoteMongoDatabase;
if (empty($migErrors)) {
// validate the remote mongo service -- begin by building the mongoDSN
$mongoDSN = MONGO_DSN;
if (isset($remoteMongoLogin)) {
$mongoDSN .= $remoteMongoLogin . COLON_NS . $remoteMongoPassword . AT;
$mongoOptions[CONFIG_DATABASE_MONGODB_AUTH_SOURCE] = $remoteMongoAuthSource;
}
if (isset($remoteMongoReplSet)) {
// replication set
$mongoOptions[MONGO_REPL_SET] = $remoteMongoReplSet;
foreach ($remoteMongoReplSetList as $remoteNode)
$mongoDSN .= $remoteNode . ',';
$mongoDSN = rtrim($mongoDSN, ',');
} else
$mongoDSN .= $remoteMongoURI . COLON_NS . $remoteMongoPort;
// add the database name to the mongoDSN
$mongoDSN .= SLASH . $remoteMongoDatabase;
// now that we have the DSN built, test the connection by connecting and pinging the authDB service
try {
$remoteConnection = remoteMongoConnect($mongoDSN, $remoteMongoAuthSource, $migErrors, $mongoOptions);
$haveValidSource = true;
$defaultCustomSchemaLabel = 'mongoDB';
$remoteSchema = STRING_MONGO;
if (isset($remoteMongoReplSet)) {
$cfgRemote[MONGO_REPL_SET] = $remoteMongoReplSet;
$savedData['remoteMongoReplSet'] = $remoteMongoReplSet;
}
} catch (TypeError $t) {
$migErrors[] = $t->getMessage();
$defaultCustomSchemaLabel = 'Error!';
}
$defaultCustomSchema = true;
$haveValidDestination = true;
$defaultRemoteMongo = false;
$defaultRemoteMysql = false;
} else {
if (empty($errorList))
$errorList = $migErrors;
else
$errorList = array_merge($errorList, $migErrors);
}
} elseif (isset($changeDefaultMysql) and $changeDefaultMysql == 1) { // MYSQL OVERRIDE
// MYSQL Override (the namaste xml file) option was selected
// validate, like the mongo section, that we have the minimum data needed for remote import
if ((!isset($remoteMysqlURI) or empty($remoteMysqlURI))
and (!isset($remoteMysqlPort) or empty($remoteMysqlPort))
and (!isset($remoteMysqlLogin) or empty($remoteMysqlLogin))
and (!isset($remoteMysqlPassword) or empty($remoteMysqlPassword))) {
$migErrors[] = ERROR_WF_MIG_REMOTE_MYSQL_404;
}
if (!isset($remoteMysqlDBName) or empty($remoteMysqlDBName)) $migErrors[] = ERROR_WF_MIG_DB_404;
if (!isset($remoteMysqlTableName) or empty($remoteMysqlTableName)) $migErrors[] = ERROR_WF_MIG_TABLE_404;
if (empty($migErrors)) {
// build the PDO connect string for the remote resource
$charset = 'charset=utf8mb4';
$PDOConnectString = 'mysql:host=' . $remoteMysqlURI . COLON_NS . $remoteMysqlPort . SEMI . 'dbname=' . $remoteMysqlDBName . SEMI . $charset;
$pdoAttributes = [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
if (!($remoteConnection = remoteMysqlConnect($PDOConnectString, $remoteMysqlLogin, $remoteMysqlPassword, $remoteMysqlTableName, $pdoAttributes, $migErrors, $rc))) {
$migErrors[] = ERROR_PDO_CONNECT . COLON . $PDOConnectString;
} else {
$defaultCustomSchema = true;
$haveValidSource = true;
$haveValidDestination = true;
$defaultCustomSchemaLabel = 'mySQL';
$defaultRemoteMongo = false;
$defaultRemoteMysql = false;
$remoteSchema = STRING_MYSQL;
}
$cfgRemote[STRING_HOST] = $remoteMysqlURI;
$cfgRemote[STRING_PORT] = $remoteMysqlPort;
$cfgRemote[STRING_USER] = $remoteMysqlLogin;
$cfgRemote[STRING_PASS] = $remoteMysqlPassword;
$cfgRemote[REMOTE_AUTH_SOURCE] = NA;
$cfgRemote[CONFIG_DATABASE] = $remoteMysqlDBName;
// $cfgRemote[REMOTE_COLLECTION_NAME] = ;
// $cfgRemote[REMOTE_START_DATE] = ;
// $cfgRemote[REMOTE_END_DATE] = ;
$cfgRemote[REMOTE_RECORD_COUNT] = $rc;
}
//} elseif (isset($startMigration) and $startMigration == 1) {
} elseif (isset($submitLTO) and $submitLTO == 1) {
// instantiate a migration broker client
if (!isset(gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER][CONFIG_BROKER_INSTANCES][CONFIG_BROKER_M_BROKER])
or (gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_APPSERVER][CONFIG_BROKER_INSTANCES][CONFIG_BROKER_M_BROKER] < 1)) {
$migErrors[] = ERROR_WF_MIG_BRK_CFG_404;
} elseif (!isset($remoteSchema)) {
$migErrors[] = ERROR_WF_MIG_REMOTE_SCHEMA;
} else {
$stopProcessing = false;
// todo -- how are the XML defaults handled at this stage?!?
switch ($savedData['remoteSchema']) {
case STRING_MONGO :
$data[MIGRATION_SOURCE_SCHEMA] = CONFIG_SCHEMA_MONGO;
$data[STRING_HOST] = $remoteMongoURI;
$data[STRING_PORT] = $remoteMongoPort;
if (!empty($remoteMongoLogin)) $data[STRING_USER] = $remoteMongoLogin;
if (!empty($remoteMongoPassword)) $data[STRING_PASS] = $remoteMongoPassword;
if (!empty($remoteMongoAuthSource)) $data[STRING_AUTH_SRC] = $remoteMongoAuthSource;
if (!empty($remoteMongoReplSet)) $data[CONFIG_DATABASE_MONGODB_REPLSET] = $remoteMongoReplSet;
if (!empty($remoteMongoReplSetList)) $data[CONFIG_DATABASE_MONGODB_REPLSET_DSN] = $remoteMongoReplSetList;
$data[CONFIG_DATABASE] = $remoteMongoDatabase;
$data[MIGRATION_SOURCE_TABLE] = $remoteMongoCollection;
break;
case STRING_MYSQL :
$data[MIGRATION_SOURCE_SCHEMA] = CONFIG_SCHEMA_MYSQL;
$data[STRING_HOST] = $remoteMysqlURI;
$data[STRING_PORT] = $remoteMysqlPort;
if (!empty($remoteMysqlLogin)) $data[STRING_USER] = $remoteMysqlLogin;
if (!empty($remoteMysqlPassword)) $data[STRING_PASS] = $remoteMysqlPassword;
$data[CONFIG_DATABASE] = $remoteMysqlDBName;
// $data[MIGRATION_SOURCE_TABLE] = ;
break;
default :
$migErrors[] = sprintf(ERROR_MIGRATION_SCHEMA_UNKNOWN, $savedData['remoteSchema']);
$data = null;
$stopProcessing = true;
break;
}
if (!$stopProcessing) {
// testing the XML conversion here... make sure this is commented-out for production runs
$newXML = gasStatic::convertWebMigrationRequest($data);
// set broker payload containers
$data[MIGRATION_DEST_SCHEMA] = $savedData['namasteSchema'];
$data[MIGRATION_DEST_TABLE] = $savedData['templateName'];
// set the schema-independent migration switches
$data[MIGRATION_FILTER_SOFT_DELETES] = boolval($importDeletes);
$data[MIGRATION_FILTER_PARTIALS] = boolval($importPartials);
$data[MIGRATION_TEST_MODE] = boolval($testMode);
// set the meta data payload
$meta[META_CLIENT] = CLIENT_SYSTEM;
$meta[META_SYSTEM_NOTES] = basename(__FILE__);
$meta[META_CLIENT_IP] = $_SERVER['REMOTE_ADDR'];
$meta[BROKER_XML_DATA] = $newXML;
$haveValidSource = true;
$beginMigration = 1;
// submit the broker-client request to initiate the migration
}
}
}
if (isset($remoteSchema) and !empty($remoteSchema)) $savedData['remoteSchema'] = $remoteSchema;
if (isset($namasteSchema) and !empty($namasteSchema)) $savedData['namasteSchema'] = $namasteSchema;
$savedDataCompressed = base64_encode(json_encode($savedData));
// test to see if we can enable the copy button, authorizing the migration
$g2g = ($haveValidTemplate == $haveValidSource and $haveValidSource == $haveValidDestination and $haveValidDestination == $remoteConnection and $remoteConnection == true and !$beginMigration);
if (!empty($migErrors)) $errorList = array_merge($errorList, $migErrors);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Namaste Data Migration Manager</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css">
<!-- Bootstrap core CSS -->
<link href="../html/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="../html/css/mdb.min.css" rel="stylesheet">
<!-- Your custom styles (optional) -->
<link href="../html/css/style.css" rel="stylesheet">
</head>
<body style="background-color:#fbe9e7;">
<input type="hidden" name="savedData" id="savedData" value="<?= $savedDataCompressed ?>">
<!--header-->
<div class="card m-5" style="width: 22rem;">
<div class="fixed-top">
<div class="card" style="background-color: #ffccbc">
<div class="card-body">
<h4 class="card-title text-center">
<img src="../html/img/namaste_100x50.png" alt="namasteLogo" />
<span style="color:#bf360c">
Data Migration Manager
</span>
</h4>
</div>
</div>
</div>
</div>
<!--/header-->
<!--processing templateName modal --->
<div class="modal fade" id="modalTemplateName" tabindex="-1" role="dialog" aria-labelledby="phpTemplateModal" aria-hidden="true">
<div class="modal-dialog modal-notify modal-info" role="document">
<!--content--->
<div class="modal-content">
<!--header--->
<div class="modal-header">
<p class="heading lead"><strong>Select the Namaste Destination Template</strong></p>
</div>
<!--/header-->
<!--body--->
<div class="modal-body">
<div class="text-center">
<!--suppress CheckTagEmptyBody -->
<i class="fa fa-file-text-o fa-4x mb-3 animated rotateIn"></i>
<p>
Please select the destination Namaste template.<br>
Only templates with a migration section will be accepted.<br>
Please select from the current list of known templates only.
</p>
<h6 class="md-form">
<input type="search" id="templateName" name="templateName" autocomplete="off"
<?php $tValue = ($templateName != STRING_UNKNOWN && !$haveTemplateNameError) ? $templateName : ''; ?>
value="<?= $tValue;?>"
class="form-control mdb-autocomplete <?php echo ($haveTemplateNameError) ? 'is-invalid' : 'is-valid';?>">
<?php
if ($templateName != STRING_UNKNOWN) {
if ($haveTemplateNameError) {
echo '<div class="invalid-feedback">' . $templateName . '</div>';
} else {
echo '<div class="valid-feedback">Valid Template</div>';
}
}
?>
<button class="mdb-autocomplete-clear">
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="https://www.w3.org/2000/svg">
<!--suppress CheckEmptyScriptTag, HtmlUnknownTag -->
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
<!--suppress CheckEmptyScriptTag, HtmlUnknownTag -->
<path d="M0 0h24v24H0z" fill="none" />
</svg>
</button>
<label for="templateName" class="active">Namaste Template Name</label>
</h6>
<h6>
<!--suppress HtmlUnknownTag -->
<div>
<button class="btn peach-gradient btn-rounded waves-effect" id="submitNewTemplate" name="submitNewTemplate" type="submit">Submit</button>
</div>
</h6>
</div>
</div>
<!--/body-->
</div>
<!--/content-->
</div>
</div>
<!--/processing templateName modal -->
<!--last-three-options modal--->
<div class="modal fade" id="modalLastThreeOptions" tabindex="-1" role="dialog" aria-labelledby="phpLTO" aria-hidden="true">
<div class="modal-dialog modal-notify modal-info" role="document">
<!--content--->
<div class="modal-content">
<!--header--->
<div class="modal-header">
<p class="heading lead"><strong>Last Three Options:</strong></p>
</div>
<!--/header-->
<!--body--->
<div class="modal-body">
<div class="text-left">
<p>
Import Soft Deletes: (default = off) If remote record has a deleted status, turning this option
on will import these records.<br><br>
Import Partials: (default = off) If (one or more) remote record field(s) fails validation,
turning this option on will import the record (minus the failed fields!).<br><br>
Test Mode: (option = off) Test mode does not import any records - you will see a status report
as if the records were imported.<br><br>
</p>
<h6 class="md-form">
<!--suppress HtmlUnknownTag -->
<h6 class="switch">
<label>
Import Soft Deletes: &nbsp;&nbsp;Off
<input type="checkbox" id="importDeletes">
<!--suppress CheckTagEmptyBody -->
<span class="lever"></span> On
</label>
</h6>
<!--suppress HtmlUnknownTag -->
<h6 class="switch">
<label>
Import Partials: &nbsp;&nbsp;Off
<input type="checkbox" id="importPartials">
<!--suppress CheckTagEmptyBody -->
<span class="lever"></span> On
</label>
</h6>
<!--suppress HtmlUnknownTag -->
<h6 class="switch">
<label>
Test Mode: &nbsp;&nbsp;Off
<input type="checkbox" id="testMode">
<!--suppress CheckTagEmptyBody -->
<span class="lever"></span> On
</label>
</h6>
</h6>
<h6>
<!--suppress HtmlUnknownTag -->
<div class="text-center">
<button class="btn peach-gradient btn-rounded waves-effect" id="submitLTO" name="submitLTO" type="submit">Start Migration!</button>
</div>
</h6>
</div>
</div>
</div>
</div>
</div>
<!--/last-three-options modal-->
<!--processing error modal--->
<div class="modal fade" id="centralErrorModal" tabindex="-1" role="dialog" aria-labelledby="phpErrorModal" aria-hidden="true">
<div class="modal-dialog modal-notify modal-danger" role="document">
<!--content--->
<div class="modal-content">
<!--header--->
<div class="modal-header">
<p class="heading lead">Processing Errors</p>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true" class="white-text">&times;</span>
</button>
</div>
<!--/header-->
<!--body--->
<div class="modal-body">
<div class="text-center">
<!--suppress CheckTagEmptyBody -->
<i class="fa fa-bug fa-4x mb-3 animated rotateIn"></i>
<p>These error(s) were raised during processing:</p>
<?php
if (!empty($errorList) and is_array($errorList))
$count = 1;
foreach ($errorList as $message)
echo "<p>" . $count++ . ": <strong>$message</strong></p>";
?>
<p>Please correct and re-submit your request</p><br/>
</div>
</div>
<!--/body-->
<!--footer--->
<div class="modal-footer justify-content-center">
<a type="button" class="btn btn-danger" data-dismiss="modal">ok</a>
</div>
<!--/footer-->
</div>
<!--/content-->
</div>
</div>
<!--/processing error modal-->
<!-- results modal -->
<div class="modal fade" id="resultsModal" tabindex="-1" role="dialog" aria-hidden="true" aria-labelledby="migrationResults">
<div class="modal-dialog modal-lg" role="document">
<!-- content -->
<div class="modal-content">
</div>
</div>
</div>
<!--/results modal -->
<!--current states-->
<div class="container-fluid" style="position: relative; top:25px;">
<div class="row">
<div class="col-md">
<div class="col">
<div class="card">
<h5 class="card-header warning-color-dark white-text text-center">
<strong>Remote Data Source</strong>
</h5>
<!--remote content--->
<div class="card-body">
<div class="card-text">
<h6>
<strong title="Namaste Destination Template">Template:&nbsp;</strong>
<?= $templateName; ?>
</h6>
<h6>
<strong title="Remote DB Host URI">Host:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[STRING_HOST])) echo $savedData[STRING_HOST]; ?>
&nbsp;&nbsp;&nbsp;
<strong title="Remote DB Host Port Number">Port:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[STRING_PORT])) echo $savedData[STRING_PORT]; ?>
</h6>
<div>
<h6>
<strong title="mongo or mysql only">
Schema:&nbsp;
</strong>
<?php
echo '<input type="radio" class="form-check-input" id="defaultRemoteMysql" ';
echo 'data-toggle="tooltip" data-placement="right" ';
if ($defaultRemoteMysql) echo 'checked ';
echo 'value="' . STRING_MYSQL . '" name="defaultRemoteSchema">' . PHP_EOL;
echo '<label class="form-check-label" for="defaultRemoteMysql">mySQL&nbsp;</label>' . PHP_EOL;
echo '<input type="radio" onchange="this.form.submit();" class="form-check-input" id="defaultRemoteMongo" ';
if ($defaultRemoteMongo) echo 'checked ';
echo 'value="' . STRING_MONGO . '" name="defaultRemoteSchema">' . PHP_EOL;
echo '<label class="form-check-label" for="defaultRemoteMongo">Mongo&nbsp;</label>' . PHP_EOL;
// todo - make this a source label, indicating if this is SOURCE_USER or SOURCE_NAMASTE instead...
if (isset($defaultCustomSchemaLabel) and $defaultCustomSchema) {
echo '<input type="radio" class="form-check-input" id="customSchema" checked disabled';
echo 'value="customSchema" name="customSchema">' . PHP_EOL;
echo '<label class="form-check-label" for="customSchema">Custom: ' . $defaultCustomSchemaLabel . '</label>' . PHP_EOL;
}
?>
</h6>
<h6>
<strong title="Database account user name">Login:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[STRING_USER])) echo $savedData[STRING_USER]; ?>
&nbsp;&nbsp;&nbsp;
<strong title="Database account user password">Password:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[STRING_PASS])) echo $savedData[STRING_PASS];
if ($defaultRemoteMongo) { ?>
&nbsp;&nbsp;&nbsp;
<strong title="Remote Database name">Auth Database:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[STRING_AUTH_SRC])) echo $cfgRemote[STRING_AUTH_SRC];
} ?>
</h6>
<h6>
<strong title="Remote Database">Remote Database:&nbsp;</strong>
<input type="text" id="remoteDatabaseName" class="form-control-sm" placeholder="Name of the remote database" size="50"<?php if (isset($savedData[CONFIG_DATABASE])) echo 'value="' . $savedData[CONFIG_DATABASE] . '"'; ?>>
</h6>
<h6>
<strong title="Remote Table name">Remote Table:&nbsp;</strong>
<input type="text" id="remoteTableName" class="form-control-sm" placeholder="Enter the name of the remote table/collection" size="50" <?php if (isset($cfgRemote) and isset($cfgRemote[REMOTE_COLLECTION_NAME])) echo ' value="' . $cfgRemote[REMOTE_COLLECTION_NAME]; ?>>
</h6>
<h6>
<strong title="Start Date Filter">Start Date:&nbsp;</strong>
<input type="text" class="form-control-sm datepicker" placeholder="(optional) Start Date Filter" id="remoteXMLStartDate" size="20"
<?php if (isset($remoteXMLStartDate)) echo 'value="' . $remoteXMLStartDate . '"'; ?>
>
<strong title="End Date Filter">End Date:&nbsp;</strong>
<input type="text" class="form-control-sm datepicker" placeholder="(optional) End Date Filter" id="remoteXMLEndDate" size="20"
<?php if (isset($remoteXMLEndDate)) echo 'value="' . $remoteXMLEndDate . '"'; ?>
>
</h6>
<?php
if (isset($savedData[MONGO_REPL_SET])) {
echo '<h6>' . PHP_EOL;
echo '<strong title="Repl Set Name">Repl Set:&nbsp;</strong>' . PHP_EOL;
echo $savedData[MONGO_REPL_SET] . PHP_EOL;
echo '</h6>' . PHP_EOL;
echo '<h6 class="form-group">' . PHP_EOL;
echo '<label for="replSetList"><strong>Replication Set List:</strong></strong></label>' . PHP_EOL;
echo '<textarea class="form-control rounded-0" id="replSetList" rows="3">' . $savedData[MONGO_REPL_SET_LIST] . '</textarea>' . PHP_EOL;
echo '</h6>' . PHP_EOL;
}
if (isset($savedData[REMOTE_SHARD_SERVER])) {
echo '<h6>' . PHP_EOL;
echo '<strong title="MongoS URI:Port">MongoS URI:Port:&nbsp;</strong>' . PHP_EOL;
echo $savedData[REMOTE_SHARD_SERVER] . PHP_EOL;
echo '</h6>' . PHP_EOL;
}
if (isset($rc) and $rc) { ?>
<h6>
<strong title="Number of records to be migrated">Num Recs:&nbsp;</strong><?= $rc; ?>
</h6>
<?php }
?>
<div class="form-row float-right">
<div class="col-auto justify-content-end">
<button class="btn peach-gradient btn-rounded waves-effect" id="validateRemoteSource" name="validateRemoteSource" type="submit">Validate Remote Source</button>
</div>
</div>
</div>
</div>
</div>
<!--/source content-->
</div>
</div>
</div>
<div class="col-1 text-center">
<div>
<input type="hidden" id="schema" value="migrate">
<?php
if ($g2g) {
echo '<button class="btn-floating btn-lg" style="margin-top: 125px;" id="startMigration" type="button" data-toggle="tooltip" data-placement="top" title="Click to start migration">' . PHP_EOL;
echo '<!--suppress CheckTagEmptyBody --><i class="fa fa-copy peach-gradient"></i>' . PHP_EOL;
} else {
echo '<button class="btn-floating btn-lg" style="margin-top: 125px;" type="button" data-toggle="tooltip" data-placement="top" title="Click to start migration" disabled>' . PHP_EOL;
echo '<!--suppress CheckTagEmptyBody --><i class="fa fa-copy lighten-5"></i>' . PHP_EOL;
}
echo '</button>' . PHP_EOL;
?>
</div>
</div>
<div class="col-md">
<div class="col">
<div class="card">
<h5 class="card-header warning-color-dark white-text text-center">
<strong>Namaste Destination</strong>
</h5>
<!--destination content--->
<div class="card-body">
<div class="card-text">
<h6>
<strong title="Namaste DB Host URI">Host:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[NAMASTE_HOST])) echo $savedData[NAMASTE_HOST]; ?>
&nbsp;&nbsp;&nbsp;
<strong title="Namaste DB Host Port Number">Port:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[NAMASTE_PORT])) echo $savedData[NAMASTE_PORT]; ?>
</h6>
<h6>
<strong title="Namaste Database">Database:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[NAMASTE_DB])) echo $savedData[NAMASTE_DB] . '&nbsp;&nbsp;&nbsp;'; ?>
<strong title="Namaste Table">Table:&nbsp;</strong>
<?php if (is_array($savedData) and isset($savedData[NAMASTE_TABLE])) echo $savedData[NAMASTE_TABLE]; ?>
</h6>
<h6>
<strong title="mongo or mysql only">Schema:&nbsp;</strong>
<?php
// should not be able to check these buttons - dest schema is defined by the template
echo '<input type="radio" class="form-check-input" id="defaultNamasteMysql" disabled ';
if ($defaultNamasteMysql) echo 'checked ';
echo 'value="' . STRING_MYSQL . '" name="defaultNamasteSchema">' . PHP_EOL;
echo '<label class="form-check-label" for="defaultNamasteMysql">mySQL&nbsp;</label>' . PHP_EOL;
echo '<input type="radio" class="form-check-input" id="defaultNamasteMongo" disabled ';
if ($defaultNamasteMongo) echo 'checked ';
echo 'value="' . STRING_MONGO . '" name="defaultNamasteSchema">' . PHP_EOL;
echo '<label class="form-check-label" for="defaultNamasteMongo">Mongo</label>' . PHP_EOL;
?>
</h6>
<h6>
<strong title="Number of records migrated">Num Recs:&nbsp;</strong>
</h6>
<br>
<div class="brown-text">
<i class="fa fa-info-circle">&nbsp;</i>&nbsp;
<small>
To start a migration, first start typing the name of the desired (required) Namaste
destination template. Next, select the source and destination schema,
<em>before</em> clicking the copy button.
Num Recs on the source side indicate the number of active records in the remote
repository. Num Recs on the destination side will indicate the total number of
records successfully migrated once the operation has completed.
</small>
</div>
</div>
</div>
<!--/destination content-->
</div>
</div>
</div>
</div>
</div>
<!--/current states-->
<!--default override--->
<div class="container-fluid" style="position: relative; top:25px;">
<!--collapse button--->
<div>
<button class="btn-floating btn-lg peach-gradient" type="button" id="showXMLOptions" data-toggle="collapse" data-target="#defCfg" aria-expanded="false" aria-controls="defCfg" title="Reconfigure Data Source">
<!--suppress CheckTagEmptyBody -->
<i class="fa fa-wrench" aria-hidden="true"></i>
</button>
<strong>Override Default Remote Migration Options</strong>
</div>
<!--/collapse button-->
<!--changeDefaults collapse section--->
<div class="collapse" id="defCfg">
<div class="card container-fluid mt-3">
<div class="card-body">
<div class="card-text">
<div class="classic-tabs">
<div class="tabs-wrapper">
<ul class="nav tabs-orange" id="cfgTabs" role="tablist">
<li class="nav-item">
<a class="nav-link waves-light active" data-toggle="tab" href="#cfgMongo" role="tab">
<!--suppress CheckTagEmptyBody -->
<i class="fa fa-leaf fa-2x" aria-hidden="true"></i>
<br>mongo
</a>
</li>
<li class="nav-item">
<a class="nav-link waves-light" data-toggle="tab" href="#cfgPDO" role="tab">
<!--suppress CheckTagEmptyBody -->
<i class="fa fa-database fa-2x" aria-hidden="true"></i>
<br>mySQL
</a>
</li>
</ul>
</div>
<!--tab panels--->
<div class="tab-content card">
<!--mongo panel--->
<div class="tab-pane fadeIn show active" id="cfgMongo" role="tabpanel">
<div>
<input type="hidden" id="schema" value="mongo">
<!-- grid row 1 -->
<div class="form-row">
<!-- grid column 1 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB URI" id="remoteMongoURI" name="remoteMongoURI"
<?php
if (is_array($savedData) and isset($savedData[STRING_HOST])) echo 'value="' . $savedData[STRING_HOST] . '"';
?>
>
<label for="remoteMongoURI">Remote mongoDB URI:</label>
</div>
<!-- grid column 2 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Port Number" id="remoteMongoPort" name="remoteMongoPort"
<?php
if (is_array($savedData) and isset($savedData[STRING_PORT])) echo 'value="' . $savedData[STRING_PORT] . '"';
?>
>
<label for="mongoPort">Remote mongoDB Port Number:</label>
</div>
<!-- grid column 3 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote Database" id="remoteMongoDatabase" name="remoteMongoDatabase"
<?php if (is_array($savedData) and isset($savedData[CONFIG_DATABASE])) echo 'value="' . $savedData[CONFIG_DATABASE] . '"'; ?>
>
<label for="remoteMongoDatabase">Remote Mongo Database Name</label>
</div>
</div>
<!-- grid row 2 -->
<div class="form-row">
<!-- grid column 1 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Login" id="remoteMongoLogin" name="remoteMongoLogin"
<?php
if (is_array($savedData) and isset($savedData[STRING_USER])) echo 'value="' . $savedData[STRING_USER] . '"';
?>
>
<label for="remoteMongoLogin">Remote mongoDB Account Login:</label>
</div>
<!-- grid column 2 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Password" id="remoteMongoPassword" name="remoteMongoPassword"
<?php
if (is_array($savedData) and isset($savedData[STRING_PASS])) echo 'value="' . $savedData[STRING_PASS] . '"';
?>
>
<label for="remoteMongoPassword">Remote mongoDB Account Password:</label>
</div>
<!-- grid column 3 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Authentication Source" id="remoteMongoAuthSource" name="remoteMongoAuthSource"
<?php
if (is_array($savedData) and isset($savedData[STRING_AUTH_SRC])) echo 'value="' . $savedData[STRING_AUTH_SRC] . '"';
?>
>
<label for="remoteMongoAuthSource">Remote Authentication Source DB:</label>
</div>
</div>
<!-- grid row 3 -->
<div class="form-row">
<!-- grid col 1 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Replication Set Name (only if replication set)" id="remoteMongoReplSet" name="remoteMongoReplSet"
<?php
if (is_array($savedData) and isset($savedData[MONGO_REPL_SET])) echo 'value="' . $savedData[MONGO_REPL_SET] . '"';
?>
>
<label for="remoteMongoReplSet">Replication Set Name:</label>
</div>
<!-- grid col 2 -->
<div class="col md-form">
<div class="form-group shadow-textarea">
<label for="#replSetList">Replication Set Members [URI:PORT]:</label>
<!--suppress CheckTagEmptyBody -->
<textarea class="form-control z-depth-1" id="replSetList" rows="3" placeholder="One entry per line and only if you are connecting to a replication set!"
><?php
if (is_array($savedData) and isset($savedData[MONGO_REPL_SET_LIST]))
foreach ($savedData[MONGO_REPL_SET_LIST] as $value)
echo $value . '<br>';
?></textarea>
</div>
</div>
</div>
<div class="form-row float-right">
<div class="col-auto justify-content-end">
<button class="btn peach-gradient btn-rounded waves-effect" id="changeDefaultMongo" name="changeDefaultMongo" type="submit">Replace Default Mongo Source</button>
</div>
</div>
</div>
</div>
<!--/mongo panel-->
<!--mysql panel--->
<div class="tab-pane fadeIn show" id="cfgPDO" role="tabpanel">
<div>
<input type="hidden" id="schema" value="mysql">
<!-- grid row 1 -->
<div class="form-row">
<!-- grid column 1 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB URI" id="remoteMysqlURI" name="remoteMysqlURI"
<?php if (is_array($savedData) and isset($savedData[STRING_HOST])) echo 'value="' . $savedData[STRING_HOST] . '"'; ?>
>
<label for="mysqlURI">Remote mySQL URI:</label>
</div>
<!-- grid column 2 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Port Number" id="remoteMysqlPort" name="remoteMysqlPort"
<?php if (is_array($savedData) and isset($savedData[STRING_PORT])) echo 'value="' . $savedData[STRING_PORT] . '"'; ?>
>
<label for="mysqlPort">Remote mySQL Port:</label>
</div>
</div>
<!-- grid row 2 -->
<div class="form-row">
<!-- grid column 1 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Login" id="remoteMysqlLogin" name="remoteMysqlLogin"
<?php if (is_array($savedData) and isset($savedData[STRING_USER])) echo 'value="' . $savedData[STRING_USER] . '"'; ?>
>
<label for="mysqlLogin">Remote mySQL Login:</label>
</div>
<!-- grid column 2 -->
<div class="col md-form">
<input type="text" class="form-control form-control-sm" placeholder="Remote DB Password" id="remoteMysqlPassword" name="remoteMysqlPassword"
<?php if (is_array($savedData) and isset($savedData[STRING_PASS])) echo 'value="' . $savedData[STRING_PASS] . '"'; ?>
>
<label for="mysqlPassword">Remote mySQL Password:</label>
</div>
</div>
<div class="col md-form">
<!-- grid column 1 -->
<input type="text" class="form-control form-control-sm" placeholder="Database Name" id="remoteMysqlDBName" name="remoteMysqlDBName"
<?php if (is_array($savedData) and isset($savedData[CONFIG_DATABASE])) echo 'value="' . $savedData[CONFIG_DATABASE] . '"'; ?>
>
<label for="remoteMysqlDBName">Remote mySQL DB Name:</label>
</div>
<div class="form-row float-right">
<div class="col-auto justify-content-end">
<button class="btn peach-gradient btn-rounded waves-effect" id="changeDefaultMysql" name="changeDefaultMysql" type="submit">Replace Default MySQL Source</button>
</div>
</div>
</div>
</div>
</div> <!--/mysql panel-->
</div> <!--/tab panels-->
</div>
</div>
</div>
</div>
<!--/changeDefaults collapse section-->
</div>
<!--/default override-->
<!-- SCRIPTS -->
<!-- JQuery -->
<script type="text/javascript" src="../html/js/jquery-3.1.1.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="../html/js/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="../html/js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="../html/js/mdb.js"></script>
<!-- Div Overlay Javascript -->
<script type="text/javascript" src="../html/js/overlay.js"></script>
<!--suppress JSUnusedAssignment, ES6ConvertVarToLetConst, EqualityComparisonWithCoercionJS, JSUnresolvedFunction -->
<script>
/**
* postME() -- file method
*
* This method generates a form at the end of the current page and posts the updated variables assigned to the
* input parameter (associative array) before submitting the form.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param parameters -- associative array of scraped (see: scrape()) fields
*
*
* HISTORY:
* ========
* 09-26-18 mks DB-43: original coding
*
*/
function postMe(parameters)
{
// this var-assignment jankiness is so PHPStorm doesn't flag the correctly-written statement as a warning in the IDE
var formLiteral = "form";
var inputLiteral = "input";
var form =$("<"+formLiteral+"></"+formLiteral+">");
form.attr("method", "post");
form.attr("action", "");
$.each(parameters, function(key, value) {
var field = $("<"+inputLiteral+"></"+inputLiteral+">");
field.attr("type", "hidden");
field.attr("name", key);
field.attr("value", value);
form.append(field);
});
$(document.body).append(form);
form.submit();
}
// scrape() -- scrape the form and pull all formVars into a single object for passing into postMe()
function scrape(whichButton)
{
var params = {};
params.defaultRemoteMysql = (document.getElementById('defaultRemoteMysql').checked) ? 1 : 0;
params.defaultRemoteMongo = (document.getElementById('defaultRemoteMongo').checked) ? 1 : 0;
// params.defaultNamasteMysql = (document.getElementById('defaultNamasteMysql').checked) ? 1 : 0;
// params.defaultNamasteMongo = (document.getElementById('defaultNamasteMongo').checked) ? 1 : 0;
var savedData = document.getElementById('savedData');
if (savedData && savedData.value)
params.savedData = savedData.value;
var tName = document.getElementById('templateName');
if (tName && tName.value)
params.templateName = tName.value;
var remoteTableName = document.getElementById('remoteTableName');
if (remoteTableName && remoteTableName.value)
params.remoteTableName = remoteTableName.value;
var remoteXMLStartDate = document.getElementById('remoteXMLStartDate');
if (remoteXMLStartDate && remoteXMLStartDate.value)
params.remoteXMLStartDate = remoteXMLStartDate.value;
var remoteXMLEndDate = document.getElementById('remoteXMLEndDate');
if (remoteXMLEndDate && remoteXMLEndDate.value)
params.remoteXMLEndDate = remoteXMLEndDate.value;
// remote mongo source form
var remoteMongoURI = document.getElementById('remoteMongoURI');
if (remoteMongoURI && remoteMongoURI.value)
params.remoteMongoURI = remoteMongoURI.value;
var remoteMongoPort = document.getElementById('remoteMongoPort');
if (remoteMongoPort && remoteMongoPort.value)
params.remoteMongoPort = remoteMongoPort.value;
var remoteMongoLogin = document.getElementById('remoteMongoLogin');
if (remoteMongoLogin && remoteMongoLogin.value)
params.remoteMongoLogin = remoteMongoLogin.value;
var remoteMongoPassword = document.getElementById('remoteMongoPassword');
if (remoteMongoPassword && remoteMongoPassword.value)
params.remoteMongoPassword = remoteMongoPassword.value;
var remoteMongoAuthSource = document.getElementById('remoteMongoAuthSource');
if (remoteMongoAuthSource && remoteMongoAuthSource.value)
params.remoteMongoAuthSource = remoteMongoAuthSource.value;
var remoteMongoReplSet = document.getElementById('remoteMongoReplSet');
if (remoteMongoReplSet && remoteMongoReplSet.value)
params.remoteMongoReplSet = remoteMongoReplSet.value;
var remoteMongoReplSetList = document.getElementById('replSetList');
if (remoteMongoReplSetList && remoteMongoReplSetList.value)
params.remoteMongoReplSetList = remoteMongoReplSetList.value;
var remoteMongoDatabase = document.getElementById('remoteMongoDatabase');
if (remoteMongoDatabase && remoteMongoDatabase.value)
params.remoteMongoDatabase = remoteMongoDatabase.value;
// remote mysql source form
var remoteMysqlURI = document.getElementById('remoteMysqlURI');
if (remoteMysqlURI && remoteMysqlURI.value)
params.remoteMysqlURI = remoteMysqlURI.value;
var remoteMysqlPort = document.getElementById('remoteMysqlPort');
if (remoteMysqlPort && remoteMysqlPort.value)
params.remoteMysqlPort = remoteMysqlPort.value;
var remoteMysqlLogin = document.getElementById('remoteMysqlLogin');
if (remoteMysqlLogin && remoteMysqlLogin.value)
params.remoteMysqlLogin = remoteMysqlLogin.value;
var remoteMysqlPassword = document.getElementById('remoteMysqlPassword');
if (remoteMysqlPassword && remoteMysqlPassword.value)
params.remoteMysqlPassword = remoteMysqlPassword.value;
var remoteMysqlDBName = document.getElementById('remoteMysqlDBName');
if (remoteMysqlDBName && remoteMysqlDBName.value)
params.remoteMysqlDBName = remoteMysqlDBName.value;
// form buttons
switch (whichButton) {
case 1 :
params.changeDefaultMongo = 1;
break;
case 2 :
params.changeDefaultMysql = 1;
break;
case 3 :
params.startMigration = 1;
break;
case 4 :
params.submitLTO = 1;
params.importDeletes = (document.getElementById('importDeletes').checked) ? 1 : 0;
console.log('import deletes: ' + params.importDeletes);
console.log('id: ' + document.getElementById('importDeletes').checked);
console.log('meh: ' + document.getElementById('importDeletes'));
params.importPartials = (document.getElementById('importPartials').checked) ? 1 : 0;
params.testMode = (document.getElementById('testMode').checked) ? 1 : 0;
break;
case 5 :
params.validateRemoteSource = 1;
break;
default :
console.log('Param value: ' + whichButton + ' is not defined');
}
// console.log('param dump: ', params);
postMe(params);
}
/*
* The following section are the event handlers for various controls...
*/
$( "#defaultRemoteMysql" ).click(function() {
event.preventDefault();
scrape();
});
$( "#defaultRemoteMongo" ).click(function() {
event.preventDefault();
$( "#defaultRemoteMysql").click();
});
// $( "#defaultNamasteMysql").click(function() {
// event.preventDefault();
// $( "#defaultRemoteMysql" ).click();
// });
//
// $( "#defaultNamasteMongo").click(function() {
// event.preventDefault();
// $( "#defaultRemoteMysql").click();
// });
$( "#submitNewTemplate").click(function(){
event.preventDefault();
scrape();
});
$( "#changeDefaultMongo").click(function(){
event.preventDefault();
scrape(1);
});
$( "#changeDefaultMysql").click(function(){
event.preventDefault();
scrape(2);
});
$( "#startMigration").click(function () {
event.preventDefault();
scrape(3);
});
$( "#submitLTO").click(function () {
event.preventDefault();
scrape(4);
});
$( "#validateRemoteSource").click(function () {
event.preventDefault();
scrape(5);
});
// populate the auto-complete options for the template name
var templates = <?php echo json_encode($templateNames); ?>;
$('#templateName').mdb_autocomplete({
data : templates
});
$(document).ready(function() {
// page is fully loaded, including all frames, objects and images
// load the errors from PHP
var errors = <?= json_encode($errorList); ?>;
// console.log(errors);
var templateName = "<?= $templateName; ?>";
// console.log(templateName);
var g2g = "<?= $g2g; ?>";
// console.log(g2g);
var beginMigration = <?= $beginMigration; ?>;
// if we're ready to begin the migration -- post the loading overlay
if (beginMigration == 1) {
// proc the overlay...
$.LoadingOverlay("show", {
text : "Migration stuffs are happening...",
image : "",
fontawesome : "fa fa-cog fa-spin"
});
console.log("overlay proc'd...");
// set-up post vars
var phpData = JSON.stringify(<?= json_encode($data); ?>);
var phpMeta = JSON.stringify(<?= json_encode($meta); ?>);
var postData = "d="+phpData+"&m="+phpMeta;
// make the ajax call
$.ajax({
url: 'launchMig.php',
type: 'POST',
data: postData,
dataType: 'html',
success: function(data) {
// console.log(data);
// process migration event results
$('#resultsModalContent').html(data);
$('#resultsModal').modal();
// Hide div overlay after broker event completes
$.LoadingOverlay("hide");
// reload the page once they've closed the overlay
var url = window.location.href;
console.log('url: ' + url);
$(location).attr('href', url);
},
error: function() {
toastr.warning("Something went wrong!");
$.LoadingOverlay("hide");
}
});
}
if (errors != null && errors.length > 0) {
$('#centralErrorModal').modal();
}
if (templateName == 'unknown') {
$('#modalTemplateName').modal();
} else {
toastr.success('No Errors!');
}
// if we're ready to start the migration, proc the modal to display the last three options
if (g2g) $('#modalLastThreeOptions').modal();
// date picker processing
var from_input = $('#remoteXMLStartDate').pickadate(),
from_picker = from_input.pickadate('picker');
var to_input = $('#remoteXMLEndDate').pickadate(),
to_picker = to_input.pickadate('picker');
// Check if theres a “from” or “to” date to start with and if so, set their appropriate properties.
if ( from_picker.get('value') ) {
to_picker.set('min', from_picker.get('select'))
}
if ( to_picker.get('value') ) {
from_picker.set('max', to_picker.get('select'))
}
// Apply event listeners in case of setting new “from” / “to” limits to have them update on the other end. If clear button is pressed, reset the value.
from_picker.on('set', function(event) {
if ( event.select ) {
to_picker.set('min', from_picker.get('select'))
}
else if ( 'clear' in event ) {
to_picker.set('min', false)
}
});
to_picker.on('set', function(event) {
if (event.select) {
from_picker.set('max', to_picker.get('select'))
}
else if ('clear' in event) {
from_picker.set('max', false)
}
});
});
// Tooltips Initialization
$(function () {
$('[data-toggle="tooltip"]').tooltip()
});
// Date Picker Initialization
$('.datepicker').pickadate();
</script>
</body>
</html>