new: [server:fixDBSchema] Preliminary work to fix database schema

pull/5412/head
mokaddem 2019-11-18 19:06:41 -05:00
parent 2f3c4778f4
commit 69746c8d4f
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
5 changed files with 107 additions and 9 deletions

View File

@ -2193,4 +2193,21 @@ misp.direct_call(relative_path, body)
}
return $this->RestResponse->viewData($this->Server->dbSchemaDiagnostic(), $this->response->type());
}
public function execSQLQuery() {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException(__('This endpoint expects POST requests.'));
}
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException(__('Only site admin accounts are allowed to perform DB schema fixes.'));
}
$sqlQuery = $this->request->data['server']['sqlQuery'];
$errorMessage = '';
try {
$this->Server->query($sqlQuery);
} catch (Exception $e) {
$errorMessage = $e->getMessage();
}
return $this->RestResponse->viewData(array('success' => empty($errorMessage), 'error' => $errorMessage), $this->response->type());
}
}

View File

@ -4371,7 +4371,8 @@ class Server extends AppModel
$dbDiff[$tableName][] = array(
'description' => sprintf(__('Table `%s` does not exist'), $tableName),
'column_name' => $tableName,
'is_critical' => true
'is_critical' => true,
'SQLQueryFix' => $this->generateSQLQueryFix($tableName, $column, 'CREATE')
);
} else {
// perform schema comparison for table's columns
@ -4419,17 +4420,21 @@ class Server extends AppModel
'column_name' => $column['column_name'],
'actual' => $keyedActualColumn[$columnName],
'expected' => $column,
'is_critical' => $isCritical
'is_critical' => $isCritical,
'SQLQueryFix' => $this->generateSQLQueryFix($tableName, $column, 'MODIFY')
);
}
// ALTER TABLE test MODIFY COLUMN locationExpect VARCHAR(120);
} else {
$dbDiff[$tableName][] = array(
'description' => sprintf(__('Column `%s` does not exist but should'), $columnName),
'column_name' => $columnName,
'actual' => array(),
'expected' => $column,
'is_critical' => true
'is_critical' => true,
'SQLQueryFix' => $this->generateSQLQueryFix($tableName, $column, 'ADD')
);
}
}
}
@ -4444,6 +4449,47 @@ class Server extends AppModel
return $dbDiff;
}
public function generateSQLQueryFix($tableName, $expected, $type)
{
$query = '';
if ($type == 'ADD') {
$query .= sprintf('ALTER TABLE `%s` ADD COLUMN ', $tableName);
} elseif ($type == 'MODIFY') {
$query .= sprintf('ALTER TABLE `%s` MODIFY COLUMN ', $tableName);
} elseif ($type == 'CREATE') {
// $query .= sprintf('CREATE TABLE IF NOT EXISTS `%s` (%s)', $tableName);
// CREATE TABLE IF NOT EXISTS `taxonomies` (
// `id` int(11) NOT NULL AUTO_INCREMENT,
// `namespace` varchar(255) COLLATE utf8_bin NOT NULL,
// )
}
$query .= $this->generateSQLQueryFixCol($expected);
return $query;
}
public function generateSQLQueryFixCol($col)
{
$colQuery = array();
$colQuery[] = sprintf('`%s`', $col['column_name']);
$precision = null;
if (!is_null($col['character_maximum_length'])) {
$precision = $col['character_maximum_length'];
} elseif (!is_null($col['numeric_precision'])) {
$precision = $col['numeric_precision'];
}
$colQuery[] = $col['data_type'];
if (!is_null($precision)) {
$colQuery[] = sprintf('(%s)', $precision);
}
if (!is_null($col['collation_name'])) {
$colQuery[] = sprintf('COLLATE %s', $col['collation_name']);
}
$colQuery[] = sprintf('%s NULL', $col['is_nullable'] == 'NO' ? 'NOT' : '');
return implode(' ', $colQuery);
}
public function writeableDirsDiagnostics(&$diagnostic_errors)
{
App::uses('File', 'Utility');

View File

@ -58,7 +58,7 @@
);
$table = sprintf('%s%s%s',
'<table class="table table-bordered table-condensed">',
sprintf('<thead><th>%s</th><th>%s</th><th>%s</th><th>%s</th></thead>', __('Table name'), __('Description'), __('Expected schema'), __('Actual schema')),
sprintf('<thead><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></thead>', __('Table name'), __('Description'), __('Expected schema'), __('Actual schema')),
'<tbody>'
);
$rows = '';
@ -83,10 +83,21 @@
$uniqueRow = empty($saneExpected) && empty($saneActual);
$rows .= sprintf('<tr class="%s">', $columnDiagnostic['is_critical'] ? 'error' : '');
$rows .= sprintf('<td %s>%s</td>', $uniqueRow ? 'colspan=3' : '', $saneDescription);
$rows .= sprintf('<td %s>%s</td>', $uniqueRow ? 'colspan=4' : '', $saneDescription);
if (!$uniqueRow) {
$rows .= sprintf('<td class="dbColumnDiagnosticRow" data-table="%s" data-index="%s">%s</td>', h($tableName), h($i), implode(' ', $saneExpected));
$rows .= sprintf('<td class="dbColumnDiagnosticRow" data-table="%s" data-index="%s">%s</td>', h($tableName), h($i), implode(' ', $saneActual));
$rows .= sprintf('<td class="" data-table="%s" data-index="%s">%s</td>', h($tableName), h($i),
empty($columnDiagnostic['SQLQueryFix']) ? '' :
sprintf('%s%s%s%s',
$this->Form->create('server', array('url' => 'execSQLQuery', 'style' => "margin-bottom: 0px;", 'data-ajax' => true)),
// sprintf('<i class="fa fa-wrench useCursorPointer" onclick="submitSQLQueryFix(this)" title="%s" data-query="%s"></i>', __('Fix schema'), h($columnDiagnostic['SQLQueryFix'])),
sprintf('<i class="fa fa-wrench useCursorPointer" onclick="popoverConfirm(this, \'%s\')" title="%s" data-query="%s"></i>', h($columnDiagnostic['SQLQueryFix']), __('Fix schema'), h($columnDiagnostic['SQLQueryFix'])),
$this->Form->input('sqlQuery', array('type' => 'hidden', 'value' => '123')),
$this->Form->end()
)
);
}
$rows .= '</tr>';
}

View File

@ -1686,10 +1686,11 @@ function popoverPopup(clicked, id, context, target, admin) {
}
// create a confirm popover on the clicked html node.
function popoverConfirm(clicked) {
function popoverConfirm(clicked, message) {
var $clicked = $(clicked);
var popoverContent = '<div>';
popoverContent += '<button id="popoverConfirmOK" class="btn btn-primary" onclick=submitPopover(this)>Yes</button>';
popoverContent += message === undefined ? '' : '<p>' + message + '</p>';
popoverContent += '<button id="popoverConfirmOK" class="btn btn-primary" style="margin-right: 5px;" onclick=submitPopover(this)>Yes</button>';
popoverContent += '<button class="btn btn-inverse" style="float: right;" onclick=cancelPrompt()>Cancel</button>';
popoverContent += '</div>';
openPopover($clicked, popoverContent);
@ -1712,7 +1713,30 @@ function submitPopover(clicked) {
var dismissid = $clicked.closest('div.popover').attr('data-dismissid');
$form = $('[data-dismissid="' + dismissid + '"]').closest('form');
}
$form.submit();
if ($form.data('ajax')) {
$.ajax({
data: $form.serialize(),
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
},
success:function (data, textStatus) {
location.reload();
},
error:function() {
showMessage('fail', 'Could not perform query.');
},
complete:function() {
$(".loading").hide();
// $("#popover_form").fadeOut();
// $("#gray_out").fadeOut();
// $('#temp').remove();
},
type:"post",
url: $form.attr('action')
});
} else {
$form.submit();
}
}
function simplePopup(url) {

File diff suppressed because one or more lines are too long