From 5f9330bd1f70b66f3801ebbfb7f4e4834be5a7be Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 13 Nov 2019 17:00:35 +0100 Subject: [sysconfig] Allow deleting modules that are still used by a config Closes #3075 --- modules-available/sysconfig/clientscript.js | 170 ++++++++++++--------- modules-available/sysconfig/install.inc.php | 16 +- .../sysconfig/lang/de/template-tags.json | 1 + .../sysconfig/lang/en/template-tags.json | 1 + modules-available/sysconfig/page.inc.php | 30 ++-- modules-available/sysconfig/templates/js.html | 9 +- .../sysconfig/templates/list-configs.html | 2 +- .../sysconfig/templates/list-modules.html | 2 +- 8 files changed, 132 insertions(+), 99 deletions(-) diff --git a/modules-available/sysconfig/clientscript.js b/modules-available/sysconfig/clientscript.js index 1553d678..cafe7b02 100644 --- a/modules-available/sysconfig/clientscript.js +++ b/modules-available/sysconfig/clientscript.js @@ -1,88 +1,110 @@ // Mouseover and clicking -var $ct = $('#conftable').find('.confrow'); -$ct.click(function() { - showmod(this, 'bold'); -}).mouseenter(function() { - showmod(this, 'fade'); -}).mouseleave(function() { - showmod(this, 'reset'); -}); -var $mt = $('#modtable').find('.modrow'); -$mt.click(function() { - showconf(this, 'bold'); -}).mouseenter(function() { - showconf(this, 'fade'); -}).mouseleave(function() { - showconf(this, 'reset'); -}); +(function() { + var boldItem = false; + var revList = false; -var boldItem = false; -var revList = false; - -function showpre(e, action) { - if (boldItem && action !== 'bold') return 'reset'; - if (boldItem) { - if (e === boldItem) action = 'fade'; - boldItem = false; - } - $mt.removeClass("slx-bold slx-fade"); - $ct.removeClass("slx-bold slx-fade"); - return action; -} - -function buildRevList() { - revList = {}; - $ct.each(function() { - var elem = $(this); - var cid = elem.data('id')+''; - var list = (elem.data('modlist')+'').split(','); + var $ct = $('#conftable').find('.confrow'); + $ct.click(function () { + showmod(this, 'bold'); + }).mouseenter(function () { + showmod(this, 'fade'); + }).mouseleave(function () { + showmod(this, 'reset'); + }); + var $mt = $('#modtable').find('.modrow'); + $mt.click(function () { + showconf(this, 'bold'); + }).mouseenter(function () { + showconf(this, 'fade'); + }).mouseleave(function () { + showconf(this, 'reset'); + }); + var $confirm = $('#delete-item-list'); + $('.btn-del-module').click(function() { + if (!revList) buildRevList(); + var mid = $(this).val() + ''; + var list = revList[mid]; + if (!list || !list.length) { + $confirm.append($msgs).addClass('hidden'); + return; + } + var $msgs = $confirm.find('ul').empty(); for (var i = 0; i < list.length; ++i) { - if (!revList[list[i]]) revList[list[i]] = []; - revList[list[i]].push(cid); + $msgs.append($('
  • ').text( + $('.confrow[data-id="' + list[i] + '"]').text() + )); } + $confirm.removeClass('hidden'); + }); + $('.btn-del-config').click(function() { + $confirm.addClass('hidden'); }); -} -function showconf(e, action) { - action = showpre(e, action); - if (action === 'reset') return; - var $e = $(e); - if (!revList) buildRevList(); - var mid = $e.data('id')+''; - var list = revList[mid]; - if (list && list.length > 0) $ct.each(function() { - var elem = $(this); - var cid = elem.data('id')+''; - if (list.indexOf(cid) === -1) - elem.addClass('slx-fade'); - else if (action === 'bold') - elem.addClass('slx-bold'); - }); else $ct.addClass('slx-fade'); - if (action === 'bold') { - boldItem = e; - $e.addClass("slx-bold"); + function showpre(e, action) { + if (boldItem && action !== 'bold') return 'reset'; + if (boldItem) { + if (e === boldItem) action = 'fade'; + boldItem = false; + } + $mt.removeClass("slx-bold slx-fade"); + $ct.removeClass("slx-bold slx-fade"); + return action; } -} -function showmod(e, action) { - action = showpre(e, action); - if (action === 'reset') return; - var $e = $(e); - var list = ($e.data('modlist')+'').split(','); - $mt.each(function () { - var elem = $(this); - if (list.indexOf(elem.data('id')+'') === -1) - elem.addClass("slx-fade"); - else if (action === 'bold') - elem.addClass("slx-bold"); - }); - if (action === 'bold') { - boldItem = e; - $e.addClass("slx-bold"); + function buildRevList() { + revList = {}; + $ct.each(function () { + var elem = $(this); + var cid = elem.data('id') + ''; + var list = (elem.data('modlist') + '').split(','); + for (var i = 0; i < list.length; ++i) { + if (!revList[list[i]]) revList[list[i]] = []; + revList[list[i]].push(cid); + } + }); } -} + + function showconf(e, action) { + action = showpre(e, action); + if (action === 'reset') return; + var $e = $(e); + if (!revList) buildRevList(); + var mid = $e.data('id') + ''; + var list = revList[mid]; + if (list && list.length > 0) $ct.each(function () { + var elem = $(this); + var cid = elem.data('id') + ''; + if (list.indexOf(cid) === -1) + elem.addClass('slx-fade'); + else if (action === 'bold') + elem.addClass('slx-bold'); + }); else $ct.addClass('slx-fade'); + if (action === 'bold') { + boldItem = e; + $e.addClass("slx-bold"); + } + } + + function showmod(e, action) { + action = showpre(e, action); + if (action === 'reset') return; + var $e = $(e); + var list = ($e.data('modlist') + '').split(','); + $mt.each(function () { + var elem = $(this); + if (list.indexOf(elem.data('id') + '') === -1) + elem.addClass("slx-fade"); + else if (action === 'bold') + elem.addClass("slx-bold"); + }); + if (action === 'bold') { + boldItem = e; + $e.addClass("slx-bold"); + } + } +})(); // Polling for updated status (outdated, missing, ok) diff --git a/modules-available/sysconfig/install.inc.php b/modules-available/sysconfig/install.inc.php index 1ccec59b..9322578e 100644 --- a/modules-available/sysconfig/install.inc.php +++ b/modules-available/sysconfig/install.inc.php @@ -40,15 +40,13 @@ $update[] = tableCreate('configtgz_location', " "); // Constraints -if (in_array(UPDATE_DONE, $update)) { - // To self - $update[] = tableAddConstraint('configtgz_x_module', 'configid', 'configtgz', 'configid', - ''); - $update[] = tableAddConstraint('configtgz_x_module', 'moduleid', 'configtgz_module', 'moduleid', - ''); - $update[] = tableAddConstraint('configtgz_location', 'configid', 'configtgz', 'configid', - 'ON DELETE CASCADE ON UPDATE CASCADE'); -} +$update[] = tableAddConstraint('configtgz_x_module', 'configid', 'configtgz', 'configid', + 'ON DELETE CASCADE ON UPDATE CASCADE'); +$update[] = tableAddConstraint('configtgz_x_module', 'moduleid', 'configtgz_module', 'moduleid', + 'ON DELETE CASCADE ON UPDATE CASCADE'); +$update[] = tableAddConstraint('configtgz_location', 'configid', 'configtgz', 'configid', + 'ON DELETE CASCADE ON UPDATE CASCADE'); +// No constraint to location table since we use locationid 0 for global (NULL would require special handling for UPDATE) // Update path diff --git a/modules-available/sysconfig/lang/de/template-tags.json b/modules-available/sysconfig/lang/de/template-tags.json index 8e6ba87a..1d0fcc6a 100644 --- a/modules-available/sysconfig/lang/de/template-tags.json +++ b/modules-available/sysconfig/lang/de/template-tags.json @@ -74,6 +74,7 @@ "lang_mapModeNativeFallback": "Nativ in der VM einbinden; Fallback auf VMware Shared Folders", "lang_mapModeNone": "Verzeichnisse nicht durchreichen", "lang_mapModeVmware": "VMware Shared Folders [VMwareTools]", + "lang_modStillUsedBy": "Modul noch in Verwendung durch:", "lang_moduleChoose": "Bitte w\u00e4hlen Sie aus, welche Art Konfigurationsmodul Sie erstellen m\u00f6chten.", "lang_moduleConfiguration": "Konfigurationsmodule", "lang_moduleName": "Modulname", diff --git a/modules-available/sysconfig/lang/en/template-tags.json b/modules-available/sysconfig/lang/en/template-tags.json index 0921ccdb..16956bf2 100644 --- a/modules-available/sysconfig/lang/en/template-tags.json +++ b/modules-available/sysconfig/lang/en/template-tags.json @@ -74,6 +74,7 @@ "lang_mapModeNativeFallback": "Natively map inside VM; fallback to VMware Shared Folders", "lang_mapModeNone": "Don't map shares at all", "lang_mapModeVmware": "VMware Shared Folders [VMwareTools]", + "lang_modStillUsedBy": "Module still in use by:", "lang_moduleChoose": "Please select which type of configuration module you want to create.", "lang_moduleConfiguration": "Module Configuration", "lang_moduleName": "Module Name", diff --git a/modules-available/sysconfig/page.inc.php b/modules-available/sysconfig/page.inc.php index 05a83924..320030f9 100644 --- a/modules-available/sysconfig/page.inc.php +++ b/modules-available/sysconfig/page.inc.php @@ -214,7 +214,7 @@ class Page_SysConfig extends Page { // Configs $res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, c.dateline, - GROUP_CONCAT(DISTINCT cl.locationid) AS loclist, GROUP_CONCAT(cxm.moduleid) AS modlist + GROUP_CONCAT(DISTINCT cl.locationid) AS loclist, GROUP_CONCAT(DISTINCT cxm.moduleid) AS modlist FROM configtgz c LEFT JOIN configtgz_x_module cxm USING (configid) LEFT JOIN configtgz_location cl ON (c.configid = cl.configid) @@ -411,20 +411,18 @@ class Page_SysConfig extends Page private function delModule() { $moduleid = Request::post('del', 'MISSING'); - $row = Database::queryFirst("SELECT title, filepath FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); - if ($row === false) { + $module = Database::queryFirst("SELECT title, filepath FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); + if ($module === false) { Message::addError('config-invalid', $moduleid); Util::redirect('?do=sysconfig'); } - $existing = Database::queryFirst("SELECT title FROM configtgz_x_module" - . " INNER JOIN configtgz USING (configid)" - . " WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); - if ($existing !== false) { - Message::addError('module-in-use', $row['title'], $existing['title']); - Util::redirect('?do=sysconfig'); - } + // Get config.tgz using this module *before* deleting it + $existing = Database::simpleQuery("SELECT configid FROM configtgz_x_module + WHERE moduleid = :moduleid", array('moduleid' => $moduleid)); + // Delete DB entries and file + Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); $task = Taskmanager::submit('DeleteFile', array( - 'file' => $row['filepath'] + 'file' => $module['filepath'] )); if (isset($task['statusCode']) && $task['statusCode'] === Taskmanager::TASK_WAITING) { $task = Taskmanager::waitComplete($task['id']); @@ -432,9 +430,15 @@ class Page_SysConfig extends Page if (!isset($task['statusCode']) || $task['statusCode'] === Taskmanager::TASK_ERROR) { Message::addWarning('main.task-error', $task['data']['error']); } elseif ($task['statusCode'] === Taskmanager::TASK_FINISHED) { - Message::addSuccess('module-deleted', $row['title']); + Message::addSuccess('module-deleted', $module['title']); + } + // Rebuild depending config.tgz + while ($crow = $existing->fetch(PDO::FETCH_ASSOC)) { + $config = ConfigTgz::get($crow['configid']); + if ($config !== false) { + $config->generate(); + } } - Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); Util::redirect('?do=sysconfig'); } diff --git a/modules-available/sysconfig/templates/js.html b/modules-available/sysconfig/templates/js.html index 157e8d12..63e2b8c6 100644 --- a/modules-available/sysconfig/templates/js.html +++ b/modules-available/sysconfig/templates/js.html @@ -1,4 +1,11 @@ - +