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.
This commit is contained in:
2026-04-05 09:49:30 -07:00
commit 373ebc8c93
1284 changed files with 409372 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
<?php
/**
* fetchSysData.php
*
* Stub program that's invoked by gaAdmin utility.
*
* This program stub connects to the admin mongo resource and pulls all (the whole one record) of system data from
* the system-data collection. (There should be either zero (edge case) or one record stored.)
*
* The program will store any user-level error messages in an array named $formErrors which will be displayed to the
* user in the next page load.
*
* There is an edge case to be accommodated -- when you request to edit a new Namaste installation and there is no
* data stored in the system-table.
*
* todo: write a program that populates the systemData collection during installation
*
* If data exists in the table, it's stored as an associative array in a variable called: $systemData.
* If data doesn't exist in the table, and if no errors were generated, we're going to assume it's a new (unpopulated)
* table. In both of the previous cases, a boolean value: $sysDataLoad is set to true.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-07-18 mks CORE-1113: original coding
*
*/
$meta = [
META_TEMPLATE => TEMPLATE_CLASS_SYS_EVENTS,
META_CLIENT => CLIENT_SYSTEM,
META_CLIENT_IP => STRING_SESSION_HOME,
];
if (!isset($data['c'])) {
$systemMessage[] = 'Choice (C) data not loaded!';
return;
}
$whichConstant = intval($data['c']);
// this script may only execute locally on the namaste admin service
// todo -- remove the "true or" when done debugging
//if (true or intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB][CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_IS_LOCAL]) != 1) {
if (intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB][CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_IS_LOCAL]) != 1) {
$formErrors[] = ERROR_LOCAL_NOT_ADMIN;
return;
}
// instantiate the systemData class object
try {
$obj = new gacFactory($meta, FACTORY_EVENT_NEW_CLASS, basename(__FILE__) . AT . __LINE__, $formErrors);
} catch (TypeError $t) {
$formErrors[] = ERROR_TYPE_EXCEPTION . COLON . $t->getMessage();
return;
}
// ensure that the systemData class object successfully instantiated
if (!$obj->status) {
$formErrors = $obj->eventMessages;
if (is_object($obj->widget)) $obj->widget->__destruct();
if (is_object($obj)) $obj->__destruct();
unset($obj);
return;
}
// fetch the systemData
$query = [null];
$obj->widget->_fetchRecords([STRING_QUERY_DATA => $query]);
if (!$obj->status) {
$formErrors = $obj->widget->eventMessages;
if (is_object($obj->widget)) $obj->widget->__destruct();
if (is_object($obj)) $obj->__destruct();
unset($obj);
return;
}
// get the data array
$obj->widget->eventMessages = null;
$systemData = $obj->widget->getData();
if (is_array($systemData)) $systemData = $systemData[0];
$sysDataLoad = (empty($obj->widget->eventMessages)) ? true : false;
if (is_null($systemData) and $sysDataLoad) {
$systemMessage[] = 'The system data table has not been created yet; the table will be created when the new data is saved.';
} elseif (!$sysDataLoad) {
$formErrors[] = $obj->widget->eventMessages;
}
if (is_object($obj->widget)) $obj->widget->__destruct();
if (is_object($obj)) $obj->__destruct();
unset($obj);

View File

@@ -0,0 +1,71 @@
/**
* gaAdmin.js
*
* This is the javascript file for the Namaste admin web-program: gaAdmin.php.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 08-06-18 CORE-1113: original coding
*
*/
/**
*
* This stub handles the click event when a user clicks on the side-nav bar (Edit Constants) and selects the option
* to edit either the STATE or STATUS constants. The stub evaluates which link was clicked and passes the result back
* to the server via AJAX which, in turn, should spawn the events to fetch the systemData record and display the
* appropriate data field on-screen.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 08-06-18 mks CORE-1113: original coding
*
*/
$('.getSysD').on('click', function () {
var id = this.id;
var which = 0;
// console.log('id: ' + id);
switch (id) {
case 'stateConstants' :
which = 'c=1';
break;
case 'statusConstants' :
which = 'c=2';
break;
}
// console.log('which: ' + which);
event.preventDefault();
event.stopImmediatePropagation();
$.ajax({
type : "POST",
data : which,
success: function ( response ) {
$('body').html(response);
console.log(response);
}
});
return false;
});
// $( "#gaConstants" ).submit(function() {
// alert( "Handler for .submit() called." );
// // event.preventDefault();
// $.ajax({
// type : "POST",
// data : 'stateConstants=1',
// success: function () {
// }
// })
// });

View File

@@ -0,0 +1,81 @@
<?php
/**
* loadConstants.php
*
* This stub is called when a user selects the option to edit the state or status constants in namaste.
*
* We call this stub to generate the main panel (HTML) which is an editable table containing the data pulled from
* the systemData collection -- depending on which link was clicked on the main page, we'll load either state or
* status constants into the table.
*
* If there is no data in the system table, the system message will display that fact and we'll proc an empty table
* for the user to begin population.
*/
// state constants == 1
// status constants == 2
if (intval($data['c']) == 1) {
$whichConstant = VALID_STATES;
$constantTitle = 'States';
} elseif (intval($data['c']) == 2) {
$whichConstant = VALID_STATUS;
$constantTitle = 'Status';
} else {
$systemMessage = 'Invalid data (status) choice!';
return;
}
$htmlMain = '
<div class="col-md-5">
<!-- Panel Header -->
<div class="view view-cascade py-3 gradient-card-header info-color-dark">
<h5>' . $whichConstant . '</h5>
</div>
<!-- Panel Content -->
<div class="card-body card-body-cascade">
<!-- Grid Row -->
<div class="row">
<!-- Grid Column -->
<div class="col-md-auto mb-4">
<!-- Editable Table -->
<div class="card">
<h3 class="card-header text-center font-weight-bold text-uppercase py-4">' . $constantTitle . '</h3>
<div class="card-body">
<div id="constantTable" class="table-editable">
<span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success">
<i class="fa fa-plus fa-2x" aria-hidden="true"></i></a>
</span>
<table class="table table-bordered table-responsive-md table-striped text-center">
<tr>
<th class="text-center">Constant Key</th>
<th class="text-center">Constant Value</th>
<th class="text-center">Remove</th>
</tr>
';
if (isset($systemData) and is_array($systemData)) {
foreach ($systemData[$whichConstant] as $key => $value) {
$htmlMain .= '<tr>';
$htmlMain .= '<td class="pt-3-half" contenteditable="true">' . $key . '</td>';
$htmlMain .= '<td class="pt-3-half" contenteditable="true">' . $value . '</td>';
$htmlMain .= '<td><span class="table-remove"><button type="button" class="btn btn-danger btn-rounded btn-sm my-0">Remove</button></span></td>';
$htmlMain .= '</tr>';
}
}
$htmlMain .= '
</table>
</div>
</div>
</div>
<!-- !Editable Table -->
</div>
<!-- !Grid Column -->
</div>
<!-- !Grid Row -->
</div>
<!-- !Panel Content -->
';
?>

298
utilities/cachejefe.php Normal file
View File

@@ -0,0 +1,298 @@
<?php
/**
* cachejefe.php -- the 21st-Century Namaste Cache Manager!
*
* This program uses the Material-Design Bootstrap framework which is licensed to Micheal Shallop, personally, but can
* can be distributed as a web-app under the developer license. (See the licensing files in ./html for more info)
*
* This program is a replacement for the old cache-manager program which has a stunning UI reminiscent of 2004. This
* app could be a lot more ajax-y but I'm about as far as it gets from being a f/e dev so you gets what you gets.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 03-05-18 mks CORE-781: original coding
* 08-29-18 mks DB-50: replaced boots with sneakers
* 01-17-20 mks DB-150: squelching sneakerstrap stdout/stderr
*
*/
// initialization
ob_start();
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc');
ob_end_clean();
ini_set('xdebug.var_display_max_depth', 10);
ini_set('xdebug.var_display_max_children', 256);
ini_set('xdebug.var_display_max_data', 1024);
$data = (isset($_REQUEST['data'])) ? $_REQUEST['data'] : STRING_CACHE_HOME;
$errorMessage = '';
$cRecord = null;
if (strlen($_REQUEST[STRING_CACHE_SEARCH])) {
// search all the keys for the submitted search string
$searchKey = htmlspecialchars($_REQUEST[STRING_CACHE_SEARCH]);
$cKeys = gasCache::getAllKeys();
$foundKeys = [];
foreach($cKeys as $key) {
if (stripos($key, $searchKey) !== false and (!in_array($key, $foundKeys))) {
$foundKeys[] = $key;
$tmp = "<a href='?data=delete&ckey=$key'><i class='fa fa-trash red-text'></i></a>&nbsp;&nbsp;";
$tmp .= "<a href='?data=fetch&ckey=$key'><i class='fa fa-eye'></i> </a>&nbsp;&nbsp;" . $key . "<br>";
$keyData[] = $tmp;
}
}
$keyCount = count($foundKeys);
$data = STRING_CACHE_SEARCH;
} else {
// otherwise, they clicked on a nav-bar option
switch ($data) {
case STRING_CACHE_FETCH :
$cRecord = gasCache::sysGet($_REQUEST[STRING_CACHE_CKEY]);
if (!empty($cRecord) and !is_array($cRecord)) {
$extractedData = json_decode(gzuncompress($cRecord), true);
if (!is_null($extractedData))
$cRecord = $extractedData;
} elseif (empty($cRecord)) {
$errorMessage = 'Data referenced by key no longer exists in-cache; the key may have expired.';
}
break;
case STRING_CACHE_FLUSH :
$res = gasCache::flush_cache();
$cRecord = 'Cache was ' . ((!$res) ? '<span class="red-text">NOT</span> ' : '') . 'flushed successfully!';
break;
case STRING_CACHE_STATS :
$cData = gasCache::get_stats();
break;
case STRING_CACHE_DELETE :
gasCache::sysDel($_REQUEST[STRING_CACHE_CKEY]);
$delMsg = 'Key ' . $_REQUEST[STRING_CACHE_CKEY] . ' was deleted.';
break;
case STRING_CACHE_KEYS :
// get a list of all keys in cache
$keyList = gasCache::getAllKeys();
sort($keyList);
$foundKeys = [];
$counter = 1;
$keyData = [];
if (is_array($keyList)) {
foreach ($keyList as $cKey) {
if (!in_array($cKey, $foundKeys)) {
$foundKeys[] = $cKey;
$tmp = "<a href='?data=delete&ckey=$cKey'><i class='fa fa-trash red-text'></i></a>&nbsp;&nbsp;";
$tmp .= "<a href='?data=fetch&ckey=$cKey'><i class='fa fa-eye'></i> </a>&nbsp;&nbsp;" . $cKey . "<br>";
$keyData[] = $tmp;
}
}
$keyCount = count($foundKeys);
}
break;
case STRING_CACHE_HOME :
; // do nothing
break;
}
}
?>
<!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 Tools: Cache Jefe</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.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>
<nav class="navbar navbar-expand-lg justify-content-between navbar-dark blue-gradient">
<a class="navbar-brand" href="#">
<!--suppress CheckImageSize -->
<img src="../html/img/namaste.png" height="50" alt="">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="cachejefeNav">
<form method="post" action="">
<ul class="navbar-nav">
<li class="nav-item <?php if ($data == STRING_CACHE_HOME) echo 'active'; ?>">
<a class="nav-link" href="?data=home">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item <?php if ($data == STRING_CACHE_KEYS) echo 'active'; ?>">
<a class="nav-link" href="?data=keys">Keys </a>
</li>
<li class="nav-item <?php if ($data == STRING_CACHE_STATS) echo 'active'; ?>">
<a class="nav-link" href="?data=stats">Stats </a>
</li>
<li class="nav-item <?php if ($data == STRING_CACHE_FLUSH) echo 'active'; ?>">
<a class="nav-link" href="?data=flush">Flush </a>
</li>
</ul>
</form>
</div>
<!-- search box -->
<form method="post" action="" class="form-inline my-0">
<div class="md-form form-sm mt-0">
<input class="form-control form-control-sm mr-sm-2 mb-0" name="keyHash" type="text" maxlength="100" placeholder="Search (partials accepted)" aria-label="Search">
</div>
<button class="btn btn-outline-white btn-sm my-0" type="submit">Search</button>
</form>
</nav>
<?php
switch ($data) {
case STRING_CACHE_HOME :
echo
'<div style="height: 50vh">
<div class="flex-center flex-column">
<h1 class="animated fadeIn mb-4">Namaste Cache Jefe</h1>
<h5 class="animated fadeIn mb-3">Diagnostic and Debugging Tool</h5>
<p class="animated fadeIn text-muted">Making cache your bitch since 2011!</p>
<div class="text-left flex-column">
<br><br>
<p><strong>Home </strong>displays this page</p>
<p><strong>Keys </strong>lists all of the available keys currently stored in cache</p>
<p><strong>Stats </strong>displays cache stats output which as some useful information</p>
<p><strong>Flush </strong>flushes cache and <strong class="red-text">deletes </strong>ALL keys</p>
<p><strong>Search </strong>allows you to search by all or part of a cache key</p>
</div>
</div>
</div>';
break;
case STRING_CACHE_FETCH :
case STRING_CACHE_FLUSH :
echo
'<div class="container-fluid">
<div class="card">
<h4 class="card-body">
<div class="card-title"><strong>';
if ($data == STRING_CACHE_FETCH)
echo 'Cached Content for ' . $_REQUEST[STRING_CACHE_CKEY];
else
echo 'Cache Flush Request';
echo '</strong>
</div>
</h4>
<div class="card-text" style="margin-left:10px;">';
if (!is_null($cRecord) and is_array($cRecord))
var_dump($cRecord);
elseif (false !== $cRecord and is_scalar($cRecord))
echo $cRecord . '<br><br>';
elseif (!empty($errorMessage))
echo "<div class='text-danger'>" . $errorMessage . "</div>";
else
echo "<div class='text-danger'>" . ERROR_UNKNOWN_EVENT . $data . "</div>";
echo '</div></div></div>';
break;
case STRING_CACHE_STATS :
echo
'<br><div class="container-fluid">
<div class="flex-center flex-column">
<div class="card">
<h4 class="card-body ">
<strong>
<div class="card-title">Cache Stats</div>
</strong>
<span class="card-text">';
if (is_array($cData)) {
var_dump($cData);
} else {
echo "Could not retrieve cache stats";
}
echo '
</span>
</h4>
</div>
</div>
</div>';
break;
case STRING_CACHE_SEARCH :
case STRING_CACHE_KEYS :
case STRING_CACHE_DELETE :
?>
<br><br>
<div class="container-fluid">
<div class="row justify-content-md-center">
<div class="col">
<div class="card">
<div class="card-body">
<?php
if ($data == STRING_CACHE_KEYS) {
echo '<h5 class="card-title">Current Cached Key Count:' . $keyCount . '</h5>';
} elseif ($data == STRING_CACHE_DELETE) {
echo '<h5 class="card-title">' . $delMsg . '</h5>';
} else {
echo '<h5 class="card-title">Cached Key Search Results Count: ' . $keyCount . '</h5>';
}
?>
<span class="card-text">
<?php
if ($data != STRING_CACHE_DELETE) {
if ($keyCount) {
echo "Click the <i class='fa fa-trash red-text'></i> to delete a cached record.&nbsp;&nbsp;";
echo "Click the <i class='fa fa-eye blue-text'></i> to view the cached record.";
} else {
if ($data == STRING_CACHE_KEYS) {
echo 'There are no records currently stored in the cache system.';
} else {
echo 'Search request: "' . $searchKey . '", returned no data.';
}
}
}
?>
<br><br>
</span>
</div>
</div>
</div>
</div>
<br>
<?php
for ($index = 0; $index < $keyCount; $index+=3) {
echo '<div class="row">' . $eos;
if (!empty($keyData[$index]))
echo '<div class="col">' . $keyData[$index] . '</div>' . $eos;
if (!empty($keyData[($index + 1)]))
echo '<div class="col">' . $keyData[$index+1] . '</div>' . $eos;
if (!empty($keyData[($index + 2)]))
echo '<div class="col">' . $keyData[$index+2] . '</div>' . $eos;
echo '</div>' . $eos;
}
?>
</div>
<?php
break;
}
?>
<!-- SCRIPTS -->
<!-- JQuery -->
<script type="text/javascript" src="../html/js/jquery-3.2.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.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="../html/js/mdb.min.js"></script>
</body>
</html>

206
utilities/cashpeak.php Normal file
View File

@@ -0,0 +1,206 @@
<?php
/**
* memcache reader utility
*
* load it - it's self documenting...
*
* todo: convert to MDB
*
* @author mike@givingassistant.org
* @version 1.0.0
*
* HISTORY:
* --------
* 07-14-17 mks CORE-470: initial coding
*
*/
// initialization
require_once(dirname(__DIR__) . '/config/bootstrap.inc');
$sizeA = 0;
$sizeB = 0;
$keyCount = 0;
$idHash = null;
$errorMsg = null;
$hashKey = null;
$data = '';
//get current maintenance mode status
if (!empty($_REQUEST['maintenanceMessage'])) {
gasCache::add('maintenance', gzcompress(json_encode(['maintenanceMessage' => $_REQUEST['maintenanceMessage']])));
}
if ($maintenance = gasCache::get('maintenance')) {
if ($maintenance !== 1) {
$maintenance = json_decode(gzuncompress($maintenance), true);
}
}
if (isset($_REQUEST['admin'])) {
switch ($_REQUEST['admin']) {
case 'getKeys' :
$info = gasCache::getAllKeys();
$data = '';
$foundKeys = array();
if (is_array($info)) {
sort($info);
foreach($info as $row) {
if (!in_array($row, $foundKeys)) {
$keyCount++;
$data .= "<a class='delete' href='?idhash=$row&delete=1'></a>";
$data .= "<a class='cachekey' href='?idhash=$row'>$row</a>";
$data .= '<br>';
$foundKeys[] = $row;
}
}
$data .= '<br><br><br>';
$data = 'Key Count: ' . $keyCount . '<br><br>' . $data;
}
break;
case 'getStats' :
$data = gasCache::get_stats();
break;
case 'doFlush' :
gasCache::flush_cache();
$data = 'Cache has been flushed';
break;
case 'doDeleteAll':
$keys = gasCache::getAllKeys();
if (is_array($keys)) {
foreach($keys as $key)
{
if(!gasCache::delete($key))
echo "Could not delete one of the keys";
}
echo "Deleted all keys!";
}
break;
case 'toggleMaintenance':
if($maintenance) {
gasCache::delete('maintenance');
} else {
gasCache::add('maintenance', gzcompress(true));
}
header("Location: ".$_SERVER['SCRIPT_NAME']."?admin=getKeys"); die;
break;
}
} elseif (isset($_REQUEST['idhash'], $_REQUEST['delete'])) {
$key = $_REQUEST['idhash'];
if(!gasCache::delete($key))
$errorMsg[] = 'Could not delete: ' . $key;
else {
header("Location: ".$_SERVER['SCRIPT_NAME']."?admin=getKeys"); die;
}
}
if (isset($_REQUEST['idhash'])) {
$eClass = '';
$idHash = htmlspecialchars(trim($_REQUEST['idhash']));
$allKeys = empty($info) ? gasCache::getAllKeys() : $info;
$data = '';
$multi = '';
$realHash = '';
$foundKeys = array();
foreach($allKeys as $key) {
if (stripos($key, $idHash) !== false and (!in_array($key, $foundKeys))) {
$foundKeys[] = $key;
$multi .= "<a class='delete' href='?idhash=$key&delete=1'></a>";
$multi .= "<a class='cachekey' href='?idhash=$key'>$key</a>";
$multi .= '<br>';
// Side effect is that only the first instance gets saved to $data
// but it doesn't matter because if there is more than on e instance
// we display all of the instances ($multi) instead of the details
if(empty($data)) {
$realHash = (strlen($idHash) > 30) ? $key : $idHash; // save the real $idHash of what we might be displaying the details of
$data = gasCache::get($realHash);
if (is_null($data)) {
$data = gasCache::sysGet($realHash);
} else {
$sizeB = strlen(serialize($data));
$data = json_decode(gzuncompress($data), true);
$sizeA = strlen(serialize($data));
}
}
}
}
if(substr_count($multi, '<br>') > 1)
$data = $multi;
else
$idHash = $realHash; // We display the $idHash in the details so display what
// the real $idHash is, not what they were looking for
if(empty($data)) {
$data = 'key not found in-cache: ' . $idHash;
}
}
?>
<HTML>
<HEAD>
<title>Cash Peak - Better than a ATM!</title>
<link rel="stylesheet" href="logger.css" type="text/css">
</HEAD>
<body>
<div class="title">
Cash Peak
</div>
<div class="container">
<form method="POST" action="">
<fieldset>
<legend>Cash Commands</legend>
<a href='?admin=getKeys'>Get All Keys</a><br>
<a href='?admin=getStats'>Get Cache Stats</a><br>
<a href='?admin=doFlush'>Flush Cache</a><br>
<a href='?admin=doDeleteAll'>Delete All Keys</a><br>
<a href='?admin=toggleMaintenance'>Toggle Maintenance Mode</a> (Status: <?=!empty($maintenance) ? 'ON' : 'OFF'?>)<br/><br/>
<textarea rows="3" style="-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;width: 100%;" name="maintenanceMessage" placeholder="Enter maintenance message here..."><?= !empty($maintenance['maintenanceMessage']) ? $maintenance['maintenanceMessage'] : '' ?></textarea><br/>
<br>
<input type="submit" value="Set message"/><br/>
</fieldset>
<br>
<label>Find HashToken:</label>&nbsp;
<input type="text" name="idhash" size="50%" placeholder=" ...also accepts partial tokens...">&nbsp;&nbsp;&nbsp;
<button type="submit">fetch!</button>
</form>
<div class="rowError">
<?php
if (is_array($errorMsg)) {
foreach($errorMsg as $row) {
echo $row . '<br>';
}
}
?>
</div>
<div class="rowData">
<?php
if (!empty($data)) {
if (is_array($data)) {
if (!empty($idHash))
echo '<div>Hash Key: ' . $realHash . '</div>';
if ($sizeA and $sizeB) {
echo '<div>Size In-Cache: ' . $sizeB . '</div>';
echo '<div>Size In-Memory: ' . $sizeA . '</div>';
echo '<div>Compression: ' . sprintf('%2.2f',(($sizeA - $sizeB) / $sizeA) * 100) . '%</div>';
}
echo "<pre>";
var_export($data); // use this one only if you've tweaked your var-dump depth
echo "</pre>";
} elseif (!empty($realHash)) {
echo '<div>Output for: ' . $realHash . COLON;
echo $data;
echo '</div>';
}
}
?>
</div>
<div
</div>
</body>
</HTML>

258
utilities/ddbtp.php Normal file
View File

@@ -0,0 +1,258 @@
<?php
/**
* DynamoDB Template Processor
*
* in this first version, we're only going to create new tables from the template files...
*
* -- added code to properly handle secondary indices with error checking and verbose error messaging
* -- cannot create a table if it already exists in the database; you must first delete a table
* before creating if if pre-exists unless you're executing this script in a development environment AND
* you've specified the "--delete" command line option.
*
* Delete a table from the command line:
* aws dynamodb delete-table --table-name development_gaLogs --endpoint-url http://localhost:8000
*
* List tables from the command line:
* aws dynamodb list-tables --endpoint-url http://localhost:8000
*
* Describe a table:
* aws dynamodb describe-table --table-name development_gaLogs_log --endpoint-url http://localhost:8000
*
* Help with ddb indexes:
* https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html
*
*
* @author mike@givingassitant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 06-13-17 mks original coding
* 06-27-17 mks processing for secondary indices
* development-env bypass for deleting an existing table
* 06-28-17 mks ensured that attribute keys are not duplicated,
* added check for template type == TEMPLATE_DB_DDB,
* added check that if secondary index, then the hash key is same as base index hash key
* 07-10-18 mks CORE-773: replaced file-logging output with consoleLog()
*
*/
use Aws\DynamoDb\Exception\DynamoDbException;
$_REDIRECT=false; // enable stdout
$opts = getopt("", [ "delete::" ]);
$eos = (isset($_SERVER['HTTP_USER_AGENT'])) ? '<br />' : PHP_EOL;
$topDir = dirname( __DIR__ );
// load the files stored in the common directory
foreach(glob($topDir . '/common/*.php') as $filename) {
/** @noinspection PhpIncludeInspection */
require_once($filename);
}
$classesDir = $topDir . DIR_CLASSES;
$configDir = $topDir . DIR_CONFIG;
$amqpLib = $topDir . DIR_LIB;
$templateDir = $topDir . DIR_CLASSES . DIR_TEMPLATE;
$logDir = $topDir . DIR_LOGS;
date_default_timezone_set(STRING_SYS_TZ);
$eol = "\n";
$res = 'DDBC: ';
/** @noinspection PhpIncludeInspection */
require($topDir . FILE_AUTOLOADER);
if(file_exists($classesDir)) {
Autoloader::register_directory($classesDir);
Autoloader::register_directory($templateDir);
}
require_once $amqpLib . '/vendor/autoload.php';
//load the base config
gasConfig::singleton($configDir . FILE_BASE_CONFIG, FILE_TYPE_XML);
// layer the env config
if (file_exists($configDir . FILE_ENV_CONFIG)) {
gasConfig::addConfig($configDir . FILE_ENV_CONFIG, FILE_TYPE_XML);
}
// environment matters
$validEnvs = [ ENV_DEVELOPMENT, ENV_STAGING, ENV_PRODUCTION ];
$env = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV];
if (!in_array($env, $validEnvs)) {
consoleLog($res, CON_ERROR, ERROR_ENV_INVALID . $env);
exit(1);
}
// check to see if user is requesting to hard-delete existing table(s)
$hardDelete = (array_key_exists('delete', $opts)) ? true : false; // won't work with a constant
// safety net to ensure that we cannot hard-delete a table in a non-development environment
if ($env != ENV_DEVELOPMENT) $hardDelete = false;
$errors = null;
consoleLog($res, CON_SUCCESS, sprintf(INFO_TEMPLATE_PROCESSING_STARTED, CONFIG_DATABASE_DDB));
/** @var Aws\DynamoDb\DynamoDbClient $ddbConnection */
$ddbConnection = gasResourceManager::fetchResource(RESOURCE_DDB);
if (is_null($ddbConnection)) {
consoleLog($res, CON_ERROR, ERROR_DDB_CONNECT);
exit(1);
}
// first, let's get a list of all the existing tables...
$result = $ddbConnection->listTables();
$meta = $result->get(DDB_METADATA);
if ($meta[DDB_STATUS_CODE] != NUMBER_HTTP_SUCCESS) {
consoleLog($res, CON_ERROR, ERROR_DDB_QUERY . 'listTables()');
exit(1);
}
$tableList = $result->get(DDB_TABLE_NAMES);
if (!sizeof($tableList)) $tableList = null;
$pt = [
DDB_STRING_READ_CAPACITY_UNITS => gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_READ_CAPACITY_UNITS],
DDB_STRING_WRITE_CAPACITY_UNITS => gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_WRITE_CAPACITY_UNITS]
];
$counter = 0;
$deleteCounter = 0;
foreach(glob(dirname(__DIR__) . DIR_CLASSES . DIR_TEMPLATE . STRING_CLASS_FILE_GAT . '*' . STRING_CLASS_FILE_EXT) as $filename) {
$currentClass = basename($filename);
$currentClass = preg_replace("/" . STRING_CLASS_FILE_EXT . "/", "", $currentClass);
consoleLog($res, CON_SUCCESS, INFO_PROCESSING . $currentClass);
try {
/** @var gatLogs() $tmpObj */
$tmpObj = new $currentClass();
} catch (Exception $e) {
consoleLog($res, CON_ERROR, $e->getMessage());
}
/** @noinspection PhpUndefinedVariableInspection */
if ($tmpObj->schema != TEMPLATE_DB_DDB) break; // skip if not a DDB template
$iKeys = array_keys($tmpObj->indexes);
$schema = null;
$gsi = null; // global secondary indexes
$lsi = null; // local secondary indexes
$attrDefs = null;
$baseHashName = '';
$uniqAttrList = null;
// process template directives for base index
for ($index = 0; $index < sizeof($tmpObj->indexes); $index++) {
$uniqAttrList[] = $iKeys[$index] . $tmpObj->extension;
if ($tmpObj->indexes[$iKeys[$index]] == DDB_INDEX_HASH) $baseHashName = $iKeys[$index];
$schema[] = [DDB_STRING_ATTRIBUTE_NAME => $iKeys[$index] . $tmpObj->extension, DDB_STRING_KEY_TYPE => $tmpObj->indexes[$iKeys[$index]]];
$attrDefs[] = [DDB_STRING_ATTRIBUTE_NAME => $iKeys[$index] . $tmpObj->extension, DDB_STRING_ATTRIBUTE_TYPE => $tmpObj->fields[$iKeys[$index]]];
}
// process directives for secondary indexes
$indexList = [ DDB_STRING_GSI, DDB_STRING_LSI ];
// loop to process the template's global and then the secondary index array structures
foreach ($indexList as $thisIndex) {
$ti = null; // this index
$requiredFieldList = [STRING_NAME, STRING_INDEXES, DDB_STRING_PT];
$ptValues = [ DDB_PT_KEYS_ONLY, DDB_PT_INCLUDE, DDB_PT_ALL ];
for ($index = 0, $c = count($tmpObj->$thisIndex); $index < $c; $index++) {
$nka = null;
$projection = null;
$keySchema = null;
if (!empty($tmpObj->$thisIndex[$index][DDB_STRING_NON_KEY_ATTRIBUTE])
and is_array($tmpObj->$thisIndex[$index][DDB_STRING_NON_KEY_ATTRIBUTE])
) {
$nka = $tmpObj->$thisIndex[$index][DDB_STRING_NON_KEY_ATTRIBUTE];
}
if (!in_array($tmpObj->$thisIndex[$index][DDB_STRING_PT], $ptValues)) {
consoleLog($res, CON_ERROR, '(' . $thisIndex . ')::Invalid index projection type: ' . $tmpObj->$thisIndex[$index][DDB_STRING_PT]);
exit(1);
}
$projection = [DDB_STRING_PROJECTION_TYPE => $tmpObj->$thisIndex[$index][DDB_STRING_PT]];
if (!is_null($nka) and $tmpObj->$thisIndex[$index][DDB_STRING_PT] == DDB_PT_INCLUDE) {
$attrList = null;
// append the class extension to the non-key attributes in a projection
foreach ($tmpObj->$thisIndex[$index][DDB_STRING_NON_KEY_ATTRIBUTE] as $attribute)
$attrList[] = $attribute . $tmpObj->extension;
$projection[DDB_STRING_NON_KEY_ATTRIBUTES] = $attrList;
// $projection[DDB_STRING_NON_KEY_ATTRIBUTES] = $tmpObj->$thisIndex[$index][DDB_STRING_NON_KEY_ATTRIBUTE];
} elseif (!is_null($nka)) {
consoleLog($res, CON_ERROR, 'Ignored non-key-attribute list because projection type is: ' . $tmpObj->$thisIndex[$index][DDB_STRING_PT]);
}
$ti[$index] = [
DDB_STRING_INDEX_NAME => $tmpObj->$thisIndex[$index][STRING_NAME],
DDB_STRING_PROJECTION => $projection,
];
$c2 = 0;
foreach ($tmpObj->$thisIndex[$index][STRING_INDEXES] as $ik => $iv) {
if ($thisIndex == DDB_STRING_LSI and $iv == DDB_INDEX_HASH and $ik != $baseHashName) {
consoleLog($res, CON_ERROR, 'Template error: a secondary index must have the same HASH key as the base index!');
consoleLog($res, CON_ERROR, 'Check template: ' . $filename . ': ' . $thisIndex . ' and correct');
exit(1);
}
$keySchema[$c2++] = [ DDB_STRING_ATTRIBUTE_NAME => ($ik . $tmpObj->extension), DDB_STRING_KEY_TYPE => $iv ];
if (!in_array(($ik . $tmpObj->extension), $uniqAttrList)) {
$uniqAttrList[] = ($ik . $tmpObj->extension);
$attrDefs[] = [DDB_STRING_ATTRIBUTE_NAME => $ik . $tmpObj->extension, DDB_STRING_ATTRIBUTE_TYPE => $tmpObj->fields[$ik]];
}
}
$ti[$index][DDB_STRING_KEY_SCHEMA] = $keySchema;
if (isset($tmpObj->$thisIndex[$index][STRING_THROUGHPUT]) and $thisIndex == DDB_STRING_GSI) {
$ti[$index][DDB_STRING_PROVISIONED_THROUGHPUT][DDB_STRING_READ_CAPACITY_UNITS] = $tmpObj->$thisIndex[$index][STRING_THROUGHPUT][CONFIG_DATABASE_READ_CAPACITY_UNITS];
$ti[$index][DDB_STRING_PROVISIONED_THROUGHPUT][DDB_STRING_WRITE_CAPACITY_UNITS] = $tmpObj->$thisIndex[$index][STRING_THROUGHPUT][CONFIG_DATABASE_WRITE_CAPACITY_UNITS];
} elseif (isset($tmpObj->$thisIndex[$index][STRING_THROUGHPUT]) and $thisIndex == DDB_STRING_LSI) {
consoleLog($res, CON_ERROR, 'Detected throughput provisioning for local secondary index which is not allowed.');
consoleLog($res, CON_ERROR, 'Check configuration for index: ' . $tmpObj->$thisIndex[$index][STRING_NAME]);
exit(1);
}
}
if ($thisIndex == DDB_STRING_GSI) $gsi = $ti;
if ($thisIndex == DDB_STRING_LSI) $lsi = $ti;
}
$tn = $env . UDASH . $tmpObj->collection . $tmpObj->extension;
$newt = [
DDB_STRING_TABLE_NAME => $tn,
DDB_STRING_KEY_SCHEMA => $schema,
DDB_STRING_ATTRIBUTE_DEFINITIONS => $attrDefs,
DDB_STRING_PROVISIONED_THROUGHPUT => $pt
];
if (!is_null($gsi)) $newt[DDB_STRING_GLOBAL_SI] = $gsi;
if (!is_null($lsi)) $newt[DDB_STRING_LOCAL_SI] = $lsi;
// to be able to delete a table, we must be in development env and explicitly passed the --delete option
$exec = true;
if (in_array($tn, $tableList) and gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] != ENV_DEVELOPMENT) {
consoleLog($res, CON_ERROR, 'Table: ' . $tn . ' already exists in the database...skipping...');
consoleLog($res, CON_ERROR, 'You must remove a table before you can create it.');
$exec = false;
} elseif (gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] == ENV_DEVELOPMENT and $hardDelete and in_array($tn, $tableList)) {
consoleLog($res, CON_SYSTEM, 'Table: ' . $tn . ' already exists, but you have authorized it to be deleted.');
try {
$res = $ddbConnection->deleteTable([DDB_STRING_TABLE_NAME => $tn]);
consoleLog($res, CON_SUCCESS, 'Successfully deleted table: ' . $tn);
$deleteCounter++;
} catch (DynamoDbException $e) {
consoleLog($res, CON_ERROR, "Failed to create table: " . $tn);
consoleLog($res, CON_ERROR, $e->getMessage());
exit(1);
} catch (InvalidArgumentException $e) {
consoleLog($res, CON_ERROR, "Failed to create table: " . $tn);
consoleLog($res, CON_ERROR, $e->getMessage());
// print_r($newt);
exit(1);
}
}
if ($exec) {
try {
$res = $ddbConnection->createTable($newt);
consoleLog($res, CON_SUCCESS, 'Successfully created table: ' . $tn);
$counter++;
} catch (DynamoDbException $e) {
consoleLog($res, CON_ERROR, 'Failed to create table: ' . $tn);
consoleLog($res, CON_ERROR, $e->getMessage());
// print_r($newt);
exit(1);
} catch (InvalidArgumentException $e) {
consoleLog($res, CON_ERROR, 'Failed to create table: ' . $tn);
consoleLog($res, CON_ERROR, $e->getMessage());
// print_r($newt);
exit(1);
}
}
}
if ($deleteCounter) {
consoleLog($res, CON_SYSTEM, 'deleted ' . $deleteCounter . ' tables...');
}
consoleLog($res, CON_SUCCESS, 'created ' . $counter . ' tables... ');
exit(0);

View File

@@ -0,0 +1,207 @@
<?php
/**
* memcache reader utility
*
* load it - it's self documenting...
*
* todo: convert to MDB
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* --------
* 07-14-17 mks CORE-470: initial coding
*
*/
// initialization
require_once(dirname(__DIR__) . '/config/bootstrap.inc');
$sizeA = 0;
$sizeB = 0;
$keyCount = 0;
$idHash = null;
$errorMsg = null;
$hashKey = null;
$data = '';
$info = null;
//get current maintenance mode status
if (!empty($_REQUEST['maintenanceMessage'])) {
gasCache::add('maintenance', gzcompress(json_encode(['maintenanceMessage' => $_REQUEST['maintenanceMessage']])));
}
if ($maintenance = gasCache::get('maintenance')) {
if ($maintenance !== 1) {
$maintenance = json_decode(gzuncompress($maintenance), true);
}
}
if (isset($_REQUEST['admin'])) {
switch ($_REQUEST['admin']) {
case 'getKeys' :
$info = gasCache::getAllKeys();
$data = '';
$foundKeys = array();
if (is_array($info)) {
sort($info);
foreach($info as $row) {
if (!in_array($row, $foundKeys)) {
$keyCount++;
$data .= "<a class='delete' href='?idhash=$row&delete=1'></a>";
$data .= "<a class='cachekey' href='?idhash=$row'>$row</a>";
$data .= '<br>';
$foundKeys[] = $row;
}
}
$data .= '<br><br><br>';
$data = 'Key Count: ' . $keyCount . '<br><br>' . $data;
}
break;
case 'getStats' :
$data = gasCache::get_stats();
break;
case 'doFlush' :
gasCache::flush_cache();
$data = 'Cache has been flushed';
break;
case 'doDeleteAll':
$keys = gasCache::getAllKeys();
if (is_array($keys)) {
foreach($keys as $key)
{
if(!gasCache::delete($key))
echo "Could not delete one of the keys";
}
echo "Deleted all keys!";
}
break;
case 'toggleMaintenance':
if($maintenance) {
gasCache::delete('maintenance');
} else {
gasCache::add('maintenance', gzcompress(true));
}
header("Location: ".$_SERVER['SCRIPT_NAME']."?admin=getKeys"); die;
break;
}
} elseif (isset($_REQUEST['idhash'], $_REQUEST['delete'])) {
$key = $_REQUEST['idhash'];
if(!gasCache::delete($key))
$errorMsg[] = 'Could not delete: ' . $key;
else {
header("Location: ".$_SERVER['SCRIPT_NAME']."?admin=getKeys"); die;
}
}
if (isset($_REQUEST['idhash'])) {
$eClass = '';
$idHash = htmlspecialchars(trim($_REQUEST['idhash']));
$allKeys = empty($info) ? gasCache::getAllKeys() : $info;
$data = '';
$multi = '';
$realHash = '';
$foundKeys = array();
foreach($allKeys as $key) {
if (stripos($key, $idHash) !== false and (!in_array($key, $foundKeys))) {
$foundKeys[] = $key;
$multi .= "<a class='delete' href='?idhash=$key&delete=1'></a>";
$multi .= "<a class='cachekey' href='?idhash=$key'>$key</a>";
$multi .= '<br>';
// Side effect is that only the first instance gets saved to $data
// but it doesn't matter because if there is more than on e instance
// we display all of the instances ($multi) instead of the details
if(empty($data)) {
$realHash = (strlen($idHash) > 30) ? $key : $idHash; // save the real $idHash of what we might be displaying the details of
$data = gasCache::get($realHash);
if (is_null($data)) {
$data = gasCache::sysGet($realHash);
} else {
$sizeB = strlen(serialize($data));
$data = json_decode(gzuncompress($data), true);
$sizeA = strlen(serialize($data));
}
}
}
}
if(substr_count($multi, '<br>') > 1)
$data = $multi;
else
$idHash = $realHash; // We display the $idHash in the details so display what
// the real $idHash is, not what they were looking for
if(empty($data)) {
$data = 'key not found in-cache: ' . $idHash;
}
}
?>
<HTML>
<HEAD>
<title>Cash Peak - Better than a ATM!</title>
<link rel="stylesheet" href="logger.css" type="text/css">
</HEAD>
<body>
<div class="title">
Cash Peak
</div>
<div class="container">
<form method="POST" action="">
<fieldset>
<legend>Cash Commands</legend>
<a href='?admin=getKeys'>Get All Keys</a><br>
<a href='?admin=getStats'>Get Cache Stats</a><br>
<a href='?admin=doFlush'>Flush Cache</a><br>
<a href='?admin=doDeleteAll'>Delete All Keys</a><br>
<a href='?admin=toggleMaintenance'>Toggle Maintenance Mode</a> (Status: <?=!empty($maintenance) ? 'ON' : 'OFF'?>)<br/><br/>
<textarea rows="3" style="-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;width: 100%;" name="maintenanceMessage" placeholder="Enter maintenance message here..."><?= !empty($maintenance['maintenanceMessage']) ? $maintenance['maintenanceMessage'] : '' ?></textarea><br/>
<br>
<input type="submit" value="Set message"/><br/>
</fieldset>
<br>
<label>Find HashToken:</label>&nbsp;
<input type="text" name="idhash" size="50%" placeholder=" ...also accepts partial tokens...">&nbsp;&nbsp;&nbsp;
<button type="submit">fetch!</button>
</form>
<div class="rowError">
<?php
if (is_array($errorMsg)) {
foreach($errorMsg as $row) {
echo $row . '<br>';
}
}
?>
</div>
<div class="rowData">
<?php
if (!empty($data)) {
if (is_array($data)) {
if (!empty($idHash))
echo '<div>Hash Key: ' . $realHash . '</div>';
if ($sizeA and $sizeB) {
echo '<div>Size In-Cache: ' . $sizeB . '</div>';
echo '<div>Size In-Memory: ' . $sizeA . '</div>';
echo '<div>Compression: ' . sprintf('%2.2f',(($sizeA - $sizeB) / $sizeA) * 100) . '%</div>';
}
echo "<pre>";
var_export($data); // use this one only if you've tweaked your var-dump depth
echo "</pre>";
} elseif (!empty($realHash)) {
echo '<div>Output for: ' . $realHash . COLON;
echo $data;
echo '</div>';
}
}
?>
</div>
<div
</div>
</body>
</HTML>

63
utilities/dumper.php Normal file
View File

@@ -0,0 +1,63 @@
<?php
// initialization
/** @noinspection PhpIncludeInspection */
ob_start();
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc');
ob_end_clean();
$logger = new gacErrorLogger();
$lines = 100;
if (isset($_GET['lines'])) {
if (is_numeric($_GET['lines'])) {
if ($_GET['lines'] < 0) {
$lines = 100;
} else {
$lines = intval($_GET['lines']);
}
}
}
$where = TEMPLATE_CLASS_LOGS;
if (isset($_GET['source'])) {
$where = $_GET['source'];
}
$dataDump = $logger->getLog($lines, $where);
?>
<HTML>
<HEAD>
<title>GA Log Dumper - Go ahead - Take a dump!</title>
<link rel="stylesheet" href="logger.css" type="text/css">
</HEAD>
<body>
<div class="title">
GA Dump of: <?= $where?> Collection
</div>
<div class="container">
<form method="get" action="dumper.php">
<input type="radio" value="Logs" name="source" checked> Logs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input type="radio" value="Metrics" name="source"> Metrics &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Lines to Display: <input type="text" value="100" size="5" name="lines"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<button type="submit">Go</button>
</form>
<div>
<?php
if (gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_TIMERS] == 1) {
$msg = sprintf(INFO_SLOW_QUERY_TIMERS, STRING_ENABLED) . sprintf(INFO_QUERY_TIMER_VALUES, gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_TIMER_SLOW_QUERY_ALERT]);
echo $msg . $eos;
$msg = sprintf(INFO_SLOW_QUERY_TIMER_WARNINGS, STRING_ENABLED) . sprintf(INFO_QUERY_TIMER_VALUES, gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_TIMER_SLOW_QUERY_WARNING]);
echo $msg . $eos;
} else {
$msg = sprintf(INFO_SLOW_QUERY_TIMERS, STRING_DISABLED);
echo $msg . $eos;
}
?>
</div>
</div>
<div class="container">
<?php
echo (empty($dataDump)) ? 'No data found in GA collection:' . $where : $dataDump;
?>
</div>
</body>
</HTML>

835
utilities/gaAdmin.php Normal file
View File

@@ -0,0 +1,835 @@
<?php
/**
* gaAdmin -- the Namaste Admin program
*
* This program provides the administrative interface for Namaste - it is a single-script PHP program that utilizes
* Material-Design Bootstrap framework and template. (Licensed to Micheal Shallop/Single-Project) See the licensing
* doc in ./html for more info.
*
* The program self-processes user-input and allows for:
*
* a) updating some table-based data used in Namaste
* b) dashboard of generalized Namaste activity
*
* Over time, additional functionality will be added as required. For now, the main purpose of the program is to allow
* the Namaste admin an easy way to edit db data values, and passively view the state of Namaste.
*
* This script will only run from the admin service and so required a web-service to be installed.
*
* Programmer Notes:
* -----------------
* This project is incomplete - it requires someone much more adept (which is pretty much anyone) at f/e programming
* than myself. The sub-directory (./utilities/admin) contains additional scripts/programs for this main program.
*
* The MDB libs are in ./html and are licensed to me for this project. I acquired the admin-theme for this project
* and it's doc is at: https://mdbootstrap.com/product/admin-theme/
*
* @author mike@givingassistant.org
* @version 1.0.0
*
*
* HISTORY:
* ========
* 08-03-18 mks CORE-1113: Initial coding.
*
*/
// initialization
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc');
$systemMessage = [];
$formErrors = [];
$data = $_POST;
$formStatus = false;
$sysDataLoad = false;
$formState = STATE_DATA_ERROR;
if (!is_null($data) and isset($data['c'])) {
require_once('admin/fetchSysData.php');
}
// request to manipulate constants (state/status)
if (isset($data['c']) and $sysDataLoad) {
switch (intval($data['c'])) {
case 1 :
// state constants
case 2 :
// status constants
require_once('admin/loadConstants.php');
break;
default :
$systemMessage[] = 'received a bad parameter for constants - could not load constant data';
break;
}
}
?>
<!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>Material Design Bootstrap</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.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 class="fixed-sn indigo-skin">
<!--Main Navigation-->
<header>
<!--Navbar-->
<nav class="navbar navbar-expand-lg justify-content-between double-nav fixed-top navbar-dark blue-gradient">
<!-- SideNav slide-out button -->
<div class="float-left">
<a href="#" data-activates="slide-out" class="button-collapse">
<i class="fa fa-bars"></i>
</a>
</div>
<!-- Breadcrumb-->
<div class="breadcrumb-dn mr-auto darken-1">
<p>Namaste Administration</p>
</div>
<!-- Links -->
<ul class="nav navbar-nav nav-flex-icons ml-auto">
<li class="nav-item">
<a class="nav-link">
<i class="fa fa-envelope"></i>
<span class="clearfix d-none d-sm-inline-block">Contact</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link">
<i class="fa fa-gear"></i>
<span class="clearfix d-none d-sm-inline-block">Settings</span>
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-user"></i>
<span class="clearfix d-none d-sm-inline-block">Account</span>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
</ul>
</nav>
<!--/.Navbar-->
<!-- Sidebar navigation -->
<div id="slide-out" class="side-nav fixed">
<ul class="custom-scrollbar list-unstyled">
<!-- Logo -->
<li class="logo-sn waves-effect">
<div class=" text-center">
<a href="#" class="pl-0">
<img src="../html/img/namaste.png" height="50" alt="">
</a>
</div>
</li>
<!--/. Logo -->
<!--Search Form-->
<li>
<form class="search-form" role="search">
<div class="md-form my-0 waves-light">
<input type="text" class="form-control py-2" placeholder="Search">
</div>
</form>
</li>
<!--/.Search Form-->
<!-- Side navigation links -->
<li>
<ul class="collapsible collapsible-accordion">
<li>
<a class="collapsible-header waves-effect arrow-r">
<i class="fa fa-gear"></i> Edit Constants
<i class="fa fa-angle-down rotate-icon"></i>
</a>
<div class="collapsible-body">
<ul>
<!-- <form id="gaConstants" action="" method="post">-->
<form id="gaConstants" action="">
<li>
<!--<a href="javascript:void(0);" onclick="$('#gaConstants').submit()" id="stateConstants" class="getSysD waves-effect">State Constants</a>-->
<a href="javascript:void(0);" id="stateConstants" class="getSysD waves-effect">State Constants</a>
</li>
<li>
<a href="javascript:void(0);" id="statusConstants" class="getSysD waves-effect">Status Constants</a>
<!--<a href="javascript:void(0);" onclick="$('#gaConstants').submit()" id="statusConstants" class="getSysD waves-effect">Status Constants</a>-->
</li>
</form>
</ul>
</div>
</li>
<li>
<a class="collapsible-header waves-effect arrow-r">
<i class="fa fa-hand-pointer-o"></i> Instruction
<i class="fa fa-angle-down rotate-icon"></i>
</a>
<div class="collapsible-body">
<ul>
<li>
<a href="#" class="waves-effect">For bloggers</a>
</li>
<li>
<a href="#" class="waves-effect">For authors</a>
</li>
</ul>
</div>
</li>
<li>
<a class="collapsible-header waves-effect arrow-r">
<i class="fa fa-eye"></i> About
<i class="fa fa-angle-down rotate-icon"></i>
</a>
<div class="collapsible-body">
<ul>
<li>
<a href="#" class="waves-effect">Introduction</a>
</li>
<li>
<a href="#" class="waves-effect">Monthly meetings</a>
</li>
</ul>
</div>
</li>
<li>
<a class="collapsible-header waves-effect arrow-r">
<i class="fa fa-envelope-o"></i> Contact me
<i class="fa fa-angle-down rotate-icon"></i>
</a>
<div class="collapsible-body">
<ul>
<li>
<a href="#" class="waves-effect">FAQ</a>
</li>
<li>
<a href="#" class="waves-effect">Write a message</a>
</li>
</ul>
</div>
</li>
</ul>
</li>
<!--/. Side navigation links -->
</ul>
<!-- Mask -->
<div class="sidenav-bg mask-strong"></div>
</div>
<!--/. Sidebar navigation -->
</header>
<!--Main Navigation-->
<!--Main layout-->
<main>
<div class="container-fluid">
<!--Section: Modals-->
<section>
<!--Modal: modalConfirmDelete-->
<div class="modal fade" id="modalConfirmDelete" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm modal-notify modal-danger" role="document">
<!--Content-->
<div class="modal-content text-center">
<!--Header-->
<div class="modal-header d-flex justify-content-center">
<p class="heading">Are you sure?</p>
</div>
<!--Body-->
<div class="modal-body">
<i class="fa fa-times fa-4x animated rotateIn"></i>
</div>
<!--Footer-->
<div class="modal-footer flex-center">
<a href="https://mdbootstrap.com/product/material-design-for-bootstrap-pro/" class="btn btn-danger">Yes</a>
<a type="button" class="btn btn-outline-danger waves-effect" data-dismiss="modal">No</a>
</div>
</div>
<!--/.Content-->
</div>
</div>
<!--Modal: modalConfirmDelete-->
</section>
<!--Section: Modals-->
<!--Section: Main panel-->
<section class="card card-cascade narrower mb-5">
<!--Grid row-->
<div class="row">
<!-- MAIN PANEL BEGINS HERE -->
<?php
// if (!empty($systemMessage)) echo $systemMessage;
if (!empty($htmlMain)) {
echo $htmlMain;
}
?>
<!-- MAIN PANEL ENDS HERE -->
</div>
<!--Grid row-->
</section>
<!--Section: Main panel-->
<!--Section: Table-->
<section class="mb-5">
<!--Top Table UI-->
<div class="card p-2 mb-5">
<!--Grid row-->
<div class="row">
<!--Grid column-->
<div class="col-lg-3 col-md-12">
<!--Name-->
<select class="mdb-select colorful-select dropdown-primary mx-2">
<option value="" disabled selected>Bulk actions</option>
<option value="1">Delete</option>
<option value="2">Export</option>
<option value="3">Change segment</option>
</select>
</div>
<!--Grid column-->
<!--Grid column-->
<div class="col-lg-3 col-md-6">
<!--Blue select-->
<select class="mdb-select colorful-select dropdown-primary mx-2">
<option value="" disabled selected>Show only</option>
<option value="1">All
<span> (2000)</span>
</option>
<option value="2">Never opened
<span> (200)</span>
</option>
<option value="3">Opened but unanswered
<span> (1800)</span>
</option>
<option value="4">Answered
<span> (200)</span>
</option>
<option value="5">Unsunscribed
<span> (50)</span>
</option>
</select>
<!--/Blue select-->
</div>
<!--Grid column-->
<!--Grid column-->
<div class="col-lg-3 col-md-6">
<!--Blue select-->
<select class="mdb-select colorful-select dropdown-primary mx-2">
<option value="" disabled selected>Filter segments</option>
<option value="1">Contacts in no segments
<span> (100)</span>
</option>
<option value="1">Segment 1
<span> (2000)</span>
</option>
<option value="2">Segment 2
<span> (1000)</span>
</option>
<option value="3">Segment 3
<span> (4000)</span>
</option>
</select>
<!--/Blue select-->
</div>
<!--Grid column-->
<!--Grid column-->
<div class="col-lg-3 col-md-6">
<form class="md-form form-inline mt-2 ml-2">
<input class="form-control my-0" type="text" placeholder="Search" style="max-width: 150px;">
<button class="btn btn-sm btn-info ml-2 px-2">
<i class="fa fa-search"></i>
</button>
</form>
</div>
<!--Grid column-->
</div>
<!--Grid row-->
</div>
<!--Top Table UI-->
<!--Card-->
<div class="card card-cascade narrower">
<!--Card header-->
<div class="view view-cascade py-3 gradient-card-header info-color-dark mx-4 d-flex justify-content-between align-items-center">
<div>
<button type="button" class="btn btn-outline-white btn-rounded btn-sm px-2">
<i class="fa fa-th-large mt-0"></i>
</button>
<button type="button" class="btn btn-outline-white btn-rounded btn-sm px-2">
<i class="fa fa-columns mt-0"></i>
</button>
</div>
<a href="" class="white-text mx-3">Table name</a>
<div>
<button type="button" class="btn btn-outline-white btn-rounded btn-sm px-2">
<i class="fa fa-pencil mt-0"></i>
</button>
<button type="button" class="btn btn-outline-white btn-rounded btn-sm px-2" data-toggle="modal" data-target="#modalConfirmDelete">
<i class="fa fa-remove mt-0"></i>
</button>
<button type="button" class="btn btn-outline-white btn-rounded btn-sm px-2">
<i class="fa fa-info-circle mt-0"></i>
</button>
</div>
</div>
<!--/Card header-->
<!--Card content-->
<div class="card-body card-body-cascade">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>
<input class="form-check-input" type="checkbox" id="checkbox">
<label for="checkbox" class="label-table form-check-label"></label>
</th>
<th class="th-lg">First column</th>
<th class="th-lg">Second column</th>
<th class="th-lg">Third column</th>
<th class="th-lg">Fourth column</th>
<th class="th-lg">Fifth column</th>
<th class="th-lg">Sixth column</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<input class="form-check-input" type="checkbox" id="checkbox1">
<label for="checkbox1" class="label-table form-check-label"></label>
</th>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
</tr>
<tr>
<th scope="row">
<input class="form-check-input" type="checkbox" id="checkbox2">
<label for="checkbox2" class="label-table form-check-label"></label>
</th>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
</tr>
<tr>
<th scope="row">
<input class="form-check-input" type="checkbox" id="checkbox3">
<label for="checkbox3" class="label-table form-check-label"></label>
</th>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
<td>Lorem Ipsum</td>
</tr>
</tbody>
</table>
</div>
<hr class="my-0">
<!--Bottom Table UI-->
<div class="d-flex justify-content-between">
<!--Name-->
<select class="mdb-select colorful-select dropdown-primary mt-2 hidden-md-down">
<option value="" disabled>Rows number</option>
<option value="1" selected>10 rows</option>
<option value="2">25 rows</option>
<option value="3">50 rows</option>
<option value="4">100 rows</option>
</select>
<!--Pagination -->
<nav class="my-4">
<ul class="pagination pagination-circle pg-blue mb-0">
<!--First-->
<li class="page-item disabled">
<a class="page-link">First</a>
</li>
<!--Arrow left-->
<li class="page-item disabled">
<a class="page-link" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
<!--Numbers-->
<li class="page-item active">
<a class="page-link">1</a>
</li>
<li class="page-item">
<a class="page-link">2</a>
</li>
<li class="page-item">
<a class="page-link">3</a>
</li>
<li class="page-item">
<a class="page-link">4</a>
</li>
<li class="page-item">
<a class="page-link">5</a>
</li>
<!--Arrow right-->
<li class="page-item">
<a class="page-link" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
<!--First-->
<li class="page-item">
<a class="page-link">Last</a>
</li>
</ul>
</nav>
<!--/Pagination -->
</div>
<!--Bottom Table UI-->
</div>
<!--/.Card content-->
</div>
<!--/.Card-->
</section>
<!--Section: Table-->
<!--Section: Accordion-->
<section class="mb-5">
<!--Accordion wrapper-->
<div class="accordion" id="accordionEx" role="tablist" aria-multiselectable="true">
<!-- Accordion card -->
<div class="card">
<!-- Card header -->
<div class="card-header" role="tab" id="headingOne">
<!--Options-->
<div class="dropdown pull-left">
<button class="btn btn-info btn-sm m-0 mr-3 p-2 dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="fa fa-pencil"></i>
</button>
<div class="dropdown-menu dropdown-info">
<a class="dropdown-item" href="#">Add new</a>
<a class="dropdown-item" href="#">Rename folder</a>
<a class="dropdown-item" href="#">Delete folder</a>
</div>
</div>
<!-- Heading -->
<a id="folder-1" data-toggle="collapse" data-parent="#accordionEx" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<h5 class="mt-1 mb-0">
<span>Folder 1</span>
<i class="fa fa-angle-down rotate-icon"></i>
</h5>
</a>
</div>
<!-- Card body -->
<div id="collapseOne" class="collapse show" role="tabpanel" aria-labelledby="headingOne">
<div class="card-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute,
non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch
3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda
shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt
sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer
farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
labore sustainable VHS.
</div>
</div>
</div>
<!-- Accordion card -->
<!-- Accordion card -->
<div class="card">
<!-- Card header -->
<div class="card-header" role="tab" id="headingTwo">
<!--Options-->
<div class="dropdown pull-left">
<button class="btn btn-info btn-sm m-0 mr-3 p-2 dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="fa fa-pencil"></i>
</button>
<div class="dropdown-menu dropdown-info">
<a class="dropdown-item" href="#">Add new</a>
<a class="dropdown-item" href="#">Rename folder</a>
<a class="dropdown-item" href="#">Delete folder</a>
</div>
</div>
<!-- Heading -->
<a id="folder-2" data-toggle="collapse" data-parent="#accordionEx" href="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo">
<h5 class="mt-1 mb-0">
<span>Folder 2</span>
<i class="fa fa-angle-down rotate-icon"></i>
</h5>
</a>
</div>
<!-- Card body -->
<div id="collapseTwo" class="collapse" role="tabpanel" aria-labelledby="headingTwo">
<div class="card-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute,
non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch
3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda
shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt
sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer
farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
labore sustainable VHS.
</div>
</div>
</div>
<!-- Accordion card -->
<!-- Accordion card -->
<div class="card">
<!-- Card header -->
<div class="card-header" role="tab" id="headingThree">
<!--Options-->
<div class="dropdown pull-left">
<button class="btn btn-info btn-sm m-0 mr-3 p-2 dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="fa fa-pencil"></i>
</button>
<div class="dropdown-menu dropdown-info">
<a class="dropdown-item" href="#">Add new</a>
<a class="dropdown-item" href="#">Rename folder</a>
<a class="dropdown-item" href="#">Delete folder</a>
</div>
</div>
<!-- Heading -->
<a id="folder-3" data-toggle="collapse" data-parent="#accordionEx" href="#collapseThree" aria-expanded="true" aria-controls="collapseThree">
<h5 class="mt-1 mb-0">
<span>Folder 3</span>
<i class="fa fa-angle-down rotate-icon"></i>
</h5>
</a>
</div>
<!-- Card body -->
<div id="collapseThree" class="collapse" role="tabpanel" aria-labelledby="headingThree">
<div class="card-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute,
non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch
3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda
shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt
sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer
farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus
labore sustainable VHS.
</div>
</div>
</div>
<!-- Accordion card -->
</div>
<!--/.Accordion wrapper-->
</section>
<!--Section: Accordion-->
</div>
</main>
<!--Main layout-->
<!--Footer-->
<footer class="page-footer mt-4">
<!--Copyright-->
<div class="footer-copyright text-center py-3">
<div class="container-fluid">
© 2018 Copyright:
<a href="https://www.givvingassistant.org"> GivingAssistant.org </a>
</div>
</div>
<!--/.Copyright-->
</footer>
<!--/.Footer-->
<!-- SCRIPTS -->
<!-- JQuery -->
<script type="text/javascript" src="../html/js/jquery-3.3.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.min.js"></script>
<!-- gaAdmin JS Processing Script -->
<script type="text/javascript" src="admin/gaAdmin.js"></script>
<!-- Initializations -->
<script>
// SideNav Initialization
$(".button-collapse").sideNav();
// Material Select Initialization
$(document).ready(function () {
$('.mdb-select').material_select();
});
// Data Picker Initialization
$('.datepicker').pickadate();
// Tooltip Initialization
$(function () {
$('[data-toggle="tooltip"]').tooltip()
});
</script>
<!-- Charts -->
<script>
// Minimalist chart
$(function () {
$('.min-chart#chart-sales').easyPieChart({
barColor: "#4caf50",
onStep: function (from, to, percent) {
$(this.el).find('.percent').text(Math.round(percent));
}
});
});
// Main chart
// var ctxL = document.getElementById("lineChart").getContext('2d');
// var myLineChart = new Chart(ctxL, {
// type: 'line',
// data: {
// labels: ["January", "February", "March", "April", "May", "June", "July"],
// datasets: [{
// label: "My First dataset",
// fillColor: "#fff",
// backgroundColor: 'rgba(255, 255, 255, .3)',
// borderColor: 'rgba(255, 255, 255)',
// data: [0, 10, 5, 2, 20, 30, 45],
// }]
// },
// options: {
// legend: {
// labels: {
// fontColor: "#fff",
// }
// },
// scales: {
// xAxes: [{
// gridLines: {
// display: true,
// color: "rgba(255,255,255,.25)"
// },
// ticks: {
// fontColor: "#fff",
// },
// }],
// yAxes: [{
// display: true,
// gridLines: {
// display: true,
// color: "rgba(255,255,255,.25)"
// },
// ticks: {
// fontColor: "#fff",
// },
// }],
// }
// }
// });
</script>
<!-- Alerts -->
<script>
$(function () {
$('#folder-1').click(function () {
toastr.error("Folder 1 has been clicked!", "Folder 1", {
"positionClass": "toast-top-right",
});
});
$('#folder-2').click(function () {
// make it not disappear
toastr.info("Folder 2 has been clicked!", "Folder 2", );
});
$('#folder-3').click(function () {
// make it not disappear
toastr.info("Folder 3 has been clicked!", "Folder 3", );
});
});
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
utilities/images/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

59
utilities/launchMig.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
/**
* launchMig.php -- help script
*
* This program is called from the: migrateData.php application as an AJAX event - the sole purpose of this script
* is to unpack the POST data from the AJAX request, and build a migration-request event broker payload.
*
* Next, we instantiate a new broker client to the migration broker and publish the migration event request - the
* output from the script is in the broker payload returned by the migration broker -- if all was successful, we'll
* output (for formatted display) the migration report -- else, we'll display the diagnostic messages.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 10-04-18 mks DB-43: original coding
*
*/
// if this page was not called by AJAX, die
if (!$_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') die('Invalid request');
// get variables sent from client-side page
$data = isset($_POST['d']) ? (json_decode(strip_tags($_POST['d']), true)) : null;
$meta = isset($_POST['m']) ? (json_decode(strip_tags($_POST['m']), true)): null;
// output an error message if the required arrays weren't posted to the form
if (is_null($data)) {
echo ERROR_DATA_404 . $eos;
exit;
}
if (is_null($meta)) {
echo ERROR_DATA_META_404 . $eos;
exit;
}
// load namaste-light
try {
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc');
} catch (ParseError | Throwable $p) {
$errorList[] = ERROR_TYPE_EXCEPTION_PARSE . $p->getMessage();
}
// todo: validate that the current Namaste config has a migration broker running...
$objMig = new gacBrokerClient(BROKER_QUEUE_M, basename(__FILE__));
if (!$objMig->status) {
echo ERROR_TEMPLATE_INSTANTIATE . BROKER_QUEUE_M . $eos;
}else {
$brokerPayload = [BROKER_REQUEST => BROKER_REQUEST_MIGRATION, BROKER_DATA => $data, BROKER_META_DATA => $meta];
$result = $objMig->call(gzcompress(json_encode($brokerPayload)));
$result = json_decode(gzuncompress($result), true);
if ($result[PAYLOAD_STATE] == true)
var_export($result[PAYLOAD_RESULTS]);
else
var_export($result[PAYLOAD_DIAGNOSTICS]);
}
if (is_object($objMig)) $objMig->__destruct();
unset($objMig);

193
utilities/logger.css Normal file
View File

@@ -0,0 +1,193 @@
body {
margin: 0;
padding: 0;
background: #AAA url('./images/lgrey064.jpg') repeat top left scroll;
width: 100%;
height: 100%;
font-family: verdanna, arial, sans-serif;
}
div.title {
margin: 0;
margin-top: 20px;
position: relative;
width: 1000px;
margin-left: auto;
margin-right: auto;
font-size: 20px;
color: blue;
}
div.container {
border: 1px solid black;
margin: 0;
margin-top: 20px;
padding: 10px;
position: relative;
width: 1000px;
margin-left: auto;
margin-right: auto;
background: url('./images/lblue047.gif') repeat;
box-shadow: 3px 3px 4px #000;
}
div.rowMeta {
margin: 0;
width: 900px;
padding-left: 10px;
text-align: left;
position: relative;
font-size: 12px;
font-weight: bold;
color: #006400;
}
div.rowData {
margin: 0;
padding-left: 25px;
width: 900px;
text-align: left;
position: relative;
font-size: 14px;
font-weight: normal;
color: black;
}
.rowText {
margin : 0;
padding-left: 25px;
width: 900px;
text-align: left;
position: relative;
font-size: 16px;
font-weight: normal;
color: black;
}
.rowTextGray {
margin : 0;
padding-left: 25px;
width: 900px;
text-align: left;
position: relative;
font-size: 14px;
font-weight: normal;
color: gray;
}
div.rowHist {
margin: 0;
padding-left: 50px;
width: 900px;
text-align: left;
position: relative;
font-size: 10px;
font-weight: normal;
color: black;
}
span.gray {
color : gray;
}
span.green {
color : green;
}
span.red {
color : red;
}
.required {
color : red;
font-size: xx-small;
vertical-align: top;
}
.rowSuccess {
margin : 0;
padding-left: 30px;
text-align: center;
position: relative;
font-size: 14px;
font-weight: bold;
color : green;
}
div.rowError {
margin: 0;
padding-left: 30px;
text-align: center;
position: relative;
font-size: 14px;
font-weight: bold;
color: #ff0000;
}
a.delete {
background-image: url('./images/delete-icon.png');
background-repeat:no-repeat;
background-size: 16px auto;
display:inline-block;
position:absolute;
width: 24px;
height: 24px;
/*cursor: pointer;*/
}
a.cachekey {
padding-left: 25px;
}
span.highlight {
background-color: yellow;
}
.buttonCenter {
text-align: center;
}
.omeSubmit {
-moz-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
-webkit-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
box-shadow:inset 0px 1px 0px 0px #bbdaf7;
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #79bbff), color-stop(1, #378de5) );
background:-moz-linear-gradient( center top, #79bbff 5%, #378de5 100% );
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#79bbff', endColorstr='#378de5');
background-color:#79bbff;
-webkit-border-top-left-radius:20px;
-moz-border-radius-topleft:20px;
border-top-left-radius:20px;
-webkit-border-top-right-radius:0px;
-moz-border-radius-topright:0px;
border-top-right-radius:0px;
-webkit-border-bottom-right-radius:20px;
-moz-border-radius-bottomright:20px;
border-bottom-right-radius:20px;
-webkit-border-bottom-left-radius:0px;
-moz-border-radius-bottomleft:0px;
border-bottom-left-radius:0px;
text-indent:0;
border:1px solid #84bbf3;
display:inline-block;
color:#ffffff;
font-family:Arial;
font-size:15px;
font-weight:bold;
font-style:normal;
height:40px;
line-height:40px;
width:100px;
text-decoration:none;
text-align:center;
text-shadow:1px 1px 0px #528ecc;
}
.omeSubmit:hover {
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #378de5), color-stop(1, #79bbff) );
background:-moz-linear-gradient( center top, #378de5 5%, #79bbff 100% );
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#378de5', endColorstr='#79bbff');
background-color:#378de5;
}.omeSubmit:active {
position:relative;
top:1px;
}

1590
utilities/migrateData.php Normal file

File diff suppressed because it is too large Load Diff

357
utilities/mongoConfig.php Normal file
View File

@@ -0,0 +1,357 @@
<?php /** @noinspection PhpComposerExtensionStubsInspection */
/**
* mongoConfig -- utility script
*
* mongoConfig is a utility script that updates the existing indexes in all mongo collections in the database.
*
* this program should be run whenever new templates are added to the source tree, or when an existing template
* is edited. Actually, the program should just be run whenever the source is pushed to a new environment.
*
* the script reads all of the files in the ./classes/templates directory and every template file is parsed. If
* the template has been configured for a mongo schema, then it's indexing information is scraped.
*
* Processing generally follows the formula of:
*
* -- process all the compound indexes first
* -- process all the other indexes individually
* -- process individual index options (unique, sparse, ttl)
*
* NOTES:
* ------
* this program writes it's output to ./logs/mongoConfig.log
* The createIndex() method only creates an index if an index of the same specification does not already exist.
*
* -- start version control in the template files and add the version number in to the index name, set in options
* -- push re-indexing into the background with the option background:true (sub-optimal)
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 08-03-17 mks CORE-467: original coding
* 02-07-19 mks DB-115: fixed index processing
* 05-21-19 mks DB-116: updated index processing to be specific to each named service environment
* 10-22-19 mks DB-136: removed assumption that mongo will always be under RBAC allowing unsecured logins
* Fixed error in $outfile processing where the parent directory is missing
*
*/
$_REDIRECT=false; // enable stdout
require_once(dirname(__DIR__) . '/config/sneakerstrap.inc'); // load env
$errors = null;
$res = 'MDBC: ';
$envList = null;
// get the database configuration
$dbConfig = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB];
// break out of the script if mongo isn't enabled
if (isset($dbConfig[CONFIG_DATABASE_MONGODB_ENABLED]) and $dbConfig[CONFIG_DATABASE_MONGODB_ENABLED] != 1) {
exit(ERROR_MDB_NOT_ENABLED);
}
// generate a list of environments this currently-running script can "see"
foreach (gasConfig::$settings[CONFIG_REGISTERED_SERVICES] as $service => $enabled)
if (gasConfig::$settings[$service][CONFIG_IS_LOCAL] and gasConfig::$settings[$service][CONFIG_ACTIVE])
$envList[] = $service;
$logFile = dirname(__DIR__) . DIR_LOGS . FILE_MONGO_CONFIG_LOG;
$outFile = dirname(__DIR__) . DIR_SCRIPTS . DIR_MONGO . FILE_MONGO_INDEX_SCRIPT;
if (!file_exists($logFile)) touch($logFile);
if (!file_exists($outFile)) {
if (!touch($outFile)) {
$hdr = basename(__FILE__) . AT . __LINE__ . COLON;
$msg = ERROR_OPEN_LOG_FILE . $outFile;
consoleLog($res, CON_ERROR, $hdr . $msg);
consoleLog($res, CON_ERROR, INFO_NO_DIR);
exit;
}
}
$pLogFile = @fopen($logFile, 'a');
$pIndexFile = @fopen($outFile, 'w');
if (false === $pLogFile) {
echo ERROR_OPEN_LOG_FILE . $logFile . PHP_EOL;
exit(1);
}
if (false === $pIndexFile) {
echo ERROR_OPEN_LOG_FILE . $outFile . PHP_EOL;
exit(1);
}
@fwrite($pLogFile, getDateTime() . CON_SUCCESS . $res . 'begin processing templates' . PHP_EOL);
@fwrite($pLogFile, getDateTime() . CON_SUCCESS . $res . 'opened output file: ' . $outFile . PHP_EOL);
@fwrite($pIndexFile, '#! /bin/sh' . PHP_EOL);
// pull a copy of the config into memory
$config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB];
$firstPass = true;
// loop through each Namaste-supported environment...
foreach ($envList as $environment) {
@fwrite($pIndexFile, '# Processing Environment: ' . $environment . PHP_EOL);
// reset RBAC credentials
$user = '';
$password = '';
$authDB = '';
$indexText = null;
// if the current env is set and if that env has enabled mongoDB then...
if (array_key_exists($environment, $config) and intval($config[$environment][STRING_ENABLED]) === 1) {
// derive port assignment based-off the current db configuration (shard v. replSet v. standAlone)
if (intval($config[$environment][CONFIG_DATABASE_MONGODB_SHARDING][CONFIG_DATABASE_MONGODB_ENABLED]) === 1) {
$port = $config[$environment][CONFIG_DATABASE_MONGODB_SHARDING][CONFIG_DATABASE_MONGODB_SHARDING_MONGOS_NODES][CONFIG_DATABASE_MONGODB_ADMIN_REPLSET_SET];
$port = intval(substr($port, -5));
} elseif (intval($config[$environment][CONFIG_DATABASE_MONGODB_REPLSET][CONFIG_DATABASE_MONGODB_REPLSET_ENABLED]) === 1) {
$port = $config[$environment][CONFIG_DATABASE_MONGODB_REPLSET][CONFIG_DATABASE_MONGODB_REPLSET_DSN][CONFIG_DATABASE_MONGODB_ADMIN_REPLSET_SET][0];
$port = intval(substr($port, -5));
} else {
$port = intval($config[$environment][CONFIG_DATABASE_MONGODB_PORT]);
}
// if RBAC is enabled, grabbed the login credentials from the current env
if ($config[$environment][CONFIG_DATABASE_MONGODB_USE_AUTH] == 1) {
$user = $config[$environment][CONFIG_DATABASE_MONGODB_USER];
$password = $config[$environment][CONFIG_DATABASE_MONGODB_PASSWORD];
$authDB = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $config[$environment][CONFIG_DATABASE_MONGODB_AUTH_SOURCE];
$command = 'mongo -u ' . $user . ' -p ' . $password . ' --port ' . $port . ' --authenticationDatabase ' . $authDB;
} else {
$command = 'mongo --port ' . $port;
}
/** @noinspection PhpComposerExtensionStubsInspection */
/** @var MongoClient $mongoResource */
$mongoResource = gasResourceManager::fetchResource(RESOURCE_MONGO_MASTER, $environment);
if (is_null($mongoResource)) {
@fwrite($pLogFile, getDateTime() . CON_ERROR . $res . ERROR_MONGO_CONNECT . AT . $environment . PHP_EOL);
fclose($pLogFile);
fclose($pIndexFile);
exit(1);
}
// STEP 1 -- for every c-type class template, load and process the template
foreach(glob(dirname(getcwd()) . DIR_CLASSES . DIR_TEMPLATE . '/*' . STRING_CLASS_FILE_EXT) as $filename) {
$currentClass = basename($filename);
$currentClass = preg_replace("/" . STRING_CLASS_FILE_EXT . "/", "", $currentClass);
// extract the $tlti from the front of the template for the factory-class instantiation
$tlti = substr($currentClass, 0, 3);
$currentClass = preg_replace("/" . $tlti . "/", "", $currentClass);
$database = null;
$collection = null;
$collectionName = null;
if ($currentClass == 'SystemData' and $environment == ENV_ADMIN)
$x = 1;
echo 'processing: ' . $currentClass . '...' . $eos;
try {
$e = array();
$meta = [ META_TEMPLATE => $currentClass, META_CLIENT => CLIENT_SYSTEM, META_TLTI => $tlti ];
$objFactory = new gacFactory($meta, FACTORY_EVENT_NEW_CLASS, '', $e);
if (is_null($objFactory)) break; // we couldn't instantiate the factory class for this template
// do not process PDO scripts
if ($objFactory->template->schema == TEMPLATE_DB_PDO) {
$objFactory->__destruct();
unset($objFactory);
continue;
}
// do not process if the template is not a member of the current environment
if ($objFactory->template->service != $environment) {
$objFactory->__destruct();
unset($objFactory);
continue;
}
$version = $objFactory->template->version;
$ext = $objFactory->template->extension;
$service = $objFactory->template->service;
$collectionName = $objFactory->template->collection;
/** @var gacMongoDB $tmpObj */
$tmpObj = $objFactory->widget;
$collectionName = $tmpObj->getCollectionName();
$dbName = $tmpObj->getDBName();
if (is_object($objFactory)) $objFactory->__destruct();
unset($objFactory);
} catch (Throwable $t) {
fclose($pLogFile);
fclose($pIndexFile);
exit($t->getMessage() . $eos);
}
$indexes = array(); // this is the index payload we'll submit to the mongoDB Manager\Command
$options = array(); // this is the options payload for the corresponding index
$commands = array(); // this is the list of commands that comprise the final ouput
// indexes
$singleIndices = $tmpObj->singleIndexes;
$compoundIndices = $tmpObj->compoundIndexes;
$multiKeyIndices = $tmpObj->multiKey;
// index properties
$uniqueIndices = $tmpObj->uniqueIndexes;
$partialIndices = $tmpObj->partialIndexes;
$t2LiveIndices = $tmpObj->ttlIndexes;
// all indexing done in the background
$sysOption = [
MONGO_STRING_BACKGROUND => true
];
// order for these two variables is critical: do *NOT* add or delete from one unless you do it to the other
// while maintaining identical positions for each index type in the arrays. If we ever support indexes
// other than what appears in these lists, we'll have not only manually add them to the lists, but also
// code the respective validation and processing bits too.
$indexTypes = [
$partialIndices, $uniqueIndices, $t2LiveIndices,
$singleIndices, $compoundIndices, $multiKeyIndices
];
$indexList = [
'partialIndices' => 0, 'uniqueIndices' => 1, 't2LiveIndices' => 2,
'singleIndices' => 3, 'compoundIndices' => 4, 'multiKeyIndices' => 5
];
// process partial index properties for the class first
$count = 0;
foreach ($indexList as $indexName => $indexCounter) {
if (!empty($indexTypes[$indexCounter])) {
$badIndexName = false;
$indexText[][MONGO_COLLECTION_NAME] = $collectionName;
// the first part of this is to validate the index column/label names as valid/declared indexes
foreach ($indexTypes[$indexCounter] as $indexLabel => $indexContents) {
// strip, if it exists, the extension of the column name so we can grep it in our index lists
$modifiedField = ($indexName == STRING_PARTIAL_INDICES) ?
preg_replace("/" . $ext . "/", "", key($indexContents[0]))
:
preg_replace("/" . $ext . "/", "", $indexLabel);
if (!in_array($modifiedField, $tmpObj->indexList)) {
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
$msg = sprintf(ERROR_MDB_INDEX_UNDECL, array_search($indexCounter, $indexList), basename($filename), $modifiedField);
echo $hdr . $msg . PHP_EOL;
$badIndexName = true;
}
// if we have one, just one, bad index reference, we need to error-out and stop processing
// (but we'll echo a list of the bad index names before exiting)
if ($badIndexName) {
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
echo $hdr . ERROR_DATA_VALIDATION;
exit(1);
}
/*
* the $indexes and $options structure contain all elements of the current index. If an index,
* or index property, does not have options, then the placeholder for that position in $options
* will be set to null.
*
*/
switch ($indexCounter) {
// changed structure of $indexes/$options to down-layer the data that will be passed to
// mongo so as to avoid index name collisions within the arrays using the column name.
//
// the goal of this section is to generate the structures that we'll convert to json-
// -encoded arrays that will ultimately be written to the bash deployment script
case 0 :
// partial indexes (done)
for ($index = 0, $max = count($indexContents[0]); $index < $max; $index++)
$indexes[][key($indexContents[$index])] = $indexContents[$index][key($indexContents[$index])];
$options[][ MONGO_STRING_PARTIAL_FE ] = $indexContents[1][0];
break;
case 1 :
// unique index (done)
$indexes[][$indexLabel] = $uniqueIndices[$indexLabel];
$options[][MONGO_STRING_UNIQUE] = true;
break;
case 2 :
// time-to-live indexes
$indexes[][$indexLabel] = 1;
$options[] = [ MONGO_STRING_EXPIRE_SEC => $t2LiveIndices[$indexLabel] ];
break;
case 3 :
// single indexes (done)
$indexes[][$indexLabel] = $singleIndices[$indexLabel];
break;
case 4 :
// compound indexes (done)
// mongo imposes a limit of 32 fields on compound indexes
// mongo does not use index labels (that's a mysql thing) but we do use the label to
// distinguish/differentiate the index lists
$indexes[][$indexLabel] = $indexContents;
break;
case 5 :
// multikey indexes
for ($index = 0, $max = count($multiKeyIndices); $index < $max; $index++)
$indexes[][$indexLabel] = $multiKeyIndices[$indexLabel];
break;
default :
// unknown index type
$hdr = sprintf(INFO_LOC, __FILE__, __LINE__);
$msg = $hdr . ERROR_MDB_UNK_IDX_TYPE . $indexLabel;
echo $msg;
exit (1);
break;
}
}
// the second part of this is to generate the BSON for each index type outputting the directives
// to a bash-script that will be executed (manually) after this script completes processing
switch ($indexCounter) {
case 0 :
// partial indexes
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode($indexes[$index]) . COMMA . json_encode($options[$index]);
break;
case 1 :
// unique indexes (done)
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode($indexes[$index]) . COMMA . json_encode($options[$index]);
break;
case 2 :
// t2Live indexes
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode([$indexes[$index], $options[$index]]);
break;
case 3 :
// single indexes (done)
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode($indexes[$index]);
break;
case 4 :
// compound indexes (done)
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode($indexes[$index][key($indexes[$index])]);
break;
case 5 :
// multi-key indexes
for ($index = 0, $max = count($indexes); $index < $max; $index++)
$indexText[] = json_encode($indexes[$index][key($indexes[$index])]);
break;
default :
// unknown index type
$hdr = sprintf(INFO_LOC, __FILE__, __LINE__);
$msg = $hdr . ERROR_MDB_UNK_IDX_TYPE . $indexLabel;
echo $msg;
exit (1);
break;
}
unset($indexes, $options); // reset the processed-index/options containers
}
}
} // close the env-enabled loop
if (!empty($indexText)) {
// we have generated indexing commands --- write out the command to log into mongo
@fwrite($pIndexFile, $command . ' << EOF' . PHP_EOL);
@fwrite($pIndexFile, 'use ' . $dbName . PHP_EOL);
for ($index = 0, $max = count($indexText); $index < $max; $index++) {
if (is_array($indexText[$index])) {
$collectionName = $indexText[$index][MONGO_COLLECTION_NAME];
continue;
}
@fwrite($pIndexFile, 'db.' . $collectionName . '.createIndex(' . $indexText[$index] . ')' . PHP_EOL);
}
@fwrite($pIndexFile, 'EOF' . PHP_EOL);
}
}
}
@fwrite($pLogFile, getDateTime() . CON_SUCCESS . $res . basename(__FILE__) . ': script processing ends' . PHP_EOL);
fclose($pLogFile);
fclose($pIndexFile);
chmod($outFile, 0755);
echo 'processing ended successfully!' . PHP_EOL;
exit(0);

1063
utilities/mysqlConfig.php Normal file

File diff suppressed because it is too large Load Diff