summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Klinger2016-08-22 11:24:03 +0200
committerChristian Klinger2016-08-22 11:24:03 +0200
commitd3c689c6730ca6749c03ffd01c670f7b191e8355 (patch)
tree9e2d7caa1ed3c45b4757621202087a64e5e87cc9
parentcss fix/hack to get roomplanner to work on medium sized screens. (diff)
parent[dozmod] Expect the client to tell wether it is running in exam mode and comp... (diff)
downloadslx-admin-d3c689c6730ca6749c03ffd01c670f7b191e8355.tar.gz
slx-admin-d3c689c6730ca6749c03ffd01c670f7b191e8355.tar.xz
slx-admin-d3c689c6730ca6749c03ffd01c670f7b191e8355.zip
Merge branch 'modularization' of git.openslx.org:openslx-ng/slx-admin into modularization
-rw-r--r--inc/dictionary.inc.php12
-rw-r--r--inc/event.inc.php2
-rw-r--r--inc/render.inc.php3
-rw-r--r--inc/taskmanagercallback.inc.php6
-rw-r--r--inc/util.inc.php35
-rw-r--r--modules-available/baseconfig/inc/baseconfigutil.inc.php22
-rw-r--r--modules-available/baseconfig/page.inc.php43
-rw-r--r--modules-available/baseconfig/templates/_page.html36
-rw-r--r--modules-available/baseconfig_bwlp/baseconfig/settings.json9
-rw-r--r--modules-available/dozmod/api.inc.php60
-rw-r--r--modules-available/dozmod/inc/pagedozmodlog.inc.php156
-rw-r--r--modules-available/dozmod/inc/pagedozmodusers.inc.php115
-rw-r--r--modules-available/dozmod/inc/pagemailtemplates.inc.php79
-rw-r--r--modules-available/dozmod/lang/de/messages.json8
-rw-r--r--modules-available/dozmod/lang/de/module.json11
-rw-r--r--modules-available/dozmod/lang/de/template-tags.json47
-rw-r--r--modules-available/dozmod/lang/en/messages.json8
-rw-r--r--modules-available/dozmod/lang/en/module.json8
-rw-r--r--modules-available/dozmod/lang/en/template-tags.json41
-rw-r--r--modules-available/dozmod/page.inc.php213
-rw-r--r--modules-available/dozmod/style.css51
-rw-r--r--modules-available/dozmod/templates/actionlog-header.html1
-rw-r--r--modules-available/dozmod/templates/actionlog-image.html30
-rw-r--r--modules-available/dozmod/templates/actionlog-lecture.html30
-rw-r--r--modules-available/dozmod/templates/actionlog-log.html41
-rw-r--r--modules-available/dozmod/templates/actionlog-user.html23
-rw-r--r--modules-available/dozmod/templates/blockstats-details.html16
-rw-r--r--modules-available/dozmod/templates/blockstats.html33
-rw-r--r--modules-available/dozmod/templates/images-delete.html12
-rw-r--r--modules-available/dozmod/templates/mailconfig.html2
-rw-r--r--modules-available/dozmod/templates/orglist.html36
-rw-r--r--modules-available/dozmod/templates/runtimeconfig.html93
-rw-r--r--modules-available/dozmod/templates/templates.html95
-rw-r--r--modules-available/dozmod/templates/userlist.html40
-rw-r--r--modules-available/exams/baseconfig/getconfig.inc.php12
-rw-r--r--modules-available/exams/inc/exams.inc.php2
-rw-r--r--modules-available/exams/install.inc.php2
-rw-r--r--modules-available/locations/inc/location.inc.php3
-rw-r--r--modules-available/locations/templates/locations.html12
-rw-r--r--modules-available/main/lang/de/messages.json1
-rw-r--r--modules-available/main/lang/en/messages.json1
-rw-r--r--modules-available/main/templates/main-menu.html19
-rw-r--r--modules-available/statistics/inc/filterset.inc.php11
-rw-r--r--modules-available/statistics/templates/clientlist.html39
-rw-r--r--modules-available/statistics/templates/filterbox.html43
-rw-r--r--modules-available/statistics/templates/kvmstate.html2
-rw-r--r--modules-available/statistics/templates/memory.html2
-rw-r--r--modules-available/statistics/templates/newclients.html2
-rw-r--r--modules-available/sysconfig/templates/custom-filelist.html2
-rw-r--r--modules-available/sysconfig/templates/custom-fileselect.html2
-rw-r--r--modules-available/sysconfig/templates/list-configs.html6
-rw-r--r--modules-available/sysconfig/templates/list-modules.html8
-rw-r--r--modules-available/translation/page.inc.php2
-rw-r--r--modules-available/webinterface/lang/de/template-tags.json3
-rw-r--r--modules-available/webinterface/lang/en/template-tags.json3
-rw-r--r--modules-available/webinterface/templates/https.html2
-rw-r--r--modules-available/webinterface/templates/passwords.html2
-rw-r--r--style/default.css26
58 files changed, 1141 insertions, 483 deletions
diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php
index cb23d0b2..634b1c3c 100644
--- a/inc/dictionary.inc.php
+++ b/inc/dictionary.inc.php
@@ -69,10 +69,13 @@ class Dictionary
return self::$stringCache[$file] = $json;
}
- public static function translateFileModule($moduleId, $path, $tag)
+ public static function translateFileModule($moduleId, $path, $tag, $returnTagOnMissing = false)
{
$strings = self::getArray($moduleId, $path);
if (!isset($strings[$tag])) {
+ if ($returnTagOnMissing) {
+ return '{{' . $tag . '}}';
+ }
return false;
}
return $strings[$tag];
@@ -85,12 +88,15 @@ class Dictionary
return self::translateFileModule(Page::getModule()->getIdentifier(), $path, $tag);
}
- public static function translate($tag)
+ public static function translate($tag, $returnTagOnMissing = false)
{
$string = self::translateFile('module', $tag);
if ($string !== false)
return $string;
- return self::translateFileModule('main', 'global-tags', $tag);
+ $string = self::translateFileModule('main', 'global-tags', $tag);
+ if ($string !== false || !$returnTagOnMissing)
+ return $string;
+ return '{{' . $tag . '}}';
}
public static function getMessage($module, $id)
diff --git a/inc/event.inc.php b/inc/event.inc.php
index dee435a8..8a69ec95 100644
--- a/inc/event.inc.php
+++ b/inc/event.inc.php
@@ -20,8 +20,6 @@ class Event
EventLog::info('System boot...');
$everythingFine = true;
- DefaultData::populate();
-
// Tasks: fire away
$mountId = Trigger::mount();
$autoIp = Trigger::autoUpdateServerIp();
diff --git a/inc/render.inc.php b/inc/render.inc.php
index 1f311868..d870768e 100644
--- a/inc/render.inc.php
+++ b/inc/render.inc.php
@@ -270,9 +270,6 @@ class Render
}
// Load from disk
$data = @file_get_contents('modules/' . $module . '/templates/' . $template . '.html');
- if ($data === false) {
- $data = '<b>Non-existent/unreadable template ' . $template . ' requested!</b>';
- }
self::$templateCache[$id] =& $data;
return $data;
}
diff --git a/inc/taskmanagercallback.inc.php b/inc/taskmanagercallback.inc.php
index c2a05609..bc959f03 100644
--- a/inc/taskmanagercallback.inc.php
+++ b/inc/taskmanagercallback.inc.php
@@ -38,7 +38,11 @@ class TaskmanagerCallback
. " VALUES (:task, UNIX_TIMESTAMP(), :callback, :args)", $data, true) !== false) {
return;
}
- Database::exec("INSERT INTO callback (taskid, dateline, cbfunction) VALUES (:task, UNIX_TIMESTAMP(), :callback)", $data);
+ // Most likely the args column is missing - try to add it on-the-fly so the update routine can properly
+ // use it (confmod updates - otherwise the status of modules is not updated properly)
+ Database::exec("ALTER TABLE `callback` ADD `args` TEXT NOT NULL DEFAULT ''", array(), true);
+ Database::exec("INSERT INTO callback (taskid, dateline, cbfunction, args)"
+ . " VALUES (:task, UNIX_TIMESTAMP(), :callback, :args)", $data);
}
/**
diff --git a/inc/util.inc.php b/inc/util.inc.php
index 14621a5a..a9ae384c 100644
--- a/inc/util.inc.php
+++ b/inc/util.inc.php
@@ -14,6 +14,11 @@ class Util
{
if (defined('API') && API) {
error_log('API ERROR: ' . $message);
+ error_log(self::formatBacktracePlain(debug_backtrace()));
+ }
+ if (php_sapi_name() === 'cli') {
+ // Don't spam HTML when invoked via cli, above error_log should have gone to stdout/stderr
+ exit(1);
}
Header('HTTP/1.1 500 Internal Server Error');
Header('Content-Type: text/html; charset=utf-8');
@@ -37,9 +42,9 @@ class Util
echo '</pre>';
}
echo "<h2>Stack Trace</h2>";
- echo '<pre>', self::formatBacktrace(debug_backtrace()), '</pre>';
+ echo '<pre>', self::formatBacktraceHtml(debug_backtrace()), '</pre>';
echo "<h2>Globals</h2><pre>";
- echo print_r($GLOBALS, true);
+ echo htmlspecialchars(print_r($GLOBALS, true));
echo '</pre>';
} else {
echo <<<SADFACE
@@ -74,7 +79,7 @@ SADFACE;
exit(0);
}
- public static function formatBacktrace($trace, $escape = true)
+ public static function formatBacktraceHtml($trace, $escape = true)
{
$output = '';
foreach ($trace as $idx => $line) {
@@ -100,6 +105,30 @@ SADFACE;
return $output;
}
+ public static function formatBacktracePlain($trace)
+ {
+ $output = '';
+ foreach ($trace as $idx => $line) {
+ $args = array();
+ foreach ($line['args'] as $arg) {
+ if (is_string($arg)) {
+ $arg = "'$arg'";
+ } elseif (is_object($arg)) {
+ $arg = 'instanceof ' . get_class($arg);
+ } elseif (is_array($arg)) {
+ $arg = 'Array(' . count($arg) . ')';
+ }
+ $args[] = $arg;
+ }
+ $frame = str_pad('#' . $idx, 3, ' ', STR_PAD_LEFT);
+ $args = implode(', ', $args);
+ // Add line
+ $output .= "\n" . $frame . ' ' . $line['function'] . '('
+ . $args . ')' . ' @ ' . $line['file'] . ':' . $line['line'];
+ }
+ return $output;
+ }
+
/**
* Redirects the user via a '302 Moved' header.
* An active session will be saved, any messages that haven't
diff --git a/modules-available/baseconfig/inc/baseconfigutil.inc.php b/modules-available/baseconfig/inc/baseconfigutil.inc.php
index ebaefbcf..75173ee6 100644
--- a/modules-available/baseconfig/inc/baseconfigutil.inc.php
+++ b/modules-available/baseconfig/inc/baseconfigutil.inc.php
@@ -47,4 +47,26 @@ class BaseConfigUtil
return $categories;
}
+ /**
+ * Mark variables that would be shadowed according to the given values.
+ *
+ * @param $vars list of vars as obtained from BaseConfigUtil::getVariables()
+ * @param $values key-value-pairs of variable assignments to work with
+ */
+ public static function markShadowedVars(&$vars, $values) {
+ foreach ($vars as $key => &$var) {
+ if (!isset($var['shadows']))
+ continue;
+ foreach ($var['shadows'] as $triggerVal => $destSettings) {
+ if (isset($values[$key]) && $values[$key] !== $triggerVal)
+ continue;
+ foreach ($destSettings as $destSetting) {
+ if (isset($vars[$destSetting])) {
+ $vars[$destSetting]['shadowed'] = true;
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/modules-available/baseconfig/page.inc.php b/modules-available/baseconfig/page.inc.php
index 0995a369..5e99f2a0 100644
--- a/modules-available/baseconfig/page.inc.php
+++ b/modules-available/baseconfig/page.inc.php
@@ -49,14 +49,16 @@ class Page_BaseConfig extends Page
Util::redirect('?do=BaseConfig');
}
}
- //echo "<pre>";
- //var_dump($_POST);
- //echo "</pre>";
// Honor override/enabled checkbox
$override = Request::post('override', array());
// Load all existing config options to validate input
$vars = BaseConfigUtil::getVariables();
+ // First, handle shadowing so we don't create warnings for empty fields
+ BaseConfigUtil::markShadowedVars($vars, $newValues);
+ // Validate input
foreach ($vars as $key => $var) {
+ if (isset($var['shadowed']))
+ continue;
if ($this->targetModule === false) {
// Global mode
$params['enabled'] = (is_array($override) && isset($override[$key]) && $override[$key] === 'on') ? 1 : 0;
@@ -103,7 +105,7 @@ class Page_BaseConfig extends Page
foreach ($this->categories as $catid => $val) {
Dashboard::addSubmenu(
'#category_' . $catid,
- Dictionary::translateFileModule($this->categories[$catid]['module'], 'config-variable-categories', $catid)
+ Dictionary::translateFileModule($this->categories[$catid]['module'], 'config-variable-categories', $catid, true)
);
}
}
@@ -180,12 +182,13 @@ class Page_BaseConfig extends Page
//echo "</pre>";
$settings[$var['catid']]['settings'][$key] += array(
'item' => $this->makeInput(
- $var['validator'],
- $key,
- $settings[$var['catid']]['settings'][$key]['displayvalue'],
- $settings[$var['catid']]['settings'][$key]['shadows']
- ),
- 'description' => Util::markup(Dictionary::translateFileModule($var['module'], 'config-variables', $key))
+ $var['validator'],
+ $key,
+ $settings[$var['catid']]['settings'][$key]['displayvalue'],
+ $settings[$var['catid']]['settings'][$key]['shadows']
+ ),
+ 'description' => Util::markup(Dictionary::translateFileModule($var['module'], 'config-variables', $key)),
+ 'setting' => $key,
);
}
//die();
@@ -264,10 +267,9 @@ class Page_BaseConfig extends Page
private function makeInput($validator, $setting, $current, $shadows)
{
/* for the html snippet we need: */
- $tag = 'input';
- $args = array('type' => 'text', 'class' => 'form-control', 'name' => "setting[$setting]", 'id' => $setting);
+ $args = array('class' => 'form-control', 'name' => "setting[$setting]", 'id' => $setting);
if (!empty($shadows)) {
- $args['data-shadows'] = $shadows;
+ $args['data-shadows'] = json_encode($shadows);
}
$inner = "";
/* -- */
@@ -308,17 +310,20 @@ class Page_BaseConfig extends Page
$tag = 'select';
unset($args['type']);
$current = '';
+ } else {
+ // Everything else is a text input for now
+ $tag = 'input';
+ $args['value'] = $current;
+ $args['type'] = 'text';
+ /* Password field guessing */
+ if (stripos($validator, 'password') !== false) {
+ $args['type'] = Property::getPasswordFieldType();
+ }
}
/* multiinput: enter multiple free-form strings*/
if ($validator === 'multiinput') {
$args['class'] .= " multiinput";
- $args['value'] = $current;
- }
-
- /* Password field guessing */
- if (stripos($validator, 'password') !== false) {
- $args['type'] = Property::getPasswordFieldType();
}
$output = "<$tag ";
diff --git a/modules-available/baseconfig/templates/_page.html b/modules-available/baseconfig/templates/_page.html
index 7bd5f6c9..11b8d8ee 100644
--- a/modules-available/baseconfig/templates/_page.html
+++ b/modules-available/baseconfig/templates/_page.html
@@ -70,27 +70,27 @@
<script type="text/javascript">
function updateShadows(e) {
- var shadowStr = $(e).data('shadows');
+ var rules = $(e).data('shadows');
+ if (!rules) return;
var currentValue = $(e).val();
- var rules = shadowStr.split(',');
- rules.forEach(function(rule) {
- var rule_parts = rule.split('->');
- var triggerVal = rule_parts[0].trim();
- var target = rule_parts[1].trim();
- var inp = $('#' + target);
- var selitem = inp.data('selitem');
-
- if (currentValue === triggerVal) {
- inp.prop('disabled', true);
- if (selitem) selitem.disable();
- $('#' + target + '.multilist').multiselect('disable');
- } else {
- inp.prop('disabled', false);
- if (selitem) selitem.enable();
- $('#' + target + '.multilist').multiselect('enable');
+ for (var triggerVal in rules) {
+ var targets = rules[triggerVal];
+ for (var i = 0; i < targets.length; ++i) {
+ var target = targets[i];
+ var inp = $('#' + target);
+ var selitem = inp.data('selitem');
+ if (currentValue === triggerVal) {
+ inp.prop('disabled', true);
+ if (selitem) selitem.disable();
+ $('#' + target + '.multilist').multiselect('disable');
+ } else {
+ inp.prop('disabled', false);
+ if (selitem) selitem.enable();
+ $('#' + target + '.multilist').multiselect('enable');
+ }
}
- });
+ }
}
diff --git a/modules-available/baseconfig_bwlp/baseconfig/settings.json b/modules-available/baseconfig_bwlp/baseconfig/settings.json
index 5b76eb3f..d5f893e3 100644
--- a/modules-available/baseconfig_bwlp/baseconfig/settings.json
+++ b/modules-available/baseconfig_bwlp/baseconfig/settings.json
@@ -46,7 +46,14 @@
"defaultvalue": "off",
"permissions": "2",
"validator": "list:off|on|auto",
- "shadows": "off -> SLX_PROXY_PORT, off -> SLX_PROXY_TYPE, off -> SLX_PROXY_IP, off -> SLX_PROXY_BLACKLIST"
+ "shadows": {
+ "off": [
+ "SLX_PROXY_PORT",
+ "SLX_PROXY_TYPE",
+ "SLX_PROXY_IP",
+ "SLX_PROXY_BLACKLIST"
+ ]
+ }
},
"SLX_PROXY_PORT": {
"catid": "networking",
diff --git a/modules-available/dozmod/api.inc.php b/modules-available/dozmod/api.inc.php
index dc9788fc..accfe813 100644
--- a/modules-available/dozmod/api.inc.php
+++ b/modules-available/dozmod/api.inc.php
@@ -99,18 +99,66 @@ function xmlToLectureIds($responseXML)
return $uuids;
}
+function sendExamModeMismatch()
+{
+ Header('Content-Type: text/xml; charset=utf-8');
+ echo
+ <<<BLA
+ <settings>
+ <eintrag>
+ <image_name param="null"/>
+ <priority param="100"/>
+ <creator param="Ernie Esslingen"/>
+ <short_description param="Klausurmodus geƤndert, bitte PC neustarten"/>
+ <long_description param="Der Klausurmodus wurde ein- oder ausgeschaltet, bitte starten Sie den PC neu"/>
+ <uuid param="exam-mode-warning"/>
+ <virtualmachine param="exam-mode-warning"/>
+ <os param="debian8"/>
+ <virtualizer_name param="null"/>
+ <os_name param="null"/>
+ <for_location param="0"/>
+ <is_template param="0"/>
+ </eintrag>
+ <eintrag>
+ <image_name param="null"/>
+ <priority param="200"/>
+ <creator param="Ernie Esslingen"/>
+ <short_description param="Exam mode changed, please reboot PC"/>
+ <long_description param="Exam mode has been activated or deactivated since this PC was booted; please reboot the PC"/>
+ <uuid param="exam-mode-warning"/>
+ <virtualmachine param="exam-mode-warning"/>
+ <os param="debian8"/>
+ <virtualizer_name param="null"/>
+ <os_name param="null"/>
+ <for_location param="0"/>
+ <is_template param="0"/>
+ </eintrag>
+ </settings>
+BLA;
+ exit(0);
+}
+
/** Caching wrapper around _getLecturesForLocations() */
function getListForLocations($locationIds, $raw)
{
/* if in any of the locations there is an exam active, consider the client
to be in "exam-mode" and only offer him exams (no lectures) */
$key = 'lectures_' . cache_hash($locationIds);
- $examMode = false;
+ $examMode = Request::get('exams', 'normal-mode', 'string') !== 'normal-mode';
+ $clientServerMismatch = false;
if (Module::isAvailable('exams')) {
- $examMode = Exams::isInExamMode($locationIds);
- if ($examMode) {
- $key .= '_exams';
- }
+ // If we have the exam mode module, we can enforce a server side check and make sure it agrees with the client
+ $serverExamMode = Exams::isInExamMode($locationIds);
+ $clientServerMismatch = ($serverExamMode !== $examMode);
+ $examMode = $serverExamMode;
+ }
+ // Only enforce exam mode validity check if the client requests the raw xml data
+ if ($raw && $clientServerMismatch) {
+ sendExamModeMismatch(); // does not return
+ }
+ // Proceed normally from here on
+ if ($examMode) {
+ $key .= '_exams';
}
$rawKey = $key . '_raw';
if ($raw) {
@@ -189,7 +237,7 @@ function outputNetrules($lecture_uuid)
function outputRunscript($lecture_uuid)
{
- $key = 'netrules_' . $lecture_uuid;
+ $key = 'runscript_' . $lecture_uuid;
if (cache_has($key)) {
cache_get_passthru($key);
} else {
diff --git a/modules-available/dozmod/inc/pagedozmodlog.inc.php b/modules-available/dozmod/inc/pagedozmodlog.inc.php
new file mode 100644
index 00000000..f31edf5b
--- /dev/null
+++ b/modules-available/dozmod/inc/pagedozmodlog.inc.php
@@ -0,0 +1,156 @@
+<?php
+
+class Page_dozmod_log extends Page
+{
+
+ private $action;
+ private $uuid;
+
+ protected function doPreprocess()
+ {
+ $this->action = Request::get('action', '', 'string');
+ if ($this->action !== '' && $this->action !== 'showtarget' && $this->action !== 'showuser') {
+ Util::traceError('Invalid action for actionlog: "' . $this->action . '"');
+ }
+ $this->uuid = Request::get('uuid', '', 'string');
+ }
+
+ protected function doRender()
+ {
+ Render::addTemplate('actionlog-header');
+ if ($this->action === '') {
+ $this->generateLog("SELECT al.dateline, al.targetid, al.description,"
+ . " img.displayname AS imgname, tu.firstname AS tfirstname, tu.lastname AS tlastname, l.displayname AS lecturename,"
+ . " al.userid AS uuserid, usr.firstname AS ufirstname, usr.lastname AS ulastname"
+ . " FROM sat.actionlog al"
+ . " LEFT JOIN sat.imagebase img ON (img.imagebaseid = targetid)"
+ . " LEFT JOIN sat.user usr ON (usr.userid = al.userid)"
+ . " LEFT JOIN sat.user tu ON (tu.userid = al.targetid)"
+ . " LEFT JOIN sat.lecture l ON (l.lectureid = targetid)"
+ . " ORDER BY al.dateline DESC LIMIT 500", array(), true, true);
+ } elseif ($this->action === 'showuser') {
+ $this->listUser();
+ } else {
+ $this->listTarget();
+ }
+ }
+
+ private function listUser()
+ {
+ // Query user
+ $user = Database::queryFirst('SELECT userid, firstname, lastname, email, lastlogin,'
+ . ' organization.displayname AS orgname FROM sat.user'
+ . ' LEFT JOIN sat.organization USING (organizationid)'
+ . ' WHERE userid = :uuid'
+ . ' LIMIT 1', array('uuid' => $this->uuid));
+ if ($user === false) {
+ Message:addError('unknown-userid', $this->uuid);
+ Util::redirect('?do=dozmod&section=actionlog');
+ }
+ // Mangle date and render
+ $user['lastlogin_s'] = date('d.m.Y H:i', $user['lastlogin']);
+ Render::addTemplate('actionlog-user', $user);
+ // Finally add the actionlog
+ $this->generateLog("SELECT al.dateline, al.targetid, al.description,"
+ . " img.displayname AS imgname, usr.firstname AS tfirstname, usr.lastname AS tlastname, l.displayname AS lecturename"
+ . " FROM sat.actionlog al"
+ . " LEFT JOIN sat.imagebase img ON (img.imagebaseid = targetid)"
+ . " LEFT JOIN sat.user usr ON (usr.userid = targetid)"
+ . " LEFT JOIN sat.lecture l ON (l.lectureid = targetid)"
+ . " WHERE al.userid = :uuid"
+ . " ORDER BY al.dateline DESC LIMIT 500", array('uuid' => $this->uuid), false, true);
+ }
+
+ private function listTarget()
+ {
+ // We have to guess what kind of target it is
+ if (!$this->addImageHeader()
+ && !$this->addLectureHeader()) {
+ Message:addError('unknown-targetid', $this->uuid);
+ // Keep going, there might still be log entries for a deleted uuid
+ }
+
+ // Finally add the actionlog
+ $this->generateLog("SELECT al.dateline, al.userid AS uuserid, al.description,"
+ . " usr.firstname AS ufirstname, usr.lastname AS ulastname"
+ . " FROM sat.actionlog al"
+ . " LEFT JOIN sat.user usr ON (usr.userid = al.userid)"
+ . " WHERE al.targetid = :uuid"
+ . " ORDER BY al.dateline DESC LIMIT 500", array('uuid' => $this->uuid), true, false);
+ }
+
+ private function addImageHeader()
+ {
+ $image = Database::queryFirst('SELECT o.userid AS ouserid, o.firstname AS ofirstname, o.lastname AS olastname,'
+ . ' u.userid AS uuserid, u.firstname AS ufirstname, u.lastname AS ulastname,'
+ . ' img.displayname, img.description, img.createtime, img.updatetime,'
+ . ' os.displayname AS osname'
+ . ' FROM sat.imagebase img'
+ . ' LEFT JOIN sat.user o ON (img.ownerid = o.userid)'
+ . ' LEFT JOIN sat.user u ON (img.updaterid = u.userid)'
+ . ' LEFT JOIN sat.operatingsystem os ON (img.osid = os.osid)'
+ . ' WHERE img.imagebaseid = :uuid'
+ . ' LIMIT 1', array('uuid' => $this->uuid));
+ if ($image !== false) {
+ // Mangle date and render
+ $image['createtime_s'] = date('d.m.Y H:i', $image['createtime']);
+ $image['updatetime_s'] = date('d.m.Y H:i', $image['updatetime']);
+ $image['descriptionHtml'] = nl2br(htmlspecialchars($image['description']));
+ Render::addTemplate('actionlog-image', $image);
+ }
+ return $image !== false;
+ }
+
+ private function addLectureHeader()
+ {
+ $lecture = Database::queryFirst('SELECT o.userid AS ouserid, o.firstname AS ofirstname, o.lastname AS olastname,'
+ . ' u.userid AS uuserid, u.firstname AS ufirstname, u.lastname AS ulastname,'
+ . ' l.displayname, l.description, l.createtime, l.updatetime,'
+ . ' img.displayname AS imgname, img.imagebaseid'
+ . ' FROM sat.lecture l'
+ . ' LEFT JOIN sat.user o ON (l.ownerid = o.userid)'
+ . ' LEFT JOIN sat.user u ON (l.updaterid = u.userid)'
+ . ' LEFT JOIN sat.imageversion ver ON (ver.imageversionid = l.imageversionid)'
+ . ' LEFT JOIN sat.imagebase img ON (img.imagebaseid = ver.imagebaseid)'
+ . ' WHERE l.lectureid = :uuid'
+ . ' LIMIT 1', array('uuid' => $this->uuid));
+ if ($lecture !== false) {
+ // Mangle date and render
+ $lecture['createtime_s'] = date('d.m.Y H:i', $lecture['createtime']);
+ $lecture['updatetime_s'] = date('d.m.Y H:i', $lecture['updatetime']);
+ $lecture['descriptionHtml'] = nl2br(htmlspecialchars($lecture['description']));
+ Render::addTemplate('actionlog-lecture', $lecture);
+ }
+ return $lecture !== false;
+ }
+
+ private function generateLog($query, $params, $showActor, $showTarget)
+ {
+ // query action log
+ $res = Database::simpleQuery($query, $params);
+ $events = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['dateline_s'] = date('d.m.Y H:i', $row['dateline']);
+ if (isset($row['imgname'])) {
+ $row['targeturl'] = '?do=dozmod&section=actionlog&action=showtarget&uuid=' . $row['targetid'];
+ $row['targetname'] = $row['imgname'];
+ } elseif (isset($row['tlastname'])) {
+ $row['targeturl'] = '?do=dozmod&section=actionlog&action=showuser&uuid=' . $row['targetid'];
+ $row['targetname'] = $row['tlastname'] . ', ' . $row['tfirstname'];
+ } elseif (isset($row['lecturename'])) {
+ $row['targeturl'] = '?do=dozmod&section=actionlog&action=showtarget&uuid=' . $row['targetid'];
+ $row['targetname'] = $row['lecturename'];
+ }
+ $events[] = $row;
+ }
+ $data = array('events' => $events);
+ if ($showActor) {
+ $data['showActor'] = true;
+ }
+ if ($showTarget) {
+ $data['showTarget'] = true;
+ }
+ Render::addTemplate('actionlog-log', $data);
+ }
+
+} \ No newline at end of file
diff --git a/modules-available/dozmod/inc/pagedozmodusers.inc.php b/modules-available/dozmod/inc/pagedozmodusers.inc.php
new file mode 100644
index 00000000..8da07923
--- /dev/null
+++ b/modules-available/dozmod/inc/pagedozmodusers.inc.php
@@ -0,0 +1,115 @@
+<?php
+
+class Page_dozmod_users extends Page
+{
+
+ protected function doPreprocess()
+ {
+
+ }
+
+ protected function doRender()
+ {
+ $this->listUsers();
+ $this->listOrganizations();
+ }
+
+ protected function doAjax()
+ {
+ $action = Request::post('action', '', 'string');
+ if ($action === 'setmail' || $action === 'setsu' || $action == 'setlogin') {
+ $this->setUserOption($action);
+ } elseif ($action === 'setorglogin') {
+ $this->setOrgOption($action);
+ } else {
+ die('No such action');
+ }
+ }
+
+ // Helpers
+
+ private function listUsers()
+ {
+ $res = Database::simpleQuery('SELECT userid, firstname, lastname, email, lastlogin, user.canlogin, issuperuser, emailnotifications,'
+ . ' organization.displayname AS orgname FROM sat.user'
+ . ' LEFT JOIN sat.organization USING (organizationid)'
+ . ' ORDER BY lastname ASC, firstname ASC');
+ $rows = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['canlogin'] = $this->checked($row['canlogin']);
+ $row['issuperuser'] = $this->checked($row['issuperuser']);
+ $row['emailnotifications'] = $this->checked($row['emailnotifications']);
+ $row['lastlogin'] = date('d.m.Y', $row['lastlogin']);
+ $rows[] = $row;
+ }
+ Render::addTemplate('userlist', array('users' => $rows));
+ }
+
+ private function listOrganizations()
+ {
+ $res = Database::simpleQuery('SELECT organizationid, displayname, canlogin FROM sat.organization'
+ . ' ORDER BY displayname ASC');
+ $rows = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['canlogin'] = $this->checked($row['canlogin']);
+ $rows[] = $row;
+ }
+ Render::addTemplate('orglist', array('organizations' => $rows));
+ }
+
+ private function checked($val)
+ {
+ if ($val)
+ return 'checked="checked"';
+ return '';
+ }
+
+ private function setUserOption($option)
+ {
+ $val = (string) Request::post('value', '-');
+ if ($val !== '1' && $val !== '0')
+ die('Nein');
+ if ($option === 'setmail') {
+ $field = 'emailnotifications';
+ } elseif ($option === 'setsu') {
+ $field = 'issuperuser';
+ } elseif ($option === 'setlogin') {
+ $field = 'canlogin';
+ } else {
+ die('Unknown');
+ }
+ $user = (string) Request::post('userid', '?');
+ $ret = Database::exec("UPDATE sat.user SET $field = :onoff WHERE userid = :userid", array(
+ 'userid' => $user,
+ 'onoff' => $val
+ ));
+ error_log("Setting $field to $val for $user - affected: $ret");
+ if ($ret === false)
+ die('Error');
+ if ($ret === 0)
+ die(1 - $val);
+ die($val);
+ }
+
+ private function setOrgOption($option)
+ {
+ $val = (string) Request::post('value', '-');
+ if ($val !== '1' && $val !== '0')
+ die('Nein');
+ if ($option === 'setorglogin') {
+ $field = 'canlogin';
+ } else {
+ die('Unknown');
+ }
+ $ret = Database::exec("UPDATE sat.organization SET $field = :onoff WHERE organizationid = :organizationid", array(
+ 'organizationid' => (string) Request::post('organizationid', ''),
+ 'onoff' => $val
+ ));
+ if ($ret === false)
+ die('Error');
+ if ($ret === 0)
+ die(1 - $val);
+ die($val);
+ }
+
+} \ No newline at end of file
diff --git a/modules-available/dozmod/inc/pagemailtemplates.inc.php b/modules-available/dozmod/inc/pagemailtemplates.inc.php
index fedb13c8..ef52ec12 100644
--- a/modules-available/dozmod/inc/pagemailtemplates.inc.php
+++ b/modules-available/dozmod/inc/pagemailtemplates.inc.php
@@ -7,19 +7,16 @@ class Page_mail_templates extends Page
protected function doPreprocess()
{
- User::load();
-
- if (!User::hasPermission('superadmin')) {
- Message::addError('main.no-permission');
- Util::redirect('?do=Main');
- }
-
- $action = Request::get('action', 'show', 'string');
-
+ $action = Request::post('action', 'show', 'string');
if ($action === 'show') {
$this->fetchTemplates();
} elseif ($action === 'save') {
$this->handleSave();
+ } elseif ($action === 'reset') {
+ $this->handleReset();
+ } else {
+ Message::addError('main.invalid-action', $action);
+ Util::redirect('?do=dozmod&section=templates');
}
}
@@ -54,32 +51,41 @@ class Page_mail_templates extends Page
}
protected function doRender()
{
- //echo '<pre>';
- //var_dump($this->templates);
- //echo '</pre>';
- //die();
$this->enrichHtml();
Render::addTemplate('templates', ['templates' => $this->templates]);
}
private function handleSave() {
- $data = [];
- $data['templates'] = Request::post('templates');
- $data = $this->cleanTemplateArray($data);
- if ($data!= NULL) {
- $data = json_encode($data, JSON_PRETTY_PRINT);
- //echo '<pre>';
- //print_r($data);
- //echo '</pre>';
- //die();
+ $data = Request::post('templates');
+ if (is_array($data)) {
+ $this->fetchTemplates();
+ foreach ($this->templates as &$template) {
+ if (isset($data[$template['name']])) {
+ $template['template'] = $data[$template['name']]['template'];
+ }
+ }
+ unset($template);
+ $data = json_encode(array('templates' => $this->templates));
Database::exec("UPDATE sat.configuration SET value = :value WHERE parameter = 'templates'", array('value' => $data));
Message::addSuccess('templates-saved');
- Util::redirect('?do=dozmod&section=templates&action=show');
} else {
- die('error while encoding');
+ Message::addError('nothing-submitted');
}
+ Util::redirect('?do=dozmod&section=templates');
+ }
+ private function handleReset()
+ {
+ $result = Download::asStringPost('http://127.0.0.1:9080/do/reset-mail-templates', array(), 10, $code);
+ if ($code == 999) {
+ Message::addError('timeout');
+ } elseif ($code != 200) {
+ Message::addError('dozmod-error', $code);
+ } else {
+ Message::addSuccess('all-templates-reset', $result);
+ }
+ Util::redirect('?do=dozmod&section=templates');
}
private function fetchTemplates() {
@@ -87,33 +93,12 @@ class Page_mail_templates extends Page
if ($templates != null) {
$templates = @json_decode($templates['value'], true);
if (is_array($templates)) {
+ $names = array_map(function ($e) { return $e['name']; }, $templates['templates']);
+ array_multisort($names, SORT_ASC, $templates['templates']);
$this->templates = $templates['templates'];
}
}
}
- private function cleanTemplateArray($in) {
- $out = [];
- foreach ($in['templates'] as $t) {
- $tcopy = $t;
- $tcopy['mandatory_variables'] = $this->toArray($t['mandatory_variables']);
- $tcopy['optional_variables'] = $this->toArray($t['optional_variables']);
- $tcopy['description'] = $t['description'];
- $tcopy['name'] = $t['name'];
-
- $out['templates'][] = $tcopy;
- }
- return $out;
- }
-
- private function toArray($value) {
- if (empty($value)) {
- return [];
- } else if(is_array($value)) {
- return $value;
- } else {
- return array($value);
- }
- }
}
diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json
index 7944ffae..e72fb1be 100644
--- a/modules-available/dozmod/lang/de/messages.json
+++ b/modules-available/dozmod/lang/de/messages.json
@@ -1,5 +1,11 @@
{
+ "all-templates-reset": "Alle Templates wurden zur\u00fcckgesetzt",
"delete-images": "L\u00f6schung: {{0}}",
+ "dozmod-error": "Fehler bei der Kommunikation mit dem bwLehrpool-Suite server: {{0}}",
"images-pending-delete-exist": "Zur L\u00f6schung markierte Abbilder: {{0}}",
- "mail-config-saved": "Mail-Konfiguration gespeichert"
+ "mail-config-saved": "Mail-Konfiguration gespeichert",
+ "nothing-submitted": "Es wurde nichts \u00fcbermittelt",
+ "runtimelimits-config-saved": "Einstellungen gespeichert",
+ "templates-saved": "Templates wurden gespeichert",
+ "timeout": "Zeit\u00fcberschreitung"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/de/module.json b/modules-available/dozmod/lang/de/module.json
index df2b5d4b..5840d8af 100644
--- a/modules-available/dozmod/lang/de/module.json
+++ b/modules-available/dozmod/lang/de/module.json
@@ -1,8 +1,9 @@
{
- "module_name": "Dozentenmodul",
- "page_title": "Verwalten des Dozentenmoduls",
+ "module_name": "bwLehrpool-Suite",
+ "page_title": "Verwalten der bwLehrpool-Suite",
+ "submenu_actionlog": "Aktions-Log",
"submenu_mailconfig": "Email-Konfiguration",
- "submenu_runtime": "Laufzeit",
- "submenu_templates": "Vorlagen E-Mail",
- "submenu_users": "Benutzer"
+ "submenu_runtime": "Limits und Standardwerte",
+ "submenu_templates": "Textbausteine f\u00fcr E-Mails",
+ "submenu_users": "Benutzer und Berechtigungen"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/de/template-tags.json b/modules-available/dozmod/lang/de/template-tags.json
index f123db5b..fe558ed5 100644
--- a/modules-available/dozmod/lang/de/template-tags.json
+++ b/modules-available/dozmod/lang/de/template-tags.json
@@ -1,37 +1,54 @@
{
+ "lang_actionTarget": "Aktionsziel",
"lang_asteriskRequired": "Felder mit (*) sind erforderlich",
"lang_canLogin": "Nutzer dieser Einrichtung k\u00f6nnen sich am Satelliten anmelden",
- "lang_defaultImagePermissionAdmin": "Administration",
+ "lang_createTime": "Erstellt",
+ "lang_currentFilter": "Aktueller Filter",
+ "lang_defaultImagePermissionAdmin": "Administrieren",
"lang_defaultImagePermissionDownload": "Download",
"lang_defaultImagePermissionEdit": "Bearbeiten",
- "lang_defaultImagePermissionLink": "Verkn\u00fcpfen",
- "lang_defaultImagePermissions": "Standard-Berechtigungen f\u00fcr Images",
- "lang_defaultLecturePermissions": "Standard-Berechtigungen f\u00fcr Vorlesungen",
- "lang_delButton": "Gew\u00e4hlte Images endg\u00fcltig l\u00f6schen",
+ "lang_defaultImagePermissionLink": "Veranstaltung Verkn\u00fcpfen",
+ "lang_defaultImagePermissions": "F\u00fcr VMs",
+ "lang_defaultLecturePermissions": "F\u00fcr Veranstaltungen",
+ "lang_defaultPermissions": "Standardberechtigungen",
+ "lang_delButton": "Gew\u00e4hlte VMs endg\u00fcltig l\u00f6schen",
"lang_description": "Beschreibung",
- "lang_descriptionRuntimeConfig": "Blah blah blah",
- "lang_description_delete_images": "Diese Liste zeigt Images, die entweder abgelaufen sind, oder deren Datei besch\u00e4digt, verschoben oder gel\u00f6scht wurde. Diese Images sind zur Zeit im Lehrpool nicht verf\u00fcgbar, ihre endg\u00fcltige L\u00f6schung muss aber manuell best\u00e4tigt werden, um gr\u00f6\u00dfere Katastrophen durch Softwarefehler, verstellte Systemuhren etc. zu vermeiden.",
+ "lang_descriptionPermissionConfig": "Dies sind die Berechtigungen, die ein Benutzer standardm\u00e4\u00dfig f\u00fcr fremde VMs\/Veranstaltungen hat. Sie werden angewandt, wenn der Besitzer keine anderweitigen Berechtigungen w\u00e4hlt.",
+ "lang_descriptionRuntimeLimits": "Hier k\u00f6nnen Sie verschiedene Limits festlegen, z.B. wie lange eine VM nach dem Hochladen g\u00fcltig ist. Nach Ablauf dieses Zeitraums ist der Verantwortliche gezwungen, eine neue Version der VM hochzuladen. Damit k\u00f6nnen Sie das Ansammeln nicht mehr ben\u00f6tigter VMs eind\u00e4mmen. Weiterhin k\u00f6nnen Sie die maximale Anzahl gleichzeitiger Transfers pro Benutzer einschr\u00e4nken.",
+ "lang_description_delete_images": "Diese Liste zeigt VMs, die entweder abgelaufen sind, oder deren Datei besch\u00e4digt, verschoben oder gel\u00f6scht wurde. Diese Images sind zur Zeit im Lehrpool nicht verf\u00fcgbar, ihre endg\u00fcltige L\u00f6schung muss aber manuell best\u00e4tigt werden, um gr\u00f6\u00dfere Katastrophen durch Softwarefehler, verstellte Systemuhren etc. zu vermeiden.",
+ "lang_dozmodLogHeading": "bwLehrpool-Suite Aktionslog",
"lang_email": "EMail",
"lang_emailNotifications": "EMail-Benachrichtigungen aktiviert",
+ "lang_error": "Fehler",
+ "lang_event": "Ereignis",
+ "lang_followingPlaceholdersUnused": "Folgende Platzhalter m\u00fcssen im Template verwendet werden",
"lang_hasNewer": "Neuere Version existiert",
- "lang_heading": "Zu l\u00f6schende Image-Versionen",
+ "lang_heading": "Zu l\u00f6schende VM-Versionen",
"lang_host": "Host",
"lang_image": "VM",
+ "lang_lastEditor": "Zuletzt bearbeitet von",
"lang_lastLogin": "Letzte Anmeldung",
+ "lang_lecture": "Veranstaltung",
"lang_lecturePermissionAdmin": "Administration",
"lang_lecturePermissionEdit": "Bearbeiten",
+ "lang_loadDefaults": "Alle Texte auf Auslieferungszustand zur\u00fccksetzen",
"lang_mailConfig": "SMTP-Konfiguration zum Versenden von Mails",
"lang_mailConfigHeadline": "EMail-Konfiguration",
"lang_mailDescription": "F\u00fcllen Sie die folgenden Felder aus, wenn sie m\u00f6chten, dass Dozenten Benachrichtigungen per Mail bekommen, falls eine von ihnen genutzte oder erstellte VM oder Veranstaltung abl\u00e4uft. Um diese Funktion zu deaktivieren, lassen Sie eines der mit (*) gekennzeichneten Felder leer. Wenn das hier angegebene E-Mail-Konto nur zum Versenden von Mails genutzt wird, sollten Sie einen Auto-Responder einrichten f\u00fcr den Fall, dass ein Dozent auf eine der automatisch generierten Mails antwortet (bzw. eine explizit angegebene Reply-To Adresse ignoriert).",
- "lang_maxImageValidity": "Maximale G\u00fcltigkeit",
- "lang_maxLectureVisibility": "Maximale Sichtbarkeit",
- "lang_maxTransfers": "Maximale Anzahl an Uploads",
+ "lang_mailTemplates": "E-Mail Templates",
+ "lang_maxImageValidity": "G\u00fcltigkeitsdauer neuer VM-Versionen (Tage)",
+ "lang_maxLectureVisibility": "Sp\u00e4testes Enddatum einer Veranstaltung (Tage in der Zukunft)",
+ "lang_maxTransfers": "Maximale Zahl gleichzeitiger Up-\/Downloads pro Benutzer",
+ "lang_name": "Name",
"lang_organization": "Einrichtung",
"lang_organizationList": "Liste der Einrichtungen",
"lang_organizationListHeader": "Nutzungsrechte f\u00fcr den Satelliten festlegen",
+ "lang_os": "Betriebssystem",
"lang_owner": "Besitzer",
"lang_password": "Passwort",
+ "lang_placeholders": "Platzhalter",
"lang_port": "Port",
+ "lang_reallyResetTemplates": "Sind Sie sicher, dass Sie alle Texte l\u00f6schen und auf die Standardwerte zur\u00fccksetzen wollen?",
"lang_replyTo": "Reply-To Adresse (z.B. Helpdesk)",
"lang_runtimeConfig": "Laufzeit-Konfiguration",
"lang_runtimeConfigHeadline": "Laufzeit-Konfiguration",
@@ -45,13 +62,19 @@
"lang_sslNone": "Kein SSL",
"lang_subHeading": "Images, die abgelaufen oder besch\u00e4digt sind",
"lang_superUser": "Ist SuperUser (darf alle Veranstaltungen und VMs bearbeiten\/l\u00f6schen)",
+ "lang_system": "System",
+ "lang_template": "Template",
+ "lang_templatePageDescription": "Hier k\u00f6nnen Sie die Textbausteine bearbeiten, aus denen die Mails generiert werden, die der bwLehrpool-Server bez\u00fcglich Virtueller Maschinen und Veranstaltungen versendet. Diese Funktionalit\u00e4t unterst\u00fctzt zur Zeit keine Internationalisierung.",
"lang_test": "Test-Mail senden",
"lang_testConfiguration": "Um die Konfiguration zu testen, geben Sie hier eine Empf\u00e4ngeradresse ein",
"lang_testRecipient": "Empf\u00e4nger",
+ "lang_updateTime": "Letzte Bearbeitung",
"lang_user": "Benutzername",
+ "lang_userId": "Benutzer-ID",
"lang_userList": "Benutzerliste",
"lang_userListDescription": "Hier k\u00f6nnen Sie individuelle Nutzer zu \"Super-Usern\" machen. Diese haben im Dozentenmodul auf alle Veranstaltungen und VMs Vollzugriff, unabh\u00e4ngig von den gesetzten Berechtigungen. Au\u00dferdem k\u00f6nnen Sie hier Benutzer vom Zugriff mittels des Dozentenmoduls ausschlie\u00dfen.",
"lang_userListHeader": "Dem Satelliten bekannte Benutzer",
"lang_username": "Benutzername (SMTP-Auth)",
- "lang_version": "Version vom"
+ "lang_version": "Version vom",
+ "lang_when": "Wann"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/en/messages.json b/modules-available/dozmod/lang/en/messages.json
index 6651e32e..e1b5eea6 100644
--- a/modules-available/dozmod/lang/en/messages.json
+++ b/modules-available/dozmod/lang/en/messages.json
@@ -1,5 +1,11 @@
{
+ "all-templates-reset": "All templates have been reset",
"delete-images": "Delete: {{0}}",
+ "dozmod-error": "Error communicating with the bwLehrpool-Suite server: {{0}}",
"images-pending-delete-exist": "Images marked for deletion: {{0}}",
- "mail-config-saved": "Mail config saved"
+ "mail-config-saved": "Mail config saved",
+ "nothing-submitted": "There was nothing submitted",
+ "runtimelimits-config-saved": "Configuration saved successfully",
+ "templates-saved": "Templates saved successfully",
+ "timeout": "Timeout"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/en/module.json b/modules-available/dozmod/lang/en/module.json
index e42d21ea..742aa848 100644
--- a/modules-available/dozmod/lang/en/module.json
+++ b/modules-available/dozmod/lang/en/module.json
@@ -1,3 +1,9 @@
{
- "module_name": "Tutor Module"
+ "module_name": "bwLehrpool-Suite",
+ "page_title": "Manage the bwLehrpool-Suite",
+ "submenu_actionlog": "action log",
+ "submenu_mailconfig": "email configuration",
+ "submenu_runtime": "limits and defaults",
+ "submenu_templates": "templates",
+ "submenu_users": "users and permissions"
} \ No newline at end of file
diff --git a/modules-available/dozmod/lang/en/template-tags.json b/modules-available/dozmod/lang/en/template-tags.json
index 2ed11a2a..6a0434a3 100644
--- a/modules-available/dozmod/lang/en/template-tags.json
+++ b/modules-available/dozmod/lang/en/template-tags.json
@@ -1,25 +1,58 @@
{
+ "lang_actionTarget": "Action target",
"lang_asteriskRequired": "Fields marked with (*) are required",
"lang_canLogin": "Members of this organization can login",
+ "lang_createTime": "Created",
+ "lang_currentFilter": "Current filter",
+ "lang_defaultImagePermissionAdmin": "Administrate",
+ "lang_defaultImagePermissionDownload": "Download",
+ "lang_defaultImagePermissionEdit": "Edit",
+ "lang_defaultImagePermissionLink": "Link lecture",
+ "lang_defaultImagePermissions": "For VMs",
+ "lang_defaultLecturePermissions": "For lectures",
+ "lang_defaultPermissions": "Default permissions",
"lang_delButton": "Permanently delete selected images",
"lang_description": "This list shows images that reached their expire date, or where the image file in the file system is damaged or missing. You need to manually confirm the deletion of these files for safety reasons (software bugs, wrong system time, etc.).",
+ "lang_descriptionPermissionConfig": "These are the default permissions being used for VMs and lectures if the owner does not specify any.",
+ "lang_descriptionRuntimeLimits": "Here you can define some limits, e.g. how long a newly uploaded VM will be valid. This should make sure that you don't end up with a lot of old, unused VMs over time.",
+ "lang_description_delete_images": "This is a list of VMs that either expired, or where the disk image is damaged or missing. These VMs are not available in bwLehrpool currently, but you have to manually confirm the deletion of the disk images for safety reasons (clock skew etc.)",
+ "lang_dozmodLogHeading": "bwLehrpool-Suite action log",
"lang_email": "E-Mail",
"lang_emailNotifications": "E-Mail notifications enabled",
+ "lang_error": "Error",
+ "lang_event": "Event",
+ "lang_followingPlaceholdersUnused": "The following placeholders are not being used",
"lang_hasNewer": "Newer version exists",
"lang_heading": "Images marked for deletion",
"lang_host": "Host",
"lang_image": "VM",
+ "lang_lastEditor": "Edited by",
"lang_lastLogin": "Last login",
+ "lang_lecture": "Lecture",
+ "lang_lecturePermissionAdmin": "Administrate",
+ "lang_lecturePermissionEdit": "Edit",
+ "lang_loadDefaults": "Reset all templates to their defaults",
"lang_mailConfig": "SMTP configuration for sending mails",
"lang_mailConfigHeadline": "email configuration",
"lang_mailDescription": "Fill in the following fields if you want to notify tutors\/professors\/lecturers about expiring VMs and lectures. If you leave one of the required fields blank, the feature will be disabled.",
+ "lang_mailTemplates": "E-Mail templates",
+ "lang_maxImageValidity": "New VM validity (days)",
+ "lang_maxLectureVisibility": "Max time lecture end date may lie in the future (days)",
+ "lang_maxTransfers": "Max concurrent transfers per user",
+ "lang_name": "Name",
"lang_organization": "Organization",
"lang_organizationList": "List of organizations",
"lang_organizationListHeader": "Set access permissions for organizations",
+ "lang_os": "Operating System",
"lang_owner": "Owner",
"lang_password": "Password",
+ "lang_placeholders": "Placeholders",
"lang_port": "Port",
+ "lang_reallyResetTemplates": "Are you sure you want to reset all texts to their default values?",
"lang_replyTo": "Reply-To address",
+ "lang_runtimeConfig": "Limits and Defaults",
+ "lang_runtimeConfigHeadline": "Configure limits and defaults for bwLehrpool-Suite",
+ "lang_runtimeConfigLimits": "Limitations",
"lang_senderAddress": "Sender address",
"lang_senderName": "Sender's display name",
"lang_size": "Size",
@@ -29,13 +62,19 @@
"lang_sslNone": "No SSL",
"lang_subHeading": "Expired or damaged images",
"lang_superUser": "Is super user (can edit\/delete all lectures and VMs)",
+ "lang_system": "System",
+ "lang_template": "Template",
+ "lang_templatePageDescription": "Here you can edit text fragments that are used to compose the information and reminder mails sent by the bwLehrpool server, e.g. when a lecture or VM is about to expire.",
"lang_test": "Send test mail",
"lang_testConfiguration": "To test the configuration, enter a recipient address here",
"lang_testRecipient": "Recipient",
+ "lang_updateTime": "Last update",
"lang_user": "User name",
+ "lang_userId": "User id",
"lang_userList": "User list",
"lang_userListDescription": "Here you can promote \"super users\", which will have all permissions in the \"Dozenzenmodul\". You can also ban users from accessing this server via the \"Dozentenmodul\".",
"lang_userListHeader": "Users known to this satellite",
"lang_username": "User name (SMTP auth)",
- "lang_version": "Version timestamp"
+ "lang_version": "Version timestamp",
+ "lang_when": "When"
} \ No newline at end of file
diff --git a/modules-available/dozmod/page.inc.php b/modules-available/dozmod/page.inc.php
index c1c19b15..dfb49e0b 100644
--- a/modules-available/dozmod/page.inc.php
+++ b/modules-available/dozmod/page.inc.php
@@ -2,8 +2,26 @@
class Page_DozMod extends Page
{
- /* sub page classes */
- private $mail_templates;
+ /** @var \Page sub page classes */
+ private $subPage = false;
+
+ private function setupSubPage()
+ {
+ if ($this->subPage !== false)
+ return;
+ /* different pages for different sections */
+ $section = Request::any('section', 'mailconfig', 'string');
+ /* instantiate sub pages */
+ if ($section === 'templates') {
+ $this->subPage = new Page_mail_templates();
+ }
+ if ($section === 'users') {
+ $this->subPage = new Page_dozmod_users();
+ }
+ if ($section === 'actionlog') {
+ $this->subPage = new Page_dozmod_log();
+ }
+ }
protected function doPreprocess()
{
@@ -15,20 +33,15 @@ class Page_DozMod extends Page
}
/* add sub-menus */
- Dashboard::addSubmenu('?do=dozmod&section=mailconfig', Dictionary::translate('submenu_mailconfig'));
- Dashboard::addSubmenu('?do=dozmod&section=templates', Dictionary::translate('submenu_templates'));
- Dashboard::addSubmenu('?do=dozmod&section=runtimeconfig', Dictionary::translate('submenu_runtime'));
- Dashboard::addSubmenu('?do=dozmod&section=users', Dictionary::translate('submenu_users'));
-
- /* instantiate sub pages */
- $this->mail_templates = new Page_mail_templates();
-
-
-
- /* different pages for different sections */
- $section = Request::get('section', 'mailconfig', 'string');
- if ($section == 'templates') {
- $this->mail_templates->doPreprocess();
+ Dashboard::addSubmenu('?do=dozmod&section=mailconfig', Dictionary::translate('submenu_mailconfig', true));
+ Dashboard::addSubmenu('?do=dozmod&section=templates', Dictionary::translate('submenu_templates', true));
+ Dashboard::addSubmenu('?do=dozmod&section=runtimeconfig', Dictionary::translate('submenu_runtime', true));
+ Dashboard::addSubmenu('?do=dozmod&section=users', Dictionary::translate('submenu_users', true));
+ Dashboard::addSubmenu('?do=dozmod&section=actionlog', Dictionary::translate('submenu_actionlog', true));
+
+ $this->setupSubPage();
+ if ($this->subPage !== false) {
+ $this->subPage->doPreprocess();
return;
}
@@ -52,15 +65,15 @@ class Page_DozMod extends Page
protected function doRender()
{
+ $this->listDeletePendingImages();
+
/* different pages for different sections */
- $section = Request::get('section', 'mailconfig', 'string');
- if ($section == 'templates') {
- $this->mail_templates->doRender();
+ if ($this->subPage !== false) {
+ $this->subPage->doRender();
return;
}
-
- $this->listDeletePendingImages();
+ $section = Request::get('section', 'mailconfig', 'string');
if ($section === 'mailconfig') {
// Mail config
@@ -102,12 +115,23 @@ class Page_DozMod extends Page
}
Render::addTemplate('runtimeconfig', $runtimeConf);
}
+ if ($section === 'blockstats') {
+ $this->showBlockStats();
+ }
- // User list for making people admin
- if ($section === 'users') {
- $this->listUsers();
- $this->listOrganizations();
+ }
+
+ private function showBlockStats()
+ {
+ $res = Database::simpleQuery("SELECT blocksha1, blocksize, Count(*) AS blockcount FROM sat.imageblock"
+ . " GROUP BY blocksha1, blocksize HAVING blockcount > 1 ORDER BY blockcount DESC, blocksha1 ASC");
+ $data = array('hashes' => array());
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['hash_hex'] = bin2hex($row['blocksha1']);
+ $row['blocksize_s'] = Util::readableFileSize($row['blocksize']);
+ $data['hashes'][] = $row;
}
+ Render::addTemplate('blockstats', $data);
}
private function listDeletePendingImages()
@@ -159,21 +183,55 @@ class Page_DozMod extends Page
protected function doAjax()
{
+ User::load();
if (!User::hasPermission('superadmin'))
return;
+ $this->setupSubPage();
+ if ($this->subPage !== false) {
+ $this->subPage->doAjax();
+ return;
+ }
+
$action = Request::post('action');
if ($action === 'mail') {
$this->handleTestMail();
- } elseif ($action === 'setmail' || $action === 'setsu' || $action == 'setlogin') {
- $this->setUserOption($action);
- } elseif ($action === 'setorglogin') {
- $this->setOrgOption($action);
} elseif ($action === 'delimages') {
die($this->handleDeleteImages());
+ } elseif ($action === 'getblockinfo') {
+ $this->ajaxGetBlockInfo();
}
}
+ private function ajaxGetBlockInfo()
+ {
+ $hash = Request::any('hash', false, 'string');
+ $size = Request::any('size', false, 'string');
+ if ($hash === false || $size === false) {
+ die('Missing parameter');
+ }
+ if (!is_numeric($size) || strlen($hash) !== 40 || !preg_match('/^[a-f0-9]+$/i', $hash)) {
+ die('Malformed parameter');
+ }
+ $res = Database::simpleQuery("SELECT i.displayname, v.createtime, v.filesize, Count(*) AS blockcount FROM sat.imageblock ib"
+ . " INNER JOIN sat.imageversion v USING (imageversionid)"
+ . " INNER JOIN sat.imagebase i USING (imagebaseid)"
+ . " WHERE ib.blocksha1 = :hash AND ib.blocksize = :size"
+ . " GROUP BY ib.imageversionid"
+ . " ORDER BY i.displayname ASC, v.createtime ASC",
+ array('hash' => hex2bin($hash), 'size' => $size), true);
+ if ($res === false) {
+ die('Database error: ' . Database::lastError());
+ }
+ $data = array('rows' => array());
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['createtime_s'] = date('d.m.Y H:i', $row['createtime']);
+ $row['filesize_s'] = Util::readableFileSize($row['filesize']);
+ $data['rows'][] = $row;
+ }
+ die(Render::parse('blockstats-details', $data));
+ }
+
private function handleDeleteImages()
{
$images = Request::post('images', false);
@@ -234,6 +292,8 @@ class Page_DozMod extends Page
'value' => $data
));
Message::addSuccess('mail-config-saved');
+ } else {
+ Message::addError('main.invalid-action', $do);
}
Util::redirect('?do=DozMod&section=mailconfig');
}
@@ -247,9 +307,14 @@ class Page_DozMod extends Page
$data['defaultLecturePermissions'] = Request::post('defaultLecturePermissions', NULL, "array");
$data['defaultImagePermissions'] = Request::post('defaultImagePermissions', NULL, "array");
- foreach(['maxImageValidityDays', 'maxLectureValidityDays', 'maxTransfers'] as $field) {
- $value = Request::post($field);
- $data[$field] = $value;
+ $intParams = [
+ 'maxImageValidityDays' => array('min' => 7, 'max' => 999),
+ 'maxLectureValidityDays' => array('min' => 7, 'max' => 999),
+ 'maxTransfers' => array('min' => 1, 'max' => 10),
+ ];
+ foreach($intParams as $field => $limits) {
+ $value = Request::post($field, 0, 'int');
+ $data[$field] = max(min($value, $limits['max']), $limits['min']);
}
/* ensure types */
@@ -275,88 +340,4 @@ class Page_DozMod extends Page
Util::redirect('?do=DozMod&section=runtimeconfig');
}
- private function listUsers()
- {
- $res = Database::simpleQuery('SELECT userid, firstname, lastname, email, lastlogin, user.canlogin, issuperuser, emailnotifications,'
- . ' organization.displayname AS orgname FROM sat.user'
- . ' LEFT JOIN sat.organization USING (organizationid)'
- . ' ORDER BY lastname ASC, firstname ASC');
- $rows = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $row['canlogin'] = $this->checked($row['canlogin']);
- $row['issuperuser'] = $this->checked($row['issuperuser']);
- $row['emailnotifications'] = $this->checked($row['emailnotifications']);
- $row['lastlogin'] = date('d.m.Y', $row['lastlogin']);
- $rows[] = $row;
- }
- Render::addTemplate('userlist', array('users' => $rows));
- }
-
- private function listOrganizations()
- {
- $res = Database::simpleQuery('SELECT organizationid, displayname, canlogin FROM sat.organization'
- . ' ORDER BY displayname ASC');
- $rows = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $row['canlogin'] = $this->checked($row['canlogin']);
- $rows[] = $row;
- }
- Render::addTemplate('orglist', array('organizations' => $rows));
- }
-
- private function checked($val)
- {
- if ($val)
- return 'checked="checked"';
- return '';
- }
-
- private function setUserOption($option)
- {
- $val = (string) Request::post('value', '-');
- if ($val !== '1' && $val !== '0')
- die('Nein');
- if ($option === 'setmail') {
- $field = 'emailnotifications';
- } elseif ($option === 'setsu') {
- $field = 'issuperuser';
- } elseif ($option === 'setlogin') {
- $field = 'canlogin';
- } else {
- die('Unknown');
- }
- $user = (string) Request::post('userid', '?');
- $ret = Database::exec("UPDATE sat.user SET $field = :onoff WHERE userid = :userid", array(
- 'userid' => $user,
- 'onoff' => $val
- ));
- error_log("Setting $field to $val for $user - affected: $ret");
- if ($ret === false)
- die('Error');
- if ($ret == 0)
- die(1 - $val);
- die($val);
- }
-
- private function setOrgOption($option)
- {
- $val = (string) Request::post('value', '-');
- if ($val !== '1' && $val !== '0')
- die('Nein');
- if ($option === 'setorglogin') {
- $field = 'canlogin';
- } else {
- die('Unknown');
- }
- $ret = Database::exec("UPDATE sat.organization SET $field = :onoff WHERE organizationid = :organizationid", array(
- 'organizationid' => (string) Request::post('organizationid', ''),
- 'onoff' => $val
- ));
- if ($ret === false)
- die('Error');
- if ($ret === 0)
- die(1 - $val);
- die($val);
- }
-
}
diff --git a/modules-available/dozmod/style.css b/modules-available/dozmod/style.css
index c6975d3e..8cc5548d 100644
--- a/modules-available/dozmod/style.css
+++ b/modules-available/dozmod/style.css
@@ -1,9 +1,3 @@
-
-
-input[type=checkbox] {
- border: 2px solid green !important;
-}
-
/* this is based on https://github.com/flatlogic/awesome-bootstrap-checkbox */
.checkbox {
@@ -47,6 +41,7 @@ input[type=checkbox] {
.checkbox input[type="radio"] {
opacity: 0;
z-index: 1;
+ top: -6px;
}
@@ -58,18 +53,44 @@ input[type=checkbox] {
}
.checkbox input[type="checkbox"]:checked + label::after,
.checkbox input[type="radio"]:checked + label::after {
- font-family: "FontAwesome";
- content: "\f00c";
+ font-family: "Glyphicons Halflings";
+ content: "\E013";
+}
+
+.witherror {
+ border: 1px solid red;
+}
+
+/*
+.table-input-group tr:first-child {
+ background: #EEEEEE url("./style/bg.png");
+ border-style: solid none solid solid;
+ border-radius: 4px 0px 0px 4px;
+ border-color: #CCCCCC #555555 #CCCCCC #CCCCCC;
+ border-width: 1px 0px 1px 1px;
+ color: #555555;
}
+*/
+.table-input-group {
+ border-collapse: separate;
+}
-input[type="checkbox"].styled:checked + label:after {
- font-family: 'FontAwesome';
- content: "\f00c";
+.table-input-group tr.input-group {
+ display: table-row;
+ width: auto;
+ border-collapse: separate;
}
-input[type="checkbox"] .styled:checked + label::before {
- color: #fff;
+
+.table-input-group tr.input-group td.input-group-addon {
+ text-align: left;
+ border-collapse: separate;
}
-input[type="checkbox"] .styled:checked + label::after {
- color: #fff;
+
+.table-input-group tr.input-group input.form-control {
+ width: auto;
+}
+
+.table-input-group tr.input-group td:last-child input {
+ border-radius: 0px 4px 4px 0px;
}
diff --git a/modules-available/dozmod/templates/actionlog-header.html b/modules-available/dozmod/templates/actionlog-header.html
new file mode 100644
index 00000000..bb32efda
--- /dev/null
+++ b/modules-available/dozmod/templates/actionlog-header.html
@@ -0,0 +1 @@
+<h2>{{lang_dozmodLogHeading}}</h2> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/actionlog-image.html b/modules-available/dozmod/templates/actionlog-image.html
new file mode 100644
index 00000000..cd8c8d1d
--- /dev/null
+++ b/modules-available/dozmod/templates/actionlog-image.html
@@ -0,0 +1,30 @@
+<h3>{{lang_currentFilter}}</h3>
+<table class="table table-bordered table-striped" style="width: auto">
+ <tr>
+ <th class="text-nowrap">{{lang_image}}</th>
+ <td>{{displayname}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_os}}</th>
+ <td>{{osname}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_owner}}</th>
+ <td><a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{ouserid}}">{{ofirstname}} {{olastname}}</a></td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_lastEditor}}</th>
+ <td><a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{uuserid}}">{{ufirstname}} {{ulastname}}</a></td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_createTime}}</th>
+ <td>{{createtime_s}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_updateTime}}</th>
+ <td>{{updatetime_s}}</td>
+ </tr>
+ <tr>
+ <td colspan="2">{{{descriptionHtml}}}</td>
+ </tr>
+</table> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/actionlog-lecture.html b/modules-available/dozmod/templates/actionlog-lecture.html
new file mode 100644
index 00000000..4fb2b4d0
--- /dev/null
+++ b/modules-available/dozmod/templates/actionlog-lecture.html
@@ -0,0 +1,30 @@
+<h3>{{lang_currentFilter}}</h3>
+<table class="table table-bordered table-striped" style="width: auto">
+ <tr>
+ <th class="text-nowrap">{{lang_lecture}}</th>
+ <td>{{displayname}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_owner}}</th>
+ <td><a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{ouserid}}">{{ofirstname}} {{olastname}}</a></td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_lastEditor}}</th>
+ <td><a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{uuserid}}">{{ufirstname}} {{ulastname}}</a></td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_createTime}}</th>
+ <td>{{createtime_s}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_updateTime}}</th>
+ <td>{{updatetime_s}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_image}}</th>
+ <td><a href="?do=dozmod&amp;section=actionlog&amp;action=showtarget&amp;uuid={{imagebaseid}}">{{imgname}}</a></td>
+ </tr>
+ <tr>
+ <td colspan="2">{{{descriptionHtml}}}</td>
+ </tr>
+</table> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/actionlog-log.html b/modules-available/dozmod/templates/actionlog-log.html
new file mode 100644
index 00000000..3b523899
--- /dev/null
+++ b/modules-available/dozmod/templates/actionlog-log.html
@@ -0,0 +1,41 @@
+<table class="table table-striped table-bordered">
+ <tr>
+ <th class="text-nowrap">{{lang_when}}</th>
+ {{#showActor}}
+ <th class="text-nowrap">{{lang_user}}</th>
+ {{/showActor}}
+ {{#showTarget}}
+ <th class="text-nowrap">{{lang_actionTarget}}</th>
+ {{/showTarget}}
+ <th class="text-nowrap">{{lang_event}}</th>
+ </tr>
+ {{#events}}
+ <tr>
+ <td>{{dateline_s}}</td>
+ {{#showActor}}
+ <td>
+ {{#uuserid}}
+ <a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{uuserid}}">{{ulastname}}, {{ufirstname}}</a>
+ {{/uuserid}}
+ {{^uuserid}}
+ {{lang_system}}
+ {{/uuserid}}
+ </td>
+ {{/showActor}}
+ {{#showTarget}}
+ <td>
+ {{#targeturl}}
+ <a href="{{targeturl}}">{{targetname}}</a>
+ {{/targeturl}}
+ {{^targeturl}}
+ {{targetname}}
+ {{^targetname}}
+ <span class="small">{{targetid}}</span>
+ {{/targetname}}
+ {{/targeturl}}
+ </td>
+ {{/showTarget}}
+ <td>{{description}}</td>
+ </tr>
+ {{/events}}
+</table> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/actionlog-user.html b/modules-available/dozmod/templates/actionlog-user.html
new file mode 100644
index 00000000..eefe1386
--- /dev/null
+++ b/modules-available/dozmod/templates/actionlog-user.html
@@ -0,0 +1,23 @@
+<h3>{{lang_currentFilter}}</h3>
+<table class="table table-bordered table-striped" style="width: auto">
+ <tr>
+ <th class="text-nowrap">{{lang_user}}</th>
+ <td>{{firstname}} {{lastname}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_userId}}</th>
+ <td>{{userid}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_organization}}</th>
+ <td>{{orgname}}</td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_email}}</th>
+ <td><a href="mailto:{{email}}">{{email}}</a></td>
+ </tr>
+ <tr>
+ <th class="text-nowrap">{{lang_lastLogin}}</th>
+ <td>{{lastlogin_s}}</td>
+ </tr>
+</table> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/blockstats-details.html b/modules-available/dozmod/templates/blockstats-details.html
new file mode 100644
index 00000000..68e03fbc
--- /dev/null
+++ b/modules-available/dozmod/templates/blockstats-details.html
@@ -0,0 +1,16 @@
+<table class="table table-bordered table-striped">
+ <tr>
+ <th>{{lang_imageName}}</th>
+ <th>{{lang_createTime}}</th>
+ <th>{{lang_fileSize}}</th>
+ <th>{{lang_blockCount}}</th>
+ </tr>
+ {{#rows}}
+ <tr>
+ <td>{{displayname}}</td>
+ <td>{{createtime_s}}</td>
+ <td>{{filesize_s}}</td>
+ <td>{{blockcount}}</td>
+ </tr>
+ {{/rows}}
+</table> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/blockstats.html b/modules-available/dozmod/templates/blockstats.html
new file mode 100644
index 00000000..82a66146
--- /dev/null
+++ b/modules-available/dozmod/templates/blockstats.html
@@ -0,0 +1,33 @@
+<table class="table table-condensed table-striped" style="width: auto">
+ <tr>
+ <th>{{lang_hash}}</th>
+ <th>{{lang_size}}</th>
+ <th>{{lang_count}}</th>
+ </tr>
+ {{#hashes}}
+ <tr>
+ <td>{{hash_hex}}</td>
+ <td>{{blocksize_s}}</td>
+ <td>{{blockcount}} <button class="btn btn-xs btn-default" onclick="slxLoadBlocks('{{hash_hex}}', '{{blocksize}}')"><span class="glyphicon glyphicon-eye-open"></span></button></td>
+ </tr>
+ {{/hashes}}
+</table>
+
+<div class="modal fade" id="block-details" tabindex="-1" role="dialog">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header"></div>
+ <div class="modal-body"></div>
+ <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
+ </div>
+ </div>
+</div>
+
+<script type="application/javascript"><!--
+function slxLoadBlocks(hash, size) {
+ $('#block-details .modal-header').text(hash + '/' + size);
+ $('#block-details .modal-body').html('<div class="slx-rotation"><span class="glyphicon glyphicon-refresh"></span></div>');
+ $('#block-details').modal('show');
+ $('#block-details .modal-body').load('?do=dozmod&section=blockstats', { token: TOKEN, action: 'getblockinfo', hash: hash, size: size });
+}
+//--></script> \ No newline at end of file
diff --git a/modules-available/dozmod/templates/images-delete.html b/modules-available/dozmod/templates/images-delete.html
index f8836b83..0ee90835 100644
--- a/modules-available/dozmod/templates/images-delete.html
+++ b/modules-available/dozmod/templates/images-delete.html
@@ -27,11 +27,11 @@
<tbody>
{{#images}}
<tr>
- <td class="text-left slx-nowrap {{name_extra_class}}">{{displayname}}<br><span class="small">{{imageversionid}}</span></td>
- <td class="text-left slx-nowrap">{{version}}</td>
- <td class="text-left slx-nowrap"><a href="mailto:{{email}}">{{lastname}}, {{firstname}}</a></td>
- <td class="text-left slx-nowrap"><span class="glyphicon {{hasNewerClass}}"></span></td>
- <td class="text-right slx-nowrap">{{filesize}}</td>
+ <td class="text-left text-nowrap {{name_extra_class}}">{{displayname}}<br><span class="small">{{imageversionid}}</span></td>
+ <td class="text-left text-nowrap">{{version}}</td>
+ <td class="text-left text-nowrap"><a href="mailto:{{email}}">{{lastname}}, {{firstname}}</a></td>
+ <td class="text-left text-nowrap"><span class="glyphicon {{hasNewerClass}}"></span></td>
+ <td class="text-right text-nowrap">{{filesize}}</td>
<td><input class="del-check" name="images[{{imageversionid}}]" type="checkbox" {{checked}}></td>
</tr>
{{/images}}
@@ -85,4 +85,4 @@ document.addEventListener("DOMContentLoaded", function() {
slxChangeSingle();
}, false);
---> </script>
+//--> </script>
diff --git a/modules-available/dozmod/templates/mailconfig.html b/modules-available/dozmod/templates/mailconfig.html
index 56850637..69622796 100644
--- a/modules-available/dozmod/templates/mailconfig.html
+++ b/modules-available/dozmod/templates/mailconfig.html
@@ -6,8 +6,6 @@
</div>
<div class="panel-body">
<p>{{lang_mailDescription}}</p>
- <p>[BETA] Diese FunktionalitƤt ist neu. Wir bitten um Nachsicht, falls es Situationen gibt, in denen zu viele
- oder zu wenige Nachrichten verschickt werden.</p>
<form action="?do=DozMod" method="post" id="mailconf">
<input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="position:absolute;top:-200px" tabindex="-1">
<input type="password" name="password_fake" id="password_fake" value="" style="position:absolute;top:-200px" tabindex="-1">
diff --git a/modules-available/dozmod/templates/orglist.html b/modules-available/dozmod/templates/orglist.html
index 34fa039c..482864de 100644
--- a/modules-available/dozmod/templates/orglist.html
+++ b/modules-available/dozmod/templates/orglist.html
@@ -16,7 +16,7 @@
<tbody>
{{#organizations}}
<tr>
- <td class="text-left slx-nowrap">{{displayname}}</td>
+ <td class="text-left text-nowrap">{{displayname}}</td>
<td class="text-nowrap">
<input onclick="seto('setorglogin', this, '{{organizationid}}')" type="checkbox" {{{canlogin}}}>
</td>
@@ -35,33 +35,35 @@ function seto(action, el, orgid) {
var v = el.checked ? '1' : '0';
var old = el.checked == true;
box.css('display', 'none');
- $.post('?do=DozMod', { token: TOKEN, action: action, organizationid: orgid, value: v }).done(function (data) {
- if (data != 1 && data != 0) {
+ $.post('?do=DozMod', { token: TOKEN, section: 'users', action: action, organizationid: orgid, value: v }).done(function (data) {
+
+ if (data !== '1' && data !== '0') {
el.checked = !old;
box.parent().css('background-color', 'red !important');
} else {
el.checked = (data == 1);
+ box.parent().css('background-color', '');
+ /* show success notification */
+ $notification = $('<span></span>')
+ .addClass('glyphicon glyphicon-saved')
+ .css('color', '#2ecc71')
+ .css('width', '0px')
+ .css('position', 'relative')
+ .css('right', '20px')
+ .hide();
+ box.before($notification);
+ $notification.fadeIn('fast', function () {
+ $notification.fadeOut('slow', function () { $notification.remove() });
+ });
}
box.css('display', '');
- /* show success notification */
- $notification = $('<span></span>')
- .addClass('glyphicon glyphicon-saved')
- .css('color', '#2ecc71')
- .css('width', '0px')
- .css('position', 'relative')
- .css('right', '20px')
- .hide();
- box.before($notification);
- $notification.fadeIn('slow', function () {$notification.fadeOut('fast');});
-
-
-
-
}).fail(function() {
+
el.checked = !old;
box.parent().css('background-color', 'red !important');
box.css('display', '');
+
});
}
diff --git a/modules-available/dozmod/templates/runtimeconfig.html b/modules-available/dozmod/templates/runtimeconfig.html
index eced5784..011fcac4 100644
--- a/modules-available/dozmod/templates/runtimeconfig.html
+++ b/modules-available/dozmod/templates/runtimeconfig.html
@@ -5,90 +5,97 @@
{{lang_runtimeConfig}}
</div>
<div class="panel-body">
- <p> {{lang_descriptionRuntimeConfig}}</p>
+ <h3>{{lang_defaultPermissions}}</h3>
+ <p><i>{{lang_descriptionPermissionConfig}}</i></p>
<form action="?do=DozMod" method="post" id="runtimeconf" role="form">
<input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="position:absolute;top:-200px" tabindex="-1">
<input type="password" name="password_fake" id="password_fake" value="" style="position:absolute;top:-200px" tabindex="-1">
<fieldset class="form-group">
- <h4>{{lang_defaultLecturePermissions}}</h4>
+ <legend>{{lang_defaultLecturePermissions}}</legend>
- <input type="hidden" name="defaultLecturePermissions[edit]" value="0"/>
- <input type="hidden" name="defaultLecturePermissions[admin]" value="0"/>
+ <input type="hidden" name="defaultLecturePermissions[edit]" value="0"/>
+ <input type="hidden" name="defaultLecturePermissions[admin]" value="0"/>
- <div class="checkbox">
- <input type="checkbox" name="defaultLecturePermissions[edit]" value="1" {{defaultLecturePermissions.edit}} id ="lecture_edit" class="form-control"/>
- <label>
- {{lang_lecturePermissionEdit}}*
- </label>
- </div>
<div class="checkbox">
- <input type="checkbox" name="defaultLecturePermissions[admin]" value="1" {{defaultLecturePermissions.admin}} id ="lecture_admin" class="form-control"/>
- <label>
- {{lang_lecturePermissionAdmin}}*
+ <input type="checkbox" name="defaultLecturePermissions[admin]" value="1" {{defaultLecturePermissions.admin}} id ="lecture_admin" class="form-control">
+ <label>
+ {{lang_lecturePermissionAdmin}}
+ </label>
+ </div>
+ <div class="checkbox">
+ <input type="checkbox" name="defaultLecturePermissions[edit]" value="1" {{defaultLecturePermissions.edit}} id ="lecture_edit" class="form-control">
+ <label>
+ {{lang_lecturePermissionEdit}}
</label>
</div>
</fieldset>
- <fieldset class="xform-group">
- <h4>{{lang_defaultImagePermissions}}</h4>
+ <fieldset class="form-group">
+ <legend>{{lang_defaultImagePermissions}}</legend>
<input type="hidden" name="defaultImagePermissions[edit]" value="0"/>
<input type="hidden" name="defaultImagePermissions[admin]" value="0"/>
<input type="hidden" name="defaultImagePermissions[download]" value="0"/>
<input type="hidden" name="defaultImagePermissions[link]" value="0"/>
<div class="checkbox">
- <input type="checkbox" name="defaultImagePermissions[edit]" value="1" {{defaultImagePermissions.edit}} id ="image_edit" class="form-control"/>
- <label>
- {{lang_defaultImagePermissionEdit}} *
+ <input type="checkbox" name="defaultImagePermissions[admin]" value="1" {{defaultImagePermissions.admin}} id ="image_admin" class="form-control">
+ <label class="" for="image_admin">
+ {{lang_defaultImagePermissionAdmin}}
</label>
</div>
<div class="checkbox">
- <input type="checkbox" name="defaultImagePermissions[admin]" value="1" {{defaultImagePermissions.admin}} id ="image_admin" class="form-control"/ >
- <label class="" for="image_admin">
- {{lang_defaultImagePermissionAdmin}} *
+ <input type="checkbox" name="defaultImagePermissions[edit]" value="1" {{defaultImagePermissions.edit}} id ="image_edit" class="form-control">
+ <label>
+ {{lang_defaultImagePermissionEdit}}
</label>
</div>
-
<div class="checkbox">
- <input type="checkbox" name="defaultImagePermissions[download]" value="1" {{defaultImagePermissions.download}} id ="image_download" class="form-control"/ >
+ <input type="checkbox" name="defaultImagePermissions[download]" value="1" {{defaultImagePermissions.download}} id ="image_download" class="form-control">
<label>
- {{lang_defaultImagePermissionDownload}} *
+ {{lang_defaultImagePermissionDownload}}
</label>
</div>
<div class="checkbox">
- <input type="checkbox" name="defaultImagePermissions[link]" value="1" {{defaultImagePermissions.link}} id ="image_link" class="form-control"/ >
+ <input type="checkbox" name="defaultImagePermissions[link]" value="1" {{defaultImagePermissions.link}} id ="image_link" class="form-control">
<label>
- {{lang_defaultImagePermissionLink}} *
+ {{lang_defaultImagePermissionLink}}
</label>
</div>
-
-
</fieldset>
- <fieldset>
- <h4>{{lang_runtimeConfigLimits}}</h4>
- <div class="input-group">
- <label class="input-group-addon slx-ga2" for="max_image_validity">{{lang_maxImageValidity}} *</label>
- <input name="maxImageValidityDays" id ="max_image_validity" class="form-control" type="number" value="{{maxImageValidityDays}}"></input>
- </div>
- <div class="input-group">
- <label class="input-group-addon slx-ga2" for="max_lecture_validity">{{lang_maxLectureVisibility}} *</label>
- <input name="maxLectureValidityDays" id ="max_lecture_validity" class="form-control" type="number" value="{{maxLectureValidityDays}}"></input>
- </div>
- <div class="input-group">
- <label class="input-group-addon slx-ga2" for="max_transfers">{{lang_maxTransfers}} *</label>
- <input name="maxTransfers" id ="max_transfers" class="form-control" type="number" value="{{maxTransfers}}"></input>
- </div>
+ <fieldset>
+ <h3>{{lang_runtimeConfigLimits}}</h3>
+ <p><i>{{lang_descriptionRuntimeLimits}}</i></p>
+ <table class="table-input-group">
+ <tr class="input-group">
+ <td class="input-group-addon" for="max_image_validity">{{lang_maxImageValidity}}</td>
+ <td>
+ <input name="maxImageValidityDays" id="max_image_validity" class="form-control" type="number" value="{{maxImageValidityDays}}" min="7" max="999" pattern="^\d+$">
+ </td>
+ </tr>
+ <tr class="input-group">
+ <td class="input-group-addon" for="max_lecture_validity">{{lang_maxLectureVisibility}}</td>
+ <td>
+ <input name="maxLectureValidityDays" id="max_lecture_validity" class="form-control" type="number" value="{{maxLectureValidityDays}}" min="1" max="999" pattern="^\d+$">
+ </td>
+ </tr>
+ <tr class="input-group">
+ <td class="input-group-addon" for="max_transfers">{{lang_maxTransfers}}</td>
+ <td>
+ <input name="maxTransfers" id="max_transfers" class="form-control" type="number" value="{{maxTransfers}}" min="1" max="10" pattern="^\d+$">
+ </td>
+ </tr>
+ </table>
</fieldset>
<br>
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="runtime">
- <button class="btn btn-primary btn-sm" type="submit" name="button" value="save">{{lang_save}}</button>
+ <button class="btn btn-primary" type="submit" name="button" value="save">{{lang_save}}</button>
</form>
</div>
</div>
diff --git a/modules-available/dozmod/templates/templates.html b/modules-available/dozmod/templates/templates.html
index e8e3f592..3b2a003f 100644
--- a/modules-available/dozmod/templates/templates.html
+++ b/modules-available/dozmod/templates/templates.html
@@ -1,15 +1,18 @@
-<h1> Templates</h1>
+<h1>{{lang_mailTemplates}}</h1>
-<form id="templateForm" role="form" method="POST" action="?do=dozmod&section=templates&action=save">
+<p><i>{{lang_templatePageDescription}}</i></p>
+
+<form id="templateForm" role="form" method="POST" action="?do=dozmod&amp;section=templates">
<input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="save">
<div class="panel-group" id="accordion">
{{#templates}}
- <div class="panel panel-default">
- <div id="heading_{{name}}" class="panel-heading">
+ <div id="frame_{{name}}" class="panel panel-default">
+ <div class="panel-heading">
<div class="panel-title">
<h4>
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#panel_{{name}}">
@@ -24,21 +27,26 @@
<div class="panel-body">
<div id="msgbox_{{name}}">
</div>
+ <!--
<label for="n_{{name}}">{{lang_name}}</label>
- <input name="templates[{{name}}][name]" value="{{name}}" class="form-control"/>
-
- <label for="n_{{description}}">{{lang_description}}</label>
- <input name="templates[{{name}}][description]" value="{{description}}" class="form-control"/>
-
+ <div class="form-group">
+ <input id="n_{{name}}" name="templates[{{name}}][name]" value="{{name}}" class="form-control"/>
+ </div>
+ <label for="d_{{name}}">{{lang_description}}</label>
+ <div class="form-group">
+ <input id="d_{{name}}" name="templates[{{name}}][description]" value="{{description}}" class="form-control"/>
+ </div>
+ -->
<label for="ta_{{name}}">{{lang_template}}</label>
- <br/>
- <textarea data-mandatory="{{list_mandatoryVariables}}" name="templates[{{name}}][template]" data-setting="{{name}}" id="ta_{{name}}"
- class="form-control templateEditor" style="min-height:200px"
- >{{template}}</textarea>
+ <div class="form-group">
+ <textarea data-mandatory="{{list_mandatoryVariables}}" name="templates[{{name}}][template]"
+ data-setting="{{name}}" id="ta_{{name}}"
+ class="form-control templateEditor" style="min-height:200px">{{template}}</textarea>
+ </div>
- <h3>{{lang_placeholders}}</h3>
+ <h4>{{lang_placeholders}}</h4>
<select name="templates[{{name}}][mandatory_variables]" multiple="multiple" class="hidden">
{{{html_mandatoryVariables}}}
</select>
@@ -56,16 +64,25 @@
{{/templates}}
</div>
- <div class="btn-group">
- <button type="button" onclick="sendForm()" class="btn btn-primary">{{lang_save}}</button>
+ <div class="pull-left">
+ <button type="submit" onclick="return validateForm()" class="btn btn-primary">{{lang_save}}</button>
</div>
</form>
+<form method="POST" action="?do=dozmod&amp;section=templates">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="reset">
+ <div>
+ <button type="submit" onclick="return confirm('{{lang_reallyResetTemplates}}')" class="btn btn-danger">{{lang_loadDefaults}}</button>
+ </div>
+</form>
+<div class="clearfix"></div>
<script type="application/javascript"><!--
/* check that all necessary placeholders are used */
function validateForm() {
var ok = true;
+ var $toppest = false;
$('.templateEditor').each(function (i, editor) {
@@ -76,7 +93,7 @@ function validateForm() {
/* ? */
- if (mandatory.length == 1 && mandatory[0] == "") {
+ if (mandatory.length === 1 && mandatory[0] === "") {
mandatory = [];
}
@@ -87,54 +104,36 @@ function validateForm() {
missing.push(v);
}
});
- console.log("missing are");
- console.log(missing);
var $msgBox = $("#msgbox_" + setting);
- var $panel = $("#panel_" + setting);
- var $header = $("#heading_" + setting);
-
+ var $frame = $("#frame_" + setting);
if (missing.length > 0) {
/* add errors */
var missingL = missing.join(", ");
- var msg="<strong>Fehler:</strong> Folgende wichtige Platzhalter wurden nicht verwendet: " +missingL;
- console.log("msg box has " + $msgBox.size());
+ var msg="<strong>{{lang_error}}:</strong> {{lang_followingPlaceholdersUnused}}: " +missingL;
$msgBox.html('<div class="alert alert-danger">' + msg + '</div>');
- $panel.addClass('witherror');
- $header.addClass('witherror');
+ $frame.addClass('witherror');
+ if ($toppest === false || $toppest.offset().top > $frame.offset().top) {
+ $toppest = $frame;
+ }
/* overall result */
ok = false;
} else {
$msgBox.html("");
- $panel.removeClass('witherror');
- $header.removeClass('witherror');
+ $frame.removeClass('witherror');
}
});
- return ok;
-}
-
-function submitForm() {
- console.log('sending form');
- $('#templateForm').submit();
-}
-
-
-function sendForm() {
- var ok = validateForm();
- if (ok) {
- console.log("is ok");
- submitForm();
- } else {
- console.log("form is not ok");
+ if ($toppest !== false) {
+ $toppest[0].scrollIntoView();
}
+ return ok;
}
document.addEventListener("DOMContentLoaded", function () {
-
-
-
+ validateForm(); // Do once in case invalid templates are in DB
});
-</script>
+
+//--></script>
diff --git a/modules-available/dozmod/templates/userlist.html b/modules-available/dozmod/templates/userlist.html
index 79d4848b..93ef7b41 100644
--- a/modules-available/dozmod/templates/userlist.html
+++ b/modules-available/dozmod/templates/userlist.html
@@ -22,10 +22,10 @@
<tbody>
{{#users}}
<tr>
- <td class="text-left slx-nowrap">{{lastname}}, {{firstname}}</td>
- <td class="text-left slx-nowrap">{{orgname}}</td>
- <td class="text-left slx-nowrap">{{lastlogin}}</td>
- <td class="text-left slx-nowrap"><a href="mailto:{{email}}">{{email}}</a></td>
+ <td class="text-left text-nowrap"><a href="?do=dozmod&amp;section=actionlog&amp;action=showuser&amp;uuid={{userid}}">{{lastname}}, {{firstname}}</a></td>
+ <td class="text-left text-nowrap">{{orgname}}</td>
+ <td class="text-left text-nowrap">{{lastlogin}}</td>
+ <td class="text-left text-nowrap"><a href="mailto:{{email}}">{{email}}</a></td>
<td><input onclick="setu('setmail', this, '{{userid}}')" type="checkbox" {{{emailnotifications}}}></td>
<td><input onclick="setu('setsu', this, '{{userid}}')" type="checkbox" {{{issuperuser}}}></td>
<td><input onclick="setu('setlogin', this, '{{userid}}')" type="checkbox" {{{canlogin}}}></td>
@@ -44,29 +44,35 @@ function setu(action, el, uid) {
var v = el.checked ? '1' : '0';
var old = el.checked == true;
box.css('display', 'none');
- $.post('?do=DozMod', { token: TOKEN, action: action, userid: uid, value: v }).done(function (data) {
- if (data != 1 && data != 0) {
+ $.post('?do=DozMod', { token: TOKEN, section: 'users', action: action, userid: uid, value: v }).done(function (data) {
+
+ if (data !== '1' && data !== '0') {
el.checked = !old;
box.parent().css('background-color', 'red !important');
} else {
el.checked = (data == 1);
+ box.parent().css('background-color', '');
+ /* show success notification */
+ $notification = $('<span></span>')
+ .addClass('glyphicon glyphicon-saved')
+ .css('color', '#2ecc71')
+ .css('width', '0px')
+ .css('position', 'relative')
+ .css('right', '20px')
+ .hide();
+ box.before($notification);
+ $notification.fadeIn('fast', function () {
+ $notification.fadeOut('slow', function () { $notification.remove() });
+ });
}
- /* show success notification */
- $notification = $('<span></span>')
- .addClass('glyphicon glyphicon-saved')
- .css('color', '#2ecc71')
- .css('width', '0px')
- .css('position', 'relative')
- .css('right', '20px')
- .hide();
- box.before($notification);
- $notification.fadeIn('slow', function () {$notification.fadeOut('fast');});
-
box.css('display', '');
+
}).fail(function() {
+
el.checked = !old;
box.parent().css('background-color', 'red !important');
box.css('display', '');
+
});
}
diff --git a/modules-available/exams/baseconfig/getconfig.inc.php b/modules-available/exams/baseconfig/getconfig.inc.php
index 2776d3a8..6a9bf03a 100644
--- a/modules-available/exams/baseconfig/getconfig.inc.php
+++ b/modules-available/exams/baseconfig/getconfig.inc.php
@@ -2,10 +2,12 @@
if (isset($configVars["SLX_LOCATIONS"])) {
$locationIds = explode(' ', $configVars["SLX_LOCATIONS"]);
- if (Exams::isInExamMode($locationIds, $lectureId)) {
- $configVars['SLX_EXAM'] = 'yes';
- if (strlen($lectureId) > 0) {
- $configVars['SLX_EXAM_START'] = $lectureId;
- }
+} else {
+ $locationIds = array();
+}
+if (Exams::isInExamMode($locationIds, $lectureId)) {
+ $configVars['SLX_EXAM'] = 'yes';
+ if (strlen($lectureId) > 0) {
+ $configVars['SLX_EXAM_START'] = $lectureId;
}
}
diff --git a/modules-available/exams/inc/exams.inc.php b/modules-available/exams/inc/exams.inc.php
index e95a9392..5fc497c7 100644
--- a/modules-available/exams/inc/exams.inc.php
+++ b/modules-available/exams/inc/exams.inc.php
@@ -11,8 +11,6 @@ class Exams
{
if (!is_array($locationIds)) {
$locationIds = array($locationIds);
- } elseif (empty($locationIds)) {
- return false;
}
$l = str_repeat(',?', count($locationIds));
$res = Database::queryFirst("SELECT lectureid FROM exams"
diff --git a/modules-available/exams/install.inc.php b/modules-available/exams/install.inc.php
index 18be0be6..b1032118 100644
--- a/modules-available/exams/install.inc.php
+++ b/modules-available/exams/install.inc.php
@@ -4,7 +4,7 @@ $res = array();
$res[] = tableCreate('exams', '
`examid` int(11) NOT NULL AUTO_INCREMENT,
- `lectureid` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL
+ `lectureid` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`starttime` int(11) NOT NULL,
`endtime` int(11) NOT NULL,
`description` varchar(500) DEFAULT NULL,
diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php
index a018208d..71a621db 100644
--- a/modules-available/locations/inc/location.inc.php
+++ b/modules-available/locations/inc/location.inc.php
@@ -362,8 +362,7 @@ class Location
private static function overlap($net1, $net2)
{
- return ($net1['startaddr'] >= $net2['startaddr'] && $net1['startaddr'] <= $net2['endaddr'])
- || ($net1['endaddr'] >= $net2['startaddr'] && $net1['endaddr'] <= $net2['endaddr']);
+ return ($net1['startaddr'] <= $net2['endaddr'] && $net1['endaddr'] >= $net2['startaddr']);
}
}
diff --git a/modules-available/locations/templates/locations.html b/modules-available/locations/templates/locations.html
index bb13131e..5fec2e2e 100644
--- a/modules-available/locations/templates/locations.html
+++ b/modules-available/locations/templates/locations.html
@@ -9,10 +9,10 @@
<th>
{{#havestatistics}}{{lang_machineCount}}{{/havestatistics}}
</th>
- <th class="slx-nowrap">
+ <th class="text-nowrap">
{{#havebaseconfig}}{{lang_editConfigVariables}}{{/havebaseconfig}}
</th>
- <th class="slx-nowrap">
+ <th class="text-nowrap">
{{#havesysconfig}}{{lang_sysConfig}}{{/havesysconfig}}
</th>
</tr>
@@ -22,13 +22,13 @@
<div style="display:inline-block;width:{{depth}}em"></div>
<a href="#" onclick="slxOpenLocation(this, {{locationid}})">{{locationname}} <b class="caret"></b></a>
</td>
- <td class="slx-nowrap" align="right">
+ <td class="text-nowrap" align="right">
{{#havestatistics}}
{{clientCount}}
<a class="btn btn-default btn-xs" href="?do=Statistics&amp;show=list&amp;filters=location={{locationid}}"><span class="glyphicon glyphicon-eye-open"></span></a>
{{/havestatistics}}
</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
{{#havebaseconfig}}
<div class="pull-right" style="z-index:-1">
<a class="btn btn-default btn-xs" href="?do=baseconfig&amp;module=locations&amp;locationid={{locationid}}"><span class="glyphicon glyphicon-edit"></span></a>
@@ -38,7 +38,7 @@
{{/overriddenVars}}
{{/havebaseconfig}}
</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
{{#havesysconfig}}
<div class="pull-right">
<a class="btn btn-default btn-xs" href="?do=sysconfig&amp;locationid={{locationid}}"><span class="glyphicon glyphicon-edit"></span></a>
@@ -53,7 +53,7 @@
{{#unassignedCount}}
<tr>
<td>{{lang_unassignedMachines}}</td>
- <td class="slx-nowrap" align="right">
+ <td class="text-nowrap" align="right">
{{unassignedCount}}
<a class="btn btn-default btn-xs" href="?do=Statistics&amp;show=list&amp;filters=location=0">
<span class="glyphicon glyphicon-eye-open"></span>
diff --git a/modules-available/main/lang/de/messages.json b/modules-available/main/lang/de/messages.json
index fc73f891..274a97bd 100644
--- a/modules-available/main/lang/de/messages.json
+++ b/modules-available/main/lang/de/messages.json
@@ -3,6 +3,7 @@
"empty-field": "Ein Feld wurde nicht ausgef\u00fcllt",
"error-read": "Fehler beim Lesen von {{0}}",
"error-write": "Fehler beim Schreiben von {{0}}",
+ "invalid-action": "Ung\u00fcltige Aktion '{{0}}'",
"module-missing-deps": "Modul {{0}} hat fehlende Abh\u00e4ngigkeiten",
"no-permission": "Keine ausreichenden Rechte, um auf diese Seite zuzugreifen",
"no-such-module": "Modul {{0}} existiert nicht oder ist nicht aktiv",
diff --git a/modules-available/main/lang/en/messages.json b/modules-available/main/lang/en/messages.json
index 2b735eec..e7314685 100644
--- a/modules-available/main/lang/en/messages.json
+++ b/modules-available/main/lang/en/messages.json
@@ -3,6 +3,7 @@
"empty-field": "A field was not filled",
"error-read": "Error reading {{0}}",
"error-write": "Failed to write {{0}}",
+ "invalid-action": "Invalid action '{{0}}'",
"module-missing-deps": "Module {{0}} has missing dependencies",
"no-permission": "No sufficient privileges to access this page",
"no-such-module": "Modul {{0}} existiert nicht",
diff --git a/modules-available/main/templates/main-menu.html b/modules-available/main/templates/main-menu.html
index 57f0fa88..8dc91f12 100644
--- a/modules-available/main/templates/main-menu.html
+++ b/modules-available/main/templates/main-menu.html
@@ -1,8 +1,5 @@
<div class="slx-topbar">
<div>
- {{#dbupdate}}
- <a href="api.php?do=update"><span class="slx-warning-badge badge"><span class="glyphicon glyphicon-exclamation-sign"></span> DB-Update</span></a>
- {{/dbupdate}}
{{#warning}}
<a href="?do=EventLog"><span class="slx-warning-badge badge"><span class="glyphicon glyphicon-exclamation-sign"></span> {{lang_warning}}</span></a>
{{/warning}}
@@ -34,7 +31,7 @@
{{#modules}}
<li class="{{className}}"><a href="?do={{identifier}}">{{displayName}}</a></li>
{{#subMenu}}
- <li class="slx-submenu"><a href="{{url}}">{{name}}</a></li>
+ <li class="slx-submenu visible-lg"><a href="{{url}}">{{name}}</a></li>
{{/subMenu}}
{{/modules}}
</ul>
@@ -86,10 +83,22 @@
</ul>
{{/user}}
{{^user}}
- <a type="button" href="?do=Session&action=login" class="btn btn-default">{{lang_login}}</a>
+ <a type="button" href="?do=Session&amp;action=login" class="btn btn-default">{{lang_login}}</a>
{{/user}}
</li>
</ul>
</div>
</div>
+ <div class="hidden-lg small">
+ <ol class="slx-smallsubmenu">
+ {{#categories}}
+ {{#modules}}
+ {{#subMenu}}
+ <li><a href="{{url}}">{{name}}</a></li>
+ {{/subMenu}}
+ {{/modules}}
+ {{/categories}}
+ </ol>
+ </div>
</nav>
+
diff --git a/modules-available/statistics/inc/filterset.inc.php b/modules-available/statistics/inc/filterset.inc.php
index 7cc075c3..8f506654 100644
--- a/modules-available/statistics/inc/filterset.inc.php
+++ b/modules-available/statistics/inc/filterset.inc.php
@@ -15,9 +15,8 @@ class FilterSet
{
$this->sortDirection = $direction === 'DESC' ? 'DESC' : 'ASC';
- if (array_key_exists($col, Page_Statistics::$columns)) {
- $isMapped = array_key_exists('map_sort', Page_Statistics::$columns[$col]);
- $this->sortColumn = $isMapped ? Page_Statistics::$columns[$col]['map_sort'] : $col;
+ if (is_string($col) && array_key_exists($col, Page_Statistics::$columns)) {
+ $this->sortColumn = $col;
} else {
/* default sorting column is clientip */
$this->sortColumn = 'clientip';
@@ -42,8 +41,10 @@ class FilterSet
}
$join = implode('', array_unique($joins));
-
- $sort = " ORDER BY " . $this->sortColumn . " " . $this->sortDirection;
+ $col = $this->sortColumn;
+ $isMapped = array_key_exists('map_sort', Page_Statistics::$columns[$col]);
+ $sort = " ORDER BY " . ($isMapped ? Page_Statistics::$columns[$col]['map_sort'] : $col) . " " . $this->sortDirection
+ . ", machineuuid ASC";
}
public function getSortDirection()
diff --git a/modules-available/statistics/templates/clientlist.html b/modules-available/statistics/templates/clientlist.html
index f2a6ba03..ca4b971a 100644
--- a/modules-available/statistics/templates/clientlist.html
+++ b/modules-available/statistics/templates/clientlist.html
@@ -58,7 +58,7 @@
</tr>
{{#rows}}
<tr>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
{{#hasnotes}}<span class="glyphicon glyphicon-exclamation-sign pull-right"></span>{{/hasnotes}}
{{#state_off}}
<span class="glyphicon glyphicon-off" title="{{lang_machineOff}}"></span>
@@ -87,3 +87,40 @@
</tr>
{{/rows}}
</table>
+
+<script type="application/javascript"><!--
+document.addEventListener("DOMContentLoaded", function () {
+ ['gbram', 'hddgb', 'realcores', 'kvmstate', 'lastseen', 'clientip'].forEach(function (v) {
+ var $sortBtn = $('#sortButton-' + v);
+ var order = 'up'; /* default */
+ if ($('#sortColumn').val() == v) {
+ $sortBtn.addClass('btn-success');
+ order = $('#sortDirection').val() == 'ASC' ? 'up' : 'down';
+ }
+ $sortBtn.html('<span class="glyphicon glyphicon-arrow-' + order + '"></span>');
+ $sortBtn.attr('onclick', 'toggleButton(\'' + v + '\');');
+ });
+});
+
+function toggleButton(v) {
+ var $sortBtn = $('#sortButton-' + v);
+ var $col = $('#sortColumn');
+ var $dir = $('#sortDirection');
+ if ($col.val() == v) {
+ /* toggle direction */
+ var newDir = $dir.val() == 'ASC' ? 'DESC' : 'ASC';
+ $dir.val(newDir);
+ /* update button */
+ var order = newDir == 'ASC' ? 'up' : 'down';
+ $sortBtn.html('<span class="glyphicon glyphicon-arrow-' + order + '"></span>');
+ } else {
+ /* remove "btn-success" from current sorting */
+ $('#sortButton-'+v).removeClass('btn-success');
+ $sortBtn.addClass('btn-success');
+ $col.val(v);
+ $dir = 'ASC';
+ }
+ $queryForm.submit();
+}
+
+//--></script> \ No newline at end of file
diff --git a/modules-available/statistics/templates/filterbox.html b/modules-available/statistics/templates/filterbox.html
index a5370a0b..544d1c48 100644
--- a/modules-available/statistics/templates/filterbox.html
+++ b/modules-available/statistics/templates/filterbox.html
@@ -29,7 +29,8 @@
<div style="height:120px" class="col-xs-12">
<!-- use GET here, to avoid the "resend form?" confirmation, and anyway this is stateless, so GET makes more sense -->
<form id="queryForm" method="GET" action="?do=Statistics" class="" role="form">
- <input type="hidden" name="do" value="Statistics"/>
+ <input type="hidden" name="do" value="statistics">
+ <input type="hidden" name="show" value="{{show}}">
<label for="filterInput">{{lang_labelFilter}}</label>
<input type="text" name="filters" class="" id="filterInput"/>
<input type="hidden" name="sortColumn" id="sortColumn" value="{{sortColumn}}"/>
@@ -115,6 +116,8 @@ document.addEventListener("DOMContentLoaded", function () {
var str = "{{{query}}}";
var eExp = /^(\w+)\s*([=><!~]+)\s*(.*)$/;
str.split(slxFilterDel).forEach(function(v) {
+ if (v.trim().length === 0)
+ return;
var match = eExp.exec(v);
if (match && match.length === 4) {
addFilter(match[1], match[2], match[3]);
@@ -156,8 +159,6 @@ document.addEventListener("DOMContentLoaded", function () {
}
});
- initButtons();
-
$('.filter-col').each(function(idx, elem) {
var e = $(elem);
var col = e.data('filter-col');
@@ -176,41 +177,6 @@ document.addEventListener("DOMContentLoaded", function () {
}, false);
-
-function initButtons() {
- ['gbram', 'hddgb', 'realcores', 'kvmstate', 'lastseen', 'clientip'].forEach(function (v) {
- var $sortBtn = $('#sortButton-' + v);
- var order = 'up'; /* default */
- if ($('#sortColumn').val() == v) {
- $sortBtn.addClass('btn-success');
- order = $('#sortDirection').val() == 'ASC' ? 'up' : 'down';
- }
- $sortBtn.html('<span class="glyphicon glyphicon-arrow-' + order + '"></span>');
- $sortBtn.attr('onclick', 'toggleButton(\'' + v + '\');');
- });
-}
-
-function toggleButton(v) {
- var $sortBtn = $('#sortButton-' + v);
- var $col = $('#sortColumn');
- var $dir = $('#sortDirection');
- if ($col.val() == v) {
- /* toggle direction */
- var newDir = $dir.val() == 'ASC' ? 'DESC' : 'ASC';
- $dir.val(newDir);
- /* update button */
- var order = newDir == 'ASC' ? 'up' : 'down';
- $sortBtn.html('<span class="glyphicon glyphicon-arrow-' + order + '"></span>');
- } else {
- /* remove "btn-success" from current sorting */
- $('#sortButton-'+v).removeClass('btn-success');
- $sortBtn.addClass('btn-success');
- $col.val(v);
- $dir = 'ASC';
- }
- refresh();
-}
-
function popupFilter(field) {
if (field != null) {
$('#columnSelect').val(field);
@@ -258,7 +224,6 @@ function myOpSort(a,b) {
}
function refresh() {
- console.log('refresh');
$queryForm.submit(); /* TODO: use AJAX */
}
// --></script>
diff --git a/modules-available/statistics/templates/kvmstate.html b/modules-available/statistics/templates/kvmstate.html
index c44fb9ab..33a00d38 100644
--- a/modules-available/statistics/templates/kvmstate.html
+++ b/modules-available/statistics/templates/kvmstate.html
@@ -13,7 +13,7 @@
</tr>
{{#rows}}
<tr id="kvm{{kvmstate}}">
- <td class="text-left slx-nowrap">
+ <td class="text-left text-nowrap">
<a class="filter-val" data-filter-val="{{kvmstate}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~kvmstate={{kvmstate}}">{{kvmstate}}</a>
</td>
<td class="text-right">{{count}}</td>
diff --git a/modules-available/statistics/templates/memory.html b/modules-available/statistics/templates/memory.html
index 2d50c47f..ae040674 100644
--- a/modules-available/statistics/templates/memory.html
+++ b/modules-available/statistics/templates/memory.html
@@ -13,7 +13,7 @@
</tr>
{{#rows}}
<tr id="ramid{{gb}}" class="{{class}}">
- <td class="text-left slx-nowrap">
+ <td class="text-left text-nowrap">
<a class="filter-val" data-filter-val="{{gb}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~gbram={{gb}}">{{gb}}&thinsp;GiB</a>
</td>
<td class="text-right">{{count}}</td>
diff --git a/modules-available/statistics/templates/newclients.html b/modules-available/statistics/templates/newclients.html
index 0d9c74df..e7d79818 100644
--- a/modules-available/statistics/templates/newclients.html
+++ b/modules-available/statistics/templates/newclients.html
@@ -14,7 +14,7 @@
</tr>
{{#rows}}
<tr style="{{style}}">
- <td class="slx-nowrap"><a href="?do=Statistics&amp;uuid={{machineuuid}}">{{hostname}}</a></td>
+ <td class="text-nowrap"><a href="?do=Statistics&amp;uuid={{machineuuid}}">{{hostname}}</a></td>
<td class="text-right">{{firstseen}}</td>
<td class="{{kvmclass}}">{{kvmicon}}</td>
<td class="text-right {{ramclass}}">{{gbram}}&thinsp;GiB</td>
diff --git a/modules-available/sysconfig/templates/custom-filelist.html b/modules-available/sysconfig/templates/custom-filelist.html
index 3ad241dd..344eece3 100644
--- a/modules-available/sysconfig/templates/custom-filelist.html
+++ b/modules-available/sysconfig/templates/custom-filelist.html
@@ -4,7 +4,7 @@
{{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry isdir" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
{{/isdir}}
{{^isdir}}
<td class="fileEntry">{{name}}</td>
diff --git a/modules-available/sysconfig/templates/custom-fileselect.html b/modules-available/sysconfig/templates/custom-fileselect.html
index 000c8d10..f14a6fde 100644
--- a/modules-available/sysconfig/templates/custom-fileselect.html
+++ b/modules-available/sysconfig/templates/custom-fileselect.html
@@ -16,7 +16,7 @@
{{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry isdir" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
{{/isdir}}
{{^isdir}}
<td class="fileEntry">{{name}}</td>
diff --git a/modules-available/sysconfig/templates/list-configs.html b/modules-available/sysconfig/templates/list-configs.html
index ed027385..987becfd 100644
--- a/modules-available/sysconfig/templates/list-configs.html
+++ b/modules-available/sysconfig/templates/list-configs.html
@@ -21,7 +21,7 @@
<table id="conftable" class="slx-table" style="max-width:100px !important">
{{#configs}}
<tr>
- <td data-modlist="{{modlist}}" class="slx-pointer slx-width-ignore slx-nowrap"onclick="showmod(this, 'bold')" onmouseover="showmod(this, 'fade')" onmouseout="showmod(this, 'reset')" width="100%">
+ <td data-modlist="{{modlist}}" class="slx-pointer slx-width-ignore text-nowrap"onclick="showmod(this, 'bold')" onmouseover="showmod(this, 'fade')" onmouseout="showmod(this, 'reset')" width="100%">
<div class="slx-dyn-ellipsis">{{config}}</div>
</td>
<td>
@@ -45,7 +45,7 @@
</span>
{{/locationCount}}
</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
<button
{{#needrebuild}}
class="refconf btn btn-primary btn-xs"
@@ -55,7 +55,7 @@
{{/needrebuild}}
name="rebuild" value="{{configid}}" title="{{lang_rebuild}}"><span class="glyphicon glyphicon-refresh"></span></button>
</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
<a class="btn btn-success btn-xs" href="?do=SysConfig&amp;action=addconfig&amp;edit={{configid}}" title="{{lang_edit}}"><span class="glyphicon glyphicon-edit"></span></a>
<button class="btn btn-danger btn-xs" name="del" value="{{configid}}" title="{{lang_delete}}"><span class="glyphicon glyphicon-trash"></span></button>
</td>
diff --git a/modules-available/sysconfig/templates/list-modules.html b/modules-available/sysconfig/templates/list-modules.html
index 5b2c940b..29726c5d 100644
--- a/modules-available/sysconfig/templates/list-modules.html
+++ b/modules-available/sysconfig/templates/list-modules.html
@@ -11,15 +11,15 @@
<table id="modtable" class="slx-table" style="max-width:100px !important">
{{#modules}}
<tr>
- <td class="badge slx-nowrap">{{moduleType}}</td>
- <td data-id="{{id}}" class="modrow slx-width-ignore slx-nowrap" width="100%"><div class="slx-dyn-ellipsis">{{title}}</div></td>
- <td class="slx-nowrap">
+ <td class="badge text-nowrap">{{moduleType}}</td>
+ <td data-id="{{id}}" class="modrow slx-width-ignore text-nowrap" width="100%"><div class="slx-dyn-ellipsis">{{title}}</div></td>
+ <td class="text-nowrap">
{{#allowDownload}}
<button class="btn btn-default btn-xs" name="list" value="{{id}}" title="{{lang_show}}"><span class="glyphicon glyphicon-eye-open"></span></button>
<button class="btn btn-default btn-xs" name="download" value="{{id}}" title="{{lang_download}}"><span class="glyphicon glyphicon-download-alt"></span></button>
{{/allowDownload}}
</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">
<button
{{#needRebuild}}
class="refmod btn btn-primary btn-xs"
diff --git a/modules-available/translation/page.inc.php b/modules-available/translation/page.inc.php
index 563ffae0..93616cd1 100644
--- a/modules-available/translation/page.inc.php
+++ b/modules-available/translation/page.inc.php
@@ -474,7 +474,7 @@ class Page_Translation extends Page
if ($module === false) {
$module = $this->module;
}
- $tags = $this->loadTagsFromPhp('/Dictionary\s*::\s*translate\s*\(\s*[\'"](?<tag>[^\'"\.]*)[\'"]\s*\)/i',
+ $tags = $this->loadTagsFromPhp('/Dictionary\s*::\s*translate\s*\(\s*[\'"](?<tag>[^\'"\.]*)[\'"]\s*[\),]/i',
$this->getModulePhpFiles($module));
foreach ($tags as &$tag) {
$tag = true;
diff --git a/modules-available/webinterface/lang/de/template-tags.json b/modules-available/webinterface/lang/de/template-tags.json
index e204adec..3ac6186c 100644
--- a/modules-available/webinterface/lang/de/template-tags.json
+++ b/modules-available/webinterface/lang/de/template-tags.json
@@ -4,12 +4,13 @@
"lang_caChain": "Optional k\u00f6nnen Sie hier die zum Zertifikat geh\u00f6rende Zertifikatkette (CA-Chain) einf\u00fcgen. Dies wird ben\u00f6tigt, wenn das Zertifikat nicht direkt von einer der in Browsern mitgeliferten CAs signiert wurde. Die Datei enth\u00e4lt ein oder meherere Zertifikatsbl\u00f6cke, im gleichen Format wie das oben gezeigte Zertifikat.",
"lang_certificate": "Bitte f\u00fcgen Sie hier das Zertifikat ein. Das Zertifikat wird im Base64-codierten x509-Format erwartet (manchmal pem genannt). Es sieht in etwa wie folgt aus:",
"lang_customCert": "Eigenes Zertifikat verwenden",
- "lang_description": "Hier k\u00f6nnen Sie festlegen, ob das Web-Interface auch per HTTPS erreichbar sein soll, und welches Zertifikat daf\u00fcr verwendet werden soll.",
"lang_hidePasswords": "Passw\u00f6rter maskieren",
+ "lang_httpsDescription": "Hier k\u00f6nnen Sie festlegen, ob das Web-Interface auch per HTTPS erreichbar sein soll, und welches Zertifikat daf\u00fcr verwendet werden soll.",
"lang_httpsSettings": "HTTPS-Konfiguration",
"lang_installAndRestart": "Zertifikat installieren und Webserver neustarten",
"lang_noHttps": "HTTPS wieder deaktivieren, aktuelles Zertifikat l\u00f6schen",
"lang_passwordFields": "Passwortfelder",
+ "lang_passwordsDescription": "Legen Sie fest, ob Passwortfelder in der Web-Schnittstelle maskiert werden, oder ob Ihr Inhalt sichtbar sein soll. Wenn Sie die Schnittstelle in einer sicheren Umgebung nutzen (keine neugierigen Augen), kann dies den Komfort erh\u00f6hen. Das Passwortfeld der Anmeldemaske ist von dieser Einstellung ausgenommen.",
"lang_privateKey": "Bitte f\u00fcgen Sie hier den privaten Schl\u00fcssel ein, der zum obigen Zertifikat geh\u00f6rt. Er muss ebenfalls im \"pem\"-Format vorliegen, und sieht wie folgt aus:",
"lang_randomCert": "Neues selbstsigniertes Zertifikat generieren",
"lang_showPasswords": "Passw\u00f6rter anzeigen"
diff --git a/modules-available/webinterface/lang/en/template-tags.json b/modules-available/webinterface/lang/en/template-tags.json
index 4a43bdc1..31bc1cc9 100644
--- a/modules-available/webinterface/lang/en/template-tags.json
+++ b/modules-available/webinterface/lang/en/template-tags.json
@@ -4,12 +4,13 @@
"lang_caChain": "Here you can paste an optional certificate chain. It should only be required if you have a certificate that was not directly signed by a certificate authority known by the browsers. It should contain one or more certificate blocks, looking just like the certificate above.",
"lang_certificate": "Please paste your certificate below. It has to be in base64 encoded x509 format (sometimes called pem). It should look something like this:",
"lang_customCert": "Supply own certificate",
- "lang_description": "Here you can set whether the web interface should be accessible via https. You can chose if you want to use a random self signed certificate, or supply your own.",
"lang_hidePasswords": "Mask passwords",
+ "lang_httpsDescription": "Here you can set whether the web interface should be accessible via https. You can chose if you want to use a random self signed certificate, or supply your own.",
"lang_httpsSettings": "HTTPS settings",
"lang_installAndRestart": "Installing certificate and restarting web server",
"lang_noHttps": "Disable HTTPS, delete current certificate",
"lang_passwordFields": "Password fields",
+ "lang_passwordsDescription": "Set whether password fields should be masked or not. The password field of the login page to the web interface is always masked.",
"lang_privateKey": "Please paste the private key belonging to the certificate here. It has to be in \"pem\" format too, which should look like this:",
"lang_randomCert": "Genenrate new self-signed certificate",
"lang_showPasswords": "Show passwords"
diff --git a/modules-available/webinterface/templates/https.html b/modules-available/webinterface/templates/https.html
index c6161cd6..dfd2a3fe 100644
--- a/modules-available/webinterface/templates/https.html
+++ b/modules-available/webinterface/templates/https.html
@@ -4,7 +4,7 @@
<div class="panel panel-default">
<div class="panel-heading">{{lang_httpsSettings}}</div>
<div class="panel-body">
- <p>{{lang_description}}</p>
+ <p>{{lang_httpsDescription}}</p>
{{^httpsEnabled}}
<p>{{lang_HttpsIsDisabled}}</p>
{{/httpsEnabled}}
diff --git a/modules-available/webinterface/templates/passwords.html b/modules-available/webinterface/templates/passwords.html
index f9fda016..1f23dfc4 100644
--- a/modules-available/webinterface/templates/passwords.html
+++ b/modules-available/webinterface/templates/passwords.html
@@ -4,7 +4,7 @@
<div class="panel panel-default">
<div class="panel-heading">{{lang_passwordFields}}</div>
<div class="panel-body">
- <p>{{lang_description}}</p>
+ <p>{{lang_passwordsDescription}}</p>
<div class="input-group" onclick="$('#pmshow').prop('checked', true)">
<span class="input-group-addon"><input id="pmshow" type="radio" name="mode" value="show" {{selected_show}}></span>
<span class="form-control">
diff --git a/style/default.css b/style/default.css
index 3d78668d..a5450742 100644
--- a/style/default.css
+++ b/style/default.css
@@ -84,10 +84,6 @@ body {
height: 34px;
}
-.isdir {
- font-weight: bold;
-}
-
.slx-litehead {
margin: 0px 10px 5px 10px;
color: #aaa;
@@ -137,10 +133,6 @@ body {
background-color: #eee;
}
-.slx-bold {
- font-weight: bold;
-}
-
.slx-ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
@@ -155,10 +147,6 @@ body {
display: block;
}
-.slx-nowrap {
- white-space: nowrap;
-}
-
.slx-space {
margin-top: 1em;
margin-bottom: 1em;
@@ -493,3 +481,17 @@ li.slx-submenu a {
nav.navbar.sidebar {
color: #eee;
}
+
+.slx-smallsubmenu > li {
+ display: inline-block;
+}
+
+.slx-smallsubmenu > li + li:before {
+ padding: 0 3px;
+ content: "\2022\00a0";
+ color: #ccc;
+}
+
+.slx-smallsubmenu a {
+ color: #fff;
+} \ No newline at end of file