diff options
-rw-r--r-- | inc/paginate.inc.php | 114 | ||||
-rw-r--r-- | inc/render.inc.php | 2 | ||||
-rw-r--r-- | modules/syslog.inc.php | 9 | ||||
-rw-r--r-- | script/bootstrap-tagsinput.min.js | 8 | ||||
-rw-r--r-- | style/bootstrap-tagsinput.css | 45 | ||||
-rw-r--r-- | style/default.css | 8 | ||||
-rw-r--r-- | templates/page-syslog.html | 6 | ||||
-rw-r--r-- | templates/page-tgz-list.html | 5 | ||||
-rw-r--r-- | templates/pagenav.html | 15 | ||||
-rw-r--r-- | updates/v2 | 43 |
10 files changed, 248 insertions, 7 deletions
diff --git a/inc/paginate.inc.php b/inc/paginate.inc.php new file mode 100644 index 00000000..62345ffe --- /dev/null +++ b/inc/paginate.inc.php @@ -0,0 +1,114 @@ +<?php + +class Paginate +{ + private $query; + private $currentPage; + private $perPage; + private $url; + private $totalRows = false; + + /** + * @query - The query that will return lines to show + * @currentPage - 0based index of currently viewed page + * @perPage - Number of items to show per page + * @url - URL of current wegpage + */ + public function __construct($query, $perPage, $url = false) + { + $this->currentPage = (isset($_GET['page']) ? (int)$_GET['page'] : 0); + $this->perPage = (int)$perPage; + if ($this->currentPage < 0) { + Util::traceError('Current page < 0'); + } + if ($this->perPage < 1) { + Util::traceError('Per page < 1'); + } + // Query + if (!preg_match('/\s*SELECT\s/is', $query)) { + Util::traceError('Query has to start with SELECT!'); + } + // XXX: MySQL only + if (preg_match('/^mysql/i', CONFIG_SQL_DSN)) { + // Sanity: Check for LIMIT specification at the end + if (preg_match('/LIMIT\s+(\d+|\:\w+|\?)\s*,\s*(\d+|\:\w+|\?)(\s|;)*(\-\-.*)?$/is', $query)) { + Util::traceError("You cannot pass a query containing a LIMIT to the Paginator class!"); + } + // Sanity: no comment or semi-colon at end (sloppy, might lead to false negatives) + if (preg_match('/(\-\-|;)(\s|[^\'"`])*$/is', $query)) { + Util::traceError("Your query must not end in a comment or semi-colon!"); + } + $query .= ' LIMIT ' . ($this->currentPage * $this->perPage) . ', ' . $this->perPage; + // Use SQL_CALC_FOUND_ROWS + if (!preg_match('/^\s*SELECT\s+SQL_CALC_FOUND_ROWS/is', $query)) { + $query = preg_replace('/^\s*SELECT/is', 'SELECT SQL_CALC_FOUND_ROWS ', $query); + } + } else { + Util::traceError('Unsupported database engine'); + } + // Mangle URL + if ($url === false) $url = $_SERVER['REQUEST_URI']; + if (strpos($url, '?') === false) { + $url .= '?'; + } else { + $url = preg_replace('/(\?|&)&*page=[^&]*(&+|$)/i', '$1', $url); + if (substr($url, -1) !== '&') $url .= '&'; + } + // + $this->query =$query; + $this->url = $url; + } + + /** + * Execute the query, returning the PDO query object + */ + public function exec($args = array()) + { + $args[':limit_start'] = $this->currentPage; + $args[':limit_count'] = $this->perPage; + $retval = Database::simpleQuery($this->query, $args); + $res = Database::queryFirst('SELECT FOUND_ROWS() AS rowcount'); + $this->totalRows = (int)$res['rowcount']; + return $retval; + } + + public function render($template, $data) + { + if ($this->totalRows == 0) { + // Shortcut for no content + Render::addTemplate($template, $data); + return; + } + // The real thing + $pages = array(); + $pageCount = floor(($this->totalRows - 1) / $this->perPage) + 1; + $skip = false; + for ($i = 0; $i < $pageCount; ++$i) { + if (($i > 0 && $i < $this->currentPage - 3) || ($i > $this->currentPage + 3 && $i < $pageCount - 1)) { + if (!$skip) { + $skip = true; + $pages[] = array( + 'text' => false, + 'current' => false + ); + } + continue; + } + $skip = false; + $pages[] = array( + 'text' => $i + 1, + 'page' => $i, + 'current' => $i == $this->currentPage, + ); + } + $pages = Render::parse('pagenav', array( + 'url' => $this->url, + 'pages' => $pages, + )); + $data['page'] = $this->currentPage; + $data['pagenav'] = $pages; + Render::addTemplate($template, $data); + } + +} + diff --git a/inc/render.inc.php b/inc/render.inc.php index 1ab93965..a3cef516 100644 --- a/inc/render.inc.php +++ b/inc/render.inc.php @@ -42,6 +42,7 @@ class Render <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Bootstrap --> <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"> ', self::$header @@ -55,6 +56,7 @@ class Render ' </div> <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> </html>' ; diff --git a/modules/syslog.inc.php b/modules/syslog.inc.php index 70c383d0..f8d99de3 100644 --- a/modules/syslog.inc.php +++ b/modules/syslog.inc.php @@ -1,5 +1,7 @@ <?php +require_once('inc/paginate.inc.php'); + User::load(); if (!User::isLoggedIn()) { @@ -14,7 +16,7 @@ function render_module() $not = ''; if (isset($_POST['filter'])) $filter = $_POST['filter']; if (!empty($filter)) { - $parts = explode(' ', $filter); + $parts = explode(',', $filter); $opt = array(); foreach ($parts as $part) { $part = preg_replace('/[^a-z0-9_\-]/', '', trim($part)); @@ -29,7 +31,8 @@ function render_module() $today = date('d.m.Y'); $yesterday = date('d.m.Y', time() - 86400); $lines = array(); - $res = Database::simpleQuery("SELECT logid, dateline, logtypeid, clientip, description, extra FROM clientlog $opt ORDER BY logid DESC LIMIT 200"); + $paginate = new Paginate("SELECT logid, dateline, logtypeid, clientip, description, extra FROM clientlog $opt ORDER BY logid DESC", 50); + $res = $paginate->exec(); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { $day = date('d.m.Y', $row['dateline']); // TODO: No output strings in source files! @@ -42,7 +45,7 @@ function render_module() $lines[] = $row; } - Render::addTemplate('page-syslog', array( + $paginate->render('page-syslog', array( 'token' => Session::get('token'), 'filter' => $filter, 'not' => $not, diff --git a/script/bootstrap-tagsinput.min.js b/script/bootstrap-tagsinput.min.js new file mode 100644 index 00000000..3d652628 --- /dev/null +++ b/script/bootstrap-tagsinput.min.js @@ -0,0 +1,8 @@ +/* + * bootstrap-tagsinput v0.3.9 by Tim Schlechter + * + */ +!function(a){"use strict";function b(b,c){this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('<div class="bootstrap-tagsinput"></div>'),this.$input=a('<input size="'+this.inputSize+'" type="text" placeholder="'+this.placeholderText+'"/>').appendTo(this.$container),this.$element.after(this.$container),this.build(c)}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?h.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}var g={tagClass:function(){return"label label-info"},itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},freeInput:!0,maxTags:void 0,confirmKeys:[13],onTagExists:function(a,b){b.hide().fadeIn()}};b.prototype={constructor:b,add:function(b,c){var d=this;if(!(d.options.maxTags&&d.itemsArray.length>=d.options.maxTags||b!==!1&&!b)){if("object"==typeof b&&!d.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(d.isSelect&&!d.multiple&&d.itemsArray.length>0&&d.remove(d.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var f=b.split(",");if(f.length>1){for(var g=0;g<f.length;g++)this.add(f[g],!0);return c||d.pushVal(),void 0}}var h=d.options.itemValue(b),i=d.options.itemText(b),j=d.options.tagClass(b),k=a.grep(d.itemsArray,function(a){return d.options.itemValue(a)===h})[0];if(k){if(d.options.onTagExists){var l=a(".tag",d.$container).filter(function(){return a(this).data("item")===k});d.options.onTagExists(b,l)}}else{d.itemsArray.push(b);var m=a('<span class="tag '+e(j)+'">'+e(i)+'<span data-role="remove"></span></span>');if(m.data("item",b),d.findInputWrapper().before(m),m.after(" "),d.isSelect&&!a('option[value="'+escape(h)+'"]',d.$element)[0]){var n=a("<option selected>"+e(i)+"</option>");n.data("item",b),n.attr("value",h),d.$element.append(n)}c||d.pushVal(),d.options.maxTags===d.itemsArray.length&&d.$container.addClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemAdded",{item:b}))}}}},remove:function(b,c){var d=this;d.objectItems&&(b="object"==typeof b?a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==d.options.itemValue(b)})[0]:a.grep(d.itemsArray,function(a){return d.options.itemValue(a)==b})[0]),b&&(a(".tag",d.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",d.$element).filter(function(){return a(this).data("item")===b}).remove(),d.itemsArray.splice(a.inArray(b,d.itemsArray),1)),c||d.pushVal(),d.options.maxTags>d.itemsArray.length&&d.$container.removeClass("bootstrap-tagsinput-max"),d.$element.trigger(a.Event("itemRemoved",{item:b}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(),b.options.maxTags&&!this.isEnabled()&&this.enable()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;e.options=a.extend({},g,b);var h=e.options.typeahead||{};e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),c(e.options,"tagClass"),e.options.source&&(h.source=e.options.source),h.source&&a.fn.typeahead&&(d(h,"source"),e.$input.typeahead({source:function(b,c){function d(a){for(var b=[],d=0;d<a.length;d++){var g=e.options.itemText(a[d]);f[g]=a[d],b.push(g)}c(b)}this.map={};var f=this.map,g=h.source(b);a.isFunction(g.success)?g.success(d):a.when(g).then(d)},updater:function(a){e.add(this.map[a])},matcher:function(a){return-1!==a.toLowerCase().indexOf(this.query.trim().toLowerCase())},sorter:function(a){return a.sort()},highlighter:function(a){var b=new RegExp("("+this.query+")","gi");return a.replace(b,"<strong>$1</strong>")}})),e.$container.on("click",a.proxy(function(){e.$input.focus()},e)),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus());break;default:e.options.freeInput&&a.inArray(b.which,e.options.confirmKeys)>=0&&(e.add(c.val()),c.val(""),b.preventDefault())}c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===g.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d){var e=[];return this.each(function(){var f=a(this).data("tagsinput");if(f){var g=f[c](d);void 0!==g&&e.push(g)}else f=new b(this,c),a(this).data("tagsinput",f),e.push(f),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?e.length>1?e:e[0]:e},a.fn.tagsinput.Constructor=b;var h=a("<div />");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery); +/* +//@ sourceMappingURL=bootstrap-tagsinput.min.js.map +*/
\ No newline at end of file diff --git a/style/bootstrap-tagsinput.css b/style/bootstrap-tagsinput.css new file mode 100644 index 00000000..98cfa7f3 --- /dev/null +++ b/style/bootstrap-tagsinput.css @@ -0,0 +1,45 @@ +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + margin-bottom: 10px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; +} +.bootstrap-tagsinput input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0; + margin: 0; + width: auto !important; + max-width: inherit; +} +.bootstrap-tagsinput input:focus { + border: none; + box-shadow: none; +} +.bootstrap-tagsinput .tag { + margin-right: 2px; + color: white; +} +.bootstrap-tagsinput .tag [data-role="remove"] { + margin-left: 8px; + cursor: pointer; +} +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; + padding: 0px 2px; +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} diff --git a/style/default.css b/style/default.css index c846f261..1a4a0be0 100644 --- a/style/default.css +++ b/style/default.css @@ -49,3 +49,11 @@ body { font-size: 90%; font-style: italic; } + +.bootstrap-tagsinput { + width: 100%; + margin: 0px; + border-radius: 0; + height: 34px; +} + diff --git a/templates/page-syslog.html b/templates/page-syslog.html index c741ab6b..c16d8da1 100644 --- a/templates/page-syslog.html +++ b/templates/page-syslog.html @@ -3,7 +3,7 @@ <form method="post" action="?do=syslog"> <div class="input-group"> <span class="input-group-addon">Filter</span> - <input id="filterstring" type="text" class="form-control" placeholder="event-id" value="{{filter}}" name="filter"> + <input id="filterstring" type="text" placeholder="event-id" value="{{filter}}" name="filter" data-role="tagsinput" /> <span class="input-group-addon"> <input type="checkbox" name="not" {{#not}}checked="checked"{{/not}}> not </span> @@ -12,6 +12,7 @@ </span> </div> </form> + {{{pagenav}}} <table class="table table-striped table-condensed"> <thead> <th></th> @@ -23,7 +24,7 @@ <tbody> {{#list}} <tr> - <td><span class="glyphicon glyphicon-off" title="{{logtypeid}}" onclick="$('#filterstring').val($('#filterstring').val() + ' {{logtypeid}}')"></span></td> + <td><span class="glyphicon glyphicon-off" title="{{logtypeid}}" onclick="$('#filterstring').tagsinput('add', '{{logtypeid}}')"></span></td> <td class="text-right" nowrap="nowrap">{{date}}</td> <td>{{clientip}}</td> <td>{{description}}</td> @@ -35,5 +36,6 @@ {{/list}} </tbody> </table> + {{{pagenav}}} </div> diff --git a/templates/page-tgz-list.html b/templates/page-tgz-list.html index bcf5ffc0..fdc11933 100644 --- a/templates/page-tgz-list.html +++ b/templates/page-tgz-list.html @@ -17,8 +17,9 @@ {{^files}} <div class="row well well-sm">Keine Konfigurationspakete gefunden!</div> {{/files}} - <a class="btn btn-lg btn-primary" href="?do=sysconfig&action=remotelist">Konfigurationen herunterladen</a> - <a class="btn btn-lg btn-primary" href="#" data-toggle="collapse" data-target="#uploadform">Eigene Konfiguration hochladen</a> + <a class="btn btn-md btn-primary" href="?do=sysconfig&action=remotelist">Konfigurationsvolagen</a> + <a class="btn btn-md btn-primary" href="#" data-toggle="collapse" data-target="#uploadform">Eigene Konfiguration hochladen</a> + <a class="btn btn-md btn-primary" href="/boot/default/config.tgz">Aktive Konfiguration herunterladen</a> <div class="collapse" id="uploadform"> <div class="well well-sm" style="margin: 5px 0px"> <form method="post" action="?do=sysconfig" enctype="multipart/form-data"> diff --git a/templates/pagenav.html b/templates/pagenav.html new file mode 100644 index 00000000..5cab6a46 --- /dev/null +++ b/templates/pagenav.html @@ -0,0 +1,15 @@ +<ul class="pagination pagination-sm pull-right"> + {{#pages}} + {{#current}} + <li class="active"><a href="{{url}}page={{page}}">{{text}} <span class="sr-only">(current)</span></a></li> + {{/current}} + {{^current}} + {{#text}} + <li><a href="{{url}}page={{page}}">{{text}}</a></li> + {{/text}} + {{^text}} + <li class="disabled"><a href="#">…</a></li> + {{/text}} + {{/current}} + {{/pages}} +</ul> diff --git a/updates/v2 b/updates/v2 new file mode 100644 index 00000000..e67a5437 --- /dev/null +++ b/updates/v2 @@ -0,0 +1,43 @@ +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +CREATE TABLE `cat_setting` ( + `catid` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(250) NOT NULL, + `sortval` smallint(5) unsigned NOT NULL, + PRIMARY KEY (`catid`), + KEY `sortval` (`sortval`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; + +INSERT INTO `cat_setting` (`catid`, `name`, `sortval`) VALUES +(0, 'Unkategorisiert', 20000), +(1, 'Inaktivität und Abschaltung', 30), +(2, 'Internetzugriff', 20), +(3, 'Zeitsynchronisation', 100), +(4, 'Grundsystem', 10); + +ALTER TABLE `setting` ADD `catid` INT( 10 ) UNSIGNED NOT NULL AFTER `setting` ; +ALTER TABLE `setting` ADD FOREIGN KEY ( `catid` ) REFERENCES `openslx`.`cat_setting` (`catid`) ON DELETE RESTRICT ON UPDATE CASCADE ; + +INSERT INTO `setting` (`setting`, `catid`, `defaultvalue`, `permissions`, `validator`, `description`) VALUES + ('SLX_LOGOUT_TIMEOUT', 1, '1800', 2, 'regex:/^\\d*$/', 'Zeit /in Sekunden/, die eine Benutzersitzung ohne Aktion sein darf, bevor sie beendet wird.\r\nFeld leer lassen, um die Funktion zu deaktivieren.'), + ('SLX_REMOTE_LOG_SESSIONS', 0, 'anonymous', 2, 'regex:/^(yes|anonymous|no)$/', 'Legt fest, ob Logins und Logouts der Benutzer an den Satelliten gemeldet werden sollen.\r\n*yes* = Mit Benutzerkennung loggen\r\n*anonymous* = Anonym loggen\r\n*no* = Nicht loggen'), + ('SLX_SHUTDOWN_SCHEDULE', 1, '22:10 00:00', 2, 'regex:/^(\\s*\\d{1,2}:\\d{1,2})*$/', 'Feste Uhrzeit, zu der sich die Rechner ausschalten, auch wenn noch ein Benutzer aktiv ist.\r\nMehrere Zeitpunkte können durch Leerzeichen getrennt angegeben werden.'), + ('SLX_SHUTDOWN_TIMEOUT', 1, '1200', 2, 'regex:/^\\d*$/', 'Zeit in Sekunden, nach dem ein Rechner abgeschaltet wird, sofern kein Benutzer angemeldet ist.\r\nFeld leer lassen, um die Funktion zu deaktivieren.'); + +UPDATE setting SET catid = 0 WHERE setting = 'SLX_ADDONS' LIMIT 1; +UPDATE setting SET catid = 0 WHERE setting = 'SLX_REMOTE_LOG_SESSIONS' LIMIT 1; +UPDATE setting SET catid = 1 WHERE setting = 'SLX_LOGOUT_TIMEOUT' LIMIT 1; +UPDATE setting SET catid = 1 WHERE setting = 'SLX_SHUTDOWN_SCHEDULE' LIMIT 1; +UPDATE setting SET catid = 1 WHERE setting = 'SLX_SHUTDOWN_TIMEOUT' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_NET_DOMAIN' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_PROXY_BLACKLIST' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_PROXY_IP' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_PROXY_MODE' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_PROXY_PORT' LIMIT 1; +UPDATE setting SET catid = 2 WHERE setting = 'SLX_PROXY_TYPE' LIMIT 1; +UPDATE setting SET catid = 3 WHERE setting = 'SLX_BIOS_CLOCK' LIMIT 1; +UPDATE setting SET catid = 3 WHERE setting = 'SLX_NTP_SERVER' LIMIT 1; +UPDATE setting SET catid = 4 WHERE setting = 'SLX_ROOT_PASS' LIMIT 1; +UPDATE setting SET catid = 4 WHERE setting = 'SLX_VM_NFS' LIMIT 1; + |