From 4a8725b8dcac3bd0e7afe463968d281e4cf8df6c Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 20 May 2014 19:20:02 +0200 Subject: JS Stuff for Taskmanager interaction More work on AD wizard --- apis/taskmanager.inc.php | 22 +++++ inc/message.inc.php | 1 + inc/render.inc.php | 8 +- inc/taskmanager.inc.php | 29 +++++- modules/sysconfig.inc.php | 31 ++++-- modules/sysconfig/addmodule.inc.php | 16 ++++ modules/sysconfig/addmodule_ad.inc.php | 89 ++++++++++++++++-- script/custom.js | 19 +++- script/taskmanager.js | 141 ++++++++++++++++++++++++++++ templates/sysconfig/ad-checkconnection.html | 42 +++++++++ templates/sysconfig/ad-finish.html | 28 ++++++ templates/sysconfig/ad-start.html | 1 + 12 files changed, 401 insertions(+), 26 deletions(-) create mode 100644 apis/taskmanager.inc.php create mode 100644 script/taskmanager.js create mode 100644 templates/sysconfig/ad-checkconnection.html create mode 100644 templates/sysconfig/ad-finish.html 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 @@ + $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 + + ', self::$header , ' -
+
', self::$body , @@ -58,7 +62,7 @@ class Render - + ' ; 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('
In Progress....
'); @@ -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('
'); + } + if (item.is('[data-tm-log]')) { + item.append('
');
+		}
+		item.prepend('');
+	});
+	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($('
').append(document.createTextNode(data.error))); + console.log("Error ERROR"); + return false; + } + // No task list is also bad + if (typeof data.tasks === 'undefined') { + $('#mainpage').prepend('
Internal Error #67452
'); + 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($('
').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 @@ +

+ Die Verbindung zum angegebenen AD-Server wird nun überprüft. Bitte haben Sie einen Moment Geduld. +

+ +
+
LDAP Test-Query
+
Dummy
+
+
+
+
+ + + + + + +
+
+
+
+ + + + + + +
+
+ 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 @@ +

+ Der AD-Proxy wird nun konfiguriert und gestartet... +

+ +
+
Konfiguration erzeugen
+
ldadp starten
+
+
+ + + 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 @@

+
Server -- cgit v1.2.3-55-g7522