diff options
author | Simon Rettberg | 2014-05-20 19:20:02 +0200 |
---|---|---|
committer | Simon Rettberg | 2014-05-20 19:20:02 +0200 |
commit | 4a8725b8dcac3bd0e7afe463968d281e4cf8df6c (patch) | |
tree | 8d1374edd2a1e74ed3a99813210ca84e999fb82c | |
parent | OO style modules (diff) | |
download | slx-admin-4a8725b8dcac3bd0e7afe463968d281e4cf8df6c.tar.gz slx-admin-4a8725b8dcac3bd0e7afe463968d281e4cf8df6c.tar.xz slx-admin-4a8725b8dcac3bd0e7afe463968d281e4cf8df6c.zip |
JS Stuff for Taskmanager interaction
More work on AD wizard
-rw-r--r-- | apis/taskmanager.inc.php | 22 | ||||
-rw-r--r-- | inc/message.inc.php | 1 | ||||
-rw-r--r-- | inc/render.inc.php | 8 | ||||
-rw-r--r-- | inc/taskmanager.inc.php | 29 | ||||
-rw-r--r-- | modules/sysconfig.inc.php | 31 | ||||
-rw-r--r-- | modules/sysconfig/addmodule.inc.php | 16 | ||||
-rw-r--r-- | modules/sysconfig/addmodule_ad.inc.php | 89 | ||||
-rw-r--r-- | script/custom.js | 19 | ||||
-rw-r--r-- | script/taskmanager.js | 141 | ||||
-rw-r--r-- | templates/sysconfig/ad-checkconnection.html | 42 | ||||
-rw-r--r-- | templates/sysconfig/ad-finish.html | 28 | ||||
-rw-r--r-- | templates/sysconfig/ad-start.html | 1 |
12 files changed, 401 insertions, 26 deletions
diff --git a/apis/taskmanager.inc.php b/apis/taskmanager.inc.php new file mode 100644 index 00000000..5994c018 --- /dev/null +++ b/apis/taskmanager.inc.php @@ -0,0 +1,22 @@ +<?php + +require_once 'inc/taskmanager.inc.php'; + +if (!is_array($_POST['ids'])) { + die('{"error" : "No Task ids given in POST data."}'); +} + +$return = array(); +foreach ($_POST['ids'] as $id) { + $status = Taskmanager::status($id); + if ($status === false) { + $return[] = array('id' => $id, 'error' => 'No connection to TaskManager'); + continue; + } + $return[] = $status; + if (!isset($status['statusCode']) || ($status['statusCode'] !== TASK_WAITING && $status['statusCode'] !== TASK_PROCESSING)) { + Taskmanager::release($id); + } +} + +echo json_encode(array('tasks' => $return)); diff --git a/inc/message.inc.php b/inc/message.inc.php index 6c95764c..8a3b5d4e 100644 --- a/inc/message.inc.php +++ b/inc/message.inc.php @@ -30,6 +30,7 @@ $error_text = array( 'error-extract' => 'Konnte Archiv nicht nach {{0}} entpacken - {{1}}', 'module-added' => 'Modul erfolgreich hinzugefügt', 'taskmanager-error' => 'Verbindung zum Taskmanager fehlgeschlagen', + 'taskmanager-format' => 'Taskmanager hat ungültige Daten zurückgeliefert', 'task-error' => 'Ausführung fehlgeschlagen: {{0}}', ); diff --git a/inc/render.inc.php b/inc/render.inc.php index dff32798..cf0958c2 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -45,12 +45,16 @@ class Render <link href="style/bootstrap.min.css" rel="stylesheet" media="screen"> <link href="style/bootstrap-tagsinput.css" rel="stylesheet" media="screen"> <link href="style/default.css" rel="stylesheet" media="screen"> + <script type="text/javascript"> + var TOKEN = "' . Session::get('token') . '"; + </script> + </body> ', self::$header , ' </head> <body> - <div class="container"> + <div class="container" id="mainpage"> ', self::$body , @@ -58,7 +62,7 @@ class Render <script src="script/jquery.js"></script> <script src="script/bootstrap.min.js"></script> <script src="script/bootstrap-tagsinput.min.js"></script> - <script src="script/custom.js"></script></body> + <script src="script/taskmanager.js"></script> </html>' ; if ($zip) { diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index f2f337be..3353050f 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -12,21 +12,40 @@ class Taskmanager { if (self::$sock !== false) return; self::$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - socket_set_option(self::$sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 0, 'usec' => 100000)); - socket_set_option(self::$sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 0, 'usec' => 100000)); + socket_set_option(self::$sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 0, 'usec' => 300000)); + socket_set_option(self::$sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 0, 'usec' => 200000)); socket_connect(self::$sock, '127.0.0.1', 9215); } - public static function submit($task, $data, $async) + public static function submit($task, $data, $async = false) { self::init(); $seq = (string)mt_rand(); - $data = json_encode($data); + if (empty($data)) { + $data = '{}'; + } else { + $data = json_encode($data); + } $message = "$seq, $task, $data"; $sent = socket_send(self::$sock, $message, strlen($message), 0); + if ($sent != strlen($message)) { + Message::addError('taskmanager-error'); + return false; + } if ($async) return true; $reply = self::readReply($seq); - if (!is_array($reply)) return false; + if ($reply === false) { + Message::addError('taskmanager-error'); + return false; + } + if (!is_array($reply)) { + Message::addError('taskmanager-format'); + return false; + } + if ($reply['statusCode'] === NO_SUCH_TASK) { + Message::addError('task-error', 'Ungültiger Task: ' . $task); + return false; + } return $reply; } diff --git a/modules/sysconfig.inc.php b/modules/sysconfig.inc.php index 28fc6a50..f177f0f1 100644 --- a/modules/sysconfig.inc.php +++ b/modules/sysconfig.inc.php @@ -7,18 +7,11 @@ class Page_SysConfig extends Page { User::load(); - // Read request vars $action = Request::any('action', 'list'); - $step = Request::any('step', 0); // Action: "addmodule" (upload new module) if ($action === 'addmodule') { - if ($step === 0) $step = 'AddModule_Start'; - require_once 'modules/sysconfig/addmodule.inc.php'; - foreach (glob('modules/sysconfig/addmodule_*.inc.php') as $file) { - require_once $file; - } - AddModule_Base::setStep($step); + $this->initAddModule(); AddModule_Base::preprocess(); } @@ -67,6 +60,17 @@ class Page_SysConfig extends Page break; } } + + protected function doAjax() + { + $action = Request::any('action', 'list'); + + // Action: "addmodule" (upload new module) + if ($action === 'addmodule') { + $this->initAddModule(); + AddModule_Base::ajax(); + } + } private function rr_list_configs() { @@ -83,5 +87,16 @@ class Page_SysConfig extends Page } Render::addTemplate('page-sysconfig-main', array('modules' => $modules, 'token' => Session::get('token'))); } + + private function initAddModule() + { + $step = Request::any('step', 0); + if ($step === 0) $step = 'AddModule_Start'; + require_once 'modules/sysconfig/addmodule.inc.php'; + foreach (glob('modules/sysconfig/addmodule_*.inc.php') as $file) { + require_once $file; + } + AddModule_Base::setStep($step); + } } diff --git a/modules/sysconfig/addmodule.inc.php b/modules/sysconfig/addmodule.inc.php index 924f18fa..883c196f 100644 --- a/modules/sysconfig/addmodule.inc.php +++ b/modules/sysconfig/addmodule.inc.php @@ -81,6 +81,14 @@ abstract class AddModule_Base // void } + /** + * Handle ajax stuff + */ + protected function ajaxInternal() + { + // void + } + public static function preprocess() { if (self::$instance === false) { @@ -96,6 +104,14 @@ abstract class AddModule_Base } self::$instance->renderInternal(); } + + public static function ajax() + { + if (self::$instance === false) { + Util::traceError('No step instance yet'); + } + self::$instance->ajaxInternal(); + } } diff --git a/modules/sysconfig/addmodule_ad.inc.php b/modules/sysconfig/addmodule_ad.inc.php index abc55df5..ab897096 100644 --- a/modules/sysconfig/addmodule_ad.inc.php +++ b/modules/sysconfig/addmodule_ad.inc.php @@ -14,13 +14,15 @@ class AdModule_Start extends AddModule_Base protected function renderInternal() { - Session::set('ad_stuff', false); + Session::set('ad_check', false); + Session::save(); Render::addDialog('Active Directory Authentifizierung', false, 'sysconfig/ad-start', array( 'step' => 'AdModule_CheckConnection', 'server' => Request::post('server'), 'searchbase' => Request::post('searchbase'), 'binddn' => Request::post('binddn'), 'bindpw' => Request::post('bindpw'), + 'token' => Session::get('token') )); } @@ -28,9 +30,8 @@ class AdModule_Start extends AddModule_Base class AdModule_CheckConnection extends AddModule_Base { - - private $taskId = false; - + private $taskIds; + protected function preprocessInternal() { $server = Request::post('server'); @@ -39,19 +40,87 @@ class AdModule_CheckConnection extends AddModule_Base $bindpw = Request::post('bindpw'); if (empty($server) || empty($searchbase) || empty($binddn)) { Message::addError('empty-field'); - AddModule_Base::setStep('AdModule_Start'); + AddModule_Base::setStep('AdModule_Start'); // Continues with AdModule_Start for render() return; } - $this->taskId = 'ad_' . mt_rand() . '-' . microtime(true); - Taskmanager::submit('LdapSearch', array( + /* + $data = Taskmanager::submit('LdapSearch', array( 'id' => $this->taskId, 'uri' => '' - ), true); + )); + */ + $ldapSearch = Taskmanager::submit('DummyTask', array()); + if (isset($ldapSearch['id'])) { + $dummy = Taskmanager::submit('DummyTask', array('parentTask' => $ldapSearch['id'])); + } + if (!isset($ldapSearch['id']) || !isset($dummy['id'])) { + AddModule_Base::setStep('AdModule_Start'); // Continues with AdModule_Start for render() + return; + } + $this->taskIds = array( + 'tm-search' => $ldapSearch['id'], + 'tm-dummy' => $dummy['id'] + ); } protected function renderInternal() { - Message::addInfo('missing-file'); + Render::addDialog('Active Directory Authentifizierung', false, 'sysconfig/ad-checkconnection', + array_merge($this->taskIds, array( + 'server' => Request::post('server'), + 'searchbase' => Request::post('searchbase'), + 'binddn' => Request::post('binddn'), + 'bindpw' => Request::post('bindpw'), + 'token' => Session::get('token'), + 'step' => 'AdModule_Finish' + )) + ); + } + +} + +class AdModule_Finish extends AddModule_Base +{ + + private $taskIds; + + protected function preprocessInternal() + { + $data = json_encode(array( + 'server' => Request::post('server'), + 'searchbase' => Request::post('searchbase'), + 'binddn' => Request::post('binddn'), + 'bindpw' => Request::post('bindpw'), + )); + Database::exec("INSERT INTO configtgz_module (title, moduletype, filename, contents) " + . " VALUES (:title, 'AD_AUTH', '', :content)", array( + 'title' => 'AD: ' . Request::post('server'), + 'content' => $data)); + $id = Database::lastInsertId(); + $name = CONFIG_TGZ_LIST_DIR . '/modules/AD_AUTH_id_' . $id . '.' . mt_rand() . '.tgz'; + Database::exec("UPDATE configtgz_module SET filename = :filename WHERE moduleid = :id LIMIT 1", array( + 'id' => $id, + 'filename' => $name + )); + $tgz = Taskmanager::submit('DummyTask', array()); + if (isset($tgz['id'])) { + $ldadp = Taskmanager::submit('DummyTask', array('parentTask' => $tgz['id'])); + } + if (!isset($tgz['id']) || !isset($ldadp['id'])) { + AddModule_Base::setStep('AdModule_Start'); // Continues with AdModule_Start for render() + return; + } + $this->taskIds = array( + 'tm-module' => $tgz['id'], + 'tm-ldadp' => $ldadp['id'] + ); } -}
\ No newline at end of file + protected function renderInternal() + { + Render::addDialog('Active Directory Authentifizierung', false, 'sysconfig/ad-finish', + $this->taskIds + ); + } + +} diff --git a/script/custom.js b/script/custom.js index 3269749e..12e760af 100644 --- a/script/custom.js +++ b/script/custom.js @@ -1,3 +1,4 @@ +/* function loadContent(elem, source) { $(elem).html('<div class="progress progress-striped active"><div class="progress-bar" style="width:100%"><span class="sr-only">In Progress....</span></div></div>'); @@ -14,4 +15,20 @@ function selectDir(obj) if (text.substr(0, dirname.length) !== dirname) return; $(this).parent().find('.fileBox')[0].checked = obj.checked; }); -}
\ No newline at end of file +} +*/ + +function updater(url, postdata, callback) +{ + var updateTimer = setInterval(function () { + if (typeof $ === 'undefined') + return; + $.post(url, postdata, function (data, status) { + if (!callback(data, status)) + clearInterval(updateTimer); + }, 'json').fail(function (jqXHR, textStatus, errorThrown) { + if (!callback(errorThrown, textStatus)) + clearInterval(updateTimer); + }); + }, 1000); +} diff --git a/script/taskmanager.js b/script/taskmanager.js new file mode 100644 index 00000000..da3a0586 --- /dev/null +++ b/script/taskmanager.js @@ -0,0 +1,141 @@ +var tmItems = false; +var tmErrors = 0; +var TM_MAX_ERRORS = 5; + +function tmInit() +{ + tmItems = $("div[data-tm-id]"); + if (tmItems.length === 0) return; + tmItems.each(function(i, item) { + item = $(item); + if (item.is('[data-tm-progress]')) { + item.append('<div class="data-tm-progress"><div class="progress"><div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div></div></div>'); + } + if (item.is('[data-tm-log]')) { + item.append('<pre class="data-tm-log" />'); + } + item.prepend('<span class="data-tm-icon" />'); + }); + setTimeout(tmUpdate, 100); +} + +function tmUpdate() +{ + var active = []; + tmItems.each(function(i, item) { + item = $(item); + var id = item.attr('data-tm-id'); + if (typeof id === 'undefined' || id === false || id === '') return; + active.push(id); + }); + if (active.length === 0) return; + $.post('api.php?do=taskmanager', { 'ids[]' : active, token : TOKEN }, function (data, status) { + // POST success + if (tmResult(data, status)) { + setTimeout(tmUpdate, 1000); + } + }, 'json').fail(function (jqXHR, textStatus, errorThrown) { + // POST failure + console.log("TaskManager Error: " + textStatus + " - " + errorThrown); + if (++tmErrors < TM_MAX_ERRORS) setTimeout(tmUpdate, 2000); + }); +} + +function tmResult(data, status) +{ + // Bail out on error + if (typeof data.error !== 'undefined') { + $('#mainpage').prepend($('<div class="alert alert-danger"/>').append(document.createTextNode(data.error))); + console.log("Error ERROR"); + return false; + } + // No task list is also bad + if (typeof data.tasks === 'undefined') { + $('#mainpage').prepend('<div class="alert alert-danger">Internal Error #67452</div>'); + console.log("Error UNEXPECTED"); + return false; + } + var lastRunOnError = (tmErrors > TM_MAX_ERRORS); + // Let's continue handling stuff + var counter = 0; + for (var idx in data.tasks) { + var task = data.tasks[idx]; + if (!task.id) continue; + counter++; + if (lastRunOnError) { + task.statusCode = 'TASK_ERROR'; + } else if (task.error) { + ++tmErrors; + continue; + } else if (tmErrors > 0) { + --tmErrors; + } + var obj = $('div[data-tm-id="' + task.id + '"]'); + if (!obj) continue; + if (task.statusCode === 'TASK_FINISHED') { + obj.attr('data-tm-id', ''); + } + var icon = obj.find('.data-tm-icon'); + if (icon) { + if (typeof task.statusCode === 'undefined') { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-question-sign'); + } else if (task.statusCode === 'TASK_WAITING') { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-pause'); + } else if (task.statusCode === 'TASK_PROCESSING') { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-play'); + } else if (task.statusCode === 'TASK_FINISHED') { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-ok'); + } else if (task.statusCode === 'TASK_ERROR') { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-remove'); + } else { + icon.attr('class', 'data-tm-icon glyphicon glyphicon-trash'); + } + } + var progress = obj.find('.data-tm-progress'); + if (progress) { + var pKey = obj.attr('data-tm-progress'); + if (task.data && task.data[pKey]) { + tmSetProgress(progress, task.data[pKey], task.statusCode); + } else { + tmSetProgress(progress, false, task.statusCode); + } + } + var log = obj.find('.data-tm-log'); + if (log) { + var lKey = obj.attr('data-tm-log'); + if (task.data && task.data[lKey]) { + log.text(task.data[lKey]); + } + } + var cb = obj.attr('data-tm-callback'); + if (cb && window[cb]) { + window[cb](task); + } + } + if (lastRunOnError) { + $('#mainpage').prepend($('<div class="alert alert-danger"/>').append(document.createTextNode(task.error))); + return false; + } + return counter > 0; +} + +function tmSetProgress(elem, percent, status) +{ + var outer = '', inner = ''; + if (status === 'TASK_PROCESSING') { + outer = ' active'; + } else if (status === 'TASK_ERROR') { + inner = ' progress-bar-danger'; + } else if (status === 'TASK_FINISHED') { + inner = ' progress-bar-success'; + } + elem.find('.progress').attr('class', 'progress progress-striped' + outer); + var bar = elem.find('.progress-bar'); + bar.attr('class', 'progress-bar' + inner); + if (percent !== false) { + bar.attr('aria-valuenow', percent); + bar.attr('style', 'width: ' + percent + '%'); + } +} + +tmInit(); diff --git a/templates/sysconfig/ad-checkconnection.html b/templates/sysconfig/ad-checkconnection.html new file mode 100644 index 00000000..91b5881e --- /dev/null +++ b/templates/sysconfig/ad-checkconnection.html @@ -0,0 +1,42 @@ +<p> + Die Verbindung zum angegebenen AD-Server wird nun überprüft. Bitte haben Sie einen Moment Geduld. +</p> + +<div id="zeug"> + <div data-tm-id="{{tm-search}}" data-tm-progress="progress">LDAP Test-Query</div> + <div data-tm-id="{{tm-dummy}}" data-tm-progress="progress" data-tm-callback="ldapCb">Dummy</div> +</div> +<br> +<div class="pull-left"> + <form role="form" method="post" action="?do=SysConfig&action=addmodule&step=AdModule_Start"> + <input type="hidden" name="token" value="{{token}}"> + <input name="server" value="{{server}}" type="hidden"> + <input name="searchbase" value="{{searchbase}}" type="hidden"> + <input name="binddn" value="{{binddn}}" type="hidden"> + <input name="bindpw" value="{{bindpw}}" type="hidden"> + <button type="submit" class="btn btn-primary">« Zurück</button> + </form> +</div> +<div class="pull-right"> + <form role="form" method="post" action="?do=SysConfig&action=addmodule&step={{step}}"> + <input type="hidden" name="token" value="{{token}}"> + <input name="server" value="{{server}}" type="hidden"> + <input name="searchbase" value="{{searchbase}}" type="hidden"> + <input name="binddn" value="{{binddn}}" type="hidden"> + <input name="bindpw" value="{{bindpw}}" type="hidden"> + <button id="nextbutton" type="submit" class="btn btn-primary">Überspringen »</button> + </form> +</div> +<script type="text/javascript"> +function ldapCb(task) +{ + if (!task || !task.statusCode) + return; + if (task.statusCode === 'TASK_FINISHED') { + $('#nextbutton').html('Weiter »'); + } + if (task.statusCode === 'TASK_ERROR' || task.statusCode === 'PARENT_FAILED') { + $('#nextbutton').html('Trotzdem weiter »'); + } +} +</script> diff --git a/templates/sysconfig/ad-finish.html b/templates/sysconfig/ad-finish.html new file mode 100644 index 00000000..f20a2ce1 --- /dev/null +++ b/templates/sysconfig/ad-finish.html @@ -0,0 +1,28 @@ +<p> + Der AD-Proxy wird nun konfiguriert und gestartet... +</p> + +<div id="zeug"> + <div data-tm-id="{{tm-tgz}}" data-tm-log="message">Konfiguration erzeugen</div> + <div data-tm-id="{{tm-ldadp}}" data-tm-log="message" data-tm-callback="ldapCb">ldadp starten</div> +</div> +<br> +<div id="back" class="pull-left" style="display:none"> + <a href="?do=SysConfig&action=addmodule&step=AdModule_Start" class="btn btn-primary">Assistent neustarten</a> +</div> +<div id="finish" class="pull-right" style="display:none"> + <a href="?do=SysConfig" class="btn btn-primary">Zur Systemkonfiguration</a> +</div> +<script type="text/javascript"> +function ldapCb(task) +{ + if (!task || !task.statusCode) + return; + if (task.statusCode === 'TASK_FINISHED') { + $('#finish').attr('style', ''); + } + if (task.statusCode === 'TASK_ERROR' || task.statusCode === 'PARENT_FAILED') { + $('#back').attr('style', ''); + } +} +</script> diff --git a/templates/sysconfig/ad-start.html b/templates/sysconfig/ad-start.html index 0ce4bbf3..f3d8235a 100644 --- a/templates/sysconfig/ad-start.html +++ b/templates/sysconfig/ad-start.html @@ -16,6 +16,7 @@ </p> <form role="form" method="post" action="?do=SysConfig&action=addmodule&step={{step}}"> + <input type="hidden" name="token" value="{{token}}"> <div class="input-group"> <span class="input-group-addon slx-ga">Server</span> <input name="server" value="{{server}}" type="text" class="form-control" placeholder="dc0.institution.example.com"> |