summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--inc/user.inc.php17
-rw-r--r--modules-available/backup/lang/en/template-tags.json2
-rw-r--r--modules-available/backup/templates/_page.html14
-rw-r--r--modules-available/baseconfig/lang/de/module.json2
-rw-r--r--modules-available/baseconfig/lang/de/template-tags.json1
-rw-r--r--modules-available/baseconfig/lang/en/module.json2
-rw-r--r--modules-available/baseconfig/lang/en/template-tags.json1
-rw-r--r--modules-available/baseconfig/templates/_page.html28
-rw-r--r--modules-available/baseconfig_partitions_cdn/lang/de/template-tags.json2
-rw-r--r--modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json2
-rw-r--r--modules-available/baseconfig_partitions_cdn/templates/_page.html74
-rw-r--r--modules-available/dozmod/inc/pagedozmodusers.inc.php15
-rw-r--r--modules-available/dozmod/inc/pagemailtemplates.inc.php16
-rw-r--r--modules-available/dozmod/lang/de/template-tags.json7
-rw-r--r--modules-available/dozmod/lang/en/template-tags.json17
-rw-r--r--modules-available/dozmod/page.inc.php45
-rw-r--r--modules-available/dozmod/permissions/permissions.json12
-rw-r--r--modules-available/dozmod/style.css13
-rw-r--r--modules-available/dozmod/templates/actionlog-log.html84
-rw-r--r--modules-available/dozmod/templates/images-delete.html34
-rw-r--r--modules-available/dozmod/templates/mailconfig.html41
-rw-r--r--modules-available/dozmod/templates/orglist.html18
-rw-r--r--modules-available/dozmod/templates/runtimeconfig.html18
-rw-r--r--modules-available/dozmod/templates/templates.html170
-rw-r--r--modules-available/dozmod/templates/userlist.html48
-rw-r--r--modules-available/eventlog/lang/de/template-tags.json2
-rw-r--r--modules-available/eventlog/lang/en/module.json2
-rw-r--r--modules-available/eventlog/lang/en/template-tags.json2
-rw-r--r--modules-available/eventlog/templates/_page.html13
-rw-r--r--modules-available/exams/config.json2
-rw-r--r--modules-available/exams/lang/de/template-tags.json3
-rw-r--r--modules-available/exams/lang/en/module.json2
-rw-r--r--modules-available/exams/lang/en/template-tags.json13
-rw-r--r--modules-available/exams/page.inc.php4
-rw-r--r--modules-available/exams/style.css8
-rw-r--r--modules-available/exams/templates/page-add-edit-exam.html219
-rw-r--r--modules-available/exams/templates/page-exams-vis.html13
-rw-r--r--modules-available/exams/templates/page-exams.html113
-rw-r--r--modules-available/exams/templates/page-upcoming-lectures.html99
-rw-r--r--modules-available/internetaccess/lang/en/template-tags.json2
-rw-r--r--modules-available/internetaccess/page.inc.php47
-rw-r--r--modules-available/internetaccess/permissions/permissions.json3
-rw-r--r--modules-available/internetaccess/style.css3
-rw-r--r--modules-available/internetaccess/templates/_page.html64
-rw-r--r--modules-available/js_stupidtable/clientscript.js181
-rw-r--r--modules-available/js_stupidtable/style.css3
-rw-r--r--modules-available/locations/inc/location.inc.php3
-rw-r--r--modules-available/locations/lang/de/template-tags.json5
-rw-r--r--modules-available/locations/lang/en/template-tags.json7
-rw-r--r--modules-available/locations/page.inc.php102
-rw-r--r--modules-available/locations/permissions/permissions.json9
-rw-r--r--modules-available/locations/style.css13
-rw-r--r--modules-available/locations/templates/location-subnets.html134
-rw-r--r--modules-available/locations/templates/locations.html83
-rw-r--r--modules-available/locations/templates/subnets.html17
-rw-r--r--modules-available/minilinux/templates/filelist.html7
-rw-r--r--modules-available/news/config.json3
-rw-r--r--modules-available/news/page.inc.php61
-rw-r--r--modules-available/news/permissions/permissions.json6
-rw-r--r--modules-available/news/style.css4
-rw-r--r--modules-available/news/templates/page-news.html65
-rw-r--r--modules-available/permissionmanager/api.inc.php7
-rw-r--r--modules-available/permissionmanager/clientscript.js48
-rw-r--r--modules-available/permissionmanager/config.json4
-rw-r--r--modules-available/permissionmanager/inc/getpermissiondata.inc.php90
-rw-r--r--modules-available/permissionmanager/inc/permissiondbupdate.inc.php53
-rw-r--r--modules-available/permissionmanager/inc/permissionutil.inc.php108
-rw-r--r--modules-available/permissionmanager/install.inc.php86
-rw-r--r--modules-available/permissionmanager/lang/de/module.json4
-rw-r--r--modules-available/permissionmanager/lang/de/template-tags.json25
-rw-r--r--modules-available/permissionmanager/lang/en/module.json4
-rw-r--r--modules-available/permissionmanager/lang/en/template-tags.json25
-rw-r--r--modules-available/permissionmanager/page.inc.php193
-rw-r--r--modules-available/permissionmanager/style.css88
-rw-r--r--modules-available/permissionmanager/templates/_page.html29
-rw-r--r--modules-available/permissionmanager/templates/locationstable.html37
-rw-r--r--modules-available/permissionmanager/templates/roleeditor.html78
-rw-r--r--modules-available/permissionmanager/templates/rolestable.html91
-rw-r--r--modules-available/permissionmanager/templates/treenode.html11
-rw-r--r--modules-available/permissionmanager/templates/treepanel.html13
-rw-r--r--modules-available/permissionmanager/templates/userstable.html170
-rw-r--r--modules-available/rebootcontrol/clientscript.js22
-rw-r--r--modules-available/rebootcontrol/lang/de/template-tags.json1
-rw-r--r--modules-available/rebootcontrol/lang/en/template-tags.json1
-rw-r--r--modules-available/rebootcontrol/templates/_page.html13
-rw-r--r--modules-available/rebootcontrol/templates/status.html4
-rw-r--r--modules-available/serversetup-bwlp/lang/de/module.json2
-rw-r--r--modules-available/serversetup-bwlp/lang/de/template-tags.json1
-rw-r--r--modules-available/serversetup-bwlp/lang/en/template-tags.json5
-rw-r--r--modules-available/serversetup-bwlp/page.inc.php2
-rw-r--r--modules-available/serversetup-bwlp/templates/heading.html1
-rw-r--r--modules-available/serversetup-bwlp/templates/ipxe.html22
-rw-r--r--modules-available/statistics/lang/de/template-tags.json3
-rw-r--r--modules-available/statistics/lang/en/template-tags.json7
-rw-r--r--modules-available/statistics/page.inc.php10
-rw-r--r--modules-available/statistics/style.css11
-rw-r--r--modules-available/statistics/templates/clientlist.html146
-rw-r--r--modules-available/statistics/templates/cpumodels.html58
-rw-r--r--modules-available/statistics/templates/filterbox.html100
-rw-r--r--modules-available/statistics/templates/id44.html46
-rw-r--r--modules-available/statistics/templates/kvmstate.html30
-rw-r--r--modules-available/statistics/templates/machine-notes.html3
-rw-r--r--modules-available/statistics/templates/memory.html46
-rw-r--r--modules-available/statistics/templates/newclients.html54
-rw-r--r--modules-available/statistics_reporting/lang/de/template-tags.json2
-rw-r--r--modules-available/statistics_reporting/lang/en/template-tags.json2
-rw-r--r--modules-available/statistics_reporting/page.inc.php78
-rw-r--r--modules-available/statistics_reporting/permissions/permissions.json10
-rw-r--r--modules-available/statistics_reporting/style.css6
-rw-r--r--modules-available/statistics_reporting/templates/columnChooser.html127
-rw-r--r--modules-available/statistics_reporting/templates/table-client.html2
-rw-r--r--modules-available/statistics_reporting/templates/table-location.html2
-rw-r--r--modules-available/statistics_reporting/templates/table-total.html2
-rw-r--r--modules-available/statistics_reporting/templates/table-user.html2
-rw-r--r--modules-available/statistics_reporting/templates/table-vm.html2
-rw-r--r--modules-available/sysconfig/lang/de/template-tags.json2
-rw-r--r--modules-available/sysconfig/lang/en/template-tags.json2
-rw-r--r--modules-available/sysconfig/page.inc.php3
-rw-r--r--modules-available/sysconfig/templates/ad-start.html33
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-checkconnection.html4
-rw-r--r--modules-available/sysconfig/templates/branding-check.html3
-rw-r--r--modules-available/sysconfig/templates/branding-start.html4
-rw-r--r--modules-available/sysconfig/templates/cfg-finish.html8
-rw-r--r--modules-available/sysconfig/templates/cfg-start.html5
-rw-r--r--modules-available/sysconfig/templates/custom-upload.html1
-rw-r--r--modules-available/sysconfig/templates/ldap-start.html36
-rw-r--r--modules-available/sysconfig/templates/list-configs.html8
-rw-r--r--modules-available/sysconfig/templates/list-modules.html8
-rw-r--r--modules-available/sysconfig/templates/sshconfig-start.html13
-rw-r--r--modules-available/sysconfig/templates/start.html2
-rw-r--r--modules-available/sysconfig/templates/sysconfig_heading.html1
-rw-r--r--modules-available/syslog/lang/de/template-tags.json3
-rw-r--r--modules-available/syslog/lang/en/template-tags.json3
-rw-r--r--modules-available/syslog/templates/page-syslog.html46
-rw-r--r--modules-available/systemstatus/lang/de/template-tags.json3
-rw-r--r--modules-available/systemstatus/lang/en/template-tags.json3
-rw-r--r--modules-available/systemstatus/page.inc.php4
-rw-r--r--modules-available/systemstatus/templates/_page.html22
-rw-r--r--modules-available/translation/lang/de/template-tags.json4
-rw-r--r--modules-available/translation/lang/en/template-tags.json4
-rw-r--r--modules-available/translation/templates/edit.html145
-rw-r--r--modules-available/translation/templates/module-heading.html2
-rw-r--r--modules-available/translation/templates/module-list.html45
-rw-r--r--modules-available/vmstore/lang/en/module.json4
-rw-r--r--modules-available/vmstore/lang/en/template-tags.json2
-rw-r--r--modules-available/vmstore/templates/page-vmstore.html128
-rw-r--r--modules-available/webinterface/lang/de/template-tags.json1
-rw-r--r--modules-available/webinterface/lang/en/template-tags.json1
-rw-r--r--modules-available/webinterface/page.inc.php1
-rw-r--r--modules-available/webinterface/templates/customization.html2
-rw-r--r--modules-available/webinterface/templates/heading.html1
-rw-r--r--modules-available/webinterface/templates/https.html37
-rw-r--r--modules-available/webinterface/templates/passwords.html16
-rw-r--r--style/default.css98
154 files changed, 3482 insertions, 1213 deletions
diff --git a/inc/user.inc.php b/inc/user.inc.php
index f7688b00..13e56cd3 100644
--- a/inc/user.inc.php
+++ b/inc/user.inc.php
@@ -26,13 +26,28 @@ class User
return self::$user['fullname'];
}
- public static function hasPermission($permission)
+ public static function hasPermission($permission, $locationid = NULL)
{
if (!self::isLoggedIn())
return false;
+ if (Module::isAvailable("permissionmanager")) {
+ $module = Page::getModule();
+ $permission = $module ? $module->getIdentifier().".".$permission : $permission;
+ return PermissionUtil::userHasPermission(self::$user['userid'], $permission, $locationid);
+ }
return (self::$user['permissions'] & (Permission::get($permission) | Permission::get('superadmin'))) != 0;
}
+ public static function getAllowedLocations($permission)
+ {
+ if (Module::isAvailable("permissionmanager")) {
+ $module = Page::getModule();
+ $permission = $module ? $module->getIdentifier().".".$permission : $permission;
+ return PermissionUtil::getAllowedLocations(self::$user['userid'], $permission);
+ }
+ return array();
+ }
+
public static function load()
{
if (self::isLoggedIn())
diff --git a/modules-available/backup/lang/en/template-tags.json b/modules-available/backup/lang/en/template-tags.json
index 027510f0..8cb131f7 100644
--- a/modules-available/backup/lang/en/template-tags.json
+++ b/modules-available/backup/lang/en/template-tags.json
@@ -1,7 +1,7 @@
{
"lang_backup": "Backup",
"lang_backupDescription": "Here you can backup the complete configuration of this satellite server. This includes lecture and virtual machine meta data. The HDD images of the virtual machines on the vm store are not included in this backup, because of their size. If desired, the store needs to be backed up manually.",
- "lang_backupRestore": "Backup and restore",
+ "lang_backupRestore": "Backup and Restore",
"lang_browseForFile": "Browse",
"lang_download": "Download",
"lang_dozmodExplanation": "This restores all the virtual machine and lecture meta data created using the \"Dozentenmodul\". Please make sure the VM-storage configured still contains all the VM-Images associated with the virtual machines. If the location of the storage changed, make sure the relative pathes on the share are still the same, otherwise the virtual machines won't be usable.",
diff --git a/modules-available/backup/templates/_page.html b/modules-available/backup/templates/_page.html
index 0f609f1d..7276bf5c 100644
--- a/modules-available/backup/templates/_page.html
+++ b/modules-available/backup/templates/_page.html
@@ -7,7 +7,7 @@
<div class="panel-heading">{{lang_backup}}</div>
<div class="panel-body">
<p>{{lang_backupDescription}}</p>
- <button class="btn btn-primary" type="submit">{{lang_download}}</button>
+ <button class="btn btn-primary pull-right" type="submit"><span class="glyphicon glyphicon-save"></span> {{lang_download}}</button>
<div class="text-right">
{{lang_lastBackup}}:
{{^last_backup}}{{lang_unknown}}{{/last_backup}}
@@ -33,14 +33,20 @@
</span>
</div>
<div>
- <label><input type="checkbox" name="restore_openslx" checked="checked"> {{lang_restoreSystemConfig}}</label>
+ <div class="checkbox">
+ <input type="checkbox" name="restore_openslx" checked="checked">
+ <label><b>{{lang_restoreSystemConfig}}</b></label>
+ </div>
<p><i>{{lang_systemExplanation}}</i></p>
</div>
<div>
- <label><input type="checkbox" name="restore_dozmod" checked="checked"> {{lang_restoreDozmodConfig}}</label>
+ <div class="checkbox">
+ <input type="checkbox" name="restore_dozmod" checked="checked">
+ <label><b>{{lang_restoreDozmodConfig}}</b></label>
+ </div>
<p><i>{{lang_dozmodExplanation}}</i></p>
</div>
- <button class="btn btn-primary" type="submit">{{lang_restore}}</button>
+ <button class="btn btn-primary pull-right" type="submit"><span class="glyphicon glyphicon-open"></span> {{lang_restore}}</button>
</div>
</div>
</form> \ No newline at end of file
diff --git a/modules-available/baseconfig/lang/de/module.json b/modules-available/baseconfig/lang/de/module.json
index 461bebdb..44b51ec3 100644
--- a/modules-available/baseconfig/lang/de/module.json
+++ b/modules-available/baseconfig/lang/de/module.json
@@ -1,3 +1,3 @@
{
- "module_name": "KonfigurationsVariablen"
+ "module_name": "Konfigurationsvariablen"
} \ No newline at end of file
diff --git a/modules-available/baseconfig/lang/de/template-tags.json b/modules-available/baseconfig/lang/de/template-tags.json
index 7d6da790..b96586bd 100644
--- a/modules-available/baseconfig/lang/de/template-tags.json
+++ b/modules-available/baseconfig/lang/de/template-tags.json
@@ -2,6 +2,7 @@
"lang_basicConfiguration": "Basiskonfiguration",
"lang_clientRelatedConfig": "Die Optionen auf dieser Seite beziehen sich auf das Verhalten der bwLehrpool-Clients.",
"lang_defaultValue": "Standard",
+ "lang_discardChanges": "Änderungen verwerfen",
"lang_editOverrideNotice": "Sie bearbeiten die Einstellungen f\u00fcr einen Unterbereich",
"lang_enableOverride": "\u00dcberschreiben",
"lang_inheritSource": "Geerbt von",
diff --git a/modules-available/baseconfig/lang/en/module.json b/modules-available/baseconfig/lang/en/module.json
index 48591f88..9ad9d10f 100644
--- a/modules-available/baseconfig/lang/en/module.json
+++ b/modules-available/baseconfig/lang/en/module.json
@@ -1,3 +1,3 @@
{
- "module_name": "Config variables"
+ "module_name": "Config Variables"
} \ No newline at end of file
diff --git a/modules-available/baseconfig/lang/en/template-tags.json b/modules-available/baseconfig/lang/en/template-tags.json
index 1a32cb0d..b39bf9aa 100644
--- a/modules-available/baseconfig/lang/en/template-tags.json
+++ b/modules-available/baseconfig/lang/en/template-tags.json
@@ -2,6 +2,7 @@
"lang_basicConfiguration": "Basic Configuration",
"lang_clientRelatedConfig": "The options on this page are related to the bwLehrpool client machines.",
"lang_defaultValue": "Default",
+ "lang_discardChanges": "Discard Changes",
"lang_editOverrideNotice": "You're editing the settings of a sub-section",
"lang_enableOverride": "Override",
"lang_inheritSource": "Inherited from",
diff --git a/modules-available/baseconfig/templates/_page.html b/modules-available/baseconfig/templates/_page.html
index e0be35bc..f2dfd17b 100644
--- a/modules-available/baseconfig/templates/_page.html
+++ b/modules-available/baseconfig/templates/_page.html
@@ -50,9 +50,12 @@
<div class="modal fade" id="help-{{setting}}" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{setting}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">&times;</button>
+ <h4 class="modal-title"><b>{{setting}}</b></h4>
+
+ </div>
<div class="modal-body">{{{description}}}</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
@@ -61,14 +64,19 @@
</div>
</div>
{{/categories}}
- <button class="btn btn-primary" type="submit">{{lang_save}}</button>
- <button class="btn btn-default" type="reset">{{lang_reset}}</button>
- {{^override}}
- <a class="btn btn-default" href="api.php?do=baseconfig&amp;user={{userid}}">Download</a>
- {{/override}}
- {{#override}}
- <a class="btn btn-default" href="api.php?do=baseconfig&amp;user={{userid}}&amp;module={{target_module}}&amp;value={{field_value}}&amp;force=1">Download</a>
- {{/override}}
+ <div class="text-right">
+ <button class="btn btn-warning" type="button" onclick="window.location.hash = '#bottom'; window.location.reload(true);"><span class="glyphicon glyphicon-refresh"></span> {{lang_discardChanges}}</button>
+ <a name="bottom"></a>
+ {{^override}}
+ <a class="btn btn-default" href="api.php?do=baseconfig&amp;user={{userid}}"><span class="glyphicon glyphicon-download-alt"></span> Download</a>
+ {{/override}}
+ {{#override}}
+ <a class="btn btn-default" href="api.php?do=baseconfig&amp;user={{userid}}&amp;module={{target_module}}&amp;value={{field_value}}&amp;force=1">Download</a>
+ {{/override}}
+ <button class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+ <br/>
+
</form>
<script type="text/javascript">
diff --git a/modules-available/baseconfig_partitions_cdn/lang/de/template-tags.json b/modules-available/baseconfig_partitions_cdn/lang/de/template-tags.json
index ea4f9f5c..99e0a487 100644
--- a/modules-available/baseconfig_partitions_cdn/lang/de/template-tags.json
+++ b/modules-available/baseconfig_partitions_cdn/lang/de/template-tags.json
@@ -1,6 +1,8 @@
{
+ "lang_areYouSureNoUndo": "Sind Sie sicher? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
"lang_confirm": "Wollen Sie die Einstellungen unter \/srv\/openslx\/www\/boot\/config speichern?",
"lang_create": "Anlegen",
+ "lang_discardChanges": "Änderungen verwerfen",
"lang_explanationText": "Hier k\u00f6nnen Sie bestimmen, welche Partitionen auf dem Client angelegt werden.",
"lang_helpId": "Partitions-ID",
"lang_helpMountPoint": "Muss ein Absolutes Verzeichnis im Zieldateisystem sein, z.B. \/mnt\/shares\/data",
diff --git a/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json b/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json
index 819d2273..04ce6c80 100644
--- a/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json
+++ b/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json
@@ -1,6 +1,8 @@
{
+ "lang_areYouSureNoUndo": "Are you sure? This cannot be undone!",
"lang_confirm": "Would you like to save the settings on [ \/srv\/openslx\/www\/boot\/config ] ?",
"lang_create": "Create",
+ "lang_discardChanges": "Discard Changes",
"lang_explanationText": "Here you can configure what kind of partitions will be created on the client computers, and where they will be mounted",
"lang_helpId": "Partition Id",
"lang_helpMountPoint": "Must be a directory: \/example\/directory\/",
diff --git a/modules-available/baseconfig_partitions_cdn/templates/_page.html b/modules-available/baseconfig_partitions_cdn/templates/_page.html
index f7331186..71cbb7db 100644
--- a/modules-available/baseconfig_partitions_cdn/templates/_page.html
+++ b/modules-available/baseconfig_partitions_cdn/templates/_page.html
@@ -23,7 +23,6 @@
<div class='col-sm-1 col-md-2'>
<a class='btn btn-danger' href='?do=BaseConfig_Partitions_CDN&amp;deletePartition={{id}}&amp;token={{token}}'>
<span class='glyphicon glyphicon-trash'></span>
- <span class="hidden-sm">{{lang_delete}}</span>
</a>
</div>
</div>
@@ -31,24 +30,52 @@
{{/partitions}}
<div class='list-group-item clearfix'>
<div class="pull-right">
- <a class='btn btn-default ' data-toggle='modal' data-target='#add-partition'>
+ <a class='btn btn-success ' data-toggle='modal' data-target='#add-partition'>
<span class='glyphicon glyphicon-plus'></span> {{lang_newPartition}}
</a>
</div>
</div>
</div>
- <button class="btn btn-lg btn-primary" type="submit">{{lang_save}}</button>
- <button class="btn btn-lg btn-primary" type="reset">{{lang_reset}}</button>
- <a class="btn btn-lg btn-primary" href="#" onclick="saveConfig()">Download</a>
+ <div class="pull-right">
+ <a class="btn btn-default" data-toggle="modal" data-target="#downloadModal"><span class="glyphicon glyphicon-download-alt"></span> Download</a>
+ <button class="btn btn-warning" type="reset"><span class="glyphicon glyphicon-refresh"></span> {{lang_discardChanges}}</button>
+ <button class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+
+ <div class ="modal fade" id="downloadModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_confirm}}
+ </div>
+ <div class="modal-footer">
+ <button type="button" onclick="saveConfig(false)" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="button" onclick="saveConfig(true)" class="btn btn-sm btn-danger" name="download"> Download</button>
+ </div>
+ </div>
+ </div>
+ </div>
</form>
-<div>
- <form method="post" action="?do=BaseConfig_Partitions_CDN">
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="action" value="reset">
- <button class="btn btn-default" type="submit" onclick="return confirm('{{lang_resetConfirm}}');">{{lang_resetDefault}}</button>
- </form>
-</div>
+<form method="post" action="?do=BaseConfig_Partitions_CDN">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="reset">
+ <button class="btn btn-danger" type="button" data-toggle="modal" data-target="#resetDefaultModal">{{lang_resetDefault}}</button>
+
+ <div class ="modal fade" id="resetDefaultModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_areYouSureNoUndo}}
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" class="btn btn-sm btn-danger" name="resetDefault"> {{lang_resetDefault}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+</form>
<!-- Create Partition Window -->
<form action="?do=BaseConfig_Partitions_CDN" method="post">
@@ -56,32 +83,37 @@
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_newPartition}}</div>
- <div class="modal-body">
+ <div class="modal-header">
+ <h4><b>{{lang_newPartition}}</b></h4>
+ </div>
+ <div class="modal-body">
<div class="input-group">
- <span class="input-group-addon">{{lang_partitionId}}</span>
+ <span class="input-group-addon" style="min-width:140px;">{{lang_partitionId}}</span>
<input name="new-partition-id" class="form-control" type="text">
</div>
<p class="help-block">{{lang_helpId}}</p>
<div class="input-group">
- <span class="input-group-addon">{{lang_partitionSize}}</span>
+ <span class="input-group-addon" style="min-width:140px;">{{lang_partitionSize}}</span>
<input name="new-partition-size" class="form-control" type="text">
</div>
<p class="help-block">{{lang_helpSize}}</p>
<div class="input-group">
- <span class="input-group-addon">{{lang_partitionMountPoint}}</span>
+ <span class="input-group-addon" style="min-width:140px;">{{lang_partitionMountPoint}}</span>
<input name="new-partition-mount-point" class="form-control" type="text">
</div>
<p class="help-block">{{lang_helpMountPoint}}</p>
<div class="input-group">
- <span class="input-group-addon">{{lang_partitionOptions}}</span>
+ <span class="input-group-addon" style="min-width:140px;">{{lang_partitionOptions}}</span>
<input name="new-partition-options" class="form-control" type="text">
</div>
<p class="help-block">{{lang_helpOptions}}</p>
+ </div>
+
+ <div class="modal-footer">
+ <a class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</a>
<input type="submit" class="btn btn-primary" value="{{lang_create}}">
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
@@ -89,8 +121,8 @@
<input type="hidden" name="token" value="{{token}}">
</form>
<script type="text/javascript">
- function saveConfig(){
- if(confirm('{{lang_confirm}}'))
+ function saveConfig(download){
+ if(download)
window.location = 'api.php?do=baseconfig&user={{user}}&save=true';
else
window.location = 'api.php?do=baseconfig&user={{user}}';
diff --git a/modules-available/dozmod/inc/pagedozmodusers.inc.php b/modules-available/dozmod/inc/pagedozmodusers.inc.php
index 8da07923..621f7d34 100644
--- a/modules-available/dozmod/inc/pagedozmodusers.inc.php
+++ b/modules-available/dozmod/inc/pagedozmodusers.inc.php
@@ -16,11 +16,22 @@ class Page_dozmod_users extends Page
protected function doAjax()
{
+ User::load();
+
$action = Request::post('action', '', 'string');
if ($action === 'setmail' || $action === 'setsu' || $action == 'setlogin') {
- $this->setUserOption($action);
+ if (User::hasPermission("users.".$action)) {
+ $this->setUserOption($action);
+ } else {
+ die("No permission.");
+ }
+
} elseif ($action === 'setorglogin') {
- $this->setOrgOption($action);
+ if (User::hasPermission("users.orglogin")) {
+ $this->setOrgOption($action);
+ } else {
+ die("No permission.");
+ }
} else {
die('No such action');
}
diff --git a/modules-available/dozmod/inc/pagemailtemplates.inc.php b/modules-available/dozmod/inc/pagemailtemplates.inc.php
index dc41d8c6..90734a50 100644
--- a/modules-available/dozmod/inc/pagemailtemplates.inc.php
+++ b/modules-available/dozmod/inc/pagemailtemplates.inc.php
@@ -7,13 +7,25 @@ class Page_mail_templates extends Page
protected function doPreprocess()
{
+ User::load();
+
$action = Request::post('action', 'show', 'string');
if ($action === 'show') {
$this->fetchTemplates();
} elseif ($action === 'save') {
- $this->handleSave();
+ if (User::hasPermission("templates.save")) {
+ $this->handleSave();
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=dozmod&section=templates');
+ }
} elseif ($action === 'reset') {
- $this->handleReset();
+ if(User::hasPermission("templates.reset")) {
+ $this->handleReset();
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=dozmod&section=templates');
+ }
} else {
Message::addError('main.invalid-action', $action);
Util::redirect('?do=dozmod&section=templates');
diff --git a/modules-available/dozmod/lang/de/template-tags.json b/modules-available/dozmod/lang/de/template-tags.json
index ad4f1142..4b49579a 100644
--- a/modules-available/dozmod/lang/de/template-tags.json
+++ b/modules-available/dozmod/lang/de/template-tags.json
@@ -4,6 +4,7 @@
"lang_allowLoginDescription": "Wenn diese Option aktiviert ist, k\u00f6nnen sich alle Mitarbeiter der Einrichtung \u00fcber die bwLehrpool-Suite anmelden und VMs\/Veranstaltungen verwalten. Wenn Sie diese Option deaktivieren, m\u00fcssen Sie in der Untersektion \"Benutzer und Berechtigungen\" jeden Benutzer nach dem ersten Loginversuch manuell freischalten.",
"lang_asteriskRequired": "Felder mit (*) sind erforderlich",
"lang_blockCount": "Anzahl Bl\u00f6cke",
+ "lang_bwlehrpoolsuite": "bwLehrpool-Suite",
"lang_canLoginOrganization": "Nutzer dieser Einrichtung k\u00f6nnen sich am Satelliten anmelden",
"lang_canLoginUser": "Nutzer kann sich am Satelliten anmelden",
"lang_createTime": "Erstellt",
@@ -54,11 +55,12 @@
"lang_os": "Betriebssystem",
"lang_owner": "Besitzer",
"lang_password": "Passwort",
+ "lang_passwordplaceholder": "SMTP 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_replaceWithOriginal": "Originaltext in Textbox laden",
- "lang_replyTo": "Reply-To Adresse (z.B. Helpdesk)",
+ "lang_replyTo": "Reply-To Adresse",
"lang_runtimeConfig": "Laufzeit-Konfiguration",
"lang_runtimeConfigHeadline": "Laufzeit-Konfiguration",
"lang_runtimeConfigLimits": "Beschr\u00e4nkungen",
@@ -85,7 +87,8 @@
"lang_userList": "Benutzerliste",
"lang_userListDescription": "Hier k\u00f6nnen Sie individuelle Nutzer zu \"Super-Usern\" machen. Diese haben in der bwLehrpool-Suite auf alle Veranstaltungen und VMs Vollzugriff, unabh\u00e4ngig von den gesetzten Berechtigungen. Au\u00dferdem k\u00f6nnen Sie hier Benutzer vom Zugriff mittels der bwLehrpool-Suite ausschlie\u00dfen.",
"lang_userListHeader": "Dem Satelliten bekannte Benutzer",
- "lang_username": "Benutzername (SMTP-Auth)",
+ "lang_username": "Benutzername",
+ "lang_usernameplaceholder": "SMTP Benutzername",
"lang_version": "Version vom",
"lang_when": "Wann"
} \ 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 875ca374..ed8f3465 100644
--- a/modules-available/dozmod/lang/en/template-tags.json
+++ b/modules-available/dozmod/lang/en/template-tags.json
@@ -4,6 +4,7 @@
"lang_allowLoginDescription": "If this option is enabled, all members of the organization marked as staff or employee are allowed to login to this server and manage VMs\/courses. Otherwise, new users need to be individually allowed access after their first login attempt by visiting the sub page \"users and permissions\" in this web interface.",
"lang_asteriskRequired": "Fields marked with (*) are required",
"lang_blockCount": "Block count",
+ "lang_bwlehrpoolsuite": "bwLehrpool-Suite",
"lang_canLoginOrganization": "Users from this organization can login",
"lang_canLoginUser": "This user can login",
"lang_createTime": "Created",
@@ -28,7 +29,7 @@
"lang_followingPlaceholdersUnused": "The following placeholders are not being used",
"lang_hasNewer": "Newer version exists",
"lang_hash": "Hash",
- "lang_heading": "Images marked for deletion",
+ "lang_heading": "Images Marked for Deletion",
"lang_host": "Host",
"lang_image": "VM",
"lang_lastEditor": "Edited by",
@@ -39,9 +40,9 @@
"lang_lecturePermissionEdit": "Edit",
"lang_loadDefaults": "Reset all templates to their defaults",
"lang_mailConfig": "SMTP configuration for sending mails",
- "lang_mailConfigHeadline": "email configuration",
+ "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_mailTemplates": "E-Mail Templates",
"lang_maxImageValidity": "New VM validity (days)",
"lang_maxLectureVisibility": "Max time lecture end date may lie in the future (days)",
"lang_maxLocationsPerLecture": "Max. explicit locations per lecture",
@@ -49,18 +50,19 @@
"lang_miscOptions": "Misc options",
"lang_modified": "modified",
"lang_organization": "Organization",
- "lang_organizationList": "List of organizations",
+ "lang_organizationList": "List of Organizations",
"lang_organizationListHeader": "Set access permissions for organizations",
"lang_os": "Operating System",
"lang_owner": "Owner",
"lang_password": "Password",
+ "lang_passwordplaceholder": "SMTP Password",
"lang_placeholders": "Placeholders",
"lang_port": "Port",
"lang_reallyResetTemplates": "Are you sure you want to reset all texts to their default values?",
"lang_replaceWithOriginal": "load original text into text box",
"lang_replyTo": "Reply-To address",
"lang_runtimeConfig": "Limits and Defaults",
- "lang_runtimeConfigHeadline": "Configure limits and defaults for bwLehrpool-Suite",
+ "lang_runtimeConfigHeadline": "Configure Limits and Defaults for bwLehrpool-Suite",
"lang_runtimeConfigLimits": "Limitations",
"lang_senderAddress": "Sender address",
"lang_senderName": "Sender's display name",
@@ -82,10 +84,11 @@
"lang_updateTime": "Last update",
"lang_user": "User name",
"lang_userId": "User id",
- "lang_userList": "User list",
+ "lang_userList": "User List",
"lang_userListDescription": "Here you can promote \"super users\", which will have all permissions in the bwLehrpool-Suite. You can also ban users from accessing this server via the bwLehrpool-Suite.",
"lang_userListHeader": "Users known to this satellite",
- "lang_username": "User name (SMTP auth)",
+ "lang_username": "Username",
+ "lang_usernameplaceholder": "SMTP Username",
"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 548084a2..ffb38663 100644
--- a/modules-available/dozmod/page.inc.php
+++ b/modules-available/dozmod/page.inc.php
@@ -27,7 +27,7 @@ class Page_DozMod extends Page
{
User::load();
- if (!User::hasPermission('superadmin')) {
+ if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
Util::redirect('?do=Main');
}
@@ -50,15 +50,30 @@ class Page_DozMod extends Page
$action = Request::post('action', false, 'string');
if ($action === 'mail') {
- $this->mailHandler();
+ if (User::hasPermission("mail.save")) {
+ $this->mailHandler();
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=dozmod&section=mailconfig');
+ }
} elseif ($action === 'runtime') {
- $this->runtimeHandler();
+ if (User::hasPermission("runtimeconfig.save")) {
+ $this->runtimeHandler();
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=dozmod&section=runtimeconfig');
+ }
} elseif ($action === 'delimages') {
- $result = $this->handleDeleteImages();
- if (!empty($result)) {
- Message::addInfo('delete-images', $result);
+ if (User::hasPermission("images.delete")) {
+ $result = $this->handleDeleteImages();
+ if (!empty($result)) {
+ Message::addInfo('delete-images', $result);
+ }
+ Util::redirect('?do=DozMod');
+ } else {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=dozmod');
}
- Util::redirect('?do=DozMod');
} elseif ($action !== false) {
Util::traceError('Invalid action: ' . $action);
}
@@ -180,6 +195,7 @@ class Page_DozMod extends Page
$row['name_extra_class'] = 'slx-strike';
}
$row['version'] = date('d.m.Y H:i:s', $row['createtime']);
+ $row['rawfilesize'] = $row['filesize'];
$row['filesize'] = Util::readableFileSize($row['filesize']);
$rows[] = $row;
}
@@ -203,8 +219,6 @@ class Page_DozMod extends Page
protected function doAjax()
{
User::load();
- if (!User::hasPermission('superadmin'))
- return;
$this->setupSubPage();
if ($this->subPage !== false) {
@@ -213,10 +227,19 @@ class Page_DozMod extends Page
}
$action = Request::post('action');
+
if ($action === 'mail') {
- $this->handleTestMail();
+ if (User::hasPermission("mail.testmail")) {
+ $this->handleTestMail();
+ } else {
+ die('No permission');
+ }
} elseif ($action === 'delimages') {
- die($this->handleDeleteImages());
+ if (User::hasPermission("images.delete")) {
+ die($this->handleDeleteImages());
+ } else {
+ die('No permission');
+ }
} elseif ($action === 'getblockinfo') {
$this->ajaxGetBlockInfo();
}
diff --git a/modules-available/dozmod/permissions/permissions.json b/modules-available/dozmod/permissions/permissions.json
new file mode 100644
index 00000000..8295d0f0
--- /dev/null
+++ b/modules-available/dozmod/permissions/permissions.json
@@ -0,0 +1,12 @@
+{
+ "images.delete": "Delete images marked for deletion.",
+ "mail.save": "Save SMTP configuration for sending mails.",
+ "mail.testmail": "Send a testmail.",
+ "runtimeconfig.save": "Save limits and defaults of a runtime configuration.",
+ "templates.save": "Save email templates",
+ "templates.reset": "Reset email templates",
+ "users.setmail": "Enable/Disable Email Notification",
+ "users.setlogin": "Enable/Disable Login",
+ "users.setsu": "Set User to superuser",
+ "users.orglogin": "Enalbe/Disable Login for Users from certain organisations."
+} \ No newline at end of file
diff --git a/modules-available/dozmod/style.css b/modules-available/dozmod/style.css
index 8612b426..23dd121e 100644
--- a/modules-available/dozmod/style.css
+++ b/modules-available/dozmod/style.css
@@ -36,3 +36,16 @@
.table-input-group tr.input-group td:last-child input {
border-radius: 0px 4px 4px 0px;
}
+
+.input-group-addon {
+ min-width:200px;
+ text-align: left;
+}
+
+.table > tbody > tr > td {
+ vertical-align: middle;
+}
+
+.table > tbody > tr > td > div {
+ display: inline-block;
+} \ No newline at end of file
diff --git a/modules-available/dozmod/templates/actionlog-log.html b/modules-available/dozmod/templates/actionlog-log.html
index 151d2545..09f3a183 100644
--- a/modules-available/dozmod/templates/actionlog-log.html
+++ b/modules-available/dozmod/templates/actionlog-log.html
@@ -1,41 +1,45 @@
-<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 class="text-nowrap">{{dateline_s}}</td>
- {{#showActor}}
- <td style="min-width:140px">
- {{#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 style="table-layout: fixed; width: 100%" class="table table-striped table-bordered stupidtable">
+ <thead>
+ <tr>
+ <th class="text-nowrap" data-sort="int">{{lang_when}}</th>
+ {{#showActor}}
+ <th class="text-nowrap" data-sort="string">{{lang_user}}</th>
+ {{/showActor}}
+ {{#showTarget}}
+ <th class="text-nowrap" data-sort="string">{{lang_actionTarget}}</th>
+ {{/showTarget}}
+ <th class="text-nowrap" data-sort="string">{{lang_event}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#events}}
+ <tr>
+ <td class="text-nowrap" data-sort-value="{{dateline}}">{{dateline_s}}</td>
+ {{#showActor}}
+ <td style="min-width:140px">
+ {{#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 style="word-wrap: break-word">
+ {{#targeturl}}
+ <a href="{{targeturl}}">{{targetname}}</a>
+ {{/targeturl}}
+ {{^targeturl}}
+ {{targetname}}
+ {{^targetname}}
+ <span class="small">{{targetid}}</span>
+ {{/targetname}}
+ {{/targeturl}}
+ </td>
+ {{/showTarget}}
+ <td style="word-wrap: break-word">{{description}}</td>
+ </tr>
+ {{/events}}
+ </tbody>
</table> \ 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 0ee90835..dd4c61bc 100644
--- a/modules-available/dozmod/templates/images-delete.html
+++ b/modules-available/dozmod/templates/images-delete.html
@@ -1,8 +1,8 @@
-<h2>{{lang_heading}}</h2>
+<h1>{{lang_bwlehrpoolsuite}}</h1>
<div class="panel panel-default">
<div class="panel-heading">
- {{lang_subHeading}}
+ {{lang_heading}}
</div>
<div class="panel-body">
<p>{{lang_description_delete_images}}</p>
@@ -10,17 +10,20 @@
<form id="delform" method="post" action="?do=DozMod" onsubmit="return slxPostdel()">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="delimages">
- <table class="table table-stripped table-condensed">
+ <table class="table table-stripped table-condensed stupidtable">
<thead>
<tr>
- <th>{{lang_image}}</th>
- <th>{{lang_version}}</th>
- <th>{{lang_owner}}</th>
+ <th data-sort="string">{{lang_image}}</th>
+ <th data-sort="int">{{lang_version}}</th>
+ <th data-sort="string">{{lang_owner}}</th>
<th><span class="glyphicon glyphicon-upload" title="{{lang_hasNewer}}"></span></th>
- <th>{{lang_size}}</th>
+ <th data-sort="int">{{lang_size}}</th>
<th>
- <input id="del-all" type="checkbox" onclick="slxChangeAll()">
- <span class="glyphicon glyphicon-trash" title="{{lang_delete}}"></span>
+ <div class="checkbox">
+ <input id="del-all" type="checkbox" onclick="slxChangeAll()">
+ <label for="del-all"></label>
+ <span class="glyphicon glyphicon-trash" title="{{lang_delete}}"></span>
+ </div>
</th>
</tr>
</thead>
@@ -28,16 +31,21 @@
{{#images}}
<tr>
<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" data-sort-value="{{createtime}}" >{{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>
+ <td class="text-left text-nowrap" data-sort-value="{{rawfilesize}}">{{filesize}}</td>
+ <td>
+ <div class="checkbox">
+ <input type="checkbox" id="images[{{imageversionid}}]" class="del-check" name="images[{{imageversionid}}]" {{checked}}>
+ <label for="images[{{imageversionid}}]"></label>
+ </div>
+ </td>
</tr>
{{/images}}
</tbody>
</table>
- <button id="delbtn" class="btn btn-danger" type="submit" name="button" value="save">{{lang_delButton}}</button>
+ <button style="margin-left: 20px" id="delbtn" class="btn btn-danger pull-right" type="submit" name="button" value="save"><span class="glyphicon glyphicon-trash"></span> {{lang_delButton}}</button>
</form>
<pre style="display:none" id="deloutput"></pre>
</div>
diff --git a/modules-available/dozmod/templates/mailconfig.html b/modules-available/dozmod/templates/mailconfig.html
index 4f8b81fa..6edc65ae 100644
--- a/modules-available/dozmod/templates/mailconfig.html
+++ b/modules-available/dozmod/templates/mailconfig.html
@@ -1,24 +1,25 @@
-<h2>{{lang_mailConfigHeadline}}</h2>
+<h1>{{lang_bwlehrpoolsuite}}</h1>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_mailConfig}}
</div>
<div class="panel-body">
+
<p>{{lang_mailDescription}}</p>
<form action="?do=DozMod" method="post" id="mailconf">
<input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="position:absolute;top:-2000px" tabindex="-1">
<input type="password" name="password_fake" id="password_fake" value="" style="position:absolute;top:-2000px" tabindex="-1">
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="host-id">{{lang_host}} *</label>
+ <label class="input-group-addon" for="host-id">{{lang_host}} *</label>
<input type="text" name="host" id ="host-id" class="form-control" placeholder="smtp.example.com" value="{{host}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="port-id">{{lang_port}} *</label>
+ <label class="input-group-addon" for="port-id">{{lang_port}} *</label>
<input type="text" name="port" id ="port-id" class="form-control" placeholder="465" value="{{port}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="ssl-id">{{lang_ssl}} *</label>
+ <label class="input-group-addon" for="ssl-id">{{lang_ssl}} *</label>
<select class="form-control" name="ssl" id="ssl-id">
<option value="NONE" {{set_NONE}}>{{lang_sslNone}}</option>
<option value="IMPLICIT" {{set_IMPLICIT}}>{{lang_sslImplicit}}</option>
@@ -26,40 +27,42 @@
</select>
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="senderAddress-id">{{lang_senderAddress}} *</label>
+ <label class="input-group-addon" for="senderAddress-id">{{lang_senderAddress}} *</label>
<input type="text" name="senderAddress" id ="senderAddress-id" class="form-control" placeholder="smtp-username@hs-example.com" value="{{senderAddress}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="serverName-id">{{lang_senderName}}</label>
+ <label class="input-group-addon" for="serverName-id">{{lang_senderName}}</label>
<input type="text" name="serverName" id ="serverName-id" class="form-control" placeholder="bwLehrpool HS Example" value="{{serverName}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="replyTo-id">{{lang_replyTo}}</label>
+ <label class="input-group-addon" for="replyTo-id">{{lang_replyTo}}</label>
<input type="text" name="replyTo" id ="replyTo-id" class="form-control" placeholder="helpdesk@hs-example.com" value="{{replyTo}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="username-id">{{lang_username}}</label>
- <input type="text" name="username" id ="username-id" class="form-control" placeholder="smtp-username" value="{{username}}">
+ <label class="input-group-addon" for="username-id">{{lang_username}}</label>
+ <input type="text" name="username" id ="username-id" class="form-control" placeholder="{{lang_usernameplaceholder}}" value="{{username}}">
</div>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="password-id">{{lang_password}}</label>
- <input type="{{password_type}}" name="password" id ="password-id" class="form-control" placeholder="geheim" value="{{password}}">
+ <label class="input-group-addon" for="password-id">{{lang_password}}</label>
+ <input type="{{password_type}}" name="password" id ="password-id" class="form-control" placeholder="{{lang_passwordplaceholder}}" value="{{password}}">
</div>
<p>{{lang_asteriskRequired}}</p>
<br>
<p>{{lang_testConfiguration}}</p>
<div class="input-group">
- <label class="input-group-addon slx-ga2" for="test-id">{{lang_testRecipient}}</label>
+ <label class="input-group-addon" for="test-id">{{lang_testRecipient}}</label>
<input type="text" name="recipient" id ="test-id" class="form-control" placeholder="test@example.com" value="">
</div>
<br>
- <button class="btn btn-primary btn-sm" type="button" id="test-button" name="button" value="test" onclick="slxTestConfig()">{{lang_test}}</button>
- <span id="test-spin" style="display:none"><span class="glyphicon glyphicon-refresh slx-rotation"></span></span>
- <pre id="test-output" style="display:none"></pre>
- <button class="btn btn-primary btn-sm" type="submit" name="button" value="save">{{lang_save}}</button>
- <br>
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="action" value="mail">
+ <div class="text-right">
+ <button class="btn btn-warning" type="button" id="test-button" name="button" value="test" onclick="slxTestConfig()"><span class="glyphicon glyphicon-envelope"></span> {{lang_test}}</button>
+ <span id="test-spin" style="display:none"><span class="glyphicon glyphicon-refresh slx-rotation"></span></span>
+ <pre id="test-output" style="display:none"></pre>
+ <button class="btn btn-primary" type="submit" name="button" value="save"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ <br>
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="mail">
+ </div>
</form>
</div>
</div>
diff --git a/modules-available/dozmod/templates/orglist.html b/modules-available/dozmod/templates/orglist.html
index 21495bba..361421c5 100644
--- a/modules-available/dozmod/templates/orglist.html
+++ b/modules-available/dozmod/templates/orglist.html
@@ -1,24 +1,25 @@
-<h2>{{lang_organizationList}}</h2>
-
<div class="panel panel-default">
<div class="panel-heading">
{{lang_organizationListHeader}}
</div>
<div class="panel-body">
<div class="table-responsive">
- <table class="table table-stripped table-condensed">
+ <table class="table table-stripped table-condensed table-hover stupidtable">
<thead>
<tr>
- <th>{{lang_organization}}</th>
- <th><span class="glyphicon glyphicon-ok" title="{{lang_canLoginOrganization}}"></span></th>
+ <th width="95%" data-sort="string">{{lang_organization}}</th>
+ <th width="5%"><span class="glyphicon glyphicon-ok" title="{{lang_canLoginOrganization}}"></span></th>
</tr>
</thead>
<tbody>
{{#organizations}}
<tr>
- <td class="text-left text-nowrap">{{displayname}}</td>
- <td class="text-nowrap">
- <input onclick="seto('setorglogin', this, '{{organizationid}}')" type="checkbox" {{{canlogin}}}>
+ <td width="95%" class="text-left text-nowrap">{{displayname}}</td>
+ <td width="5%">
+ <div class="checkbox">
+ <input onclick="seto('setorglogin', this, '{{organizationid}}')" type="checkbox" {{{canlogin}}}>
+ <label></label>
+ </div>
</td>
</tr>
{{/organizations}}
@@ -32,6 +33,7 @@
function seto(action, el, orgid) {
var box = $(el);
+ box = box.parent();
var v = el.checked ? '1' : '0';
var old = el.checked == true;
box.css('display', 'none');
diff --git a/modules-available/dozmod/templates/runtimeconfig.html b/modules-available/dozmod/templates/runtimeconfig.html
index 8d7300ae..cff61441 100644
--- a/modules-available/dozmod/templates/runtimeconfig.html
+++ b/modules-available/dozmod/templates/runtimeconfig.html
@@ -1,11 +1,11 @@
-<h2 id="runtime-configuration">{{lang_runtimeConfigHeadline}}</h2>
+<h1>{{lang_bwlehrpoolsuite}}</h1>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_runtimeConfig}}
</div>
<div class="panel-body">
- <h3>{{lang_defaultPermissions}}</h3>
+ <legend>{{lang_defaultPermissions}}</legend>
<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:-2000px" tabindex="-1">
@@ -13,7 +13,7 @@
<fieldset class="form-group">
- <legend>{{lang_defaultLecturePermissions}}</legend>
+ <h4>{{lang_defaultLecturePermissions}}</h4>
<input type="hidden" name="defaultLecturePermissions[edit]" value="0"/>
<input type="hidden" name="defaultLecturePermissions[admin]" value="0"/>
@@ -34,7 +34,7 @@
</fieldset>
<fieldset class="form-group">
- <legend>{{lang_defaultImagePermissions}}</legend>
+ <h4>{{lang_defaultImagePermissions}}</h4>
<input type="hidden" name="defaultImagePermissions[edit]" value="0"/>
<input type="hidden" name="defaultImagePermissions[admin]" value="0"/>
<input type="hidden" name="defaultImagePermissions[download]" value="0"/>
@@ -67,7 +67,7 @@
</fieldset>
<fieldset>
- <h3>{{lang_runtimeConfigLimits}}</h3>
+ <legend>{{lang_runtimeConfigLimits}}</legend>
<p><i>{{lang_descriptionRuntimeLimits}}</i></p>
<table class="table-input-group">
<tr class="input-group">
@@ -96,9 +96,9 @@
</tr>
</table>
</fieldset>
-
+ <br/>
<fieldset>
- <h3>{{lang_miscOptions}}</h3>
+ <legend>{{lang_miscOptions}}</legend>
<div class="checkbox">
<input type="hidden" name="allowLoginByDefault" value="0">
<input type="checkbox" name="allowLoginByDefault" value="1" {{allowLoginByDefault}} id="allowLoginByDefault" class="form-control">
@@ -112,7 +112,9 @@
<br>
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="runtime">
- <button class="btn btn-primary" type="submit" name="button" value="save">{{lang_save}}</button>
+ <div class="text-right">
+ <button class="btn btn-primary" type="submit" name="button" value="save"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
</form>
</div>
</div>
diff --git a/modules-available/dozmod/templates/templates.html b/modules-available/dozmod/templates/templates.html
index 8a3caf26..4764c0e9 100644
--- a/modules-available/dozmod/templates/templates.html
+++ b/modules-available/dozmod/templates/templates.html
@@ -1,91 +1,119 @@
-<h1>{{lang_mailTemplates}}</h1>
+<h1>{{lang_bwlehrpoolsuite}}</h1>
-<p><i>{{lang_templatePageDescription}}</i></p>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_mailTemplates}}
+ </div>
+ <div class="panel-body">
-<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">
+ <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-group" id="accordion">
- <div id="frame_{{name}}" class="panel panel-default">
- <div class="panel-heading">
- <div class="panel-title">
- {{#conflict}}
- <span class="glyphicon glyphicon-exclamation-sign pull-left text-danger"></span>
- {{/conflict}}
- {{#modified}}
- <span class="glyphicon glyphicon-pencil pull-left"></span>
- {{/modified}}
- <h4>
- <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#panel_{{name}}">
- {{name}}
- </a>
- </h4>
- <small>{{description}}</small>
+ {{#templates}}
- </div>
- </div>
- <div id="panel_{{name}}" class="panel-collapse collapse">
- <div class="panel-body">
- <div id="msgbox_{{name}}">
- </div>
+ <div id="frame_{{name}}" class="panel panel-default">
+ <div class="panel-heading">
+ <div class="panel-title">
+ {{#conflict}}
+ <span class="glyphicon glyphicon-exclamation-sign pull-left text-danger"></span>
+ {{/conflict}}
+ {{#modified}}
+ <span class="glyphicon glyphicon-pencil pull-left"></span>
+ {{/modified}}
+ <h4>
+ <a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#panel_{{name}}">
+ {{name}}
+ </a>
+ </h4>
+ <small>{{description}}</small>
- <label for="ta_{{name}}">{{lang_template}}</label>
- <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>
</div>
+ <div id="panel_{{name}}" class="panel-collapse collapse">
+ <div class="panel-body">
+ <div id="msgbox_{{name}}">
+ </div>
+
+ <label for="ta_{{name}}">{{lang_template}}</label>
+ <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>
+
+ <h4>{{lang_placeholders}}</h4>
+ <select name="templates[{{name}}][mandatory_variables]" multiple="multiple" class="hidden">
+ {{{html_mandatoryVariables}}}
+ </select>
+ <select name="templates[{{name}}][optional_variables]" multiple="multiple" class="hidden">
+ {{{html_optionalVariables}}}
+ </select>
+ <ul>
+ {{{html_availableVariables}}}
+ </ul>
+ {{#original_template}}
+ <textarea class="hidden" id="orig_{{name}}">{{original_template}}</textarea>
+ <div class="pull-right">
+ <a href="#" class="btn btn-default" onclick="$('#ta_{{name}}').val($('#orig_{{name}}').val());return false">
+ <span class="glyphicon glyphicon-refresh"></span>
+ {{lang_replaceWithOriginal}}
+ </a>
+ </div>
+ {{/original_template}}
+ <div class="small">
+ {{lang_modified}}: {{#modified}}<b>{{lang_yes}}</b>{{/modified}}{{^modified}}{{lang_no}}{{/modified}},
+ {{lang_hasNewer}}: {{#conflict}}<b>{{lang_yes}}</b>{{/conflict}}{{^conflict}}{{lang_no}}{{/conflict}},
+ {{lang_thisVersion}}: {{edit_version}},
+ {{lang_latestVersion}}: {{version}}
+ </div>
+ </div>
+ </div>
+ </div>
- <h4>{{lang_placeholders}}</h4>
- <select name="templates[{{name}}][mandatory_variables]" multiple="multiple" class="hidden">
- {{{html_mandatoryVariables}}}
- </select>
- <select name="templates[{{name}}][optional_variables]" multiple="multiple" class="hidden">
- {{{html_optionalVariables}}}
- </select>
- <ul>
- {{{html_availableVariables}}}
- </ul>
- {{#original_template}}
- <textarea class="hidden" id="orig_{{name}}">{{original_template}}</textarea>
- <div class="pull-right">
- <a href="#" class="btn btn-default" onclick="$('#ta_{{name}}').val($('#orig_{{name}}').val());return false">
- <span class="glyphicon glyphicon-refresh"></span>
- {{lang_replaceWithOriginal}}
- </a>
+
+ {{/templates}}
+ </div>
+
+ <button type="submit" onclick="return validateForm()" class="btn btn-primary pull-right"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </form>
+ <form method="POST" action="?do=dozmod&amp;section=templates">
+ <input type="hidden" name="token" value="{{token}}">
+ <div>
+ <button type="button" data-toggle="modal" data-target="#resetTemplatesModal" class="btn btn-danger">{{lang_loadDefaults}}</button>
+ </div>
+
+ <div id="resetTemplatesModal" class="modal fade" role="dialog">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">&times;</button>
+ <h4 class="modal-title"></h4>
+ </div>
+ <div class="modal-body">
+ <p>{{lang_reallyResetTemplates}}</p>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" name="action" value ="reset" class="btn btn-primary">{{lang_reset}}</button>
+ </div>
</div>
- {{/original_template}}
- <div class="small">
- {{lang_modified}}: {{#modified}}<b>{{lang_yes}}</b>{{/modified}}{{^modified}}{{lang_no}}{{/modified}},
- {{lang_hasNewer}}: {{#conflict}}<b>{{lang_yes}}</b>{{/conflict}}{{^conflict}}{{lang_no}}{{/conflict}},
- {{lang_thisVersion}}: {{edit_version}},
- {{lang_latestVersion}}: {{version}}
+
</div>
</div>
- </div>
+
+ </form>
+ <div class="clearfix"></div>
</div>
+</div>
- {{/templates}}
- </div>
- <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"><!--
diff --git a/modules-available/dozmod/templates/userlist.html b/modules-available/dozmod/templates/userlist.html
index a4f415e1..378a2be1 100644
--- a/modules-available/dozmod/templates/userlist.html
+++ b/modules-available/dozmod/templates/userlist.html
@@ -1,4 +1,4 @@
-<h2 id="users">{{lang_userList}}</h2>
+<h1>{{lang_bwlehrpoolsuite}}</h1>
<div class="panel panel-default">
<div class="panel-heading">
@@ -7,13 +7,13 @@
<div class="panel-body">
<p>{{lang_userListDescription}}</p>
<div class="table-responsive">
- <table class="table table-stripped table-condensed">
+ <table class="table table-stripped table-condensed table-hover stupidtable">
<thead>
<tr>
- <th>{{lang_user}}</th>
- <th>{{lang_organization}}</th>
- <th>{{lang_lastLogin}}</th>
- <th>{{lang_email}}</th>
+ <th data-sort="string">{{lang_user}}</th>
+ <th data-sort="string">{{lang_organization}}</th>
+ <th data-sort="int">{{lang_lastLogin}}</th>
+ <th data-sort="string">{{lang_email}}</th>
<th><span class="glyphicon glyphicon-envelope" title="{{lang_emailNotifications}}"></span></th>
<th><span class="glyphicon glyphicon-king" title="{{lang_superUser}}"></span></th>
<th><span class="glyphicon glyphicon-ok" title="{{lang_canLoginUser}}"></span></th>
@@ -26,9 +26,24 @@
<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>
+ <td>
+ <div class="checkbox">
+ <input onclick="setu('setmail', this, '{{userid}}')" type="checkbox" {{{emailnotifications}}}>
+ <label></label>
+ </div>
+ </td>
+ <td>
+ <div class="checkbox">
+ <input onclick="setu('setsu', this, '{{userid}}')" type="checkbox" {{{issuperuser}}}>
+ <label></label>
+ </div>
+ </td>
+ <td>
+ <div class="checkbox">
+ <input onclick="setu('setlogin', this, '{{userid}}')" type="checkbox" {{{canlogin}}}>
+ <label></label>
+ </div>
+ </td>
</tr>
{{/users}}
</tbody>
@@ -41,6 +56,7 @@
function setu(action, el, uid) {
var box = $(el);
+ box = box.parent();
var v = el.checked ? '1' : '0';
var old = el.checked == true;
box.css('display', 'none');
@@ -48,7 +64,19 @@ function setu(action, el, uid) {
if (data !== '1' && data !== '0') {
el.checked = !old;
- box.parent().css('background-color', 'red !important');
+ box.parent().css('background-color', '');
+ /* show success notification */
+ $notification = $('<span></span>')
+ .addClass('glyphicon glyphicon-remove')
+ .css('color', 'red')
+ .css('width', '0px')
+ .css('position', 'relative')
+ .css('right', '20px')
+ .hide();
+ box.before($notification);
+ $notification.fadeIn('fast', function () {
+ $notification.fadeOut('slow', function () { $notification.remove() });
+ });
} else {
el.checked = (data == 1);
box.parent().css('background-color', '');
diff --git a/modules-available/eventlog/lang/de/template-tags.json b/modules-available/eventlog/lang/de/template-tags.json
index b1a292e6..6ad75329 100644
--- a/modules-available/eventlog/lang/de/template-tags.json
+++ b/modules-available/eventlog/lang/de/template-tags.json
@@ -1,6 +1,6 @@
{
"lang_details": "Details",
"lang_event": "Ereignis",
- "lang_eventLog": "Ereignisprotokoll",
+ "lang_eventLog": "Serverprotokoll",
"lang_when": "Wann"
} \ No newline at end of file
diff --git a/modules-available/eventlog/lang/en/module.json b/modules-available/eventlog/lang/en/module.json
index 0fc536f3..8217fc02 100644
--- a/modules-available/eventlog/lang/en/module.json
+++ b/modules-available/eventlog/lang/en/module.json
@@ -1,3 +1,3 @@
{
- "module_name": "Server Log"
+ "module_name": "Server-Log"
} \ No newline at end of file
diff --git a/modules-available/eventlog/lang/en/template-tags.json b/modules-available/eventlog/lang/en/template-tags.json
index 21ec64ea..3132b97c 100644
--- a/modules-available/eventlog/lang/en/template-tags.json
+++ b/modules-available/eventlog/lang/en/template-tags.json
@@ -1,6 +1,6 @@
{
"lang_details": "Details",
"lang_event": "Event",
- "lang_eventLog": "Event log",
+ "lang_eventLog": "Server Log",
"lang_when": "When"
} \ No newline at end of file
diff --git a/modules-available/eventlog/templates/_page.html b/modules-available/eventlog/templates/_page.html
index 2e657805..0875664e 100644
--- a/modules-available/eventlog/templates/_page.html
+++ b/modules-available/eventlog/templates/_page.html
@@ -3,18 +3,18 @@
<table class="table table-striped table-condensed">
<thead>
<th width="1"></th>
- <th>{{lang_when}}</th>
- <th>{{lang_event}}</th>
+ <th class="text-center">{{lang_when}}</th>
+ <th class="text-center">{{lang_event}}</th>
<th width="1">{{lang_details}}</th>
</thead>
<tbody>
{{#list}}
<tr>
<td><span class="glyphicon glyphicon-{{icon}}" title="{{logtypeid}}"></span></td>
- <td class="text-right" nowrap="nowrap">{{date}}</td>
+ <td class="text-center" nowrap="nowrap">{{date}}</td>
<td class="{{color}}">{{description}}</td>
- <td>{{#extra}}
- <a class="btn btn-default btn-xs pull-left" onclick="$('#details-body').html($('#extra-{{logid}}').html())" data-toggle="modal" data-target="#myModal">&raquo;</a>
+ <td class="text-center">{{#extra}}
+ <a class="btn btn-default btn-xs" onclick="$('#details-body').html($('#extra-{{logid}}').html())" data-toggle="modal" data-target="#myModal">&raquo;</a>
<div class="hidden" id="extra-{{logid}}">{{extra}}</div>
{{/extra}}</td>
</tr>
@@ -33,9 +33,6 @@
<div class="modal-body">
<pre id="details-body"></pre>
</div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
- </div>
</div>
</div>
</div>
diff --git a/modules-available/exams/config.json b/modules-available/exams/config.json
index 95d8aa3e..0780ebef 100644
--- a/modules-available/exams/config.json
+++ b/modules-available/exams/config.json
@@ -1,5 +1,5 @@
{
"category":"main.content",
- "dependencies": [ "locations", "js_vis", "bootstrap_datepicker", "bootstrap_timepicker", "bootstrap_multiselect"],
+ "dependencies": [ "locations", "js_vis", "js_stupidtable", "bootstrap_datepicker", "bootstrap_timepicker", "bootstrap_multiselect"],
"permission": "0"
}
diff --git a/modules-available/exams/lang/de/template-tags.json b/modules-available/exams/lang/de/template-tags.json
index e011ee20..8bf37143 100644
--- a/modules-available/exams/lang/de/template-tags.json
+++ b/modules-available/exams/lang/de/template-tags.json
@@ -12,6 +12,7 @@
"lang_begin_date": "Beginn Datum",
"lang_begin_time": "Uhrzeit",
"lang_comfirmGlobalExam": "Wollen Sie wirklich eine globale Pr\u00fcfung definieren? Im gew\u00e4hlten Zeitraum werden s\u00e4mtliche R\u00e4ume in den Pr\u00fcfungsmodus geschaltet.",
+ "lang_dateTime": "Datum\/Uhrzeit",
"lang_deleteConfirmation": "Wirklich l\u00f6schen?",
"lang_description": "Beschreibung",
"lang_duration": "Dauer",
@@ -21,7 +22,9 @@
"lang_end_time": "Uhrzeit",
"lang_examModeDescription": "Hier k\u00f6nnen Sie bwLehrpool-R\u00e4ume zeitgesteuert in den Pr\u00fcfungsmodus versetzen. Im Pr\u00fcfungsmodus ist das Client-System st\u00e4rker abgeriegelt, sodass es sich zum Schreiben von E-Pr\u00fcfungen eignet. Nach dem Ein- bzw. Ausschalten des Pr\u00fcfungsmodus ist es notwendig, die Rechner in den betroffenen R\u00e4umen neuzustarten.",
"lang_global": "Global",
+ "lang_headingAddExam": "Zeitraum hinzuf\u00fcgen",
"lang_headingAllExamLectures": "Ausstehende Pr\u00fcfungsveranstaltungen (30 Tage)",
+ "lang_headingEditExam": "Zeitraum bearbeiten",
"lang_headingGraphicalOverview": "Grafische Darstellung",
"lang_headingMain": "bwLehrpool Pr\u00fcfungsmodus",
"lang_id": "ID",
diff --git a/modules-available/exams/lang/en/module.json b/modules-available/exams/lang/en/module.json
index a066b3aa..a2403da1 100644
--- a/modules-available/exams/lang/en/module.json
+++ b/modules-available/exams/lang/en/module.json
@@ -1,5 +1,5 @@
{
- "module_name": "Exam mode",
+ "module_name": "Exam Mode",
"title_add-exam": "Add exam",
"title_edit-exam": "Edit exam",
"warning_lecture_is_not_enabled": "Warning: Lecture is not enabled by tutor"
diff --git a/modules-available/exams/lang/en/template-tags.json b/modules-available/exams/lang/en/template-tags.json
index a4ae9325..af87bb01 100644
--- a/modules-available/exams/lang/en/template-tags.json
+++ b/modules-available/exams/lang/en/template-tags.json
@@ -2,7 +2,7 @@
"lang_actions": "Actions",
"lang_addExam": "Add exam period",
"lang_addingBasedOnLecture": "Adding exam period based on lecture",
- "lang_allExamPeriods": "All exam periods",
+ "lang_allExamPeriods": "All Exam Periods",
"lang_autoLogin": "Skip login",
"lang_autoLoginInfo": "If this option is enabled, the login mask will not be shown and instead, an anonymous session is opened. This is useful if there is another authentication mechanism in place inside the VM, e.g. web-based (LMS). The user will see the vmChooser right away after booting up the computer. You can combine this option with the \"Automatically launched course\" feature, so the boot process is completely automated. Note that when using \"skip login\", no personalization like mapping of home directories is possible inside the VM without additional actions by the user and\/or creator of the VM.",
"lang_autoStartInfo": "Here you can select a course that will be launched automatically after the user logged in. This will skip the vmChooser screen, and directly start the couse selected here. This function can be combined with the \"skip login\" feature to further automate the boot-up process.",
@@ -12,18 +12,21 @@
"lang_begin_date": "Begin Date",
"lang_begin_time": "Time",
"lang_comfirmGlobalExam": "Do you really want to create a global exam? Every single room will be set to lecture mode during the selected time period.",
+ "lang_dateTime": "Date\/Time",
"lang_deleteConfirmation": "Are you sure?",
"lang_description": "Description",
"lang_duration": "Duration",
- "lang_editExam": "Edit Exam Period",
+ "lang_editExam": "Edit exam period",
"lang_end": "End",
"lang_end_date": "End Date",
"lang_end_time": "Time",
"lang_examModeDescription": "Here you can define time spans during which selected rooms will be set to exam mode. In exam mode, the client computers are more locked down than usual so it is suitable for writing electronic exams.",
"lang_global": "Global",
- "lang_headingAllExamLectures": "Upcoming lectures marked as exams (30 days)",
- "lang_headingGraphicalOverview": "Graphical overview",
- "lang_headingMain": "bwLehrpool exam mode",
+ "lang_headingAddExam": "Add Exam Period",
+ "lang_headingAllExamLectures": "Upcoming Lectures Marked As Exams (30 Days)",
+ "lang_headingEditExam": "Edit Exam Period",
+ "lang_headingGraphicalOverview": "Graphical Overview",
+ "lang_headingMain": "bwLehrpool Exam Mode",
"lang_id": "ID",
"lang_lectureName": "Lecture name",
"lang_lectureOutOfRange": "Hint: Start or end date of given lecture lies outside of exam period given above",
diff --git a/modules-available/exams/page.inc.php b/modules-available/exams/page.inc.php
index 48af287a..a6bd7e16 100644
--- a/modules-available/exams/page.inc.php
+++ b/modules-available/exams/page.inc.php
@@ -150,10 +150,10 @@ class Page_Exams extends Page
foreach ($this->exams as $exam) {
if ($exam['endtime'] < $now) {
$exam['rowClass'] = 'text-muted';
- $exam['btnClass'] = 'btn-success';
+ $exam['btnClass'] = 'btn-default';
$exam['liesInPast'] = true;
} else {
- $exam['btnClass'] = 'btn-default';
+ $exam['btnClass'] = 'btn-danger';
}
$exam['starttime_s'] = date('Y-m-d H:i', $exam['starttime']);
$exam['endtime_s'] = date('Y-m-d H:i', $exam['endtime']);
diff --git a/modules-available/exams/style.css b/modules-available/exams/style.css
index 4a6cd7da..c6e5bada 100644
--- a/modules-available/exams/style.css
+++ b/modules-available/exams/style.css
@@ -15,3 +15,11 @@
.vis-item.disabled {
background-color: rgba(189, 195, 199, 1.0) !important;
}
+
+.table > tbody > tr > td {
+ vertical-align: middle;
+}
+
+label {
+ font-weight: inherit;
+} \ No newline at end of file
diff --git a/modules-available/exams/templates/page-add-edit-exam.html b/modules-available/exams/templates/page-add-edit-exam.html
index bf000df5..58c61b11 100644
--- a/modules-available/exams/templates/page-add-edit-exam.html
+++ b/modules-available/exams/templates/page-add-edit-exam.html
@@ -1,108 +1,122 @@
{{#exam.examid}}
-<h1>{{lang_editExam}}</h1>
+<h1>{{lang_headingEditExam}}</h1>
{{/exam.examid}}
{{^exam.examid}}
-<h1>{{lang_addExam}}</h1>
+<h1>{{lang_headingAddExam}}</h1>
{{/exam.examid}}
{{#exam.displayname}}
<div class="alert alert-info">{{lang_addingBasedOnLecture}}:<br><b>{{exam.displayname}}</b></div>
{{/exam.displayname}}
+
<form class="form" method="POST" action="?do=exams" id="tolleform">
- <div class="form-group">
- <div>
- <label for="locations">{{lang_location}}</label>
- <p><i>{{lang_locationInfo}}</i></p>
+ <div class="panel panel-default">
+ <div class="panel-heading"><label for="locations">{{lang_location}}</label></div>
+ <div class="panel-body">
+ <div class="form-group">
+ <div>
+ <p><i>{{lang_locationInfo}}</i></p>
+ </div>
+ <select id="locations" multiple name="locations[]">
+ {{#locations}}
+ <option value="{{locationid}}" {{#selected}}selected{{/selected}}>{{locationpad}} {{locationname}}</option>
+ {{/locations}}
+ </select>
+ </div>
</div>
- <select id="locations" multiple name="locations[]">
- {{#locations}}
- <option value="{{locationid}}" {{#selected}}selected{{/selected}}>{{locationpad}} {{locationname}}</option>
- {{/locations}}
- </select>
</div>
- <div class="row form-group">
- <div class="col-xs-6">
- <label for="starttime_date">{{lang_begin_date}}</label>
- <div class="input-group">
- <span class="input-group-addon">
- <span class="glyphicon glyphicon-calendar"></span>
- </span>
- <input required class="form-control datepicker" name="starttime_date" id="starttime_date"
- value="{{exam.starttime_date}}">
- </div>
- </div>
- <div class="col-xs-6">
- <label for="starttime_time">{{lang_begin_time}}</label>
- <div class="input-group bootstrap-timepicker timepicker">
- <span class="input-group-addon">
- <span class="glyphicon glyphicon-time"></span>
- </span>
- <input required type="text" class="form-control timepicker2" name="starttime_time" id="starttime_time"
- value="{{exam.starttime_time}}"
- pattern="[0-9]{1,2}:[0-9]{2}">
+ <div class="panel panel-default">
+ <div class="panel-heading">{{lang_dateTime}}</div>
+ <div class="panel-body">
+ <div class="row form-group">
+ <div class="col-xs-6">
+ <label for="starttime_date">{{lang_begin_date}}</label>
+ <div class="input-group">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-calendar"></span>
+ </span>
+ <input required class="form-control datepicker" name="starttime_date" id="starttime_date"
+ value="{{exam.starttime_date}}">
+ </div>
+ </div>
+ <div class="col-xs-6">
+ <label for="starttime_time">{{lang_begin_time}}</label>
+ <div class="input-group bootstrap-timepicker timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input required type="text" class="form-control timepicker2" name="starttime_time" id="starttime_time"
+ value="{{exam.starttime_time}}"
+ pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </div>
</div>
- </div>
- </div>
- <div class="row form-group">
- <div class="col-xs-6">
- <label for="endtime_date">{{lang_end_date}}</label>
- <div class="input-group">
- <span class="input-group-addon">
- <span class="glyphicon glyphicon-calendar"></span>
- </span>
- <input required class="form-control datepicker" name="endtime_date" id="endtime_date"
- value="{{exam.endtime_date}}">
+ <div class="row form-group">
+ <div class="col-xs-6">
+ <label for="endtime_date">{{lang_end_date}}</label>
+ <div class="input-group">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-calendar"></span>
+ </span>
+ <input required class="form-control datepicker" name="endtime_date" id="endtime_date"
+ value="{{exam.endtime_date}}">
+ </div>
+ </div>
+ <div class="col-xs-6">
+ <label for="endtime_time">{{lang_end_time}}</label>
+ <div class="input-group bootstrap-timepicker timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input required type="text" class="form-control timepicker2" name="endtime_time" id="endtime_time"
+ value="{{exam.endtime_time}}"
+ pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </div>
</div>
- </div>
- <div class="col-xs-6">
- <label for="endtime_time">{{lang_end_time}}</label>
- <div class="input-group bootstrap-timepicker timepicker">
- <span class="input-group-addon">
- <span class="glyphicon glyphicon-time"></span>
- </span>
- <input required type="text" class="form-control timepicker2" name="endtime_time" id="endtime_time"
- value="{{exam.endtime_time}}"
- pattern="[0-9]{1,2}:[0-9]{2}">
+
+ <div class="panel">
+ <div class="panel-body">
+ {{lang_duration}}: <span id="exam-duration">-</span>
+ </div>
</div>
</div>
</div>
- <div class="panel">
+ <div class="panel panel-default">
+ <div class="panel-heading"><label for="lecturelist">{{lang_autoStartLecture}}</label></div>
<div class="panel-body">
- {{lang_duration}}: <span id="exam-duration">-</span>
- </div>
- </div>
-
- <div class="row form-group">
- <div class="form-group col-xs-12">
- <label for="description">{{lang_autoStartLecture}}</label>
- <p><i>{{lang_autoStartInfo}}</i></p>
- <div class="input-group">
- <span class="input-group-addon">
- <span class="glyphicon glyphicon-pencil"></span>
- </span>
- <select class="form-control" id="lecturelist" name="lectureid">
- <option value="">{{lang_none}}</option>
- {{#lectures}}
- <option data-from="{{starttime}}" data-to="{{endtime}}" value="{{lectureid}}" {{selected}} >{{displayname}}</option>
- {{/lectures}}
- </select>
+ <div class="row form-group">
+ <div class="form-group col-xs-12">
+ <p><i>{{lang_autoStartInfo}}</i></p>
+ <div class="input-group">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-pencil"></span>
+ </span>
+ <select class="form-control" id="lecturelist" name="lectureid">
+ <option value="">{{lang_none}}</option>
+ {{#lectures}}
+ <option data-from="{{starttime}}" data-to="{{endtime}}" value="{{lectureid}}" {{selected}} >{{displayname}}</option>
+ {{/lectures}}
+ </select>
+ </div>
+ </div>
+ <div class="form-group col-xs-12">
+ <div class="checkbox"><input id="autologin" type="checkbox" name="autologin" value="demo" class="form-control" {{#exam.autologin}}checked{{/exam.autologin}}><label for="autologin">{{lang_autoLogin}}</label></div>
+ <p><i>{{lang_autoLoginInfo}}</i></p>
+ </div>
+ <div class="col-xs-12" id="lecture-info">
+ -
+ </div>
</div>
</div>
- <div class="form-group col-xs-12">
- <div class="checkbox"><input id="autologin" type="checkbox" name="autologin" value="demo" class="form-control" {{#exam.autologin}}checked{{/exam.autologin}}><label for="autologin">{{lang_autoLogin}}</label></div>
- <p><i>{{lang_autoLoginInfo}}</i></p>
- </div>
- <div class="col-xs-12" id="lecture-info">
- -
- </div>
</div>
- <div class="row form-group">
- <div class="form-group col-xs-12">
- <label for="description">{{lang_description}}</label>
+ <div class="panel panel-default">
+ <div class="panel-heading"><label for="description">{{lang_description}}</label></div>
+ <div class="panel-body">
<textarea class="form-control" type="textarea" name="description" id="description">{{exam.description}}</textarea>
</div>
</div>
@@ -110,10 +124,39 @@
<input type="hidden" name="action" value="save">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="examid" value="{{exam.examid}}">
- <button class="btn btn-success" type="submit">{{lang_save}}</button>
+ <div class="text-right" style="margin-bottom: 20px">
+ <button type="button" id="cancelButton" class="btn btn-default"< style="margin-right: 10px">{{lang_cancel}}</button>
+ <button type="button" onclick="checkGlobalExam()" id="saveButton" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+
+ <div class ="modal fade" id="confirmGlobalModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_comfirmGlobalExam}}
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" class="btn btn-sm btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
</form>
+
+
<script type="application/javascript"><!--
+
+function checkGlobalExam() {
+ if ($('#locations option:selected').length === 0 && $('#locations option').length > 1) {
+ $("#confirmGlobalModal").modal();
+ } else {
+ $('#tolleform').submit();
+ }
+}
+
document.addEventListener("DOMContentLoaded", function () {
var filename = "modules/bootstrap_datepicker/lang/bootstrap-datepicker." + LANG + ".js";
moment.locale(LANG);
@@ -189,7 +232,7 @@ document.addEventListener("DOMContentLoaded", function () {
}
});
updateLectureInfo();
- }
+ };
var updateLectureInfo = function() {
var sel = $('#lecturelist option:selected');
@@ -198,7 +241,7 @@ document.addEventListener("DOMContentLoaded", function () {
} else {
$('#lecture-info').text('{{lang_lectureOutOfRange}} (' + slxMoment(sel.data('from') * 1000).format('YYYY-MM-DD H:mm') + ' - ' + slxMoment(sel.data('to') * 1000).format('YYYY-MM-DD H:mm') + ')');
}
- }
+ };
start_date.change(startEndChanged);
start_time.change(startEndChanged);
@@ -206,12 +249,8 @@ document.addEventListener("DOMContentLoaded", function () {
end_time.change(startEndChanged);
$('#lecturelist').change(updateLectureInfo);
- $('#tolleform').submit(function(ev) {
- if ($('#locations option:selected').length === 0 && $('#locations option').length > 1) {
- if (!confirm('{{lang_comfirmGlobalExam}}')) {
- ev.preventDefault();
- }
- }
+ $("#cancelButton").click(function () {
+ window.location.replace("?do=exams");
});
}, false);
diff --git a/modules-available/exams/templates/page-exams-vis.html b/modules-available/exams/templates/page-exams-vis.html
index e347900b..caf4aea2 100644
--- a/modules-available/exams/templates/page-exams-vis.html
+++ b/modules-available/exams/templates/page-exams-vis.html
@@ -1,6 +1,15 @@
-<h2>{{lang_headingGraphicalOverview}}</h2>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_headingGraphicalOverview}}
+ </div>
+ <div class="panel-body">
+ <div id="timeline" class="slx-space"></div>
+ </div>
+</div>
+
+
+
-<div id="timeline" class="slx-space"></div>
<script type="application/javascript"><!--
diff --git a/modules-available/exams/templates/page-exams.html b/modules-available/exams/templates/page-exams.html
index fc88e4f4..29b8c319 100644
--- a/modules-available/exams/templates/page-exams.html
+++ b/modules-available/exams/templates/page-exams.html
@@ -1,52 +1,63 @@
-<h2>{{lang_allExamPeriods}}</h2>
-<div class="slx-space">
- <table class="table">
- <tr>
- <th>{{lang_id}}</th>
- <th>{{lang_locations}}</th>
- <th>{{lang_begin}}</th>
- <th>{{lang_end}}</th>
- <th>{{lang_actions}}</th>
- </tr>
- {{#exams}}
- <tr class="{{rowClass}}">
- <td>{{examid}}</td>
- <td>
- {{locationnames}}
- {{^locationnames}}
- <i>{{lang_global}}</i>
- {{/locationnames}}
- {{#lecturename}}
- <div>
- <b>{{lang_autostart}}</b>: {{lecturename}}
- </div>
- {{/lecturename}}
- <div class="small">
- {{description}}
- {{^description}}
- <i>{{lang_noDescription}}</i>
- {{/description}}
- </div>
- </td>
- <td class="text-nowrap">{{starttime_s}}</td>
- <td class="text-nowrap">{{endtime_s}}</td>
- <td class="text-nowrap text-right">
- <form method="POST" action="?do=exams&action=delete" {{^liesInPast}}onsubmit="return confirm('{{lang_deleteConfirmation}}');"{{/liesInPast}} >
- {{^liesInPast}}
- <a onclick="slxShow({{starttime}}, {{endtime}})" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-eye-open"></span></a>
- {{/liesInPast}}
- <a href="?do=exams&action=edit&examid={{examid}}" class="btn btn-default btn-sm" >{{lang_edit}}</a>
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="examid" value="{{examid}}">
- <button class="btn {{btnClass}} btn-sm">{{lang_delete}}</button>
- </form>
- </td>
- </tr>
- {{/exams}}
- </table>
-</div>
-
-<div class="btn-group" role="group">
- <a href="?do=exams&action=add" class="btn btn-success">{{lang_addExam}}</a>
-</div>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_allExamPeriods}}
+ </div>
+ <div class="panel-body">
+ <div class="slx-space">
+ <table class="table table-bordered stupidtable">
+ <thead>
+ <tr>
+ <th data-sort="int">{{lang_id}}</th>
+ <th data-sort="string">{{lang_locations}}</th>
+ <th data-sort="int">{{lang_begin}}</th>
+ <th data-sort="int">{{lang_end}}</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#exams}}
+ <tr class="{{rowClass}}">
+ <td>{{examid}}</td>
+ <td>
+ {{locationnames}}
+ {{^locationnames}}
+ <i>{{lang_global}}</i>
+ {{/locationnames}}
+ {{#lecturename}}
+ <div>
+ <b>{{lang_autostart}}</b>: {{lecturename}}
+ </div>
+ {{/lecturename}}
+ <div class="small">
+ {{description}}
+ {{^description}}
+ <i>{{lang_noDescription}}</i>
+ {{/description}}
+ </div>
+ </td>
+ <td class="text-nowrap" data-sort-value={{starttime}}>{{starttime_s}}</td>
+ <td class="text-nowrap" data-sort-value={{endtime}}>{{endtime_s}}</td>
+ <td class="text-nowrap text-right">
+ <form method="POST" action="?do=exams&action=delete" {{^liesInPast}}onsubmit="return confirm('{{lang_deleteConfirmation}}');"{{/liesInPast}} >
+ {{^liesInPast}}
+ <a onclick="slxShow({{starttime}}, {{endtime}})" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-eye-open"></span></a>
+ {{/liesInPast}}
+ <a href="?do=exams&action=edit&examid={{examid}}" class="btn btn-default btn-sm" >{{lang_edit}}</a>
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="examid" value="{{examid}}">
+ <button class="btn {{btnClass}} btn-sm">{{lang_delete}}</button>
+ </form>
+ </td>
+ </tr>
+ {{/exams}}
+ </tbody>
+ </table>
+ </div>
+ <div class="text-right">
+ <div class="btn-group" role="group">
+ <a href="?do=exams&action=add" class="btn btn-success"><span class="glyphicon glyphicon-plus-sign"></span> {{lang_addExam}}</a>
+ </div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/modules-available/exams/templates/page-upcoming-lectures.html b/modules-available/exams/templates/page-upcoming-lectures.html
index 323b1017..8ff8143e 100644
--- a/modules-available/exams/templates/page-upcoming-lectures.html
+++ b/modules-available/exams/templates/page-upcoming-lectures.html
@@ -1,46 +1,55 @@
-<h2>{{lang_headingAllExamLectures}}</h2>
-
-<div class="slx-space">
- <table class="table">
- <tr>
- <th>{{lang_lectureName}}</th>
- <th>{{lang_timeFrame}}</th>
- <th>{{lang_actions}}</th>
- </tr>
- {{#pending_lectures}}
- <tr class="{{class}}">
- <td>
- {{displayname}}
- <div class="small">
- <a href="mailto:{{email}}">{{lastname}}, {{firstname}}</a>
- </div>
- </td>
- <td width="30%" class="text-nowrap">
- {{starttime_s}} &ensp; {{endtime_s}}
- <div class="small">
- {{lang_duration}}: {{duration_s}}
- {{^duration_s}}{{lang_moreThanOneDay}}{{/duration_s}}
- </div>
- </td>
- <td width="20%">
- <div class="pull-right text-nowrap">
- <a class="btn btn-sm btn-default" role="button" onclick="slxShow({{starttime}}, {{endtime}})"><span class="glyphicon glyphicon-eye-open"></span></a>
- <a href="?do=exams&amp;action=add&amp;lectureid={{lectureid}}" class="btn btn-sm btn-default" role="button">
- <span class="glyphicon glyphicon-plus-sign"></span>
- <span class="hidden-sm">{{lang_addExam}}</span>
- </a>
- </div>
- </td>
- </tr>
- {{/pending_lectures}}
- {{#decollapse}}
- <tr class="slx-decollapse">
- <td colspan="3">
- <span class="btn-group btn-group-justified">
- <span class="btn btn-default btn-sm"><span class="glyphicon glyphicon-menu-down"></span></span>
- </span>
- </td>
- </tr>
- {{/decollapse}}
- </table>
+<div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_headingAllExamLectures}}
+ </div>
+ <div class="panel-body">
+ <div class="slx-space">
+ <table class="table stupidtable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_lectureName}}</th>
+ <th data-sort="int">{{lang_timeFrame}}</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#pending_lectures}}
+ <tr class="{{class}}">
+ <td>
+ {{displayname}}
+ <div class="small">
+ <a href="mailto:{{email}}">{{lastname}}, {{firstname}}</a>
+ </div>
+ </td>
+ <td data-sort-value={{starttime}} width="30%" class="text-nowrap">
+ {{starttime_s}} &ensp; {{endtime_s}}
+ <div class="small">
+ {{lang_duration}}: {{duration_s}}
+ {{^duration_s}}{{lang_moreThanOneDay}}{{/duration_s}}
+ </div>
+ </td>
+ <td width="20%">
+ <div class="pull-right text-nowrap">
+ <a class="btn btn-sm btn-default" role="button" onclick="slxShow({{starttime}}, {{endtime}})"><span class="glyphicon glyphicon-eye-open"></span></a>
+ <a href="?do=exams&amp;action=add&amp;lectureid={{lectureid}}" class="btn btn-sm btn-success" role="button">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ <span class="hidden-sm">{{lang_addExam}}</span>
+ </a>
+ </div>
+ </td>
+ </tr>
+ {{/pending_lectures}}
+ {{#decollapse}}
+ <tr class="slx-decollapse">
+ <td colspan="3">
+ <span class="btn-group btn-group-justified">
+ <span class="btn btn-default btn-sm"><span class="glyphicon glyphicon-menu-down"></span></span>
+ </span>
+ </td>
+ </tr>
+ {{/decollapse}}
+ </tbody>
+ </table>
+ </div>
+ </div>
</div> \ No newline at end of file
diff --git a/modules-available/internetaccess/lang/en/template-tags.json b/modules-available/internetaccess/lang/en/template-tags.json
index 1be62f43..2ac50527 100644
--- a/modules-available/internetaccess/lang/en/template-tags.json
+++ b/modules-available/internetaccess/lang/en/template-tags.json
@@ -1,7 +1,7 @@
{
"lang_automatic": "Auto",
"lang_description": "Here you can configure how the satellite server has to access the internet.",
- "lang_internetAccess": "Internet access",
+ "lang_internetAccess": "Internet Access",
"lang_manual": "Manual",
"lang_manualProxyConfig": "If you want to configure a proxy server manually, please supply the credentials here.",
"lang_no": "None",
diff --git a/modules-available/internetaccess/page.inc.php b/modules-available/internetaccess/page.inc.php
index 246d4477..a92ba3e3 100644
--- a/modules-available/internetaccess/page.inc.php
+++ b/modules-available/internetaccess/page.inc.php
@@ -6,27 +6,35 @@ class Page_InternetAccess extends Page
protected function doPreprocess()
{
User::load();
- if (!User::hasPermission('superadmin')) {
+
+ if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
Util::redirect('?do=Main');
}
- if (isset($_POST['PROXY_CONF'])) {
- $data = array();
- foreach (array('PROXY_CONF', 'PROXY_ADDR', 'PROXY_PORT', 'PROXY_USERNAME', 'PROXY_PASSWORD') as $key) {
- $data[$key] = Request::post($key, '');
- }
- if (!FileUtil::arrayToFile(CONFIG_PROXY_CONF, $data)) {
- Message::addError('main.error-write', CONFIG_PROXY_CONF);
- Util::redirect();
- } else {
- Message::addSuccess('settings-updated');
- Taskmanager::release(Taskmanager::submit('ReloadProxy'));
- $taskids = array();
- Trigger::stopDaemons(NULL, $taskids);
- $taskids = array();
- Trigger::startDaemons(NULL, $taskids);
- Session::set('ia-restart', $taskids);
- Util::redirect('?do=InternetAccess&show=update');
+
+ $action = Request::any('action', 'show');
+
+ if ($action == 'save') {
+ if (User::hasPermission("configuration.safe")) {
+ if (isset($_POST['PROXY_CONF'])) {
+ $data = array();
+ foreach (array('PROXY_CONF', 'PROXY_ADDR', 'PROXY_PORT', 'PROXY_USERNAME', 'PROXY_PASSWORD') as $key) {
+ $data[$key] = Request::post($key, '');
+ }
+ if (!FileUtil::arrayToFile(CONFIG_PROXY_CONF, $data)) {
+ Message::addError('main.error-write', CONFIG_PROXY_CONF);
+ Util::redirect();
+ } else {
+ Message::addSuccess('settings-updated');
+ Taskmanager::release(Taskmanager::submit('ReloadProxy'));
+ $taskids = array();
+ Trigger::stopDaemons(null, $taskids);
+ $taskids = array();
+ Trigger::startDaemons(null, $taskids);
+ Session::set('ia-restart', $taskids);
+ Util::redirect('?do=InternetAccess&show=update');
+ }
+ }
}
}
}
@@ -45,6 +53,9 @@ class Page_InternetAccess extends Page
if (!isset($data['PROXY_CONF']))
$data['PROXY_CONF'] = 'AUTO';
$data['selected_' . $data['PROXY_CONF']] = 'selected';
+
+ $data['allowedSave'] = User::hasPermission("configuration.safe");
+
Render::addTemplate('_page', $data);
}
diff --git a/modules-available/internetaccess/permissions/permissions.json b/modules-available/internetaccess/permissions/permissions.json
new file mode 100644
index 00000000..6d88ccc5
--- /dev/null
+++ b/modules-available/internetaccess/permissions/permissions.json
@@ -0,0 +1,3 @@
+{
+ "configuration.safe": "Safe new configuration."
+} \ No newline at end of file
diff --git a/modules-available/internetaccess/style.css b/modules-available/internetaccess/style.css
new file mode 100644
index 00000000..77fa7213
--- /dev/null
+++ b/modules-available/internetaccess/style.css
@@ -0,0 +1,3 @@
+.input-group-addon {
+ min-width:150px;
+}
diff --git a/modules-available/internetaccess/templates/_page.html b/modules-available/internetaccess/templates/_page.html
index ac82325c..1413e280 100644
--- a/modules-available/internetaccess/templates/_page.html
+++ b/modules-available/internetaccess/templates/_page.html
@@ -1,40 +1,38 @@
<h1>{{lang_internetAccess}}</h1>
-<form action="?do=InternetAccess" method="post">
+<form action="?do=InternetAccess&amp;action=save" method="post">
<input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="position:absolute;top:-2000px" tabindex="-1">
<input type="password" name="password_fake" id="password_fake" value="" style="position:absolute;top:-2000px" tabindex="-1">
<input type="hidden" name="token" value="{{token}}">
- <div class="panel panel-default">
- <div class="panel-heading">{{lang_internetAccess}}</div>
- <div class="panel-body">
- <p>{{lang_description}}</p>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_proxyType}}</span>
- <select name="PROXY_CONF" class="form-control">
- <option value="AUTO" {{selected_AUTO}}>{{lang_automatic}} (dns-wpad)</option>
- <option value="NO" {{selected_NO}}>{{lang_no}}</option>
- <option value="YES" {{selected_YES}}>{{lang_manual}}</option>
- </select>
- </div>
- <br>
- <p>{{lang_manualProxyConfig}}</p>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_proxyAddress}} *</span>
- <input name="PROXY_ADDR" value="{{PROXY_ADDR}}" type="text" class="form-control">
- </div>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_proxyPort}} *</span>
- <input name="PROXY_PORT" value="{{PROXY_PORT}}" type="text" class="form-control">
- </div>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_proxyUsername}}</span>
- <input name="PROXY_USERNAME" value="{{PROXY_USERNAME}}" type="text" class="form-control">
- </div>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_proxyPassword}}</span>
- <input name="PROXY_PASSWORD" value="{{PROXY_PASSWORD}}" type="{{password_type}}" class="form-control">
- </div>
- <button class="btn btn-primary" type="submit">{{lang_save}}</button>
- </div>
+ <p>{{lang_description}}</p>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_proxyType}}</span>
+ <select name="PROXY_CONF" class="form-control">
+ <option value="AUTO" {{selected_AUTO}}>{{lang_automatic}} (dns-wpad)</option>
+ <option value="NO" {{selected_NO}}>{{lang_no}}</option>
+ <option value="YES" {{selected_YES}}>{{lang_manual}}</option>
+ </select>
+ </div>
+ <br>
+ <p>{{lang_manualProxyConfig}}</p>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_proxyAddress}} *</span>
+ <input name="PROXY_ADDR" value="{{PROXY_ADDR}}" type="text" class="form-control">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_proxyPort}} *</span>
+ <input name="PROXY_PORT" value="{{PROXY_PORT}}" type="text" class="form-control">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_proxyUsername}}</span>
+ <input name="PROXY_USERNAME" value="{{PROXY_USERNAME}}" type="text" class="form-control">
+ </div>
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_proxyPassword}}</span>
+ <input name="PROXY_PASSWORD" value="{{PROXY_PASSWORD}}" type="{{password_type}}" class="form-control">
+ </div>
+ <br/>
+ <div class="text-right">
+ <button {{^allowedSave}}disabled{{/allowedSave}} class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</form>
diff --git a/modules-available/js_stupidtable/clientscript.js b/modules-available/js_stupidtable/clientscript.js
index bfbc9112..8b8fc107 100644
--- a/modules-available/js_stupidtable/clientscript.js
+++ b/modules-available/js_stupidtable/clientscript.js
@@ -24,7 +24,180 @@
SOFTWARE.
*/
-(function(c){c.fn.stupidtable=function(b){return this.each(function(){var a=c(this);b=b||{};b=c.extend({},c.fn.stupidtable.default_sort_fns,b);a.data("sortFns",b);a.on("click.stupidtable","thead th",function(){c(this).stupidsort()})})};c.fn.stupidsort=function(b){var a=c(this),g=0,f=c.fn.stupidtable.dir,e=a.closest("table"),k=a.data("sort")||null;if(null!==k){a.parents("tr").find("th").slice(0,c(this).index()).each(function(){var a=c(this).attr("colspan")||1;g+=parseInt(a,10)});var d;1==arguments.length?
- d=b:(d=b||a.data("sort-default")||f.ASC,a.data("sort-dir")&&(d=a.data("sort-dir")===f.ASC?f.DESC:f.ASC));if(a.data("sort-dir")!==d)return a.data("sort-dir",d),e.trigger("beforetablesort",{column:g,direction:d}),e.css("display"),setTimeout(function(){var b=[],l=e.data("sortFns")[k],h=e.children("tbody").children("tr");h.each(function(a,d){var e=c(d).children().eq(g),f=e.data("sort-value");"undefined"===typeof f&&(f=e.text(),e.data("sort-value",f));b.push([f,d])});b.sort(function(a,b){return l(a[0],
- b[0])});d!=f.ASC&&b.reverse();h=c.map(b,function(a){return a[1]});e.children("tbody").append(h);e.find("th").data("sort-dir",null).removeClass("sorting-desc sorting-asc");a.data("sort-dir",d).addClass("sorting-"+d);e.trigger("aftertablesort",{column:g,direction:d});e.css("display")},10),a}};c.fn.updateSortVal=function(b){var a=c(this);a.is("[data-sort-value]")&&a.attr("data-sort-value",b);a.data("sort-value",b);return a};c.fn.stupidtable.dir={ASC:"asc",DESC:"desc"};c.fn.stupidtable.default_sort_fns=
- {"int":function(b,a){return parseInt(b,10)-parseInt(a,10)},"float":function(b,a){return parseFloat(b)-parseFloat(a)},string:function(b,a){return b.toString().localeCompare(a.toString())},"string-ins":function(b,a){b=b.toString().toLocaleLowerCase();a=a.toString().toLocaleLowerCase();return b.localeCompare(a)}}})(jQuery);
+(function($) {
+ $.fn.stupidtable = function(sortFns) {
+ return this.each(function() {
+ var $table = $(this);
+ sortFns = sortFns || {};
+ sortFns = $.extend({}, $.fn.stupidtable.default_sort_fns, sortFns);
+ $table.data('sortFns', sortFns);
+
+ $table.on("click.stupidtable", "thead th", function() {
+ $(this).stupidsort();
+ });
+
+ // to show the sort-arrow next to the table header
+ $table.on("aftertablesort", function (event, data) {
+ var th = $(this).find("th");
+ th.find(".arrow").remove();
+ var dir = $.fn.stupidtable.dir;
+ var arrow = data.direction === dir.ASC ? "down" : "up";
+ th.eq(data.column).append(' <span class="arrow glyphicon glyphicon-chevron-'+arrow+'"></span>');
+ });
+ });
+ };
+
+
+ // Expects $("#mytable").stupidtable() to have already been called.
+ // Call on a table header.
+ $.fn.stupidsort = function(force_direction){
+ var $this_th = $(this);
+ var th_index = 0; // we'll increment this soon
+ var dir = $.fn.stupidtable.dir;
+ var $table = $this_th.closest("table");
+ var datatype = $this_th.data("sort") || null;
+
+ // No datatype? Nothing to do.
+ if (datatype === null) {
+ return;
+ }
+
+ // Account for colspans
+ $this_th.parents("tr").find("th").slice(0, $(this).index()).each(function() {
+ var cols = $(this).attr("colspan") || 1;
+ th_index += parseInt(cols,10);
+ });
+
+ var sort_dir;
+ if(arguments.length == 1){
+ sort_dir = force_direction;
+ }
+ else{
+ sort_dir = force_direction || $this_th.data("sort-default") || dir.ASC;
+ if ($this_th.data("sort-dir"))
+ sort_dir = $this_th.data("sort-dir") === dir.ASC ? dir.DESC : dir.ASC;
+ }
+
+ // Bail if already sorted in this direction
+ if ($this_th.data("sort-dir") === sort_dir) {
+ return;
+ }
+ // Go ahead and set sort-dir. If immediately subsequent calls have same sort-dir they will bail
+ $this_th.data("sort-dir", sort_dir);
+
+ $table.trigger("beforetablesort", {column: th_index, direction: sort_dir});
+
+ // More reliable method of forcing a redraw
+ $table.css("display");
+
+ // Run sorting asynchronously on a timout to force browser redraw after
+ // `beforetablesort` callback. Also avoids locking up the browser too much.
+ setTimeout(function() {
+ // Gather the elements for this column
+ var column = [];
+ var sortFns = $table.data('sortFns');
+ var sortMethod = sortFns[datatype];
+ var collapsedCount = $table.children("tbody").children("tr.collapse").length;
+ var trs = $table.children("tbody").children("tr:not(.slx-decollapse)");
+
+ // Extract the data for the column that needs to be sorted and pair it up
+ // with the TR itself into a tuple. This way sorting the values will
+ // incidentally sort the trs.
+ trs.each(function(index,tr) {
+ var $e = $(tr).children().eq(th_index);
+ var sort_val = $e.data("sort-value");
+
+ // Store and read from the .data cache for display text only sorts
+ // instead of looking through the DOM every time
+ if(typeof(sort_val) === "undefined"){
+ var txt = $e.text();
+ $e.data('sort-value', txt);
+ sort_val = txt;
+ }
+ column.push([sort_val, tr]);
+ });
+
+ // Sort by the data-order-by value
+ column.sort(function(a, b) { return sortMethod(a[0], b[0]); });
+ if (sort_dir != dir.ASC)
+ column.reverse();
+
+ // Replace the content of tbody with the sorted rows. Strangely
+ // enough, .append accomplishes this for us.
+ trs = $.map(column, function(kv) { return kv[1]; });
+
+ if (collapsedCount > 0) {
+ var showCount = trs.length - collapsedCount;
+ for (var i = 0; i < trs.length; i++) {
+ if (i < showCount) {
+ $(trs[i]).removeClass("collapse");
+ } else {
+ $(trs[i]).addClass("collapse");
+ }
+ }
+ }
+
+ $table.children("tbody").prepend(trs);
+
+ // Reset siblings
+ $table.find("th").data("sort-dir", null).removeClass("sorting-desc sorting-asc");
+ $this_th.data("sort-dir", sort_dir).addClass("sorting-"+sort_dir);
+
+ $table.trigger("aftertablesort", {column: th_index, direction: sort_dir});
+ $table.css("display");
+ }, 10);
+
+ return $this_th;
+ };
+
+ // Call on a sortable td to update its value in the sort. This should be the
+ // only mechanism used to update a cell's sort value. If your display value is
+ // different from your sort value, use jQuery's .text() or .html() to update
+ // the td contents, Assumes stupidtable has already been called for the table.
+ $.fn.updateSortVal = function(new_sort_val){
+ var $this_td = $(this);
+ if($this_td.is('[data-sort-value]')){
+ // For visual consistency with the .data cache
+ $this_td.attr('data-sort-value', new_sort_val);
+ }
+ $this_td.data("sort-value", new_sort_val);
+ return $this_td;
+ };
+
+ // ------------------------------------------------------------------
+ // Default settings
+ // ------------------------------------------------------------------
+ $.fn.stupidtable.dir = {ASC: "asc", DESC: "desc"};
+ $.fn.stupidtable.default_sort_fns = {
+ "int": function(a, b) {
+ return parseInt(a, 10) - parseInt(b, 10);
+ },
+ "float": function(a, b) {
+ return parseFloat(a) - parseFloat(b);
+ },
+ "string": function(a, b) {
+ return a.toString().localeCompare(b.toString());
+ },
+ "string-ins": function(a, b) {
+ a = a.toString().toLocaleLowerCase();
+ b = b.toString().toLocaleLowerCase();
+ return a.localeCompare(b);
+ },
+ "ipv4":function(a,b){
+ var aa = a.split(".");
+ var bb = b.split(".");
+
+ var resulta = aa[0]*0x1000000 + aa[1]*0x10000 + aa[2]*0x100 + aa[3]*1;
+ var resultb = bb[0]*0x1000000 + bb[1]*0x10000 + bb[2]*0x100 + bb[3]*1;
+
+ return resulta-resultb;
+ }
+ };
+})(jQuery);
+
+document.addEventListener("DOMContentLoaded", function() {
+ var table = $(".stupidtable");
+ if (table.length) {
+ table = table.stupidtable();
+ }
+}); \ No newline at end of file
diff --git a/modules-available/js_stupidtable/style.css b/modules-available/js_stupidtable/style.css
new file mode 100644
index 00000000..614a3d38
--- /dev/null
+++ b/modules-available/js_stupidtable/style.css
@@ -0,0 +1,3 @@
+th[data-sort] {
+ cursor: pointer;
+} \ No newline at end of file
diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php
index 0576e660..42026f8b 100644
--- a/modules-available/locations/inc/location.inc.php
+++ b/modules-available/locations/inc/location.inc.php
@@ -385,7 +385,8 @@ class Location
*/
public static function getSubnets()
{
- $res = Database::simpleQuery("SELECT startaddr, endaddr, locationid FROM subnet");
+ $res = Database::simpleQuery("SELECT startaddr, endaddr, locationid FROM subnet WHERE locationid IN (:locations)",
+ array("locations" => User::getAllowedLocations("subnetlist.view")));
$subnets = array();
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
settype($row['locationid'], 'int');
diff --git a/modules-available/locations/lang/de/template-tags.json b/modules-available/locations/lang/de/template-tags.json
index 29a19b85..04d10d06 100644
--- a/modules-available/locations/lang/de/template-tags.json
+++ b/modules-available/locations/lang/de/template-tags.json
@@ -6,6 +6,7 @@
"lang_deleteChildLocations": "Untergeordnete Orte ebenfalls l\u00f6schen",
"lang_deleteLocation": "Ort l\u00f6schen",
"lang_deleteSubnet": "Bereich l\u00f6schen",
+ "lang_deleteSubnetWarning": "Alle zum L\u00f6schen markierten Subnetze werden gelöscht. Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
"lang_editConfigVariables": "Konfig.-Variablen",
"lang_editRoomplan": "Raumplan bearbeiten",
"lang_endAddress": "Endadresse",
@@ -28,7 +29,7 @@
"lang_startAddress": "Startadresse",
"lang_subnet": "IP-Bereich",
"lang_sysConfig": "Lokalisierung",
- "lang_thisListByLocation": "Zur Ortsansicht",
- "lang_thisListBySubnet": "Nach Subnetzen auflisten",
+ "lang_thisListByLocation": "Orte",
+ "lang_thisListBySubnet": "Subnetze",
"lang_unassignedMachines": "Rechner, die in keinen definierten Ort fallen"
} \ No newline at end of file
diff --git a/modules-available/locations/lang/en/template-tags.json b/modules-available/locations/lang/en/template-tags.json
index 7256c958..ddb90f83 100644
--- a/modules-available/locations/lang/en/template-tags.json
+++ b/modules-available/locations/lang/en/template-tags.json
@@ -6,8 +6,9 @@
"lang_deleteChildLocations": "Delete child locations aswell",
"lang_deleteLocation": "Delete location",
"lang_deleteSubnet": "Delete range",
+ "lang_deleteSubnetWarning": "All subnets marked for deletion will be deleted. This cannot be undone!",
"lang_editConfigVariables": "Config vars",
- "lang_editRoomplan": "edit roomplan",
+ "lang_editRoomplan": "Edit roomplan",
"lang_endAddress": "End address",
"lang_listOfSubnets": "List of subnets",
"lang_location": "Location",
@@ -28,7 +29,7 @@
"lang_startAddress": "Start address",
"lang_subnet": "IP range",
"lang_sysConfig": "Localization\/Integration",
- "lang_thisListByLocation": "List by location",
- "lang_thisListBySubnet": "List by subnet",
+ "lang_thisListByLocation": "Locations",
+ "lang_thisListBySubnet": "Subnets",
"lang_unassignedMachines": "Machines not matching any location"
}
diff --git a/modules-available/locations/page.inc.php b/modules-available/locations/page.inc.php
index 20af7b63..d9bc7130 100644
--- a/modules-available/locations/page.inc.php
+++ b/modules-available/locations/page.inc.php
@@ -12,7 +12,7 @@ class Page_Locations extends Page
protected function doPreprocess()
{
User::load();
- if (!User::hasPermission('superadmin')) {
+ if (!User::isLoggedIn()) {
Message::addError('main.no-permission');
Util::redirect('?do=Main');
}
@@ -47,6 +47,12 @@ class Page_Locations extends Page
Message::addError('main.value-invalid', 'locationid', $loc);
continue;
}
+
+ $oldLoc = Database::queryFirst("SELECT locationid FROM subnet WHERE subnetid = :subnetid", array("subnetid" => $subnetid))["locationid"];
+ if (($loc == $oldLoc && !User::hasPermission("subnet.edit", $loc)) ||
+ ($loc != $oldLoc && (!User::hasPermission("subnet.delete", $oldLoc) || !User::hasPermission("subnet.add", $loc))))
+ continue;
+
$range = $this->rangeToLongVerbose($start, $end);
if ($range === false)
continue;
@@ -57,7 +63,7 @@ class Page_Locations extends Page
}
AutoLocation::rebuildAll();
Message::addSuccess('subnets-updated', $count);
- Util::redirect('?do=Locations');
+ Util::redirect('?do=Locations&action=showsubnets');
}
private function addLocations()
@@ -75,6 +81,8 @@ class Page_Locations extends Page
if (empty($name))
continue;
$parent = isset($parents[$idx]) ? (int)$parents[$idx] : 0;
+ if (!User::hasPermission("location.add", $parent))
+ continue;
if ($parent !== 0) {
$ok = false;
foreach ($locs as $loc) {
@@ -115,15 +123,25 @@ class Page_Locations extends Page
$change = false;
// Delete location?
if ($locationId === $del) {
+ if (!User::hasPermission("location.delete", $locationId)) {
+ Message::addError('main.no-permission', 'locationid', $locationId);
+ Util::redirect('?do=Locations');
+ }
$this->deleteLocation($location);
$change = true;
}
// Update subnets
$change |= $this->updateLocationSubnets();
- // Insert subnets
- $change |= $this->addNewLocationSubnets($location);
- // Update location!
- $change |= $this->updateLocationData($location);
+
+ if (User::hasPermission("subnet.add", $locationId)) {
+ // Insert subnets
+ $change |= $this->addNewLocationSubnets($location);
+ }
+ if (User::hasPermission("location.edit", $locationId)) {
+ // Update location!
+ $change |= $this->updateLocationData($location);
+ }
+
if ($change) {
// In case subnets or tree layout changed, recalc this
AutoLocation::rebuildAll();
@@ -195,9 +213,12 @@ class Page_Locations extends Page
private function updateLocationSubnets()
{
$change = false;
+
+ $locationId = Request::post('locationid', false, 'integer');
+
// Deletion first
$dels = Request::post('deletesubnet', false);
- if (is_array($dels)) {
+ if (is_array($dels) && User::hasPermission("subnet.delete", $locationId)) {
$count = 0;
$stmt = Database::prepare('DELETE FROM subnet WHERE subnetid = :id');
foreach ($dels as $key => $value) {
@@ -212,6 +233,9 @@ class Page_Locations extends Page
$change = true;
}
}
+ if (!User::hasPermission("subnet.edit", $locationId))
+ return $change;
+
// Now actual updates
$starts = Request::post('startaddr', false);
$ends = Request::post('endaddr', false);
@@ -291,15 +315,28 @@ class Page_Locations extends Page
Util::redirect('?do=Locations&action=showlocations');
}
if ($getAction === 'showsubnets') {
- $res = Database::simpleQuery("SELECT subnetid, startaddr, endaddr, locationid FROM subnet");
+ $res = Database::simpleQuery("SELECT subnetid, startaddr, endaddr, locationid FROM subnet
+ WHERE locationid IN (:locations) ORDER BY startaddr ASC",
+ array("locations" => User::getAllowedLocations("location.view")));
$rows = array();
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
$row['startaddr'] = long2ip($row['startaddr']);
$row['endaddr'] = long2ip($row['endaddr']);
$row['locations'] = Location::getLocations($row['locationid']);
+
+ $allowedLocs = User::getAllowedLocations("subnet.add");
+ foreach ($row['locations'] as &$loc) {
+ if (!(in_array($loc["locationid"], $allowedLocs) || $loc["locationid"] == $row['locationid'])) {
+ $loc["disabled"] = "disabled";
+ }
+ }
+
+ $row['editThisSubnetAllowed'] = User::hasPermission("subnet.edit", $row['locationid']);
+ $row['deleteThisSubnetAllowed'] = User::hasPermission("subnet.delete", $row['locationid']);
$rows[] = $row;
}
- Render::addTemplate('subnets', array('list' => $rows));
+
+ Render::addTemplate('subnets', array('list' => $rows, 'editSubnetAllowed' => User::hasPermission("subnet.edit")));
} elseif ($getAction === 'showlocations') {
$this->showLocationList();
}
@@ -388,6 +425,32 @@ class Page_Locations extends Page
}
}
}
+
+ $allowedLocs = User::getAllowedLocations("location.view");
+ $withParents = array();
+ foreach ($allowedLocs as $loc) {
+ $withParents = array_merge($withParents, Location::getLocationRootChain($loc));
+ }
+
+ foreach ($locs as $key => $loc) {
+ if (!in_array($loc["locationid"], $withParents)) {
+ unset($locs[$key]);
+ } elseif (!in_array($loc["locationid"], $allowedLocs)) {
+ $id = $locs[$key]["locationid"];
+ $name = $locs[$key]["locationname"];
+ $depth = $locs[$key]["depth"];
+ $locs[$key] = array("locationid" => $id, "locationname" => $name, "depth" => $depth, "linkClass" => "not-allowed");
+ }
+ }
+
+ $addAllowedLocs = User::getAllowedLocations("location.add");
+ $addAllowedList = Location::getLocations(0, 0, True);
+ foreach ($addAllowedList as &$loc) {
+ if (!in_array($loc["locationid"], $addAllowedLocs)) {
+ $loc["disabled"] = "disabled";
+ }
+ }
+
// Output
Render::addTemplate('locations', array(
'list' => array_values($locs),
@@ -400,6 +463,8 @@ class Page_Locations extends Page
'haveOverlapOther' => !empty($overlapOther),
'unassignedCount' => $unassigned,
'defaultConfig' => $defaultConfig,
+ 'addAllowed' => User::hasPermission("location.add"),
+ 'addAllowedList' => array_values($addAllowedList)
));
}
@@ -422,6 +487,11 @@ class Page_Locations extends Page
private function ajaxShowLocation()
{
$locationId = Request::any('locationid', 0, 'integer');
+
+ if (!User::hasPermission("location.view", $locationId)) {
+ die('Permission denied');
+ }
+
$loc = Database::queryFirst('SELECT locationid, parentlocationid, locationname FROM location WHERE locationid = :lid',
array('lid' => $locationId));
if ($loc === false) {
@@ -442,6 +512,14 @@ class Page_Locations extends Page
'roomplanner' => Module::get('roomplanner') !== false && Location::isLeaf($locationId),
'parents' => Location::getLocations($loc['parentlocationid'], $locationId, true)
);
+
+ $allowedLocs = User::getAllowedLocations("location.edit");
+ foreach ($data['parents'] as &$parent) {
+ if (!(in_array($parent["locationid"], $allowedLocs) || $parent["locationid"] == $loc['parentlocationid'])) {
+ $parent["disabled"] = "disabled";
+ }
+ }
+
if (Module::get('dozmod') !== false) {
$lectures = Database::queryFirst('SELECT Count(*) AS cnt FROM sat.lecture l '
. ' INNER JOIN sat.lecture_x_location ll ON (l.lectureid = ll.lectureid AND ll.locationid = :lid)',
@@ -474,6 +552,12 @@ class Page_Locations extends Page
$data['havebaseconfig'] = Module::get('baseconfig') !== false;
$data['havesysconfig'] = Module::get('sysconfig') !== false;
+ $data['editAllowed'] = User::hasPermission("location.edit", $locationId);
+ $data['deleteAllowed'] = User::hasPermission("location.delete", $locationId);
+ $data['editSubnetAllowed'] = User::hasPermission("subnet.edit", $locationId);
+ $data['deleteSubnetAllowed'] = User::hasPermission("subnet.delete", $locationId);
+ $data['addSubnetAllowed'] = User::hasPermission("subnet.add", $locationId);
+ $data['saveButton'] = $data['editAllowed'] || $data['editSubnetAllowed'] || $data['deleteSubnetAllowed'] || $data['addSubnetAllowed'];
// echo '<pre>';
// var_dump($data);
diff --git a/modules-available/locations/permissions/permissions.json b/modules-available/locations/permissions/permissions.json
new file mode 100644
index 00000000..db0ac5f6
--- /dev/null
+++ b/modules-available/locations/permissions/permissions.json
@@ -0,0 +1,9 @@
+{
+ "location.view": "View locations.",
+ "location.edit": "Edit locations.",
+ "location.add": "Add locations.",
+ "location.delete": "Delete locations.",
+ "subnet.edit": "Edit subnets.",
+ "subnet.add": "Add subnets.",
+ "subnet.delete": "Delete subnets."
+} \ No newline at end of file
diff --git a/modules-available/locations/style.css b/modules-available/locations/style.css
index 86f9dfca..042ac4d1 100644
--- a/modules-available/locations/style.css
+++ b/modules-available/locations/style.css
@@ -1,3 +1,14 @@
table.locations tbody td:nth-of-type(even) {
background-color: rgba(0, 0, 0, 0.025);
-} \ No newline at end of file
+}
+
+.not-allowed {
+ pointer-events: none;
+ cursor: default;
+ color: inherit;
+}
+
+.disabled {
+ pointer-events: none;
+ opacity: 0.6;
+}
diff --git a/modules-available/locations/templates/location-subnets.html b/modules-available/locations/templates/location-subnets.html
index b8a2b091..2cc8e98b 100644
--- a/modules-available/locations/templates/location-subnets.html
+++ b/modules-available/locations/templates/location-subnets.html
@@ -1,6 +1,6 @@
<div class="slx-well">
<div class="slx-bold">{{lang_locationSettings}}</div>
- <form method="post" action="?do=Locations">
+ <form id="locationForm{{locationid}}" method="post" action="?do=Locations">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="updatelocation">
<input type="hidden" name="locationid" value="{{locationid}}">
@@ -8,30 +8,25 @@
<button type="submit" class="btn btn-primary">Save</button>
</div>
<div class="row">
- <div class="col-sm-6">
- <div class="input-group">
- <span class="input-group-addon slx-ga2">{{lang_name}}</span>
- <input class="form-control" type="text" name="locationname" value="{{locationname}}" pattern=".*\S.*">
+ <div class="{{^editAllowed}}disabled{{/editAllowed}}">
+ <div class="col-sm-6">
+ <div class="input-group">
+ <span class="input-group-addon slx-ga">{{lang_name}}</span>
+ <input class="form-control" type="text" name="locationname" value="{{locationname}}" pattern=".*\S.*">
+ </div>
</div>
- </div>
- <div class="col-sm-6">
- <div class="input-group">
- <span class="input-group-addon slx-ga2">{{lang_parentLocation}}</span>
- <select class="form-control" name="parentlocationid">
- {{#parents}}
- <option value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
- {{/parents}}
- </select>
+ <div class="col-sm-6">
+ <div class="input-group">
+ <span class="input-group-addon slx-ga2">{{lang_parentLocation}}</span>
+ <select class="form-control" name="parentlocationid">
+ {{#parents}}
+ <option {{disabled}} value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
+ {{/parents}}
+ </select>
+ </div>
</div>
</div>
</div>
- <div>
- <div class="pull-right">
- <label><input type="checkbox" name="recursive" value="on"> {{lang_deleteChildLocations}}</label>
- <button type="submit" class="btn btn-sm btn-danger" name="deletelocation" value="{{locationid}}" onclick="return slxConfirm()">{{lang_deleteLocation}}</button>
- </div>
- <div class="clearfix"></div>
- </div>
<br>
<div class="slx-bold">{{lang_assignedSubnets}}</div>
<div><i>{{lang_assignSubnetExplanation}}</i></div>
@@ -40,47 +35,92 @@
<th>#</th>
<th>{{lang_startAddress}}</th>
<th>{{lang_endAddress}}</th>
- <th title="{{lang_deleteSubnet}}"><span class="glyphicon glyphicon-trash"></span></th>
+ <th title="{{lang_deleteSubnet}}" class="text-center"><span class="glyphicon glyphicon-trash"></span></th>
</tr>
{{#list}}
<tr class="cidrmagic">
<td>{{subnetid}}</td>
- <td><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
- <td><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
- <td class="danger" align="center"><input type="checkbox" name="deletesubnet[{{subnetid}}]" value="on"></td>
+ <td class="{{^editSubnetAllowed}}disabled{{/editSubnetAllowed}}"><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
+ <td class="{{^editSubnetAllowed}}disabled{{/editSubnetAllowed}}"><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></td>
+ <td class="danger">
+ <div class="checkbox text-center" style="margin-left: 9px">
+ <input {{^deleteSubnetAllowed}}disabled{{/deleteSubnetAllowed}} type="checkbox" name="deletesubnet[{{subnetid}}]" value="on">
+ <label class="text-left"></label>
+ </div>
+ </td>
</tr>
{{/list}}
<tr id="loc-sub-{{locationid}}">
<td colspan="4">
- <button class="btn btn-success btn-sm" type="button" onclick="slxAddSubnetRow(this, {{locationid}})" title="{{lang_addNewSubnet}}">
- <span class="glyphicon glyphicon-plus-sign"></span> {{lang_subnet}}
+ <button {{^addSubnetAllowed}}disabled{{/addSubnetAllowed}} class="btn btn-success btn-sm pull-right" type="button" onclick="slxAddSubnetRow(this, {{locationid}})" title="{{lang_addNewSubnet}}">
+ <span class="glyphicon glyphicon-plus"></span> {{lang_subnet}}
</button>
</td>
</tr>
</table>
- <br>
- <div class="btn-group">
- {{#roomplanner}}
- <a class="btn btn-default" href="?do=roomplanner&amp;locationid={{locationid}}" target="_blank"
+ <div class="slx-bold">{{lang_locationInfo}}</div>
+
+ <div class="row">
+ <div class="col-md-4">
+ {{#haveDozmod}}
+ <div>
+ <span class="slx-ga2">{{lang_referencingLectures}}:</span> {{lectures}}
+ </div>
+ {{/haveDozmod}}
+ {{#haveStatistics}}
+ <div>
+ <span class="slx-ga2">{{lang_matchingMachines}}:</span> <a href="?do=Statistics&amp;show=list&amp;filters=location={{locationid}}">{{machines}} / {{machines_online}} / {{machines_used}} ({{used_percent}}%)</a>
+ </div>
+ {{/haveStatistics}}
+ </div>
+ <div class="col-md-4 text-center">
+ <div class="btn-group">
+ {{#roomplanner}}
+ <a class="btn btn-default" href="?do=roomplanner&amp;locationid={{locationid}}" target="_blank"
onclick="window.open(this.href, '_blank', 'toolbar=0,scrollbars,resizable');return false">
- <span class="glyphicon glyphicon-move"></span>{{lang_editRoomplan}}
- </a>
- {{/roomplanner}}
+ <span class="glyphicon glyphicon-move"></span> {{lang_editRoomplan}}
+ </a>
+ {{/roomplanner}}
+ </div>
+ </div>
+ <div class="col-md-4 text-right">
+ <button style="margin-right: 10px" {{^deleteAllowed}}disabled{{/deleteAllowed}} type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteLocationModal{{locationid}}"><span class="glyphicon glyphicon-trash"></span> {{lang_deleteLocation}}</button>
+ <button onclick="deleteSubnetWarning('{{locationid}}')" {{^saveButton}}disabled{{/saveButton}} type="button" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
</div>
- <div class="pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
- </div>
- <div class="slx-bold">{{lang_locationInfo}}</div>
- {{#haveDozmod}}
- <div>
- <span class="slx-ga2">{{lang_referencingLectures}}:</span> {{lectures}}
+
+ <div class="modal fade" id="deleteLocationModal{{locationid}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_areYouSureNoUndo}}
+ <div class="checkbox">
+ <input type="checkbox" name="recursive" value="on">
+ <label>{{lang_deleteChildLocations}}</label>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" class="btn btn-danger" name="deletelocation" value="{{locationid}}"><span class="glyphicon glyphicon-trash"></span> {{lang_deleteLocation}}</button>
+ </div>
+ </div>
+ </div>
</div>
- {{/haveDozmod}}
- {{#haveStatistics}}
- <div>
- <span class="slx-ga2">{{lang_matchingMachines}}:</span> <a href="?do=Statistics&amp;show=list&amp;filters=location={{locationid}}">{{machines}} / {{machines_online}} / {{machines_used}} ({{used_percent}}%)</a>
+
+ <div class="modal fade" id="saveWarningModal{{locationid}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_deleteSubnetWarning}}
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+ </div>
+ </div>
</div>
- {{/haveStatistics}}
+
</form>
-</div>
+</div> \ No newline at end of file
diff --git a/modules-available/locations/templates/locations.html b/modules-available/locations/templates/locations.html
index c2dc610e..fb09a45e 100644
--- a/modules-available/locations/templates/locations.html
+++ b/modules-available/locations/templates/locations.html
@@ -1,6 +1,7 @@
<div>
- <div class="pull-right">
- <a href="?do=Locations&amp;action=showsubnets">{{lang_thisListBySubnet}}</a>
+ <div class="btn-group pull-right">
+ <a href="?do=Locations&amp;action=showlocations" class="btn btn-default active"><span class="glyphicon glyphicon-home"></span> {{lang_thisListByLocation}}</a>
+ <a href="?do=Locations&amp;action=showsubnets" class="btn btn-default"><span class="glyphicon glyphicon-list-alt"></span> {{lang_thisListBySubnet}}</a>
</div>
<h1>{{lang_locationsMainHeading}}</h1>
<table class="table table-condensed locations" style="margin-bottom:0px">
@@ -23,9 +24,10 @@
<tr>
<td>
<div style="display:inline-block;width:{{depth}}em"></div>
- <a href="#" onclick="slxOpenLocation(this, {{locationid}}); return false">{{locationname}} <b class="caret"></b></a>
+ <a href="#" class="{{linkClass}}" onclick="slxOpenLocation(this, {{locationid}}); return false">{{locationname}}{{^linkClass}} <b class="caret"></b>{{/linkClass}}</a>
</td>
<td class="text-nowrap" align="right">
+ {{^linkClass}}
{{#havestatistics}}
{{clientCount}}
<span class="text-muted">
@@ -34,13 +36,17 @@
</span>
<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}}
+ {{/linkClass}}
</td>
<td class="text-nowrap" align="right">
+ {{^linkClass}}
{{#havestatistics}}
{{clientLoad}}
{{/havestatistics}}
+ {{/linkClass}}
</td>
<td class="text-nowrap">
+ {{^linkClass}}
{{#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>
@@ -49,8 +55,10 @@
{{lang_overrideCount}}: {{overriddenVars}}&emsp;&emsp;
{{/overriddenVars}}
{{/havebaseconfig}}
+ {{/linkClass}}
</td>
<td class="text-nowrap">
+ {{^linkClass}}
{{#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>
@@ -59,6 +67,7 @@
{{configName}}&emsp;&emsp;
</span>
{{/havesysconfig}}
+ {{/linkClass}}
</td>
</tr>
{{/list}}
@@ -84,14 +93,14 @@
<input type="hidden" name="action" value="addlocations">
<table class="table table-condensed table-hover">
<tr id="lasttr">
- <td>
- <button class="btn btn-success btn-sm" type="button" onclick="slxAddLocationRow()">
- <span class="glyphicon glyphicon-plus-sign"></span> {{lang_location}}
+ <td width="60%">&emsp;</td>
+ <td class="text-right" colspan="2">
+ <button id="saveLocationRows" type="submit" class="btn btn-primary" style="display: none">
+ <span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}
+ </button>
+ <button {{^addAllowed}}disabled{{/addAllowed}} class="btn btn-success" type="button" onclick="slxAddLocationRow()">
+ <span class="glyphicon glyphicon-plus"></span> {{lang_location}}
</button>
- </td>
- <td width="80%">&emsp;</td>
- <td width="20%" align="right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
</td>
</tr>
</table>
@@ -111,17 +120,28 @@
var slxAddCounter = 0;
var slxLastLocation = false;
+var newRowCounter = 0;
+
function slxAddLocationRow() {
+ $("#saveLocationRows").show();
var tr = $('#lasttr');
- tr.before('<tr>\
- <td>#</td>\
+ tr.before('<tr id="row' + slxAddCounter + '">\
<td><input class="form-control" type="text" name="newlocation[' + slxAddCounter + ']" placeholder="{{lang_locationName}}" pattern=".*\\S.*"></td>\
<td><select class="form-control" name="newparent[' + slxAddCounter + ']">\
- <option value="0">{{lang_noParent}}</option>\
- {{#list}}<option value="{{locationid}}">{{locationpad}} {{locationname}}</option>{{/list}}\
+ {{#addAllowedList}}<option {{disabled}} value="{{locationid}}">{{locationpad}} {{locationname}}</option>{{/addAllowedList}}\
</select></td>\
+ <td class="text-center"><button class="btn btn-default btn-sm" type="button" onclick="removeNewLocationRow(' + slxAddCounter + ')"><span class="glyphicon glyphicon-remove"></span></button></td>\
</tr>');
slxAddCounter++;
+ newRowCounter++;
+}
+
+function removeNewLocationRow(r) {
+ $("#row"+r).remove();
+ newRowCounter--;
+ if (newRowCounter === 0) {
+ $("#saveLocationRows").hide();
+ }
}
function slxOpenLocation(e, lid) {
@@ -134,9 +154,10 @@ function slxOpenLocation(e, lid) {
if (existing.is(slxLastLocation)) {
slxLastLocation = false;
} else {
- existing.show()[0].scrollIntoView();
+ existing.show();
$(e).closest('tr').addClass('active slx-bold');
slxLastLocation = existing;
+ scollIntoView(existing);
}
return;
}
@@ -146,25 +167,51 @@ function slxOpenLocation(e, lid) {
$(e).closest('tr').addClass('active slx-bold').after(tr);
td.load('?do=Locations&action=showlocation&locationid=' + lid, function() {
slxAttachCidr();
- $('#location-details-' + lid)[0].scrollIntoView();
+ scollIntoView(tr);
});
slxLastLocation = tr;
}
+function scollIntoView(el) {
+ var offset = $(el).offset();
+ var win = $(window);
+ var h = $(el).height();
+ if (offset.top + h > win.scrollTop() + win.height()) {
+ offset.top -= win.height();
+ offset.top += h;
+ $('html, body').animate({
+ scrollTop: offset.top
+ });
+ }
+}
+
function slxAddSubnetRow(e, lid) {
var tr = $('#loc-sub-' + lid);
- tr.before('<tr class="cidrmagic">\
+ tr.before('<tr id="row' + slxAddCounter + '" class="cidrmagic">\
<td>#</td>\
<td><input class="form-control cidrstart" type="text" name="newstartaddr[' + slxAddCounter + ']" pattern="\\d{1,3}\.\\d{1,3}\.\\d{1,3}\.\\d{1,3}"></td>\
<td><input class="form-control cidrend" type="text" name="newendaddr[' + slxAddCounter + ']" pattern="\\d{1,3}\.\\d{1,3}\.\\d{1,3}\.\\d{1,3}"></td>\
- <td></td>\
+ <td class="text-center"><button class="btn btn-default btn-sm" type="button" onclick="removeNewSubnetRow(' + slxAddCounter + ')"><span class="glyphicon glyphicon-remove"></span></button></td>\
</tr>');
slxAddCounter++;
slxAttachCidr();
}
+function removeNewSubnetRow(r) {
+ $("#row"+r).remove();
+}
+
function slxConfirm() {
return confirm('{{lang_areYouSureNoUndo}}');
}
+
+function deleteSubnetWarning(locid) {
+ var form = $("#locationForm"+locid);
+ if (form.find("input[type=checkbox]:checked").length > 0) {
+ $("#saveWarningModal"+locid).modal();
+ } else {
+ form.submit();
+ }
+}
// -->
</script>
diff --git a/modules-available/locations/templates/subnets.html b/modules-available/locations/templates/subnets.html
index 15fa28f2..cb7fb758 100644
--- a/modules-available/locations/templates/subnets.html
+++ b/modules-available/locations/templates/subnets.html
@@ -1,6 +1,7 @@
<div>
- <div class="pull-right">
- <a href="?do=Locations&amp;action=showlocations">{{lang_thisListByLocation}}</a>
+ <div class="btn-group pull-right">
+ <a href="?do=Locations&amp;action=showlocations" class="btn btn-default"><span class="glyphicon glyphicon-home"></span> {{lang_thisListByLocation}}</a>
+ <a href="?do=Locations&amp;action=showsubnets" class="btn btn-default active"><span class="glyphicon glyphicon-list-alt"></span> {{lang_thisListBySubnet}}</a>
</div>
<h1>{{lang_listOfSubnets}}</h1>
<form method="post" action="?do=Locations">
@@ -16,20 +17,20 @@
{{#list}}
<tr class="cidrmagic">
<td>{{subnetid}}</td>
- <td><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}"></td>
- <td><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}"></td>
- <td>
+ <td class="{{^editThisSubnetAllowed}}disabled{{/editThisSubnetAllowed}}"><input class="form-control cidrstart" type="text" name="startaddr[{{subnetid}}]" value="{{startaddr}}"></td>
+ <td class="{{^editThisSubnetAllowed}}disabled{{/editThisSubnetAllowed}}"><input class="form-control cidrend" type="text" name="endaddr[{{subnetid}}]" value="{{endaddr}}"></td>
+ <td class="{{^deleteThisSubnetAllowed}}disabled{{/deleteThisSubnetAllowed}}">
<select class="form-control" name="location[{{subnetid}}]">
{{#locations}}
- <option value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
+ <option {{disabled}} value="{{locationid}}" {{#selected}}selected="selected"{{/selected}}>{{locationpad}} {{locationname}}</option>
{{/locations}}
</select>
</td>
</tr>
{{/list}}
</table>
- <div>
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <div class="text-right" style="margin-bottom: 20px">
+ <button {{^editSubnetAllowed}}disabled{{/editSubnetAllowed}} type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</form>
</div>
diff --git a/modules-available/minilinux/templates/filelist.html b/modules-available/minilinux/templates/filelist.html
index ca94f4d0..ec3aee57 100644
--- a/modules-available/minilinux/templates/filelist.html
+++ b/modules-available/minilinux/templates/filelist.html
@@ -1,9 +1,6 @@
{{#systems}}
- <div class="panel panel-default">
- <div class="panel-heading">
- <h4>{{title}}</h4>
- </div>
- <div class="panel-body" id="download-{{id}}">
+ <h1>{{title}}</h1>
+ <div id="download-{{id}}">
<div class="input-group pull-right" style="max-width: 400px">
<span class="input-group-addon slx-ga">{{lang_desiredVersion}}</span>
<select id="versionbox" class="form-control" onchange="loadSystemList($('#versionbox').val())">
diff --git a/modules-available/news/config.json b/modules-available/news/config.json
index 706412d0..e076ea5c 100644
--- a/modules-available/news/config.json
+++ b/modules-available/news/config.json
@@ -1,3 +1,4 @@
{
- "category":"main.content"
+ "category":"main.content",
+ "dependencies": [ "js_stupidtable" ]
}
diff --git a/modules-available/news/page.inc.php b/modules-available/news/page.inc.php
index ee377dc4..5ad79b0e 100644
--- a/modules-available/news/page.inc.php
+++ b/modules-available/news/page.inc.php
@@ -31,12 +31,10 @@ class Page_News extends Page
// load user, we will need it later
User::load();
-
- // only admins should be able to edit news
- if (!User::hasPermission('superadmin')) {
- Message::addError('main.no-permission');
- Util::redirect('?do=Main');
- }
+ if (!User::isLoggedIn()) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=Main');
+ }
// check which action we need to do
$action = Request::any('action', 'show');
@@ -66,26 +64,41 @@ class Page_News extends Page
$pageType = Request::post('news-type');
if ($pageType == 'news') {
- if (!$this->saveNews()) {
- // re-set the fields we got
- Request::post('news-title') ? $this->newsTitle = Request::post('news-title') : $this->newsTitle = false;
- Request::post('news-content') ? $this->newsContent = Request::post('news-content') : $this->newsContent = false;
- } else {
- Message::addSuccess('news-save-success');
- $lastId = Database::lastInsertId();
- Util::redirect("?do=News&newsid=$lastId");
- }
+ if (User::hasPermission("news.save")) {
+ if (!$this->saveNews()) {
+ // re-set the fields we got
+ Request::post('news-title') ? $this->newsTitle = Request::post('news-title') : $this->newsTitle = false;
+ Request::post('news-content') ? $this->newsContent = Request::post('news-content') : $this->newsContent = false;
+ } else {
+ Message::addSuccess('news-save-success');
+ $lastId = Database::lastInsertId();
+ Util::redirect("?do=News&newsid=$lastId");
+ }
+ }
} elseif ($pageType == 'help') {
- if ($this->saveHelp()) {
- Message::addSuccess('help-save-success');
- $lastId = Database::lastInsertId();
- Util::redirect("?do=News&newsid=$lastId");
- }
+ if (User::hasPermission("help.save")) {
+ if ($this->saveHelp()) {
+ Message::addSuccess('help-save-success');
+ $lastId = Database::lastInsertId();
+ Util::redirect("?do=News&newsid=$lastId");
+ }
+ }
}
} elseif ($action === 'delete') {
// delete it
- $this->delNews(Request::post('newsid'));
- Util::redirect('?do=News&editHelp='.Request::any('editHelp'));
+ $pageType = Request::post('news-type');
+
+ if ($pageType == 'news') {
+ if(User::hasPermission("news.delete")) {
+ $this->delNews(Request::post('newsid'));
+ Util::redirect('?do=News&editHelp='.Request::any('editHelp'));
+ }
+ } elseif ($pageType == 'help') {
+ if(User::hasPermission("help.delete")) {
+ $this->delNews(Request::post('newsid'));
+ Util::redirect('?do=News&editHelp='.Request::any('editHelp'));
+ }
+ }
} else {
// unknown action, redirect user
Message::addError('invalid-action', $action);
@@ -134,6 +147,10 @@ class Page_News extends Page
'editHelp' => $this->editHelp,
'list' => $lines,
'listHelp' => $linesHelp,
+ 'allowedNewsSave' => User::hasPermission("news.save"),
+ 'allowedNewsDelete' => User::hasPermission("news.delete"),
+ 'allowedHelpSave' => User::hasPermission("help.save"),
+ 'allowedHelpDelete' => User::hasPermission("help.delete"),
'hasSummernote' => $this->hasSummernote, ));
}
/**
diff --git a/modules-available/news/permissions/permissions.json b/modules-available/news/permissions/permissions.json
new file mode 100644
index 00000000..90d07aef
--- /dev/null
+++ b/modules-available/news/permissions/permissions.json
@@ -0,0 +1,6 @@
+{
+ "news.save": "Save new news.",
+ "news.delete": "Delete old news.",
+ "help.save": "Save new help texts.",
+ "help.delete": "Delete old help texts"
+} \ No newline at end of file
diff --git a/modules-available/news/style.css b/modules-available/news/style.css
index c11567ec..fc4bccab 100644
--- a/modules-available/news/style.css
+++ b/modules-available/news/style.css
@@ -4,3 +4,7 @@
background: none;
border: none;
}
+
+.bottom-margin-50 {
+ margin-bottom: 50px;
+}
diff --git a/modules-available/news/templates/page-news.html b/modules-available/news/templates/page-news.html
index 192635ea..6293b62d 100644
--- a/modules-available/news/templates/page-news.html
+++ b/modules-available/news/templates/page-news.html
@@ -1,5 +1,5 @@
-
<h1>{{lang_vmChooser_title}}</h1>
+
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="{{^editHelp}}active{{/editHelp}}"><a href="#news" role="tab" data-toggle="tab">{{lang_editNews}}</a></li>
<li role="presentation" class="{{#editHelp}}active{{/editHelp}}" ><a href="#help" role="tab" data-toggle="tab">{{lang_editHelp}}</a></li>
@@ -17,9 +17,16 @@
<label for="news-content-id">{{lang_content}}</label>
<textarea name="news-content" id ="news-content-id" class="form-control summernote" rows="5" cols="30" placeholder="">{{latestContent}}</textarea>
</div>
- <p>{{lang_latestUpdate}}: {{latestDate}}</p>
- <button class="btn btn-primary btn-sm sn-btn" name="news-type" value="news" type="submit">{{lang_save}}</button>
- <input type="hidden" name="token" value="{{token}}">
+ <div class="row">
+ <div class="text-left col-md-6">
+ <p>{{lang_latestUpdate}}: {{latestDate}}</p>
+ </div>
+ <div class="text-right col-md-6">
+ <button {{^allowedNewsSave}}disabled{{/allowedNewsSave}} class="btn btn-primary sn-btn" name="news-type" value="news" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ <input type="hidden" name="token" value="{{token}}">
+ </div>
+ </div>
+
</form>
<br/>
<div class="panel panel-default">
@@ -29,24 +36,28 @@
<div class="panel-body">
<div class="table-responsive">
<form method="post" action="?do=News&amp;action=delete">
- <table class="table table-stripped table-condensed">
+ <table class="table table-stripped table-condensed stupidtable">
<thead>
<tr>
- <th>{{lang_date}}</th>
- <th>{{lang_title}}</th>
- <th>{{lang_content}}</th>
- <th></th>
+ <th data-sort="int">{{lang_date}}</th>
+ <th data-sort="string">{{lang_title}}</th>
+ <th data-sort="string">{{lang_content}}</th>
+ <th class="text-center">{{lang_show}}</th>
+ <th class="text-center">{{lang_delete}}</th>
</tr>
</thead>
<tbody>
{{#list}}
<tr {{#active}}class="active"{{/active}}>
- <td class="text-left text-nowrap">{{date}}</td>
+ <td class="text-left text-nowrap" data-sort-value={{dateline}}>{{date}}</td>
<td><table class="slx-ellipsis"><tr><td>{{title}}</td></tr></table></td>
<td><table class="slx-ellipsis"><tr><td>{{content}}</td></tr></table></td>
- <td class="text-nowrap">
- <a class="btn btn-primary btn-xs" href="?do=news&amp;newsid={{newsid}}&amp;action=show"><span class="glyphicon glyphicon-share-alt"></span> {{lang_show}}</a>
- <button class="btn btn-danger btn-xs" type="submit" name="newsid" value="{{newsid}}"><span class="glyphicon glyphicon-remove"></span> {{lang_delete}}</button>
+ <td class="text-center">
+ <a class="btn btn-primary btn-xs" href="?do=news&amp;newsid={{newsid}}&amp;action=show"><span class="glyphicon glyphicon-share-alt"></span></a>
+ </td>
+ <td class="text-center">
+ <input type="hidden" name="news-type" value="news">
+ <button {{^allowedNewsDelete}}disabled{{/allowedNewsDelete}} class="btn btn-danger btn-xs" type="submit" name="newsid" value="{{newsid}}"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
{{/list}}
@@ -61,12 +72,16 @@
<div role="tabpanel" class="tab-pane {{#editHelp}}active{{/editHelp}}" id="help">
<form action="?do=News&amp;action=save" method="post">
<div class="form-group">
+ <br/>
<label for="news-content-id">{{lang_content}}</label>
<textarea name="help-content" id="help-content-id" class="form-control summernote" style="min-height:400px" placeholder="">{{latestHelp}}</textarea>
</div>
- <button class="btn btn-primary btn-sm sn-btn" name="news-type" value="help" type="submit">{{lang_save}}</button>
- <input type="hidden" name="token" value="{{token}}">
+ <div class="text-right">
+ <button {{^allowedHelpSave}}disabled{{/allowedHelpSave}} class="btn btn-primary sn-btn" name="news-type" value="help" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ <input type="hidden" name="token" value="{{token}}">
+ </div>
</form>
+ <br/>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_oldHelp}}
@@ -74,22 +89,26 @@
<div class="panel-body">
<div class="table-responsive">
<form method="post" action="?do=News&amp;action=delete&editHelp=true">
- <table class="table table-stripped table-condensed">
+ <table class="table table-stripped table-condensed stupidtable">
<thead>
<tr>
- <th>{{lang_date}}</th>
- <th>{{lang_content}}</th>
- <th></th>
+ <th data-sort="int">{{lang_date}}</th>
+ <th data-sort="string">{{lang_content}}</th>
+ <th class="text-center">{{lang_show}}</th>
+ <th class="text-center">{{lang_delete}}</th>
</tr>
</thead>
<tbody>
{{#listHelp}}
<tr {{#active}}class="active"{{/active}}>
- <td class="text-left text-nowrap">{{date}}</td>
+ <td class="text-left text-nowrap" data-sort-value={{dateline}}>{{date}}</td>
<td><table class="slx-ellipsis"><tr><td>{{content}}</td></tr></table></td>
- <td class="text-nowrap">
- <a class="btn btn-primary btn-xs" href="?do=news&amp;newsid={{newsid}}&amp;action=show"><span class="glyphicon glyphicon-share-alt"></span> {{lang_show}}</a>
- <button class="btn btn-danger btn-xs" type="submit" name="newsid" value="{{newsid}}"><span class="glyphicon glyphicon-remove"></span> {{lang_delete}}</button>
+ <td class="text-center">
+ <a class="btn btn-primary btn-xs" href="?do=news&amp;newsid={{newsid}}&amp;action=show"><span class="glyphicon glyphicon-share-alt"></span></a>
+ </td>
+ <td class="text-center">
+ <input type="hidden" name="news-type" value="help">
+ <button {{^allowedHelpDelete}}disabled{{/allowedHelpDelete}} class="btn btn-danger btn-xs" type="submit" name="newsid" value="{{newsid}}"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
{{/listHelp}}
diff --git a/modules-available/permissionmanager/api.inc.php b/modules-available/permissionmanager/api.inc.php
new file mode 100644
index 00000000..0d84ebce
--- /dev/null
+++ b/modules-available/permissionmanager/api.inc.php
@@ -0,0 +1,7 @@
+<?php
+
+echo json_encode(array(
+ 'key' => 'value',
+ 'number' => 123,
+ 'list' => array(1,2,3,4,5,6,'foo')
+));
diff --git a/modules-available/permissionmanager/clientscript.js b/modules-available/permissionmanager/clientscript.js
new file mode 100644
index 00000000..700ebc11
--- /dev/null
+++ b/modules-available/permissionmanager/clientscript.js
@@ -0,0 +1,48 @@
+document.addEventListener("DOMContentLoaded", function() {
+ var selectize = $('#select-role');
+ if (selectize.length) {
+ selectize = selectize.selectize({
+ allowEmptyOption: false,
+ maxItems: null,
+ highlight: false,
+ hideSelected: true,
+ create: false,
+ plugins: ["remove_button"]
+ })[0].selectize;
+
+ // If Site gets refreshed, all data-selectizeCounts will be reset to 0, so delete the filters from the selectize
+ selectize.clear();
+
+ selectize.on('item_add', function (value, $item) {
+ // When first item gets added the filter isn't empty anymore, so hide all rows
+ if (selectize.items.length === 1) {
+ $('.dataTable tbody').find('tr').hide();
+ }
+ // Find all rows which shall be shown and increase their counter by 1
+ $(".roleid-" + value).closest("tr").each(function () {
+ $(this).data("selectizeCount", $(this).data("selectizeCount") + 1);
+ $(this).show();
+ });
+ });
+
+ selectize.on('item_remove', function (value, $item) {
+ // When no items in the filter, show all rows again
+ if (selectize.items.length === 0) {
+ $('.dataTable tbody').find('tr').show();
+ } else {
+ // Find all rows which have the delete role, decrease their counter by 1
+ $(".roleid-" + value).closest("tr").each(function () {
+ $(this).data("selectizeCount", $(this).data("selectizeCount") - 1);
+ // If counter is 0, hide the row (no filter given to show the row anymore)
+ if ($(this).data("selectizeCount") === 0) {
+ $(this).closest("tr").hide();
+ }
+ });
+ }
+ });
+ }
+
+ $("form input").keydown(function(e) {
+ if (e.keyCode === 13) e.preventDefault();
+ });
+}); \ No newline at end of file
diff --git a/modules-available/permissionmanager/config.json b/modules-available/permissionmanager/config.json
new file mode 100644
index 00000000..c92e917a
--- /dev/null
+++ b/modules-available/permissionmanager/config.json
@@ -0,0 +1,4 @@
+{
+ "category":"main.content",
+ "dependencies": [ "locations", "js_stupidtable", "bootstrap_switch", "js_selectize" ]
+}
diff --git a/modules-available/permissionmanager/inc/getpermissiondata.inc.php b/modules-available/permissionmanager/inc/getpermissiondata.inc.php
new file mode 100644
index 00000000..13c7ca89
--- /dev/null
+++ b/modules-available/permissionmanager/inc/getpermissiondata.inc.php
@@ -0,0 +1,90 @@
+<?php
+
+class GetPermissionData {
+
+ // get UserIDs, User Login Names, User Roles
+ public static function getUserData() {
+ $res = self::queryUserData();
+ $userdata= array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $userdata[$row['userid'].' '.$row['login']][] = array(
+ 'roleid' => $row['roleid'],
+ 'rolename' => $row['rolename']
+ );
+ }
+ $data = array();
+ foreach($userdata AS $user => $roles) {
+ $user = explode(" ", $user, 2);
+ $data[] = array(
+ 'userid' => $user[0],
+ 'username' => $user[1],
+ 'roles' => $roles
+ );
+ }
+ return $data;
+ }
+
+ // get LocationIDs, Location Names, Roles of each Location
+ public static function getLocationData() {
+ $res = Database::simpleQuery("SELECT role.roleid as roleid, rolename, GROUP_CONCAT(COALESCE(locationid, 0)) AS locationids FROM role
+ INNER JOIN role_x_location ON role.roleid = role_x_location.roleid GROUP BY roleid ORDER BY rolename ASC");
+ $locations = Location::getLocations(0, 0, false, true);
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $locationids = explode(",", $row['locationids']);
+ if (in_array("0", $locationids)) {
+ $locationids = array_map("intval", Location::extractIds(Location::getTree()));
+ } else {
+ $locationids = PermissionUtil::getSublocations(Location::getTree(), $locationids);
+ }
+ foreach ($locationids as $locationid) {
+ $locations[$locationid]['roles'][] = array(
+ 'roleid' => $row['roleid'],
+ 'rolename' => $row['rolename']
+ );
+ }
+ }
+ return array_values($locations);
+ }
+
+ // get all roles from database (id and name)
+ public static function getRoles() {
+ $res = Database::simpleQuery("SELECT roleid, rolename FROM role ORDER BY rolename ASC");
+ $data = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $data[] = array(
+ 'roleid' => $row['roleid'],
+ 'rolename' => $row['rolename']
+ );
+ }
+ return $data;
+ }
+
+ public static function getRoleData($roleid) {
+ $query = "SELECT roleid, rolename FROM role WHERE roleid = :roleid";
+ $data = Database::queryFirst($query, array("roleid" => $roleid));
+ $query = "SELECT roleid, locationid FROM role_x_location WHERE roleid = :roleid";
+ $res = Database::simpleQuery($query, array("roleid" => $roleid));
+ $data["locations"] = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $data["locations"][] = $row['locationid'];
+ }
+ $query = "SELECT roleid, permissionid FROM role_x_permission WHERE roleid = :roleid";
+ $res = Database::simpleQuery($query, array("roleid" => $roleid));
+ $data["permissions"] = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $data["permissions"][] = $row['permissionid'];
+ }
+ return $data;
+ }
+
+ // UserID, User Login Name, Roles of each User
+ private static function queryUserData() {
+ $res = Database::simpleQuery("SELECT user.userid AS userid, user.login AS login, role.rolename AS rolename, role.roleid AS roleid
+ FROM user
+ LEFT JOIN user_x_role ON user.userid = user_x_role.userid
+ LEFT JOIN role ON user_x_role.roleid = role.roleid
+ ");
+ return $res;
+ }
+
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/inc/permissiondbupdate.inc.php b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php
new file mode 100644
index 00000000..f144b35e
--- /dev/null
+++ b/modules-available/permissionmanager/inc/permissiondbupdate.inc.php
@@ -0,0 +1,53 @@
+<?php
+
+class PermissionDbUpdate {
+
+ // insert new user_x_role to database. "ignore" to ignore duplicate entry try
+ public static function addRoleToUser($users, $roles) {
+ $query = "INSERT IGNORE INTO user_x_role (userid, roleid) VALUES (:userid, :roleid)";
+ foreach($users AS $userid) {
+ foreach ($roles AS $roleid) {
+ Database::exec($query, array("userid" => $userid, "roleid" => $roleid));
+ }
+ }
+ }
+
+ // remove user_x_role entry from database
+ public static function removeRoleFromUser($users, $roles) {
+ $query = "DELETE FROM user_x_role WHERE userid IN (:users) AND roleid IN (:roles)";
+ Database::exec($query, array("users" => $users, "roles" => $roles));
+ }
+
+ // delete role, delete user_x_role relationships, delete role_x_location relationships, delete role_x_permission relationships
+ public static function deleteRole($roleid) {
+ $query = "DELETE FROM role WHERE roleid = :roleid";
+ Database::exec($query, array("roleid" => $roleid));
+ $query = "DELETE FROM user_x_role WHERE roleid = :roleid";
+ Database::exec($query, array("roleid" => $roleid));
+ $query = "DELETE FROM role_x_location WHERE roleid = :roleid";
+ Database::exec($query, array("roleid" => $roleid));
+ $query = "DELETE FROM role_x_permission WHERE roleid = :roleid";
+ Database::exec($query, array("roleid" => $roleid));
+ }
+
+ public static function saveRole($rolename, $locations, $permissions, $roleid = NULL) {
+ if ($roleid) {
+ Database::exec("UPDATE role SET rolename = :rolename WHERE roleid = :roleid",
+ array("rolename" => $rolename, "roleid" => $roleid));
+ Database::exec("DELETE FROM role_x_location WHERE roleid = :roleid", array("roleid" => $roleid));
+ Database::exec("DELETE FROM role_x_permission WHERE roleid = :roleid", array("roleid" => $roleid));
+ } else {
+ Database::exec("INSERT INTO role (rolename) VALUES (:rolename)", array("rolename" => $rolename));
+ $roleid = Database::lastInsertId();
+ }
+ foreach ($locations as $locationid) {
+ Database::exec("INSERT INTO role_x_location (roleid, locationid) VALUES (:roleid, :locationid)",
+ array("roleid" => $roleid, "locationid" => $locationid));
+ }
+ foreach ($permissions as $permissionid) {
+ Database::exec("INSERT INTO role_x_permission (roleid, permissionid) VALUES (:roleid, :permissionid)",
+ array("roleid" => $roleid, "permissionid" => $permissionid));
+ }
+ }
+
+}
diff --git a/modules-available/permissionmanager/inc/permissionutil.inc.php b/modules-available/permissionmanager/inc/permissionutil.inc.php
new file mode 100644
index 00000000..391cd047
--- /dev/null
+++ b/modules-available/permissionmanager/inc/permissionutil.inc.php
@@ -0,0 +1,108 @@
+<?php
+
+class PermissionUtil
+{
+ public static function userHasPermission($userid, $permissionid, $locationid) {
+ $locations = array();
+ if (!is_null($locationid)) {
+ $locations = Location::getLocationRootChain($locationid);
+ if (count($locations) == 0) return false;
+ else $locations[] = 0;
+ }
+
+ $res = Database::simpleQuery("SELECT role_x_permission.permissionid as 'permissionid',
+ role_x_location.locationid as 'locationid'
+ FROM user_x_role
+ INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid
+ LEFT JOIN role_x_location ON role_x_permission.roleid = role_x_location.roleid
+ WHERE user_x_role.userid = :userid", array("userid" => $userid));
+
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $userPermission = trim($row["permissionid"], "*");
+ if (substr($permissionid, 0, strlen($userPermission)) === $userPermission
+ && (is_null($locationid) || in_array($row["locationid"], $locations))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static function getAllowedLocations($userid, $permissionid) {
+
+ $res = Database::simpleQuery("SELECT permissionid, COALESCE(locationid, 0) AS locationid FROM user_x_role
+ INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid
+ INNER JOIN role_x_location ON role_x_permission.roleid = role_x_location.roleid
+ WHERE user_x_role.userid = :userid", array("userid" => $userid));
+
+ $allowedLocations = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ $userPermission = trim($row["permissionid"], "*");
+ if (!is_null($row["locationid"]) && substr($permissionid, 0, strlen($userPermission)) === $userPermission) {
+ $allowedLocations[$row["locationid"]] = 1;
+ }
+ }
+ $allowedLocations = array_keys($allowedLocations);
+ $locations = Location::getTree();
+ if (in_array("0", $allowedLocations)) {
+ $allowedLocations = array_map("intval", Location::extractIds($locations));
+ } else {
+ $allowedLocations = self::getSublocations($locations, $allowedLocations);
+ }
+ return $allowedLocations;
+ }
+
+ public static function getSublocations($tree, $locations) {
+ $result = array_flip($locations);
+ foreach ($tree as $location) {
+ if (array_key_exists("children", $location)) {
+ if (in_array($location["locationid"], $locations)) {
+ $result += array_flip(Location::extractIds($location["children"]));
+ } else {
+ $result += array_flip(self::getSublocations($location["children"], $locations));
+ }
+ }
+ }
+ return array_keys($result);
+ }
+
+ public static function getPermissions()
+ {
+ $permissions = array();
+ foreach (glob("modules/*/permissions/permissions.json", GLOB_NOSORT) as $file) {
+ $data = json_decode(file_get_contents($file), true);
+ if (!is_array($data))
+ continue;
+ preg_match('#^modules/([^/]+)/#', $file, $out);
+ $newData = array();
+ foreach( $data as $k => $v ) {
+ $newData[] = $v;
+ $permissions = self::putInPermissionTree($out[1].".".$k, $v, $permissions);
+ }
+ }
+ ksort($permissions);
+ global $MENU_CAT_OVERRIDE;
+ $sortingOrder = $MENU_CAT_OVERRIDE;
+ foreach ($permissions as $module => $v) $sortingOrder[Module::get($module)->getCategory()][] = $module;
+ $permissions = array_replace(array_flip(call_user_func_array('array_merge', $sortingOrder)), $permissions);
+ foreach ($permissions as $module => $v) if (is_int($v)) unset($permissions[$module]);
+
+
+ return $permissions;
+ }
+
+ private static function putInPermissionTree($permission, $description, $tree)
+ {
+ $subPermissions = explode('.', $permission);
+ $original =& $tree;
+ foreach ($subPermissions as $subPermission) {
+ if ($subPermission) {
+ if (!array_key_exists($subPermission, $tree)) {
+ $tree[$subPermission] = array();
+ }
+ $tree =& $tree[$subPermission];
+ }
+ }
+ $tree = $description;
+ return $original;
+ }
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/install.inc.php b/modules-available/permissionmanager/install.inc.php
new file mode 100644
index 00000000..71ee7a1e
--- /dev/null
+++ b/modules-available/permissionmanager/install.inc.php
@@ -0,0 +1,86 @@
+<?php
+
+$res = array();
+
+$res[] = tableCreate('role', "
+ roleid int(10) unsigned NOT NULL AUTO_INCREMENT,
+ rolename varchar(200) NOT NULL,
+ PRIMARY KEY (roleid)
+");
+
+$res[] = tableCreate('user_x_role', "
+ userid int(10) unsigned NOT NULL,
+ roleid int(10) unsigned NOT NULL,
+ PRIMARY KEY (userid, roleid)
+");
+
+$res[] = tableCreate('role_x_location', "
+ id int(10) unsigned NOT NULL AUTO_INCREMENT,
+ roleid int(10) unsigned NOT NULL,
+ locationid int(11),
+ PRIMARY KEY (id)
+");
+
+$res[] = tableCreate('role_x_permission', "
+ roleid int(10) unsigned NOT NULL,
+ permissionid varchar(200) NOT NULL,
+ PRIMARY KEY (roleid, permissionid)
+");
+
+if (!tableExists('user') || !tableExists('location')) {
+ finalResponse(UPDATE_RETRY, 'Cannot add constraint yet. Please retry.');
+} else {
+ $c = tableGetContraints('user_x_role', 'userid', 'user', 'userid');
+ if ($c === false)
+ finalResponse(UPDATE_FAILED, 'Cannot get constraints of user table: ' . Database::lastError());
+ if (empty($c)) {
+ $alter = Database::exec('ALTER TABLE user_x_role ADD FOREIGN KEY (userid) REFERENCES user (userid) ON DELETE CASCADE ON UPDATE CASCADE');
+ if ($alter === false)
+ finalResponse(UPDATE_FAILED, 'Cannot add userid constraint referencing user table: ' . Database::lastError());
+ $res[] = UPDATE_DONE;
+ }
+
+ $c = tableGetContraints('user_x_role', 'roleid', 'role', 'roleid');
+ if ($c === false)
+ finalResponse(UPDATE_FAILED, 'Cannot get constraints of role table: ' . Database::lastError());
+ if (empty($c)) {
+ $alter = Database::exec('ALTER TABLE user_x_role ADD FOREIGN KEY (roleid) REFERENCES role (roleid) ON DELETE CASCADE ON UPDATE CASCADE');
+ if ($alter === false)
+ finalResponse(UPDATE_FAILED, 'Cannot add roleid constraint referencing role table: ' . Database::lastError());
+ $res[] = UPDATE_DONE;
+ }
+
+ $c = tableGetContraints('role_x_location', 'roleid', 'role', 'roleid');
+ if ($c === false)
+ finalResponse(UPDATE_FAILED, 'Cannot get constraints of role table: ' . Database::lastError());
+ if (empty($c)) {
+ $alter = Database::exec('ALTER TABLE role_x_location ADD FOREIGN KEY (roleid) REFERENCES role (roleid) ON DELETE CASCADE ON UPDATE CASCADE');
+ if ($alter === false)
+ finalResponse(UPDATE_FAILED, 'Cannot add roleid constraint referencing role table: ' . Database::lastError());
+ $res[] = UPDATE_DONE;
+ }
+
+ $c = tableGetContraints('role_x_location', 'locationid', 'location', 'locationid');
+ if ($c === false)
+ finalResponse(UPDATE_FAILED, 'Cannot get constraints of location table: ' . Database::lastError());
+ if (empty($c)) {
+ $alter = Database::exec('ALTER TABLE role_x_location ADD FOREIGN KEY (locationid) REFERENCES location (locationid) ON DELETE CASCADE ON UPDATE CASCADE');
+ if ($alter === false)
+ finalResponse(UPDATE_FAILED, 'Cannot add locationid constraint referencing location table: ' . Database::lastError());
+ $res[] = UPDATE_DONE;
+ }
+
+ $c = tableGetContraints('role_x_permission', 'roleid', 'role', 'roleid');
+ if ($c === false)
+ finalResponse(UPDATE_FAILED, 'Cannot get constraints of role table: ' . Database::lastError());
+ if (empty($c)) {
+ $alter = Database::exec('ALTER TABLE role_x_permission ADD FOREIGN KEY (roleid) REFERENCES role (roleid) ON DELETE CASCADE ON UPDATE CASCADE');
+ if ($alter === false)
+ finalResponse(UPDATE_FAILED, 'Cannot add roleid constraint referencing role table: ' . Database::lastError());
+ $res[] = UPDATE_DONE;
+ }
+}
+if (in_array(UPDATE_DONE, $res)) {
+ finalResponse(UPDATE_DONE, 'Tables created successfully');
+}
+finalResponse(UPDATE_NOOP, 'Everything already up to date');
diff --git a/modules-available/permissionmanager/lang/de/module.json b/modules-available/permissionmanager/lang/de/module.json
new file mode 100644
index 00000000..aa73da91
--- /dev/null
+++ b/modules-available/permissionmanager/lang/de/module.json
@@ -0,0 +1,4 @@
+{
+ "module_name": "Rechtemanager",
+ "page_title": "Rechtemanager"
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/lang/de/template-tags.json b/modules-available/permissionmanager/lang/de/template-tags.json
new file mode 100644
index 00000000..23b2dc68
--- /dev/null
+++ b/modules-available/permissionmanager/lang/de/template-tags.json
@@ -0,0 +1,25 @@
+{
+ "lang_Roles": "Rollen",
+ "lang_Users": "Nutzer",
+ "lang_Locations": "Räume",
+ "lang_addRole": "Rolle zuweisen",
+ "lang_removeRole": "Rolle entfernen",
+ "lang_newRole": "Rolle anlegen",
+ "lang_Selected": "Ausgewählt",
+ "lang_Edit": "Bearbeiten",
+ "lang_Remove": "Entfernen",
+ "lang_Delete": "Löschen",
+ "lang_removeCheck": "Sind Sie sich sicher, dass Sie diese Rolle entfernen wollen?",
+ "lang_deleteCheck": "Sind Sie sich sicher, dass Sie diese Rolle löschen wollen?",
+ "lang_emptyNameWarning": "Der Name der Rolle darf nicht leer sein!",
+ "lang_Name": "Name",
+ "lang_Cancel": "Abbrechen",
+ "lang_Save": "Speichern",
+ "lang_all": "alle",
+ "lang_selected": "ausgewählte",
+ "lang_Permissions": "Rechte",
+ "lang_selectizePlaceholder": "Nach Rollen filtern...",
+ "lang_searchPlaceholder": "Nach Rollen suchen...",
+ "lang_moduleName": "Rechtemanager",
+ "lang_roleEditor": "Rollen Editor"
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/lang/en/module.json b/modules-available/permissionmanager/lang/en/module.json
new file mode 100644
index 00000000..5a5c838b
--- /dev/null
+++ b/modules-available/permissionmanager/lang/en/module.json
@@ -0,0 +1,4 @@
+{
+ "module_name": "Permission Manager",
+ "page_title": "Permission Manager"
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/lang/en/template-tags.json b/modules-available/permissionmanager/lang/en/template-tags.json
new file mode 100644
index 00000000..01056632
--- /dev/null
+++ b/modules-available/permissionmanager/lang/en/template-tags.json
@@ -0,0 +1,25 @@
+{
+ "lang_Roles": "Roles",
+ "lang_Users": "Users",
+ "lang_Locations": "Locations",
+ "lang_addRole": "Add Role",
+ "lang_removeRole": "Remove Role",
+ "lang_newRole": "New Role",
+ "lang_Selected": "Selected",
+ "lang_Edit": "Edit",
+ "lang_Remove": "Remove",
+ "lang_Delete": "Delete",
+ "lang_removeCheck": "Are you sure you want to remove this role?",
+ "lang_deleteCheck": "Are you sure you want to delete this role?",
+ "lang_emptyNameWarning": "Role name can not be empty!",
+ "lang_Name": "Name",
+ "lang_Cancel": "Cancel",
+ "lang_Save": "Save",
+ "lang_all": "all",
+ "lang_selected": "selected",
+ "lang_Permissions": "Permissions",
+ "lang_selectizePlaceholder": "Filter for roles...",
+ "lang_searchPlaceholder": "Search for roles...",
+ "lang_moduleName": "Permission Manager",
+ "lang_roleEditor": "Role Editor"
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/page.inc.php b/modules-available/permissionmanager/page.inc.php
new file mode 100644
index 00000000..9aba80b3
--- /dev/null
+++ b/modules-available/permissionmanager/page.inc.php
@@ -0,0 +1,193 @@
+<?php
+
+class Page_PermissionManager extends Page
+{
+
+ /**
+ * Called before any page rendering happens - early hook to check parameters etc.
+ */
+ protected function doPreprocess()
+ {
+ User::load();
+
+ if (!User::isLoggedIn()) {
+ Message::addError('main.no-permission');
+ Util::redirect('?do=Main'); // does not return
+ }
+
+ $action = Request::any('action', 'show', 'string');
+ if ($action === 'addRoleToUser') {
+ $users = Request::post('users', '');
+ $roles = Request::post('roles', '');
+ PermissionDbUpdate::addRoleToUser($users, $roles);
+ } elseif ($action === 'removeRoleFromUser') {
+ $users = Request::post('users', '');
+ $roles = Request::post('roles', '');
+ PermissionDbUpdate::removeRoleFromUser($users, $roles);
+ } elseif ($action === 'deleteRole') {
+ $id = Request::post('deleteId', false, 'string');
+ PermissionDbUpdate::deleteRole($id);
+ } elseif ($action === 'saveRole') {
+ $roleID = Request::post("roleid", false);
+ $rolename = Request::post("rolename");
+ $locations = self::processLocations(Request::post("locations"));
+ $permissions = self::processPermissions(Request::post("permissions"));
+ PermissionDbUpdate::saveRole($rolename, $locations, $permissions, $roleID);
+ }
+ }
+
+ /**
+ * Menu etc. has already been generated, now it's time to generate page content.
+ */
+ protected function doRender()
+ {
+ $show = Request::get("show", "roles");
+
+ // switch between tables, but always show menu to switch tables
+ if ( $show === 'roles' || $show === 'users' || $show === 'locations' ) {
+ // get menu button colors
+ $buttonColors = array();
+ $buttonColors['rolesButtonClass'] = $show === 'roles' ? 'active' : '';
+ $buttonColors['usersButtonClass'] = $show === 'users' ? 'active' : '';
+ $buttonColors['locationsButtonClass'] = $show === 'locations' ? 'active' : '';
+
+ Render::addtemplate('_page', $buttonColors);
+
+ if ($show === "roles") {
+ $data = array("roles" => GetPermissionData::getRoles());
+ Render::addTemplate('rolestable', $data);
+ } elseif ($show === "users") {
+ $data = array("user" => GetPermissionData::getUserData(), "roles" => GetPermissionData::getRoles());
+ Render::addTemplate('userstable', $data);
+ } elseif ($show === "locations") {
+ $data = array("location" => GetPermissionData::getLocationData(), "allroles" => GetPermissionData::getRoles());
+ Render::addTemplate('locationstable', $data);
+ }
+ } elseif ($show === "roleEditor") {
+ $data = array();
+
+ $selectedPermissions = array();
+ $selectedLocations = array();
+ $roleID = Request::get("roleid", false);
+ if ($roleID) {
+ $roleData = GetPermissionData::getRoleData($roleID);
+ $data["roleid"] = $roleID;
+ $data["rolename"] = $roleData["rolename"];
+ $selectedPermissions = $roleData["permissions"];
+ $selectedLocations = $roleData["locations"];
+ }
+
+ $data["permissionHTML"] = self::generatePermissionHTML(PermissionUtil::getPermissions(), $selectedPermissions);
+ $data["locationHTML"] = self::generateLocationHTML(Location::getTree(), $selectedLocations);
+
+ Render::addTemplate('roleeditor', $data);
+
+ }
+ }
+
+ private static function generatePermissionHTML($subPermissions, $selectedPermissions = array(), $selectAll = false, $permString = "")
+ {
+ $res = "";
+ $toplevel = $permString == "";
+ if ($toplevel && in_array("*", $selectedPermissions)) $selectAll = true;
+ foreach ($subPermissions as $k => $v) {
+ $leaf = !is_array($v);
+ $nextPermString = $permString ? $permString.".".$k : $k;
+ $id = $leaf ? $nextPermString : $nextPermString.".*";
+ $selected = $selectAll || in_array($id, $selectedPermissions);
+ $res .= Render::parse("treenode",
+ array("id" => $id,
+ "name" => $toplevel ? Module::get($k)->getDisplayName() : $k,
+ "toplevel" => $toplevel,
+ "checkboxname" => "permissions",
+ "selected" => $selected,
+ "HTML" => $leaf ? "" : self::generatePermissionHTML($v, $selectedPermissions, $selected, $nextPermString),
+ "description" => $leaf ? $v : ""));
+ }
+ if ($toplevel) {
+ $res = Render::parse("treepanel",
+ array("id" => "*",
+ "name" => Dictionary::translateFile("template-tags", "lang_Permissions"),
+ "checkboxname" => "permissions",
+ "selected" => $selectAll,
+ "HTML" => $res));
+ }
+ return $res;
+ }
+
+ private static function generateLocationHTML($locations, $selectedLocations = array(), $selectAll = false, $toplevel = true)
+ {
+ $res = "";
+ if ($toplevel && in_array(0, $selectedLocations)) $selectAll = true;
+ foreach ($locations as $location) {
+ $selected = $selectAll || in_array($location["locationid"], $selectedLocations);
+ $res .= Render::parse("treenode",
+ array("id" => $location["locationid"],
+ "name" => $location["locationname"],
+ "toplevel" => $toplevel,
+ "checkboxname" => "locations",
+ "selected" => $selected,
+ "HTML" => array_key_exists("children", $location) ?
+ self::generateLocationHTML($location["children"], $selectedLocations, $selected, false) : ""));
+ }
+ if ($toplevel) {
+ $res = Render::parse("treepanel",
+ array("id" => 0,
+ "name" => Dictionary::translateFile("template-tags", "lang_Locations"),
+ "checkboxname" => "locations",
+ "selected" => $selectAll,
+ "HTML" => $res));
+ }
+ return $res;
+ }
+
+ private static function processLocations($locations)
+ {
+ if (in_array(0, $locations)) return array(NULL);
+ $result = array();
+ foreach ($locations as $location) {
+ $rootchain = array_reverse(Location::getLocationRootChain($location));
+ foreach ($rootchain as $l) {
+ if (in_array($l, $result)) break;
+ if (in_array($l, $locations)) {
+ $result[] = $l;
+ break;
+ }
+ }
+ }
+ return $result;
+ }
+
+ private static function processPermissions($permissions)
+ {
+ if (in_array("*", $permissions)) return array("*");
+ $result = array();
+ foreach ($permissions as $permission) {
+ $x =& $result;
+ foreach (explode(".", $permission) as $p) {
+ $x =& $x[$p];
+ }
+ }
+ return self::extractPermissions($result);
+ }
+
+ private static function extractPermissions($permissions)
+ {
+ $result = array();
+ foreach ($permissions as $permission => $a) {
+ if (is_array($a)) {
+ if (array_key_exists("*", $a)) {
+ $result[] = $permission.".*";
+ } else {
+ foreach (self::extractPermissions($a) as $subPermission) {
+ $result[] = $permission.".".$subPermission;
+ }
+ }
+ } else {
+ $result[] = $permission;
+ }
+ }
+ return $result;
+ }
+
+}
diff --git a/modules-available/permissionmanager/style.css b/modules-available/permissionmanager/style.css
new file mode 100644
index 00000000..bb03d153
--- /dev/null
+++ b/modules-available/permissionmanager/style.css
@@ -0,0 +1,88 @@
+#switchForm {
+ text-align: center;
+ margin-bottom: 50px;
+}
+
+#saveButton {
+ margin-left: 10px;
+}
+
+#rolename {
+ width: 200px;
+ display: inline-block;
+ margin-left: 10px;
+}
+
+.table {
+ margin-top: 20px;
+}
+
+.table > tbody > tr > td {
+ vertical-align: middle;
+ height: 50px;
+}
+
+.scrollingTable {
+ height: 500px;
+ overflow: auto;
+}
+
+.customSpanMargin {
+ display: inline-block;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+.panel-primary > .panel-heading {
+ background-image: none;
+}
+
+.panel{
+ margin-bottom: 20px;
+}
+
+
+.tree-container .selected {
+ background-color: rgba(0, 182, 41, 0.23);
+}
+
+.tree-container {
+ -moz-column-gap: 20px;
+ -webkit-column-gap: 20px;
+ column-gap: 20px;
+}
+
+
+.tree-container > ul {
+ display: inline-block;
+ width: 100%;
+ padding: 0;
+}
+
+@media (max-width: 767px) {
+ .tree-container {
+ -moz-column-count: 1;
+ -webkit-column-count: 1;
+ column-count: 1;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 991px) {
+ .tree-container {
+ -moz-column-count: 2;
+ -webkit-column-count: 2;
+ column-count: 2;
+ }
+}
+
+@media (min-width: 992px) {
+ .tree-container {
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+ column-count: 3;
+ }
+}
+
+ul {
+ list-style-type: none;
+} \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/_page.html b/modules-available/permissionmanager/templates/_page.html
new file mode 100644
index 00000000..405462f7
--- /dev/null
+++ b/modules-available/permissionmanager/templates/_page.html
@@ -0,0 +1,29 @@
+<div class="row">
+ <div class="col-md-12" style="margin-bottom: 0;">
+ <div class='page-header'>
+ <div class='pull-right'>
+ <form id="switchForm" method="GET" action="?do=permissionmanager">
+ <input type="hidden" name="do" value="permissionmanager">
+
+ <div class="btn-group">
+ <button class="btn btn-default {{rolesButtonClass}}" type="submit" name="show" value="roles">
+ <span class="glyphicon glyphicon-education"></span>
+ {{lang_Roles}}
+ </button>
+
+ <button class="btn btn-default {{usersButtonClass}}" type="submit" name="show" value="users">
+ <span class="glyphicon glyphicon-user"></span>
+ {{lang_Users}}
+ </button>
+
+ <button class="btn btn-default {{locationsButtonClass}}" type="submit" name="show" value="locations">
+ <span class="glyphicon glyphicon-home"></span>
+ {{lang_Locations}}
+ </button>
+ </div>
+ </form>
+ </div>
+ <h1>{{lang_moduleName}}</h1>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/locationstable.html b/modules-available/permissionmanager/templates/locationstable.html
new file mode 100644
index 00000000..dcfefa94
--- /dev/null
+++ b/modules-available/permissionmanager/templates/locationstable.html
@@ -0,0 +1,37 @@
+<div class="row">
+ <div class="col-md-4"></div>
+ <div class="col-md-4">
+ <select multiple name="roles[]" id="select-role">
+ <option value>{{lang_selectizePlaceholder}}</option>
+ {{#allroles}}
+ <option value="{{roleid}}">{{rolename}}</option>
+ {{/allroles}}
+ </select>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-12">
+ <table id="locationsTable" class="table table-condensed table-hover stupidtable dataTable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_Locations}}</th>
+ <th>{{lang_Roles}}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {{#location}}
+ <tr data-selectizeCount='0'>
+ <td>{{locationpad}} {{locationname}}</td>
+ <td>
+ {{#roles}}
+ <span class="label label-default customSpanMargin roleid-{{roleid}}">{{rolename}}</span>
+ {{/roles}}
+ </td>
+ </tr>
+ {{/location}}
+ </tbody>
+ </table>
+ </div>
+</div> \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/roleeditor.html b/modules-available/permissionmanager/templates/roleeditor.html
new file mode 100644
index 00000000..14839ee2
--- /dev/null
+++ b/modules-available/permissionmanager/templates/roleeditor.html
@@ -0,0 +1,78 @@
+<h1>{{lang_roleEditor}}</h1>
+<form method="post" action="?do=permissionmanager">
+ <input type="hidden" name="action" value="saveRole">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="roleid" value="{{roleid}}">
+
+ <div class="row">
+ <div class="col-md-12" style="margin-bottom: 20px;">
+ <ul class="nav nav-tabs text-center" role="tablist">
+ <li role="presentation" class="active"><a href="#permissions" role="tab" data-toggle="tab">{{lang_Permissions}}</a></li>
+ <li role="presentation"><a href="#locations" role="tab" data-toggle="tab">{{lang_Locations}}</a></li>
+ <li style="float: none; display: inline-block">
+ <b>{{lang_Name}}:</b>
+ <input name="rolename" value="{{rolename}}" type="text" id="rolename" class="form-control">
+ </li>
+ <li style="float: right;">
+ <button type="button" id="cancelButton" class="btn btn-default">{{lang_Cancel}}</button>
+ <button type="submit" id="saveButton" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_Save}}</button>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div class="row" style="margin-bottom: 20px;">
+ <div class="col-md-12">
+ <div class="tab-content">
+ <div role="tabpanel" class="tab-pane active" id="permissions">
+ {{{permissionHTML}}}
+ </div>
+ <div role="tabpanel" class="tab-pane" id="locations">
+ {{{locationHTML}}}
+ </div>
+ </div>
+ </div>
+ </div>
+
+</form>
+
+<script type="application/javascript">
+
+ document.addEventListener("DOMContentLoaded", function () {
+
+ $(".tree-panel input[type=checkbox]").change(function () {
+ var checked = $(this).prop("checked");
+ var parent = $(this).parent().parent();
+ if (parent.hasClass("panel-heading")) parent = parent.parent();
+
+ var checkboxes = parent.find("input[type=checkbox]");
+ if (checked) {
+ checkboxes.prop("checked", true);
+ } else {
+ checkboxes.prop("checked", false);
+ while (!parent.hasClass("tree-panel")) {
+ parent = parent.parent().parent();
+ if (parent.hasClass("tree-container")) parent = parent.parent().parent();
+ parent.find("input[type=checkbox]:first").prop("checked", false);
+ }
+ }
+ });
+
+ $("#cancelButton").click(function () {
+ window.location.replace("?do=permissionmanager&show=roles");
+ });
+
+ $('form').submit(function () {
+ var name = $.trim($('#rolename').val());
+ if (name === '') {
+ alert('{{lang_emptyNameWarning}}');
+ return false;
+ }
+ });
+
+ $('[data-toggle="tooltip"]').tooltip({
+ container: 'body',
+ trigger : 'hover'
+ });
+ });
+
+</script> \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/rolestable.html b/modules-available/permissionmanager/templates/rolestable.html
new file mode 100644
index 00000000..99401624
--- /dev/null
+++ b/modules-available/permissionmanager/templates/rolestable.html
@@ -0,0 +1,91 @@
+<form method="post" action="?do=permissionmanager">
+ <input type="hidden" name="token" value="{{token}}">
+
+ <div class="row">
+ <div class="col-md-4">
+ <button class="btn btn-success" type="button" onclick="openRoleEditor()"><span class="glyphicon glyphicon-plus"></span> {{lang_newRole}}</button>
+ </div>
+ <div class="col-md-4">
+ <input type="text" class="form-control" id="roleNameSearchField" onkeyup="searchFieldFunction()" placeholder="{{lang_searchPlaceholder}}">
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <table id="rolesTable" class="table table-condensed table-hover stupidtable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_Roles}}</th>
+ <th class="text-center">{{lang_Edit}}</th>
+ <th class="text-center">{{lang_Delete}}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {{#roles}}
+ <tr class="rolesRow">
+ <td class="rolesData">{{rolename}}</td>
+ <td class="text-center">
+ <a class="btn btn-xs btn-info" href="?do=permissionmanager&show=roleEditor&roleid={{roleid}}"><span class="glyphicon glyphicon-edit"></span></a>
+ </td>
+ <td class="text-center">
+ <a class="btn btn-xs btn-danger" href="#deleteModal" data-toggle="modal" data-target="#deleteModal" onclick="deleteRole('{{roleid}}')"><span class="glyphicon glyphicon-trash"></span></a>
+ </td>
+ </tr>
+ {{/roles}}
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+
+ <!-- Modals -->
+ <div class ="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="myModalLabel">{{lang_Delete}}</h4>
+ </div>
+ <div class="modal-body">
+ {{lang_deleteCheck}}
+ </div>
+ <div class="modal-footer">
+ <input type="hidden" id="deleteId" name="deleteId" value=""/>
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" name="action" value="deleteRole" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> {{lang_Delete}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+</form>
+
+<script>
+ function openRoleEditor() {
+ window.location.href = "?do=permissionmanager&show=roleEditor"
+ }
+
+ function deleteRole($roleid) {
+ $(".modal-footer #deleteId").val($roleid);
+ }
+
+ function searchFieldFunction() {
+ // Declare variables
+ var input, filter, table, trs, a, i;
+ input = document.getElementById('roleNameSearchField');
+ filter = input.value.toUpperCase();
+ table = document.getElementById("rolesTable");
+ trs = table.getElementsByClassName('rolesRow');
+
+ // Loop through all list items, and hide those who don't match the search query
+ for (i = 0; i < trs.length; i++) {
+ a = trs[i].getElementsByClassName("rolesData")[0];
+ if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
+ trs[i].style.display = "";
+ } else {
+ trs[i].style.display = "none";
+ }
+ }
+ }
+</script> \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/treenode.html b/modules-available/permissionmanager/templates/treenode.html
new file mode 100644
index 00000000..336ca13e
--- /dev/null
+++ b/modules-available/permissionmanager/templates/treenode.html
@@ -0,0 +1,11 @@
+{{#toplevel}}<ul>{{/toplevel}}
+ <li title="{{description}}" data-toggle="tooltip" data-placement="left">
+ <div class='checkbox'>
+ <input name='{{checkboxname}}[]' value='{{id}}' type='checkbox' class='form-control' {{#selected}}checked{{/selected}}>
+ <label>{{#toplevel}}<b>{{/toplevel}}{{name}}{{#toplevel}}</b>{{/toplevel}}</label>
+ </div>
+ <ul>
+ {{{HTML}}}
+ </ul>
+ </li>
+{{#toplevel}}</ul>{{/toplevel}}
diff --git a/modules-available/permissionmanager/templates/treepanel.html b/modules-available/permissionmanager/templates/treepanel.html
new file mode 100644
index 00000000..53e316c9
--- /dev/null
+++ b/modules-available/permissionmanager/templates/treepanel.html
@@ -0,0 +1,13 @@
+<div class='panel panel-primary tree-panel'>
+ <div class='panel-heading'>
+ <div class='checkbox'>
+ <input name='{{checkboxname}}[]' value='{{id}}' type='checkbox' class='form-control' {{#selected}}checked{{/selected}}>
+ <label>{{name}}</label>
+ </div>
+ </div>
+ <div class='panel-body'>
+ <div class="tree-container" style="padding-left: 20px; padding-right: 20px;">
+ {{{HTML}}}
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/modules-available/permissionmanager/templates/userstable.html b/modules-available/permissionmanager/templates/userstable.html
new file mode 100644
index 00000000..bd48d16d
--- /dev/null
+++ b/modules-available/permissionmanager/templates/userstable.html
@@ -0,0 +1,170 @@
+<form method="post" action="?do=permissionmanager&show=users">
+ <input type="hidden" name="token" value="{{token}}">
+
+ <div class="row">
+ <div class="col-md-4">
+ <button class="btn btn-success" type="button" data-toggle="modal" data-target="#addRoleToUserModal"><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button>
+ <button class="btn btn-danger" type="button" data-toggle="modal" data-target="#removeRoleFromUserModal"><span class="glyphicon glyphicon-trash"></span> {{lang_removeRole}}</button>
+ </div>
+ <div class="col-md-4 text-left">
+ <select multiple name="roles[]" id="select-role">
+ <option value>{{lang_selectizePlaceholder}}</option>
+ {{#roles}}
+ <option value="{{roleid}}">{{rolename}}</option>
+ {{/roles}}
+ </select>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <table id="usersTable" class="table table-condensed table-hover stupidtable dataTable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_Users}}</th>
+ <th>{{lang_Roles}}</th>
+ <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {{#user}}
+ <tr data-selectizeCount='0'>
+ <td>{{username}}</td>
+ <td>
+ {{#roles}}
+ <span class="label label-default customSpanMargin roleid-{{roleid}}">{{rolename}}</span>
+ {{/roles}}
+ </td>
+ <td data-sort-value="0">
+ <div class="checkbox">
+ <input id="{{userid}}" type="checkbox" name="users[]" value='{{userid}}'>
+ <label for="{{userid}}"></label>
+ </div>
+ </td>
+ </tr>
+ {{/user}}
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <!-- Modals -->
+ <div class ="modal fade" id="addRoleToUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="myModalLabel">{{lang_addRole}}</h4>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-md-12 scrollingTable">
+ <table id="addRoleToUserTable" class="table table-condensed table-hover stupidtable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_Roles}}</th>
+ <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {{#roles}}
+ <tr>
+ <td>{{rolename}}</td>
+ <td data-sort-value="0">
+ <div class="checkbox">
+ <input id="add{{roleid}}" type="checkbox" name="roles[]" value='{{roleid}}'>
+ <label for="add{{roleid}}"></label>
+ </div>
+ </td>
+ </tr>
+ {{/roles}}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" name="action" value="addRoleToUser" class="btn btn-success" onclick="clearRemoveRoleModal()"><span class="glyphicon glyphicon-share-alt"></span> {{lang_addRole}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class ="modal fade" id="removeRoleFromUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="myModalLabel2">{{lang_Remove}}</h4>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-md-12 scrollingTable">
+ <table id="removeRoleFromUserTable" class="table table-condensed table-hover stupidtable">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_Roles}}</th>
+ <th data-sort="int" data-sort-default="desc">{{lang_Selected}}</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {{#roles}}
+ <tr>
+ <td>{{rolename}}</td>
+ <td data-sort-value="0">
+ <div class="checkbox">
+ <input id="remove{{roleid}}" type="checkbox" name="roles[]" value='{{roleid}}'>
+ <label for="remove{{roleid}}"></label>
+ </div>
+ </td>
+ </tr>
+ {{/roles}}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" name="action" value="removeRoleFromUser" class="btn btn-danger" onclick="clearAddRoleModal()"><span class="glyphicon glyphicon-trash"></span> {{lang_Remove}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+</form>
+
+<script>
+ document.addEventListener("DOMContentLoaded", function() {
+ // if checked,: mark green, else: unmark
+ $('input:checkbox').change(function() {
+ if ($(this).is(':checked')) {
+ $(this).closest("td").data("sort-value", 1);
+ $(this).closest("tr").css("background-color", "#f2ffe6");
+ } else {
+ $(this).closest("td").data("sort-value", 0);
+ $(this).closest("tr").css("background-color", "");
+ }
+
+ });
+ });
+
+ // if remove-Role button is clicked, uncheck all checkboxes in add-role modal so they aren't submitted too
+ function clearAddRoleModal () {
+ $('#addRoleToUserModal')
+ .find("input[type=checkbox]")
+ .prop("checked", "")
+ .end();
+ }
+
+ // if add-Role button is clicked, uncheck all checkboxes in remove-role modal so they aren't submitted too
+ function clearRemoveRoleModal() {
+ $('#removeRoleFromUserModal')
+ .find("input[type=checkbox]")
+ .prop("checked", "")
+ .end();
+ }
+</script> \ No newline at end of file
diff --git a/modules-available/rebootcontrol/clientscript.js b/modules-available/rebootcontrol/clientscript.js
deleted file mode 100644
index d3ecbe48..00000000
--- a/modules-available/rebootcontrol/clientscript.js
+++ /dev/null
@@ -1,22 +0,0 @@
-document.addEventListener("DOMContentLoaded", function() {
- var table = $("table");
- table.stupidtable({
- "ipsort":function(a,b){
- var aa = a.split(".");
- var bb = b.split(".");
-
- var resulta = aa[0]*0x1000000 + aa[1]*0x10000 + aa[2]*0x100 + aa[3]*1;
- var resultb = bb[0]*0x1000000 + bb[1]*0x10000 + bb[2]*0x100 + bb[3]*1;
-
- return resulta-resultb;
- }
- });
-
- table.on("aftertablesort", function (event, data) {
- var th = $(this).find("th");
- th.find(".arrow").remove();
- var dir = $.fn.stupidtable.dir;
- var arrow = data.direction === dir.ASC ? "down" : "up";
- th.eq(data.column).append(' <span class="arrow glyphicon glyphicon-chevron-'+arrow+'"></span>');
- });
-}); \ No newline at end of file
diff --git a/modules-available/rebootcontrol/lang/de/template-tags.json b/modules-available/rebootcontrol/lang/de/template-tags.json
index 57164f02..c5bd1670 100644
--- a/modules-available/rebootcontrol/lang/de/template-tags.json
+++ b/modules-available/rebootcontrol/lang/de/template-tags.json
@@ -15,6 +15,7 @@
"lang_rebootAt": "Neustart um:",
"lang_rebootButton": "Neustarten",
"lang_rebootCheck": "Wollen Sie die ausgew\u00e4hlten Rechner wirklich neustarten?",
+ "lang_rebootControl": "Reboot Control",
"lang_rebooting": "Neustart...",
"lang_selectall": "Alle ausw\u00e4hlen",
"lang_selected": "Ausgew\u00e4hlt",
diff --git a/modules-available/rebootcontrol/lang/en/template-tags.json b/modules-available/rebootcontrol/lang/en/template-tags.json
index ca44171a..63a5b4a8 100644
--- a/modules-available/rebootcontrol/lang/en/template-tags.json
+++ b/modules-available/rebootcontrol/lang/en/template-tags.json
@@ -15,6 +15,7 @@
"lang_rebootAt": "Reboot at:",
"lang_rebootButton": "Reboot",
"lang_rebootCheck": "Do you really want to reboot the selected clients?",
+ "lang_rebootControl": "Reboot Control",
"lang_rebooting": "Rebooting...",
"lang_selectall": "Select all",
"lang_selected": "Selected",
diff --git a/modules-available/rebootcontrol/templates/_page.html b/modules-available/rebootcontrol/templates/_page.html
index 065a9f01..1bef8dd4 100644
--- a/modules-available/rebootcontrol/templates/_page.html
+++ b/modules-available/rebootcontrol/templates/_page.html
@@ -1,3 +1,9 @@
+<div class="page-header">
+ <button type="button" id="settingsButton" class="btn btn-default pull-right" data-toggle="modal" data-target="#settingsModal"><span class="glyphicon glyphicon-cog"></span> {{lang_settings}}</button>
+ <h1>{{lang_rebootControl}}</h1>
+</div>
+
+
<form id="tableDataForm" method="post" action="?do=rebootcontrol" class="form-inline">
<input type="hidden" name="token" value="{{token}}">
<div class="row">
@@ -9,7 +15,6 @@
{{/locations}}
</select>
</label>
- <button type="button" id="settingsButton" class="btn btn-default pull-right" data-toggle="modal" data-target="#settingsModal"><span class="glyphicon glyphicon-cog"></span></button>
<button type="button" id="selectAllButton" class="btn btn-primary pull-right" onclick="selectAllRows()"><span class="glyphicon glyphicon-check"></span> {{lang_selectall}}</button>
<button type="button" id="unselectAllButton" class="btn btn-default pull-right" onclick="unselectAllRows()" style="display: none;"><span class="glyphicon glyphicon-unchecked"></span> {{lang_unselectall}}</button>
<button type="button" id="rebootButton" class="btn btn-warning pull-right" data-toggle="modal" data-target="#rebootModal" disabled><span class="glyphicon glyphicon-repeat"></span> {{lang_rebootButton}}</button>
@@ -18,11 +23,11 @@
</div>
<div class="row">
<div class="col-md-12">
- <table class="table table-condensed table-hover" id="dataTable">
+ <table class="table table-condensed table-hover stupidtable" id="dataTable">
<thead>
<tr>
<th data-sort="string">{{lang_client}}</th>
- <th data-sort="ipsort">{{lang_ip}}</th>
+ <th data-sort="ipv4">{{lang_ip}}</th>
<th data-sort="string">{{lang_status}}</th>
<th data-sort="string">{{lang_session}}</th>
<th data-sort="string">{{lang_user}}</th>
@@ -74,7 +79,7 @@
</div>
<div class="modal-body">
<span id="pubKeyTitle">{{lang_pubKey}}</span>
- <button class="btn btn-s btn-warning pull-right" onclick="generateNewKeypair()" type="button">{{lang_genNew}}</button>
+ <button class="btn btn-s btn-warning pull-right" onclick="generateNewKeypair()" type="button"><span class="glyphicon glyphicon-refresh"></span> {{lang_genNew}}</button>
<pre id="pubKey">{{pubKey}}</pre>
</div>
<div class="modal-footer">
diff --git a/modules-available/rebootcontrol/templates/status.html b/modules-available/rebootcontrol/templates/status.html
index 35bbe42f..c2fdab46 100644
--- a/modules-available/rebootcontrol/templates/status.html
+++ b/modules-available/rebootcontrol/templates/status.html
@@ -10,11 +10,11 @@
<div data-tm-id="{{taskId}}" data-tm-log="error" data-tm-callback="updateStatus"></div>
<div>
- <table class="table table-hover" id="dataTable">
+ <table class="table table-hover stupidtable" id="dataTable">
<thead>
<tr>
<th data-sort="string">{{lang_client}}</th>
- <th data-sort="ipsort">{{lang_ip}}</th>
+ <th data-sort="ipv4">{{lang_ip}}</th>
<th data-sort="string">
{{lang_status}}
</th>
diff --git a/modules-available/serversetup-bwlp/lang/de/module.json b/modules-available/serversetup-bwlp/lang/de/module.json
index eb777343..da71d558 100644
--- a/modules-available/serversetup-bwlp/lang/de/module.json
+++ b/modules-available/serversetup-bwlp/lang/de/module.json
@@ -1,4 +1,4 @@
{
- "module_name": "PXE\/Boot",
+ "module_name": "iPXE \/ Boot Menu",
"page_title": "PXE- und Boot-Einstellungen"
} \ No newline at end of file
diff --git a/modules-available/serversetup-bwlp/lang/de/template-tags.json b/modules-available/serversetup-bwlp/lang/de/template-tags.json
index 537b7761..f80febb0 100644
--- a/modules-available/serversetup-bwlp/lang/de/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/de/template-tags.json
@@ -21,6 +21,7 @@
"lang_menuCustomHint3": "und w\u00e4hlen Sie als Standard-Bootverhalten ebenfalls custom.",
"lang_menuDisplayTime": "Anzeigedauer des Men\u00fcs",
"lang_menuGeneration": "Erzeugen des Bootmen\u00fcs",
+ "lang_moduleHeading": "iPXE / Boot Menu",
"lang_seconds": "Sekunden",
"lang_set": "Setzen",
"lang_usbImage": "USB-Image",
diff --git a/modules-available/serversetup-bwlp/lang/en/template-tags.json b/modules-available/serversetup-bwlp/lang/en/template-tags.json
index 533dacba..1948718b 100644
--- a/modules-available/serversetup-bwlp/lang/en/template-tags.json
+++ b/modules-available/serversetup-bwlp/lang/en/template-tags.json
@@ -8,12 +8,12 @@
"lang_bootMenuCreate": "Create Boot Menu",
"lang_chooseIP": "Please select the IP address that the client server will use to boot.",
"lang_customEntry": "Custom entry",
- "lang_downloadImage": "Download USB image",
+ "lang_downloadImage": "Download USB Image",
"lang_downloadRufus": "Download Rufus",
"lang_example": "Example",
"lang_generationFailed": "Could not generate boot menu. The bwLehrpool-System might not work properly. If you can't fix the problem, please report the error message above to the bwLehrpool project.",
"lang_localHDD": "Local HDD",
- "lang_masterPassword": "Master password",
+ "lang_masterPassword": "Master Password",
"lang_masterPasswordHelp": "The master password is required to edit a boot menu entry. This should be set for security reasons.",
"lang_menuCustom": "Custom Extra Menu",
"lang_menuCustomHint1": "Here you have the opportunity to add your own menu code to the displayed PXE menu, eg to refer to other PXE server. The format corresponds to the syslinux menu format.",
@@ -21,6 +21,7 @@
"lang_menuCustomHint3": "and select as the default boot behavior custom as well.",
"lang_menuDisplayTime": "Menu Display Time",
"lang_menuGeneration": "Generating boot menu...",
+ "lang_moduleHeading": "iPXE / Boot Menu",
"lang_seconds": "Seconds",
"lang_set": "Set",
"lang_usbImage": "USB image",
diff --git a/modules-available/serversetup-bwlp/page.inc.php b/modules-available/serversetup-bwlp/page.inc.php
index 9d7d11ac..a8d29d6e 100644
--- a/modules-available/serversetup-bwlp/page.inc.php
+++ b/modules-available/serversetup-bwlp/page.inc.php
@@ -44,7 +44,7 @@ class Page_ServerSetup extends Page
protected function doRender()
{
-
+ Render::addTemplate("heading");
$taskid = Request::any('taskid');
if ($taskid !== false && Taskmanager::isTask($taskid)) {
Render::addTemplate('ipxe_update', array('taskid' => $taskid));
diff --git a/modules-available/serversetup-bwlp/templates/heading.html b/modules-available/serversetup-bwlp/templates/heading.html
new file mode 100644
index 00000000..d68360f1
--- /dev/null
+++ b/modules-available/serversetup-bwlp/templates/heading.html
@@ -0,0 +1 @@
+<h1>{{lang_moduleHeading}}</h1> \ No newline at end of file
diff --git a/modules-available/serversetup-bwlp/templates/ipxe.html b/modules-available/serversetup-bwlp/templates/ipxe.html
index e1ecb6f1..fbe3fb9e 100644
--- a/modules-available/serversetup-bwlp/templates/ipxe.html
+++ b/modules-available/serversetup-bwlp/templates/ipxe.html
@@ -15,9 +15,9 @@
<div class="form-group">
<strong>{{lang_bootBehavior}}</strong>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="net" {{active-net}}> bwLehrpool</label></div>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="hdd" {{active-hdd}}> {{lang_localHDD}}</label></div>
- <div><label class="radio-inline"><input type="radio" name="defaultentry" value="custom" {{active-custom}}> {{lang_customEntry}} (&quot;custom&quot;)</label></div>
+ <div class="radio"><input type="radio" name="defaultentry" value="net" {{active-net}}><label>bwLehrpool</label></div>
+ <div class="radio"><input type="radio" name="defaultentry" value="hdd" {{active-hdd}}><label>{{lang_localHDD}}</label></div>
+ <div class="radio"><input type="radio" name="defaultentry" value="custom" {{active-custom}}><label>{{lang_customEntry}} (&quot;custom&quot;)</label></div>
</div>
<div class="form-group">
@@ -43,7 +43,8 @@
</div>
<div class="panel-footer">
- <div class="pull-right">
+ <button class="btn btn-primary pull-right" name="action" value="ipxe">{{lang_bootMenuCreate}}</button>
+ <div>
<div class="btn-group" role="group">
<a class="btn btn-default" href="?do=ServerSetup&amp;action=getimage">
<span class="glyphicon glyphicon-download-alt"></span>
@@ -52,7 +53,6 @@
<span class="btn btn-default" data-toggle="modal" data-target="#help-usbimg"><span class="glyphicon glyphicon-question-sign"></span></span>
</div>
</div>
- <button class="btn btn-primary" name="action" value="ipxe">{{lang_bootMenuCreate}}</button>
</div>
</div>
</form>
@@ -60,7 +60,10 @@
<div class="modal fade" id="help-custom" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_menuCustom}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ {{lang_menuCustom}}
+ </div>
<div class="modal-body">
{{lang_menuCustomHint1}}
<br>{{lang_example}}:
@@ -73,7 +76,6 @@
{{lang_menuCustomHint2}} LABEL <strong>custom</strong>
{{lang_menuCustomHint3}}
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
@@ -81,7 +83,10 @@
<div class="modal fade" id="help-usbimg" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_usbImage}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ {{lang_usbImage}}
+ </div>
<div class="modal-body">
<p>{{lang_usbImgHelp}}</p>
<p>
@@ -98,7 +103,6 @@
<a href="https://rufus.akeo.ie/#download">{{lang_downloadRufus}}</a>
</p>
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div> \ No newline at end of file
diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json
index c755db7a..56cf55d7 100644
--- a/modules-available/statistics/lang/de/template-tags.json
+++ b/modules-available/statistics/lang/de/template-tags.json
@@ -46,6 +46,7 @@
"lang_modelName": "Modellname",
"lang_modelNo": "Modell",
"lang_modelStats": "PC-Modelle",
+ "lang_moduleHeading": "Client-Statistiken",
"lang_more": "Mehr",
"lang_newMachines": "Neue Ger\u00e4te",
"lang_noEdid": "Kein EDID",
@@ -77,7 +78,7 @@
"lang_tempPartStats": "Tempor\u00e4re Partition",
"lang_thoseAreProjectors": "Diese Modellnamen werden als Beamer behandelt, auch wenn die EDID-Informationen des Ger\u00e4tes anderes berichten.",
"lang_timebarDesc": "Visuelle Darstellung der letzten Tage. Rote Abschnitte zeigen, wann der Rechner belegt war, gr\u00fcne, wann er nicht verwendet wurde, aber eingeschaltet war. Die leicht abgedunkelten Abschnitte markieren N\u00e4chte (22 bis 8 Uhr).",
- "lang_tmpGb": "HDD-Temp",
+ "lang_tmpGb": "Temp-HDD",
"lang_total": "Gesamt",
"lang_usageDetails": "Nutzungsdetails",
"lang_usageState": "Zustand",
diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json
index 25847fc5..ab7a7d0a 100644
--- a/modules-available/statistics/lang/en/template-tags.json
+++ b/modules-available/statistics/lang/en/template-tags.json
@@ -46,6 +46,7 @@
"lang_modelName": "Model name",
"lang_modelNo": "Model",
"lang_modelStats": "PC models",
+ "lang_moduleHeading": "Client Statistics",
"lang_more": "More",
"lang_newMachines": "New machines",
"lang_noEdid": "No EDID",
@@ -69,15 +70,15 @@
"lang_runmodeMachines": "With special mode of operation",
"lang_screens": "Screens",
"lang_serialNo": "Serial no",
- "lang_showList": "Show list",
- "lang_showVisualization": "Show visualization",
+ "lang_showList": "List",
+ "lang_showVisualization": "Visualization",
"lang_sockets": "Sockets",
"lang_subnet": "Subnet",
"lang_tempPart": "Temp. partition",
"lang_tempPartStats": "Temporary partition",
"lang_thoseAreProjectors": "These model names will always be treated as beamers, even if the device's EDID data says otherwise.",
"lang_timebarDesc": "Visual representation of the last few days. Red parts mark periods where the client was occupied, green parts where the client was idle. Dimmed parts mark nights (10pm to 8am).",
- "lang_tmpGb": "HDD temp",
+ "lang_tmpGb": "Temp HDD",
"lang_total": "Total",
"lang_usageDetails": "Detailed usage",
"lang_usageState": "State",
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index 4227f3e8..d80d4614 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -258,11 +258,11 @@ class Page_Statistics extends Page
);
if ($show === 'list') {
- $data['listButtonClass'] = 'btn-primary';
- $data['statButtonClass'] = 'btn-default';
+ $data['listButtonClass'] = 'active';
+ $data['statButtonClass'] = '';
} else {
- $data['listButtonClass'] = 'btn-default';
- $data['statButtonClass'] = 'btn-primary';
+ $data['listButtonClass'] = '';
+ $data['statButtonClass'] = 'active';
}
@@ -554,6 +554,7 @@ class Page_Statistics extends Page
if (empty($row['hostname'])) {
$row['hostname'] = $row['clientip'];
}
+ $row['firstseen_int'] = $row['firstseen'];
$row['firstseen'] = date('d.m. H:i', $row['firstseen']);
$row['gbram'] = round(round($row['mbram'] / 500) / 2, 1); // Trial and error until we got "expected" rounding..
$row['gbtmp'] = round($row['id44mb'] / 1024);
@@ -601,6 +602,7 @@ class Page_Statistics extends Page
}
$row['state_' . $row['state']] = true;
//$row['firstseen'] = date('d.m.Y H:i', $row['firstseen']);
+ $row['lastseen_int'] = $row['lastseen'];
$row['lastseen'] = date('d.m. H:i', $row['lastseen']);
//$row['lastboot'] = date('d.m. H:i', $row['lastboot']);
$row['gbram'] = round(round($row['mbram'] / 500) / 2, 1); // Trial and error until we got "expected" rounding..
diff --git a/modules-available/statistics/style.css b/modules-available/statistics/style.css
new file mode 100644
index 00000000..1496ac87
--- /dev/null
+++ b/modules-available/statistics/style.css
@@ -0,0 +1,11 @@
+.to-top-btn {
+ position: fixed;
+ right: 10px;
+ bottom: 10px;
+ z-index: 100;
+ width: 50px;
+ height: 50px;
+ border-radius: 25px;
+ font-size: 20px;
+ line-height: 40px;
+} \ No newline at end of file
diff --git a/modules-available/statistics/templates/clientlist.html b/modules-available/statistics/templates/clientlist.html
index 0e88a15c..0b6fb37f 100644
--- a/modules-available/statistics/templates/clientlist.html
+++ b/modules-available/statistics/templates/clientlist.html
@@ -1,98 +1,85 @@
+<table class="stupidtable table table-condensed table-striped">
-
-<h1>{{lang_clientList}} ({{rowCount}})</h1>
-
-<table class="table table-condensed table-striped">
- <tr>
- <th>{{lang_machine}}</th>
- <th>{{lang_address}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-clientip"></button>
- </div>
-
- </th>
- <th class="text-right">{{lang_lastSeen}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-lastseen"></button>
+ <thead>
+ <tr>
+ <td></td>
+ <td></td>
+ <td class="text-right">
<button class="btn btn-default btn-xs" onclick="popupFilter('lastseen')">
<span id="btn_filter_lastseen" class="glyphicon glyphicon-filter"></span>
</button>
- </div>
- </th>
- <th>
- {{lang_kvmSupport}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-kvmstate"></button>
- <button class="btn btn-default btn-xs" onclick="popupFilter('kvmstate')">
- <span id="btn_filter_kvmstate" class="glyphicon glyphicon-filter"></span>
- </button>
- </div>
- </th>
- <th class="text-right">
- {{lang_gbRam}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-gbram"></button>
+ </td>
+ <td>
+ <button class="btn btn-default btn-xs" onclick="popupFilter('kvmstate')">
+ <span id="btn_filter_kvmstate" class="glyphicon glyphicon-filter"></span>
+ </button>
+ </td>
+ <td class="text-right">
<button class="btn btn-default btn-xs" onclick="popupFilter('gbram')">
<span id="btn_filter_gbram" class="glyphicon glyphicon-filter"></span>
</button>
- </div>
- </th>
- <th class="text-right">
- {{lang_tmpGb}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-hddgb"></button>
- <button class="btn btn-default btn-xs" onclick="popupFilter('hddgb')">
- <span id="btn_filter_hddgb" class="glyphicon glyphicon-filter"></span>
- </button>
- </div>
- </th>
- <th>{{lang_cpuModel}}
- <div class="btn-group pull-right">
- <button class="btn btn-default btn-xs" id="sortButton-realcores"></button>
- <button class="btn btn-default btn-xs" onclick="popupFilter('realcores')">
- <span id="btn_filter_cpu" class="glyphicon glyphicon-filter"></span>
- </button>
- </div>
- </th>
- </tr>
- {{#rows}}
- <tr>
- <td class="text-nowrap">
- {{#hasnotes}}<span class="glyphicon glyphicon-exclamation-sign pull-right"></span>{{/hasnotes}}
+ </td>
+ <td class="text-right">
+ <button class="btn btn-default btn-xs" onclick="popupFilter('hddgb')">
+ <span id="btn_filter_hddgb" class="glyphicon glyphicon-filter"></span>
+ </button>
+ </td>
+ <td>
+ <button class="btn btn-default btn-xs" onclick="popupFilter('realcores')">
+ <span id="btn_filter_cpu" class="glyphicon glyphicon-filter"></span>
+ </button>
+ </td>
+ </tr>
+ <tr>
+ <th data-sort="string">{{lang_machine}}</th>
+ <th data-sort="ipv4">{{lang_address}}</th>
+ <th data-sort="int" class="text-right">{{lang_lastSeen}}</th>
+ <th data-sort="string">{{lang_kvmSupport}}</th>
+ <th data-sort="int" class="text-right">{{lang_gbRam}}</th>
+ <th data-sort="int" class="text-right">{{lang_tmpGb}}</th>
+ <th data-sort="int">{{lang_cpuModel}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr>
+ <td data-sort-value="{{hostname}}" class="text-nowrap">
+ {{#hasnotes}}<span class="glyphicon glyphicon-exclamation-sign pull-right"></span>{{/hasnotes}}
{{#state_OFFLINE}}
- <span class="glyphicon glyphicon-off" title="{{lang_machineOff}}"></span>
+ <span class="glyphicon glyphicon-off" title="{{lang_machineOff}}"></span>
{{/state_OFFLINE}}
{{#state_IDLE}}
- <span class="glyphicon glyphicon-ok green" title="{{lang_machineIdle}}"></span>
+ <span class="glyphicon glyphicon-ok green" title="{{lang_machineIdle}}"></span>
{{/state_IDLE}}
{{#state_OCCUPIED}}
- <span class="glyphicon glyphicon-user red" title="{{lang_machineOccupied}}"></span>
+ <span class="glyphicon glyphicon-user red" title="{{lang_machineOccupied}}"></span>
{{/state_OCCUPIED}}
{{#state_STANDBY}}
<span class="glyphicon glyphicon-off green" title="{{lang_machineStandby}}"></span>
{{/state_STANDBY}}
- <a href="?do=Statistics&amp;uuid={{machineuuid}}"><b>{{hostname}}</b></a>
- <div class="small">{{machineuuid}}</div>
+ <a href="?do=Statistics&amp;uuid={{machineuuid}}"><b>{{hostname}}</b></a>
+ <div class="small">{{machineuuid}}</div>
{{#rmmodule}}<div class="small">{{lang_runMode}}: <a class="slx-bold" href="?do=runmode&amp;module={{rmmodule}}">{{rmmodule}}</a></div>{{/rmmodule}}
- </td>
- <td><b><a href="?do=Statistics&amp;show=list&amp;filters=subnet={{subnet}}">{{subnet}}</a>{{lastoctet}}</b><br>{{macaddr}}</td>
- <td class="text-right">{{lastseen}}</td>
- <td class="{{kvmclass}}">{{kvmstate}}</td>
- <td class="text-right {{ramclass}}">{{gbram}}&thinsp;GiB</td>
- <td class="text-right {{hddclass}}">
- {{gbtmp}}&thinsp;GiB
- {{#badsectors}}<div>
- <span class="glyphicon glyphicon-exclamation-sign"></span>
- {{badsectors}}
- </div>{{/badsectors}}
- {{#nohdd}}<div>
- <span class="glyphicon glyphicon-hdd red"></span>
- </div>{{/nohdd}}
- </td>
- <td>{{lang_realCores}}: {{realcores}}<div class="small">{{cpumodel}}</div></td>
- </tr>
- {{/rows}}
+ </td>
+ <td data-sort-value="{{clientip}}"><b><a href="?do=Statistics&amp;show=list&amp;filters=subnet={{subnet}}">{{subnet}}</a>{{lastoctet}}</b><br>{{macaddr}}</td>
+ <td data-sort-value="{{lastseen_int}}" class="text-right">{{lastseen}}</td>
+ <td class="{{kvmclass}}">{{kvmstate}}</td>
+ <td data-sort-value="{{gbram}}" class="text-right {{ramclass}}">{{gbram}}&thinsp;GiB</td>
+ <td data-sort-value="{{gbtmp}}" class="text-right {{hddclass}}">
+ {{gbtmp}}&thinsp;GiB
+ {{#badsectors}}<div>
+ <span class="glyphicon glyphicon-exclamation-sign" data-toggle="tooltip" title="{{lang_reallocatedSectors}}" data-placement="left"></span>
+ {{badsectors}}
+ </div>{{/badsectors}}
+ {{#nohdd}}<div>
+ <span class="glyphicon glyphicon-hdd red"></span>
+ </div>{{/nohdd}}
+ </td>
+ <td data-sort-value="{{realcores}}">{{lang_realCores}}: {{realcores}}<div class="small">{{cpumodel}}</div></td>
+ </tr>
+ {{/rows}}
+ </tbody>
</table>
<script type="application/javascript"><!--
@@ -107,6 +94,11 @@ document.addEventListener("DOMContentLoaded", function () {
$sortBtn.html('<span class="glyphicon glyphicon-arrow-' + order + '"></span>');
$sortBtn.attr('onclick', 'toggleButton(\'' + v + '\');');
});
+
+ $('[data-toggle="tooltip"]').tooltip({
+ container: 'body',
+ trigger : 'hover'
+ });
});
function toggleButton(v) {
diff --git a/modules-available/statistics/templates/cpumodels.html b/modules-available/statistics/templates/cpumodels.html
index d9b0298b..d684c914 100644
--- a/modules-available/statistics/templates/cpumodels.html
+++ b/modules-available/statistics/templates/cpumodels.html
@@ -6,34 +6,38 @@
<div class="panel-body">
<div class="row">
<div class="col-md-8">
- <table class="table table-condensed table-striped table-responsive">
- <tr>
- <th>{{lang_modelName}}</th>
- <th class="text-right text-nowrap">{{lang_cpuCores}}</th>
- <th class="text-right text-nowrap">{{lang_modelCount}}</th>
- </tr>
- {{#rows}}
- <tr id="{{id}}" class="{{collapse}}">
- <td class="text-left text-nowrap filter-col" data-filter-col="systemmodel">
- <table style="width:100%; table-layout: fixed;"><tr><td style="overflow:hidden;text-overflow: ellipsis;">
- <a class="filter-val" data-filter-val="{{systemmodel}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~systemmodel={{urlsystemmodel}}">{{systemmodel}}</a>
- </td></tr></table>
- </td>
- <td class="text-right filter-col" data-filter-col="realcores">
- <a class="filter-val" data-filter-val="{{cores}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~realcores={{cores}}">{{cores}}</a>
- </td>
- <td class="text-right">{{count}}</td>
- </tr>
- {{/rows}}
- <tr class="slx-decollapse">
- <td colspan="3">
- <span class="btn-group btn-group-justified">
- <span class="btn btn-default btn-sm">
- <span class="glyphicon glyphicon-menu-down"></span>
+ <table class="stupidtable table table-condensed table-striped table-responsive">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_modelName}}</th>
+ <th data-sort="int" class="text-right text-nowrap">{{lang_cpuCores}}</th>
+ <th data-sort="int" class="text-right text-nowrap">{{lang_modelCount}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr id="{{id}}" class="{{collapse}}">
+ <td data-sort-value="{{systemmodel}}" class="text-left text-nowrap filter-col" data-filter-col="systemmodel">
+ <table style="width:100%; table-layout: fixed;"><tr><td style="overflow:hidden;text-overflow: ellipsis;">
+ <a class="filter-val" data-filter-val="{{systemmodel}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~systemmodel={{urlsystemmodel}}">{{systemmodel}}</a>
+ </td></tr></table>
+ </td>
+ <td data-sort-value="{{cores}}" class="text-right filter-col" data-filter-col="realcores">
+ <a class="filter-val" data-filter-val="{{cores}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~realcores={{cores}}">{{cores}}</a>
+ </td>
+ <td class="text-right">{{count}}</td>
+ </tr>
+ {{/rows}}
+ <tr class="slx-decollapse">
+ <td colspan="3">
+ <span class="btn-group btn-group-justified">
+ <span class="btn btn-default btn-sm">
+ <span class="glyphicon glyphicon-menu-down"></span>
+ </span>
</span>
- </span>
- </td>
- </tr>
+ </td>
+ </tr>
+ </tbody>
</table>
</div>
<div class="col-md-4">
diff --git a/modules-available/statistics/templates/filterbox.html b/modules-available/statistics/templates/filterbox.html
index 7cd0f617..c2630ed9 100644
--- a/modules-available/statistics/templates/filterbox.html
+++ b/modules-available/statistics/templates/filterbox.html
@@ -1,59 +1,82 @@
-<div id="modal-add-filter" class="modal modal-sm fade" role="dialog"
- style="position:absolute; min-width:600px; min-height: 400px;margin:auto">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span
- class="sr-only">Close</span></button>
- {{lang_add_filter}}
- </div>
- <form class="modal-body form-inline center" onsubmit="$('#add-btn').click(); return false">
- <div class="form-group">
- <select id="columnSelect" name="column" class="form-control col-4-xs"> </select>
- </div>
- <div class="form-group">
- <select id="operatorSelect" name="operator" class="form-control col-4-xs"> </select>
- </div>
- <div class="form-group">
- <input name="argument" id="argumentInput" class="form-control col-4-xs"> </input>
- <select name="argument" id="argumentSelect" class="form-control col-4-xs"> </select>
+<div id="modal-add-filter" class="modal fade" role="dialog" style="position: absolute">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <b>{{lang_add_filter}}</b>
</div>
- <button id="add-btn" type="button" class="btn btn-primary" onclick="addFilterFromForm()">
- <span class="glyphicon glyphicon-plus"></span>
- {{lang_add}}
- </button>
- </form>
+ <form class="form-inline center" onsubmit="$('#add-btn').click(); return false">
+ <div class="modal-body">
+ <div class="form-group">
+ <select id="columnSelect" name="column" class="form-control col-4-xs"> </select>
+ </div>
+ <div class="form-group">
+ <select id="operatorSelect" name="operator" class="form-control col-4-xs"> </select>
+ </div>
+ <div class="form-group">
+ <input name="argument" id="argumentInput" class="form-control col-4-xs"> </input>
+ <select name="argument" id="argumentSelect" class="form-control col-4-xs"> </select>
+ </div>
+
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button id="add-btn" type="button" class="btn btn-success" onclick="addFilterFromForm()">
+ <span class="glyphicon glyphicon-plus"></span>
+ {{lang_add}}
+ </button>
+ </div>
+ </form>
+ </div>
</div>
</div>
+<a href="#top" class="btn btn-default to-top-btn"><span class="glyphicon glyphicon-menu-up"></span></a>
-<div style="height:120px" class="col-xs-12">
+
+<div class="col-md-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="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}}"/>
- <input type="hidden" name="sortDirection" id="sortDirection" value="{{sortDirection}}"/>
+ <button type="submit" hidden></button>
+
- <button type="button" class="btn btn-success pull-left" onclick="popupFilter(null)">
- <span class="glyphicon glyphicon-plus"></span>
- {{lang_add_filter}}
- </button>
<div class="btn-group pull-right">
- <button class="btn {{statButtonClass}}" type="submit" name="show" value="stat">
+ <button class="btn btn-default {{statButtonClass}}" type="submit" name="show" value="stat">
<span class="glyphicon glyphicon-stats"></span>
{{lang_showVisualization}}
</button>
- <button class="btn {{listButtonClass}}" type="submit" name="show" value="list">
+ <button class="btn btn-default {{listButtonClass}}" type="submit" name="show" value="list">
<span class="glyphicon glyphicon-list"></span>
{{lang_showList}}
</button>
</div>
+ <h1>{{lang_moduleHeading}}</h1>
+
+ <br/>
+
+ <input type="hidden" name="do" value="statistics">
+ <input type="hidden" name="sortColumn" id="sortColumn" value="{{sortColumn}}"/>
+ <input type="hidden" name="sortDirection" id="sortDirection" value="{{sortDirection}}"/>
+
+ <label for="filterInput">{{lang_labelFilter}}</label>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="input-group">
+ <input type="text" name="filters" class="" id="filterInput"/>
+ <span class="input-group-btn" style=" width: 1%; padding-bottom: 5px;">
+ <button type="button" class="btn btn-success" onclick="popupFilter(null)">
+ <span class="glyphicon glyphicon-plus"></span>
+ {{lang_add_filter}}
+ </button>
+ </span>
+ </div>
+ </div>
+ </div>
+
+ <br/>
</form>
- <br/>
- <br/>
</div>
+
<script type="application/javascript"><!--
var filterSelectize;
@@ -112,6 +135,9 @@ document.addEventListener("DOMContentLoaded", function () {
// if (initComplete && !$('#filterInput').is(':focus')) {
// reload();
// }
+ },
+ onItemRemove: function(value) {
+ refresh();
}
})[0].selectize;
/* add query */
diff --git a/modules-available/statistics/templates/id44.html b/modules-available/statistics/templates/id44.html
index 38cf028f..d3b1ab1c 100644
--- a/modules-available/statistics/templates/id44.html
+++ b/modules-available/statistics/templates/id44.html
@@ -6,28 +6,32 @@
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
- <table class="filter-col table table-condensed table-striped" data-filter-col="hddgb">
- <tr>
- <th>{{lang_partitionSize}}</th>
- <th class="text-right">{{lang_machineCount}}</th>
- </tr>
- {{#rows}}
- <tr id="tmpid{{gb}}" class="{{class}} {{collapse}}">
- <td class="text-left text-nowrap">
- <a class="filter-val" data-filter-val="{{gb}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~hddgb={{gb}}">{{gb}}&thinsp;GiB</a>
- </td>
- <td class="text-right">{{count}}</td>
- </tr>
- {{/rows}}
- <tr class="slx-decollapse">
- <td colspan="2">
- <span class="btn-group btn-group-justified">
- <span class="btn btn-default btn-sm">
- <span class="glyphicon glyphicon-menu-down"></span>
+ <table class="stupidtable filter-col table table-condensed table-striped" data-filter-col="hddgb">
+ <thead>
+ <tr>
+ <th data-sort="int">{{lang_partitionSize}}</th>
+ <th data-sort="int" class="text-right">{{lang_machineCount}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr id="tmpid{{gb}}" class="{{class}} {{collapse}}">
+ <td data-sort-value="{{gb}}" class="text-left text-nowrap">
+ <a class="filter-val" data-filter-val="{{gb}}" href="?do=Statistics&amp;show=stat&amp;filters={{query}}~,~hddgb={{gb}}">{{gb}}&thinsp;GiB</a>
+ </td>
+ <td class="text-right">{{count}}</td>
+ </tr>
+ {{/rows}}
+ <tr class="slx-decollapse">
+ <td colspan="2">
+ <span class="btn-group btn-group-justified">
+ <span class="btn btn-default btn-sm">
+ <span class="glyphicon glyphicon-menu-down"></span>
+ </span>
</span>
- </span>
- </td>
- </tr>
+ </td>
+ </tr>
+ </tbody>
</table>
</div>
<div class="col-sm-6">
diff --git a/modules-available/statistics/templates/kvmstate.html b/modules-available/statistics/templates/kvmstate.html
index 33a00d38..3704eda0 100644
--- a/modules-available/statistics/templates/kvmstate.html
+++ b/modules-available/statistics/templates/kvmstate.html
@@ -6,19 +6,23 @@
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
- <table class="filter-col table table-condensed table-striped" data-filter-col="kvmstate">
- <tr>
- <th>{{lang_kvmState}}</th>
- <th class="text-right">{{lang_machineCount}}</th>
- </tr>
- {{#rows}}
- <tr id="kvm{{kvmstate}}">
- <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>
- </tr>
- {{/rows}}
+ <table class="stupidtable filter-col table table-condensed table-striped" data-filter-col="kvmstate">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_kvmState}}</th>
+ <th data-sort="int" class="text-right">{{lang_machineCount}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr id="kvm{{kvmstate}}">
+ <td data-sort-value="{{kvmstate}}" 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>
+ </tr>
+ {{/rows}}
+ </tbody>
</table>
</div>
<div class="col-sm-6">
diff --git a/modules-available/statistics/templates/machine-notes.html b/modules-available/statistics/templates/machine-notes.html
index c4f97543..22ed96e9 100644
--- a/modules-available/statistics/templates/machine-notes.html
+++ b/modules-available/statistics/templates/machine-notes.html
@@ -9,7 +9,8 @@
<input type="hidden" name="action" value="setnotes">
<input type="hidden" name="uuid" value="{{machineuuid}}">
<textarea name="content" class="form-control" cols="101" rows="10">{{notes}}</textarea>
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <br/>
+ <button type="submit" class="btn btn-primary pull-right"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</form>
</div>
</div>
diff --git a/modules-available/statistics/templates/memory.html b/modules-available/statistics/templates/memory.html
index f17f55ca..6bc13980 100644
--- a/modules-available/statistics/templates/memory.html
+++ b/modules-available/statistics/templates/memory.html
@@ -6,28 +6,32 @@
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
- <table class="filter-col table table-condensed table-striped" data-filter-col="gbram">
- <tr>
- <th>{{lang_ramSize}}</th>
- <th class="text-right">{{lang_machineCount}}</th>
- </tr>
- {{#rows}}
- <tr id="ramid{{gb}}" class="{{class}} {{collapse}}">
- <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>
- </tr>
- {{/rows}}
- <tr class="slx-decollapse">
- <td colspan="2">
- <span class="btn-group btn-group-justified">
- <span class="btn btn-default btn-sm">
- <span class="glyphicon glyphicon-menu-down"></span>
+ <table class="stupidtable filter-col table table-condensed table-striped" data-filter-col="gbram">
+ <thead>
+ <tr>
+ <th data-sort="int">{{lang_ramSize}}</th>
+ <th data-sort="int" class="text-right">{{lang_machineCount}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr id="ramid{{gb}}" class="{{class}} {{collapse}}">
+ <td class="text-left text-nowrap" data-sort-value="{{gb}}">
+ <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>
+ </tr>
+ {{/rows}}
+ <tr class="slx-decollapse">
+ <td colspan="2">
+ <span class="btn-group btn-group-justified">
+ <span class="btn btn-default btn-sm">
+ <span class="glyphicon glyphicon-menu-down"></span>
+ </span>
</span>
- </span>
- </td>
- </tr>
+ </td>
+ </tr>
+ </tbody>
</table>
</div>
<div class="col-sm-6">
diff --git a/modules-available/statistics/templates/newclients.html b/modules-available/statistics/templates/newclients.html
index c5c704d1..6dc04144 100644
--- a/modules-available/statistics/templates/newclients.html
+++ b/modules-available/statistics/templates/newclients.html
@@ -4,32 +4,36 @@
{{lang_newMachines}}
</div>
<div class="panel-body">
- <table class="table table-condensed table-striped">
- <tr>
- <th>{{lang_machine}}</th>
- <th class="text-right"></th>
- <th>64Bit</th>
- <th class="text-right">RAM</th>
- <th class="text-right">HDD</th>
- </tr>
- {{#rows}}
- <tr class="{{collapse}}">
- <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>
- <td class="text-right {{hddclass}}">{{gbtmp}}&thinsp;GiB</td>
- </tr>
- {{/rows}}
- <tr class="slx-decollapse">
- <td colspan="5">
- <span class="btn-group btn-group-justified">
- <span class="btn btn-default btn-sm">
- <span class="glyphicon glyphicon-menu-down"></span>
+ <table class="stupidtable table table-condensed table-striped">
+ <thead>
+ <tr>
+ <th data-sort="string">{{lang_machine}}</th>
+ <th data-sort="int" class="text-right" style="min-width: 80px;">{{lang_firstSeen}}</th>
+ <th data-sort="string" class="text-center">64Bit</th>
+ <th data-sort="int" class="text-right">RAM</th>
+ <th data-sort="int" class="text-right">HDD</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#rows}}
+ <tr class="{{collapse}}">
+ <td data-sort-value="{{hostname}}" class="text-nowrap"><a href="?do=Statistics&amp;uuid={{machineuuid}}">{{hostname}}</a></td>
+ <td data-sort-value="{{firstseen_int}}" class="text-right">{{firstseen}}</td>
+ <td class="text-center {{kvmclass}}">{{kvmicon}}</td>
+ <td data-sort-value="{{gbram}}" class="text-right {{ramclass}}">{{gbram}}&thinsp;GiB</td>
+ <td data-sort-value="{{gbtmp}}" class="text-right {{hddclass}}">{{gbtmp}}&thinsp;GiB</td>
+ </tr>
+ {{/rows}}
+ <tr class="slx-decollapse">
+ <td colspan="5">
+ <span class="btn-group btn-group-justified">
+ <span class="btn btn-default btn-sm">
+ <span class="glyphicon glyphicon-menu-down"></span>
+ </span>
</span>
- </span>
- </td>
- </tr>
+ </td>
+ </tr>
+ </tbody>
</table>
</div>
</div>
diff --git a/modules-available/statistics_reporting/lang/de/template-tags.json b/modules-available/statistics_reporting/lang/de/template-tags.json
index fb624fad..f8829b79 100644
--- a/modules-available/statistics_reporting/lang/de/template-tags.json
+++ b/modules-available/statistics_reporting/lang/de/template-tags.json
@@ -10,11 +10,13 @@
"lang_location": "Ort",
"lang_longSessions": "Sitzungen \u2265 60s",
"lang_medianSessionLength": "Sitzungsdauer Median",
+ "lang_moduleName": "Statistikauswertung",
"lang_reportMoreInfo": "Weitere Informationen...",
"lang_reportingDescription": "Helfen Sie uns bwLehrpool durch das w\u00f6chentliche Verschicken eines anonymisierten Statistikberichts zu verbessern. Wenn Sie den Inhalt eines solchen Reports genauer inspizieren wollen, k\u00f6nnen Sie \u00fcber den untenstehenden Button einen aktuellen Report Ihres Servers herunterladen.",
"lang_reportingLabel": "Anonymisierte Nutzungsstatistiken \u00fcbermitteln",
"lang_sessions": "Sitzungen",
"lang_shortSessions": "Sitzungen < 60s",
+ "lang_show": "Anzeigen",
"lang_total": "Gesamt",
"lang_totalOffTime": "Gesamtzeit offline",
"lang_totalTime": "Gesamtzeit",
diff --git a/modules-available/statistics_reporting/lang/en/template-tags.json b/modules-available/statistics_reporting/lang/en/template-tags.json
index 4e33ffed..73c21112 100644
--- a/modules-available/statistics_reporting/lang/en/template-tags.json
+++ b/modules-available/statistics_reporting/lang/en/template-tags.json
@@ -10,11 +10,13 @@
"lang_location": "Location",
"lang_longSessions": "Sessions \u2265 60s",
"lang_medianSessionLength": "Median Session Length",
+ "lang_moduleName": "Statistics Reporting",
"lang_reportMoreInfo": "More information...",
"lang_reportingDescription": "Help us improve bwLehrpool by automatically sending an anonymized statistics report once a week. If you want to check what data the report contains, you can download such a report for reference below.",
"lang_reportingLabel": "Send anonymized usage statistics",
"lang_sessions": "Sessions",
"lang_shortSessions": "Sessions < 60s",
+ "lang_show": "Show",
"lang_total": "Total",
"lang_totalOffTime": "Total Time Offline",
"lang_totalTime": "Total Time",
diff --git a/modules-available/statistics_reporting/page.inc.php b/modules-available/statistics_reporting/page.inc.php
index 52accaea..5d586b6c 100644
--- a/modules-available/statistics_reporting/page.inc.php
+++ b/modules-available/statistics_reporting/page.inc.php
@@ -52,16 +52,20 @@ class Page_Statistics_Reporting extends Page
// Export - handle in doPreprocess so we don't render the menu etc.
if ($this->action === 'export') {
- $this->doExport();
- // Does not return
+ if (User::hasPermission("table.export") && User::hasPermission("table.view.$this->type")) {
+ $this->doExport();
+ // Does not return
+ }
}
// Get report - fetch data exactly the way it would automatically be reported
// so the user can know what is going on
if ($this->action === 'getreport') {
- $report = RemoteReport::generateReport(time());
- Header('Content-Disposition: attachment; filename=remote-report.json');
- Header('Content-Type: application/json; charset=utf-8');
- die(json_encode($report));
+ if(User::hasPermission("reporting.download")) {
+ $report = RemoteReport::generateReport(time());
+ Header('Content-Disposition: attachment; filename=remote-report.json');
+ Header('Content-Type: application/json; charset=utf-8');
+ die(json_encode($report));
+ }
}
}
@@ -100,6 +104,7 @@ class Page_Statistics_Reporting extends Page
$data['tables'][] = array(
'name' => Dictionary::translate('table_' . $table, true),
'value' => $table,
+ 'allowed' => User::hasPermission("table.view.$table"),
'selected' => ($this->type === $table) ? 'selected' : '',
);
}
@@ -121,10 +126,17 @@ class Page_Statistics_Reporting extends Page
$data['settingsButtonClass'] = 'danger';
}
+ $data['allowedExport'] = User::hasPermission("table.export") && User::hasPermission("table.view.$this->type");
+ $data['allowedDownload'] = User::hasPermission("reporting.download");
+ $data['allowedReportChange'] = User::hasPermission("reporting.change");
+
Render::addTemplate('columnChooser', $data);
$data['data'] = $this->fetchData(GETDATA_PRINTABLE);
- Render::addTemplate('table-' . $this->type, $data);
+
+ if (User::hasPermission("table.view.$this->type")) {
+ Render::addTemplate('table-' . $this->type, $data);
+ }
}
}
@@ -132,23 +144,24 @@ class Page_Statistics_Reporting extends Page
{
$this->action = Request::any('action', false, 'string');
if ($this->action === 'setReporting') {
- if (!User::isLoggedIn()) {
- die("No.");
- }
- $state = Request::post('reporting', false, 'string');
- if ($state === false) {
- die('Missing setting value.');
- }
- RemoteReport::setReportingEnabled($state);
- $data = array();
- if (RemoteReport::isReportingEnabled()) {
- $data['class'] = 'default';
- $data['checked'] = true;
+ if (User::hasPermission("reporting.change")) {
+ $state = Request::post('reporting', false, 'string');
+ if ($state === false) {
+ die('Missing setting value.');
+ }
+ RemoteReport::setReportingEnabled($state);
+ $data = array();
+ if (RemoteReport::isReportingEnabled()) {
+ $data['class'] = 'default';
+ $data['checked'] = true;
+ } else {
+ $data['class'] = 'danger';
+ }
+ Header('Content-Type: application/json; charset=utf-8');
+ die(json_encode($data));
} else {
- $data['class'] = 'danger';
+ die('No permission.');
}
- Header('Content-Type: application/json; charset=utf-8');
- die(json_encode($data));
} else {
echo 'Invalid action.';
}
@@ -266,9 +279,28 @@ class Page_Statistics_Reporting extends Page
}
}
}
+ // only show locations which you have permission for
+ $filterLocs = User::getAllowedLocations("table.view.location");
+ foreach ($data as $key => $row) {
+ if (!in_array($row['locationId'], $filterLocs)) {
+ unset($data[$key]);
+ }
+ }
+ // correct indexing of array after deletions
+ $data = array_values($data);
return $data;
case 'client':
- return GetData::perClient($flags);
+ $data = GetData::perClient($flags);
+ // only show clients from locations which you have permission for
+ $filterLocs = User::getAllowedLocations("table.view.location");
+ foreach ($data as $key => $row) {
+ if (!in_array($row['locationId'], $filterLocs)) {
+ unset($data[$key]);
+ }
+ }
+ // correct indexing of array after deletions
+ $data = array_values($data);
+ return $data;
case 'user':
return GetData::perUser($flags);
case 'vm':
diff --git a/modules-available/statistics_reporting/permissions/permissions.json b/modules-available/statistics_reporting/permissions/permissions.json
new file mode 100644
index 00000000..e6e550eb
--- /dev/null
+++ b/modules-available/statistics_reporting/permissions/permissions.json
@@ -0,0 +1,10 @@
+{
+ "table.view.total": "View total table.",
+ "table.view.location": "View location table.",
+ "table.view.client": "View client table.",
+ "table.view.user": "View user table.",
+ "table.view.vm": "View lecture table.",
+ "table.export": "Export tables as JSON/CSV/XML. Needs the permission to view the table to export it.",
+ "reporting.download": "Download weekly report.",
+ "reporting.change": "Change weekly reporting settings."
+} \ No newline at end of file
diff --git a/modules-available/statistics_reporting/style.css b/modules-available/statistics_reporting/style.css
index 81dc74b0..3cd6653f 100644
--- a/modules-available/statistics_reporting/style.css
+++ b/modules-available/statistics_reporting/style.css
@@ -35,8 +35,4 @@
margin-left: -1.5em;
text-align: center;
line-height: 1.6em;
-}
-
-th[data-sort] {
- cursor: pointer;
-}
+} \ No newline at end of file
diff --git a/modules-available/statistics_reporting/templates/columnChooser.html b/modules-available/statistics_reporting/templates/columnChooser.html
index e4069be9..a6561c47 100644
--- a/modules-available/statistics_reporting/templates/columnChooser.html
+++ b/modules-available/statistics_reporting/templates/columnChooser.html
@@ -1,64 +1,79 @@
<form method="get" id="controlsForm">
<input type="hidden" name="do" value="statistics_reporting">
- <div class="row">
- <div class="col-md-12">
- <button id="button-settings" type="button" class="pull-right btn btn-{{settingsButtonClass}}" data-toggle="modal" data-target="#modal-settings"><span class="glyphicon glyphicon-cog"></span></button>
- <strong class="text-capitalize">{{lang_displaySelection}}</strong>
- </div>
+
+ <div class="page-header">
+ <button id="button-settings" type="button" class="btn btn-{{settingsButtonClass}} pull-right" data-toggle="modal" data-target="#modal-settings"><span class="glyphicon glyphicon-cog"></span> Settings</button>
+ <h1>{{lang_moduleName}}</h1>
</div>
- <div class="row top-row">
- <div class="col-md-4">
- <select name="type" id="select-table" class="form-control">
- {{#tables}}
- <option value="{{value}}" {{selected}}>{{name}}</option>
- {{/tables}}
- </select>
- </div>
- <div class="col-md-4">
- <select name="cutoff" id="select-cutoff" class="form-control">
- {{#days}}
- <option value="{{days}}" {{selected}}>{{days}} {{lang_days}}</option>
- {{/days}}
- </select>
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_displaySelection}}
</div>
- <div class="col-md-3">
- <div id="slider">
- <div id="lower-handle" class="ui-slider-handle"></div>
- <div id="upper-handle" class="ui-slider-handle"></div>
- <input type="hidden" id="lower-field" name="lower" value="{{lower}}">
- <input type="hidden" id="upper-field" name="upper" value="{{upper}}">
+ <div class="panel-body">
+ <div class="row top-row">
+ <div class="col-md-2">
+ <select name="type" id="select-table" class="form-control">
+ {{#tables}}
+ <option {{^allowed}}disabled{{/allowed}} value="{{value}}" {{selected}}>{{name}}</option>
+ {{/tables}}
+ </select>
+ </div>
+ <div class="col-md-2">
+ <select name="cutoff" id="select-cutoff" class="form-control">
+ {{#days}}
+ <option value="{{days}}" {{selected}}>{{days}} {{lang_days}}</option>
+ {{/days}}
+ </select>
+ </div>
+ <div class="col-md-3" style="margin-top: 10px;">
+ <div id="slider">
+ <div id="lower-handle" class="ui-slider-handle"></div>
+ <div id="upper-handle" class="ui-slider-handle"></div>
+ <input type="hidden" id="lower-field" name="lower" value="{{lower}}">
+ <input type="hidden" id="upper-field" name="upper" value="{{upper}}">
+ </div>
+ </div>
+ <div class="col-md-1">
+ <button type="submit" class="btn btn-primary">{{lang_show}}</button>
+ </div>
+ <div class="col-md-3">
+ <div class="input-group">
+ <select class="form-control" name="format">
+ <option value="json">JSON</option>
+ <option value="csv">CSV (Excel)</option>
+ <option value="xml">XML</option>
+ </select>
+ <div class="input-group-btn">
+ <button {{^allowedExport}}disabled {{/allowedExport}} type="submit" class="btn btn-default" name="action" value="export">{{lang_export}}</button>
+ </div>
+ </div>
+ </div>
+
</div>
+
</div>
</div>
- <div class="row top-row">
- <div class="col-md-12 form-inline">
- <div><strong class="text-capitalize">{{lang_displayColumns}}</strong></div>
- {{#columns}}
- <div class="checkbox">
- <input id="id_{{id}}" name="{{id}}" value="on" type="checkbox" class="column-toggle form-control" {{checked}}>
- <label for="id_{{id}}">{{name}}</label>
- </div>
- {{/columns}}
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_displayColumns}}
</div>
- </div>
- <div class="row top-row">
- <div class="col-md-12 form-inline">
- <div class="pull-right input-group">
- <select class="form-control" name="format">
- <option value="json">JSON</option>
- <option value="csv">CSV (Excel)</option>
- <option value="xml">XML</option>
- </select>
- <div class="input-group-btn">
- <button type="submit" class="btn btn-default" name="action" value="export">{{lang_export}}</button>
+ <div class="panel-body">
+ <div class="row top-row">
+ <div class="col-md-12 form-inline">
+ {{#columns}}
+ <div class="checkbox">
+ <input id="id_{{id}}" name="{{id}}" value="on" type="checkbox" class="column-toggle form-control" {{checked}}>
+ <label for="id_{{id}}">{{name}}</label>
+ </div>
+ {{/columns}}
</div>
</div>
- <button type="submit" class="btn btn-primary">{{lang_apply}}</button>
</div>
</div>
</form>
-<hr>
<div id="modal-settings" class="modal fade" role="dialog">
<div class="modal-dialog">
@@ -71,17 +86,18 @@
</div>
<div class="modal-body">
<div class="checkbox">
- <input id="checkbox-reporting" type="checkbox" value="on" {{reportChecked}}>
- <label for="checkbox-reporting" style="padding-left: 40px">{{lang_reportingLabel}}</label>
+ <input {{^allowedReportChange}}disabled {{/allowedReportChange}} id="checkbox-reporting" type="checkbox" value="on" {{reportChecked}}>
+ <label for="checkbox-reporting" style="padding-left: 20px">{{lang_reportingLabel}}</label>
</div>
<div>
<p>{{lang_reportingDescription}}</p>
<p><a href="https://www.bwlehrpool.de/doku.php/satellite/statistics_reporting" target="_blank">{{lang_reportMoreInfo}}</a></p>
- <a class="btn btn-success" href="?do=statistics_reporting&amp;action=getreport">{{lang_downloadReport}}</a>
</div>
</div>
<div class="modal-footer">
- <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="saveSettings()">{{lang_save}}</button>
+ <button {{^allowedDownload}}disabled {{/allowedDownload}} class="btn btn-warning pull-left" onclick="window.location.href='?do=statistics_reporting&amp;action=getreport'">{{lang_downloadReport}}</button>
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button {{^allowedReportChange}}disabled {{/allowedReportChange}} type="button" class="btn btn-primary" data-dismiss="modal" onclick="saveSettings()">{{lang_save}}</button>
</div>
</div>
@@ -112,15 +128,6 @@
},
});
- var table = $("table").stupidtable();
- table.on("aftertablesort", function (event, data) {
- var th = $(this).find("th");
- th.find(".arrow").remove();
- var dir = $.fn.stupidtable.dir;
- var arrow = data.direction === dir.ASC ? "up" : "down";
- th.eq(data.column).append(' <span class="arrow glyphicon glyphicon-chevron-'+arrow+'"></span>');
- });
-
$(".locationLink").click(function(e) {
e.preventDefault();
var form = $('#controlsForm');
diff --git a/modules-available/statistics_reporting/templates/table-client.html b/modules-available/statistics_reporting/templates/table-client.html
index be504cef..59153e01 100644
--- a/modules-available/statistics_reporting/templates/table-client.html
+++ b/modules-available/statistics_reporting/templates/table-client.html
@@ -1,4 +1,4 @@
-<table id="table-perclient" class="table table-condensed table-striped">
+<table id="table-perclient" class="table table-condensed table-striped stupidtable">
<thead>
<tr>
<th data-sort="string" class="text-left col-md-4">{{lang_hostname}}</th>
diff --git a/modules-available/statistics_reporting/templates/table-location.html b/modules-available/statistics_reporting/templates/table-location.html
index ccac623d..a0867208 100644
--- a/modules-available/statistics_reporting/templates/table-location.html
+++ b/modules-available/statistics_reporting/templates/table-location.html
@@ -1,4 +1,4 @@
-<table id="table-perlocation" class="table table-condensed table-striped">
+<table id="table-perlocation" class="table table-condensed table-striped stupidtable">
<thead>
<tr>
<th data-sort="string" class="text-left col-md-2">{{lang_location}}</th>
diff --git a/modules-available/statistics_reporting/templates/table-total.html b/modules-available/statistics_reporting/templates/table-total.html
index 4048a178..8d5d7571 100644
--- a/modules-available/statistics_reporting/templates/table-total.html
+++ b/modules-available/statistics_reporting/templates/table-total.html
@@ -1,4 +1,4 @@
-<table id="table-total" class="table table-condensed table-striped">
+<table id="table-total" class="table table-condensed table-striped stupidtable">
<thead>
<tr>
<th class="text-left col-md-2"></th>
diff --git a/modules-available/statistics_reporting/templates/table-user.html b/modules-available/statistics_reporting/templates/table-user.html
index 5c2ba56f..ea4d20f5 100644
--- a/modules-available/statistics_reporting/templates/table-user.html
+++ b/modules-available/statistics_reporting/templates/table-user.html
@@ -1,4 +1,4 @@
-<table id="table-peruser" class="table table-condensed table-striped">
+<table id="table-peruser" class="table table-condensed table-striped stupidtable">
<thead>
<tr>
<th data-sort="string" class="text-left col-md-4">{{lang_user}}</th>
diff --git a/modules-available/statistics_reporting/templates/table-vm.html b/modules-available/statistics_reporting/templates/table-vm.html
index 9a775709..4ffb4df2 100644
--- a/modules-available/statistics_reporting/templates/table-vm.html
+++ b/modules-available/statistics_reporting/templates/table-vm.html
@@ -1,4 +1,4 @@
-<table id="table-pervm" class="table table-condensed table-striped">
+<table id="table-pervm" class="table table-condensed table-striped stupidtable">
<thead>
<tr>
<th data-sort="string" class="text-left col-md-4">{{lang_vm}}</th>
diff --git a/modules-available/sysconfig/lang/de/template-tags.json b/modules-available/sysconfig/lang/de/template-tags.json
index d3b0bb9f..900b67a8 100644
--- a/modules-available/sysconfig/lang/de/template-tags.json
+++ b/modules-available/sysconfig/lang/de/template-tags.json
@@ -109,7 +109,7 @@
"lang_supportedFiles": "Unterst\u00fctzte Archivformate",
"lang_systemConfiguration": "Systemkonfiguration",
"lang_systemConfigurationAlert": "Bevor Sie eine Systemkonfiguration erstellen k\u00f6nnen, m\u00fcssen Sie zun\u00e4chst ein Konfigurationsmodul erzeugen.",
- "lang_systemConfigurationNotFound": "Keine Systemkonfigurationen gefunden.Erstellen Sie eine neue Konfiguration aus den unten aufgef\u00fchrten Konfigurationsmodulen.",
+ "lang_systemConfigurationNotFound": "Keine Systemkonfigurationen gefunden. Erstellen Sie eine neue Konfiguration aus den unten aufgef\u00fchrten Konfigurationsmodulen.",
"lang_title": "Titel",
"lang_to": "Zur",
"lang_toSystemConfiguration": "Zur Systemkonfiguration",
diff --git a/modules-available/sysconfig/lang/en/template-tags.json b/modules-available/sysconfig/lang/en/template-tags.json
index 1374d87f..6a482772 100644
--- a/modules-available/sysconfig/lang/en/template-tags.json
+++ b/modules-available/sysconfig/lang/en/template-tags.json
@@ -37,7 +37,7 @@
"lang_determiningHomeDirectory": "Trying to determine home directory attribute...",
"lang_dnLookup": "Looking up bind dn",
"lang_download": "Download",
- "lang_downloadLong": "Download module \"as is\".",
+ "lang_downloadLong": "Download module \"as it is\".",
"lang_driveLetterNote": "IMPORTANT: Pick a drive letter for the home directory that will be free in the Virtual Machines. Otherwise, a random letter will be assigned.",
"lang_editLong": "Edit module or configuration.",
"lang_editingLocationInfo": "You're setting the configuration for a specific location, not the global one",
diff --git a/modules-available/sysconfig/page.inc.php b/modules-available/sysconfig/page.inc.php
index 8e5c706b..043645df 100644
--- a/modules-available/sysconfig/page.inc.php
+++ b/modules-available/sysconfig/page.inc.php
@@ -135,6 +135,9 @@ class Page_SysConfig extends Page
*/
protected function doRender()
{
+
+ Render::addTemplate('sysconfig_heading');
+
$action = Request::any('action', 'list');
switch ($action) {
case 'addmodule':
diff --git a/modules-available/sysconfig/templates/ad-start.html b/modules-available/sysconfig/templates/ad-start.html
index 1f8e1e01..4a183dfc 100644
--- a/modules-available/sysconfig/templates/ad-start.html
+++ b/modules-available/sysconfig/templates/ad-start.html
@@ -1,8 +1,10 @@
<p>
{{lang_adText1}}
<br>
+ <br/>
{{lang_adText2}}
<br>
+ <br/>
{{lang_adText3}}
</p>
<pre>dsquery user -name &quot;Username&quot;</pre>
@@ -18,35 +20,35 @@
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_moduleTitle}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_moduleTitle}}</span>
<input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" autofocus>
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">Server *</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">Server *</span>
<input tabindex="2" name="server" value="{{server}}" type="text" class="form-control" placeholder="dc0.institution.example.com">
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_bindDN}} *</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_bindDN}} *</span>
<input tabindex="3" name="binddn" value="{{binddn}}" type="text" class="form-control" placeholder="domain\bwlp *ODER* CN=bwlp,OU=Benutzer,DC=domain,DC=hs-beispiel,DC=de">
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_password}} *</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_password}} *</span>
<input tabindex="4" name="bindpw" value="{{bindpw}}" type="{{password_type}}" class="form-control" placeholder="{{lang_password}}">
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_searchBase}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_searchBase}}</span>
<input tabindex="5" name="searchbase" value="{{searchbase}}" type="text" class="form-control" placeholder="dc=windows,dc=hs-beispiel,dc=de">
</div>
<br>
<div class="input-group">
- <span class="input-group-addon slx-ga">Home</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">Home</span>
<input tabindex="6" name="home" value="{{home}}" type="text" class="form-control" placeholder="\\server.example.com\%s">
<span class="input-group-btn">
<a class="btn btn-default" data-toggle="modal" data-target="#help-home"><span class="glyphicon glyphicon-question-sign"></span></a>
</span>
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_homeAttr}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_homeAttr}}</span>
<input tabindex="6" name="homeattr" value="{{homeattr}}" type="text" class="form-control" placeholder="homeDirectory">
<span class="input-group-btn">
<a class="btn btn-default" data-toggle="modal" data-target="#help-homeattr"><span class="glyphicon glyphicon-question-sign"></span></a>
@@ -54,23 +56,26 @@
</div>
<br>
<div>
- <label>
- <input type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}> {{lang_fixNumeric}}
- </label>
+ <div class="checkbox">
+ <input type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
+ <label><b>{{lang_fixNumeric}}</b></label>
+ </div>
<div>
<i>{{lang_fixNumericDescription}}</i>
</div>
</div>
<br>
<div>
- <label>
- <input type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}> {{lang_ssl}}
- </label>
+ <div class="checkbox">
+ <input type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
+ <label><b>{{lang_ssl}}</b></label>
+ </div>
<div>
<i>{{lang_sslDescription}}</i>
</div>
</div>
<br/>
+
<hr>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
@@ -78,8 +83,10 @@
<div class="btn-group pull-right">
<button type="submit" class="btn btn-primary">{{lang_next}} &raquo;</button>
</div>
+
<div class="clearfix"></div>
<div {{^ssl}}style="display:none"{{/ssl}} id="cert-box">
+ <hr>
<div class="well well-sm" id="wcustom">
{{lang_customCertificate}}
<pre class="small">
diff --git a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
index f3194308..35c8f1ee 100644
--- a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
+++ b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
@@ -11,7 +11,7 @@
<div id="supplied-cert-invalid" style="display:none" class="alert alert-danger">{{lang_userCertInvalid}}</div>
<div id="trying-fingerprint" style="display:none" class="alert alert-warning">{{lang_tryingFingerprint}}</div>
<br>
-<div class="pull-left">
+<div class="text-left">
<form role="form" method="post" action="?do=SysConfig&amp;action=addmodule&amp;step={{prev}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="edit" value="{{edit}}">
@@ -30,7 +30,7 @@
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
</div>
-<div class="pull-right">
+<div class="text-right">
<form id="nextform" role="form" method="post" action="?do=SysConfig&amp;action=addmodule&amp;step={{next}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="edit" value="{{edit}}">
diff --git a/modules-available/sysconfig/templates/branding-check.html b/modules-available/sysconfig/templates/branding-check.html
index 1a021309..d48f9631 100644
--- a/modules-available/sysconfig/templates/branding-check.html
+++ b/modules-available/sysconfig/templates/branding-check.html
@@ -13,6 +13,7 @@
</div>
<div class="clearfix"></div>
<div>{{error}}</div>
+<br/>
<div>
<form role="form" enctype="multipart/form-data" method="post" action="?do=SysConfig&amp;action=addmodule&amp;step={{step}}">
<input type="hidden" name="token" value="{{token}}">
@@ -25,7 +26,7 @@
<a class="btn btn-default" href="?do=SysConfig&action=addmodule&step=Branding_Start">{{lang_cancel}}</a>
</div>
<div class="btn-group pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</form>
</div>
diff --git a/modules-available/sysconfig/templates/branding-start.html b/modules-available/sysconfig/templates/branding-start.html
index 7f2a0132..0db085d9 100644
--- a/modules-available/sysconfig/templates/branding-start.html
+++ b/modules-available/sysconfig/templates/branding-start.html
@@ -8,9 +8,8 @@
<label for="input-url">{{lang_urlLoad}}</label>
<input class="form-control" type="text" name="url" id="input-url">
</div>
- {{lang_or}}
<div class="form-group">
- <label for="input-file">{{lang_computerLoad}}</label>
+ <label for="input-file">{{lang_or}} {{lang_computerLoad}}</label>
<div class="input-group upload-ex">
<input type="text" class="form-control" readonly placeholder="{{lang_selectFile}}">
<span class="input-group-btn">
@@ -21,6 +20,7 @@
</div>
</div>
+ <hr/>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
</div>
diff --git a/modules-available/sysconfig/templates/cfg-finish.html b/modules-available/sysconfig/templates/cfg-finish.html
index c9622db0..21c7c690 100644
--- a/modules-available/sysconfig/templates/cfg-finish.html
+++ b/modules-available/sysconfig/templates/cfg-finish.html
@@ -6,8 +6,10 @@
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="config">
<input type="hidden" name="activate" value="{{configid}}">
- <div class="btn-group">
- <button type="submit" class="btn btn-primary">{{lang_activateGlobally}}</button>
- <a href="?do=SysConfig" class="btn btn-default">{{lang_backToSysconfig}}</a>
+ <div class="text-right">
+ <div class="btn-group">
+ <a href="?do=SysConfig" class="btn btn-default">{{lang_backToSysconfig}}</a>
+ <button type="submit" class="btn btn-primary">{{lang_activateGlobally}}</button>
+ </div>
</div>
</form>
diff --git a/modules-available/sysconfig/templates/cfg-start.html b/modules-available/sysconfig/templates/cfg-start.html
index 8c33f0e5..6196d475 100644
--- a/modules-available/sysconfig/templates/cfg-start.html
+++ b/modules-available/sysconfig/templates/cfg-start.html
@@ -18,7 +18,10 @@
<input type="radio" name="module[{{groupid}}]" value="{{moduleid}}" id="module{{moduleid}}" {{#active}}checked{{/active}}>
{{/unique}}
{{^unique}}
- <input type="checkbox" name="module[{{moduleid}}]" value="{{moduleid}}" id="module{{moduleid}}" {{#active}}checked{{/active}}>
+ <div class="checkbox">
+ <input type="checkbox" name="module[{{moduleid}}]" value="{{moduleid}}" id="module{{moduleid}}" {{#active}}checked{{/active}}>
+ <label></label>
+ </div>
{{/unique}}
</span>
<label class="form-control" for="module{{moduleid}}">{{title}}</label>
diff --git a/modules-available/sysconfig/templates/custom-upload.html b/modules-available/sysconfig/templates/custom-upload.html
index 51677f8b..43636a49 100644
--- a/modules-available/sysconfig/templates/custom-upload.html
+++ b/modules-available/sysconfig/templates/custom-upload.html
@@ -15,6 +15,7 @@
</div>
<p class="help-block">{{lang_supportedFiles}}: .tar.gz, .tar.bz2, .zip</p>
+ <hr/>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
</div>
diff --git a/modules-available/sysconfig/templates/ldap-start.html b/modules-available/sysconfig/templates/ldap-start.html
index 22f4e2fa..a457ecd3 100644
--- a/modules-available/sysconfig/templates/ldap-start.html
+++ b/modules-available/sysconfig/templates/ldap-start.html
@@ -10,32 +10,32 @@
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_moduleTitle}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_moduleTitle}}</span>
<input tabindex="1" name="title" value="{{title}}" type="text" class="form-control">
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">Server *</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">Server *</span>
<input tabindex="2" name="server" value="{{server}}" type="text" class="form-control" placeholder="dc0.institution.example.com">
<!--span class="input-group-btn">
<a class="btn btn-default"><span class="glyphicon glyphicon-question-sign"></span></a>
</span-->
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_bindDN}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_bindDN}}</span>
<input tabindex="3" name="binddn" value="{{binddn}}" type="text" class="form-control" placeholder="CN=bwlp,OU=Benutzer,DC=domain,DC=hs-beispiel,DC=de">
<!--span class="input-group-btn">
<a class="btn btn-default"><span class="glyphicon glyphicon-question-sign"></span></a>
</span-->
</div>
<div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_password}}</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_password}}</span>
<input tabindex="4" name="bindpw" value="{{bindpw}}" type="{{password_type}}" class="form-control" placeholder="{{lang_password}}">
<!--span class="input-group-btn">
<a class="btn btn-default"><span class="glyphicon glyphicon-question-sign"></span></a>
</span-->
</div>
- <div class="input-group">
- <span class="input-group-addon slx-ga">{{lang_searchBase}} *</span>
+ <div style="min-width:150px;" class="input-group">
+ <span style="min-width:150px;" class="input-group-addon slx-ga">{{lang_searchBase}} *</span>
<input tabindex="5" name="searchbase" value="{{searchbase}}" type="text" class="form-control" placeholder="ou=users,dc=hochschule,dc=de">
<!--span class="input-group-btn">
<a class="btn btn-default"><span class="glyphicon glyphicon-question-sign"></span></a>
@@ -43,7 +43,7 @@
</div>
<br>
<div class="input-group">
- <span class="input-group-addon slx-ga">Home</span>
+ <span style="min-width:150px;" class="input-group-addon slx-ga">Home</span>
<input tabindex="6" name="home" value="{{home}}" type="text" class="form-control" placeholder="\\server.example.com\%s">
<span class="input-group-btn">
<a class="btn btn-default" data-toggle="modal" data-target="#help-home"><span class="glyphicon glyphicon-question-sign"></span></a>
@@ -51,23 +51,27 @@
</div>
<br>
<div>
- <label>
- <input type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}> {{lang_fixNumeric}}
- </label>
+ <div class="checkbox">
+ <input type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
+ <label><b>{{lang_fixNumeric}}</b></label>
+ </div>
<div>
<i>{{lang_fixNumericDescription}}</i>
</div>
</div>
<br>
<div>
- <label>
- <input type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}> {{lang_ssl}}
- </label>
+ <div class="checkbox">
+ <input type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
+ <label><b>{{lang_ssl}}</b></label>
+ </div>
+ <div>
+ <i>{{lang_sslDescription}}</i>
+ </div>
</div>
- <i>{{lang_sslDescription}}</i>
<br>
-
+ <hr>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
@@ -77,8 +81,8 @@
</div>
<div class="clearfix"></div>
- <hr>
<div {{^ssl}}style="display:none"{{/ssl}} id="cert-box">
+ <hr>
<div class="well well-sm" id="wcustom">
{{lang_customCertificate}}
<pre class="small">
diff --git a/modules-available/sysconfig/templates/list-configs.html b/modules-available/sysconfig/templates/list-configs.html
index d2cedca4..eb67d7a3 100644
--- a/modules-available/sysconfig/templates/list-configs.html
+++ b/modules-available/sysconfig/templates/list-configs.html
@@ -100,7 +100,7 @@
</form>
</div>
{{^locationid}}
- <div class="panel-footer">
+ <div class="panel-footer text-right">
<a class="btn btn-primary" href="?do=SysConfig&amp;action=addconfig">{{lang_newConfiguration}}</a>
</div>
{{/locationid}}
@@ -109,11 +109,13 @@
<div class="modal fade" id="help-config" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_systemConfiguration}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">&times;</button>
+ <h4 class="modal-title"><b>{{lang_systemConfiguration}}</b></h4>
+ </div>
<div class="modal-body">
{{lang_helpSystemConfiguration}}
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
diff --git a/modules-available/sysconfig/templates/list-modules.html b/modules-available/sysconfig/templates/list-modules.html
index c6622ee7..f15814f2 100644
--- a/modules-available/sysconfig/templates/list-modules.html
+++ b/modules-available/sysconfig/templates/list-modules.html
@@ -39,7 +39,7 @@
{{/modules}}
</form>
</div>
- <div class="panel-footer">
+ <div class="panel-footer text-right">
<a class="btn btn-primary" href="?do=SysConfig&amp;action=addmodule">{{lang_newModule}}</a>
</div>
</div>
@@ -47,11 +47,13 @@
<div class="modal fade" id="help-module" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_moduleConfiguration}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">&times;</button>
+ <h4 class="modal-title"><b>{{lang_moduleConfiguration}}</b></h4>
+ </div>
<div class="modal-body">
{{lang_helpModuleConfiguration}}
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
diff --git a/modules-available/sysconfig/templates/sshconfig-start.html b/modules-available/sysconfig/templates/sshconfig-start.html
index a208dbac..c0b4b379 100644
--- a/modules-available/sysconfig/templates/sshconfig-start.html
+++ b/modules-available/sysconfig/templates/sshconfig-start.html
@@ -6,11 +6,13 @@
<input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
</div>
<div class="form-group">
- <label>
+ <div class="checkbox">
<input type="checkbox" name="allowPasswordLogin" value="yes" {{#apl}}checked{{/apl}}>
- {{lang_allowPass}}
- </label>
- <p><i>{{lang_allowPassInfo}}</i></p>
+ <label><b>{{lang_allowPass}}</b></label>
+ </div>
+ <div>
+ <i>{{lang_allowPassInfo}}</i>
+ </div>
</div>
<div class="form-group">
<label for="root-key">{{lang_rootKey}}</label>
@@ -22,11 +24,12 @@
<input class="form-control" type="text" name="listenPort" value="{{listenPort}}" id="port" pattern="\d+">
<i>{{lang_listenPortInfo}}</i>
</div>
+ <hr/>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
</div>
<div class="btn-group pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</form>
diff --git a/modules-available/sysconfig/templates/start.html b/modules-available/sysconfig/templates/start.html
index 360d20fa..4bdd4853 100644
--- a/modules-available/sysconfig/templates/start.html
+++ b/modules-available/sysconfig/templates/start.html
@@ -10,6 +10,6 @@
</div>
</div>
{{/modules}}
-<div class="btn-group">
+<div class="text-right">
<a class="btn btn-default" href="?do=SysConfig">{{lang_cancel}}</a>
</div>
diff --git a/modules-available/sysconfig/templates/sysconfig_heading.html b/modules-available/sysconfig/templates/sysconfig_heading.html
new file mode 100644
index 00000000..2cef3326
--- /dev/null
+++ b/modules-available/sysconfig/templates/sysconfig_heading.html
@@ -0,0 +1 @@
+<h1>{{lang_systemConfiguration}}</h1> \ No newline at end of file
diff --git a/modules-available/syslog/lang/de/template-tags.json b/modules-available/syslog/lang/de/template-tags.json
index 49e94602..c8b2bb45 100644
--- a/modules-available/syslog/lang/de/template-tags.json
+++ b/modules-available/syslog/lang/de/template-tags.json
@@ -6,5 +6,6 @@
"lang_filter": "Filter",
"lang_go": "Go",
"lang_not": "not",
- "lang_when": "Wann"
+ "lang_when": "Wann",
+ "lang_applyFilter": "Filter anwenden"
} \ No newline at end of file
diff --git a/modules-available/syslog/lang/en/template-tags.json b/modules-available/syslog/lang/en/template-tags.json
index 71f61693..7dae52d9 100644
--- a/modules-available/syslog/lang/en/template-tags.json
+++ b/modules-available/syslog/lang/en/template-tags.json
@@ -6,5 +6,6 @@
"lang_filter": "Filter",
"lang_go": "Go",
"lang_not": "not",
- "lang_when": "When"
+ "lang_when": "When",
+ "lang_applyFilter": "Apply Filter"
} \ No newline at end of file
diff --git a/modules-available/syslog/templates/page-syslog.html b/modules-available/syslog/templates/page-syslog.html
index 28ab739a..8b590038 100644
--- a/modules-available/syslog/templates/page-syslog.html
+++ b/modules-available/syslog/templates/page-syslog.html
@@ -10,37 +10,45 @@
<label for="filterstring">{{lang_filter}}</label>
</div>
<div class="clearfix"></div>
- <div class="input-group">
- <input id="filterstring" placeholder="id" value="{{filter}}" name="filter">
- <span class="input-group-btn">
- <button class="btn btn-default" type="submit">{{lang_go}}</button>
- </span>
- </div>
- <div class="pull-left">
- <div class="checkbox">
- <input id="notbox" type="checkbox" name="not" {{#not}}checked="checked"{{/not}}>
- <label for="notbox">{{lang_not}}</label>
+
+
+ <div class="row">
+ <div class="col-sm-1">
+ <div class="checkbox">
+ <input id="notbox" type="checkbox" name="not" {{#not}}checked="checked"{{/not}}>
+ <label for="notbox">{{lang_not}}</label>
+ </div>
+ </div>
+ <div class="col-sm-11">
+ <div class="input-group">
+ <input id="filterstring" placeholder="id" value="{{filter}}" name="filter">
+ <span style="padding-bottom: 5px;" class="input-group-btn">
+ <button class="btn btn-primary" type="submit">{{lang_applyFilter}}</button>
+ </span>
+ </div>
</div>
</div>
</form>
{{{pagenav}}}
+
+
<table class="table table-striped table-condensed">
<thead>
<th width="1"></th>
- <th>{{lang_when}}</th>
- <th>{{lang_client}}</th>
- <th>{{lang_event}}</th>
+ <th class="text-center">{{lang_when}}</th>
+ <th class="text-center">{{lang_client}}</th>
+ <th class="text-center">{{lang_event}}</th>
<th width="1">{{lang_details}}</th>
</thead>
<tbody>
{{#list}}
<tr>
<td><span class="type-button glyphicon {{icon}}" title="{{logtypeid}}"></span></td>
- <td class="text-right" nowrap="nowrap">{{date}}</td>
- <td>{{clientip}}</td>
+ <td class="text-center" nowrap="nowrap">{{date}}</td>
+ <td class="text-left">{{clientip}}</td>
<td>{{description}}</td>
- <td>{{#extra}}
- <a class="btn btn-default btn-xs pull-left" onclick="$('#details-body').html($('#extra-{{logid}}').html())"
+ <td class="text-center">{{#extra}}
+ <a class="btn btn-default btn-xs" onclick="$('#details-body').html($('#extra-{{logid}}').html())"
data-toggle="modal" data-target="#myModal">&raquo;</a>
<div class="hidden" id="extra-{{logid}}">{{extra}}</div>
{{/extra}}</td>
@@ -48,6 +56,7 @@
{{/list}}
</tbody>
</table>
+
{{{pagenav}}}
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
@@ -61,9 +70,6 @@
<div class="modal-body">
<pre id="details-body"></pre>
</div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
- </div>
</div>
</div>
</div>
diff --git a/modules-available/systemstatus/lang/de/template-tags.json b/modules-available/systemstatus/lang/de/template-tags.json
index 1333fb7d..94488d89 100644
--- a/modules-available/systemstatus/lang/de/template-tags.json
+++ b/modules-available/systemstatus/lang/de/template-tags.json
@@ -1,5 +1,6 @@
{
"lang_addressConfiguration": "Adresskonfiguration",
+ "lang_areYouSureNoUndo": "Sind Sie sicher? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.",
"lang_attention": "Achtung!",
"lang_average": "Durchschnitt",
"lang_capacity": "Kapazit\u00e4t",
@@ -12,11 +13,13 @@
"lang_iAmSure": "Ja, ich bin sicher",
"lang_logicCPUs": "Logische CPUs",
"lang_maintenance": "Maintenance",
+ "lang_moduleHeading": "System-Status",
"lang_notDetermined": "Konnte nicht ermittelt werden",
"lang_occupied": "Belegt",
"lang_onlyOS": "Nur OS",
"lang_overview": "\u00dcbersicht",
"lang_ramUsage": "RAM-Nutzung",
+ "lang_serverReboot": "Server neustarten",
"lang_services": "Dienste",
"lang_space": "Speicherplatz",
"lang_storeMissingExpected": "VM-Store nicht eingebunden. Erwartet:",
diff --git a/modules-available/systemstatus/lang/en/template-tags.json b/modules-available/systemstatus/lang/en/template-tags.json
index 46b7e18b..3e5a4433 100644
--- a/modules-available/systemstatus/lang/en/template-tags.json
+++ b/modules-available/systemstatus/lang/en/template-tags.json
@@ -1,5 +1,6 @@
{
"lang_addressConfiguration": "Address Configuration",
+ "lang_areYouSureNoUndo": "Are you sure? This cannot be undone!",
"lang_attention": "Attention!",
"lang_average": "Average",
"lang_capacity": "Capacity",
@@ -12,11 +13,13 @@
"lang_iAmSure": "Yes, I am sure",
"lang_logicCPUs": "Logic CPUs",
"lang_maintenance": "Maintenance",
+ "lang_moduleHeading": "System Status",
"lang_notDetermined": "Could not be determined",
"lang_occupied": "Occupied",
"lang_onlyOS": "OS Only",
"lang_overview": "Overview",
"lang_ramUsage": "RAM Usage",
+ "lang_serverReboot": "Reboot Server",
"lang_services": "Services",
"lang_space": "Space",
"lang_storeMissingExpected": "VM store not mounted. Expected:",
diff --git a/modules-available/systemstatus/page.inc.php b/modules-available/systemstatus/page.inc.php
index f7ec7022..7ee9e5a4 100644
--- a/modules-available/systemstatus/page.inc.php
+++ b/modules-available/systemstatus/page.inc.php
@@ -15,10 +15,6 @@ class Page_SystemStatus extends Page
}
if (Request::post('action') === 'reboot') {
- if (Request::post('confirm') !== 'yep') {
- Message::addError('reboot-unconfirmed');
- Util::redirect('?do=SystemStatus');
- }
$this->rebootTask = Taskmanager::submit('Reboot');
}
}
diff --git a/modules-available/systemstatus/templates/_page.html b/modules-available/systemstatus/templates/_page.html
index 48a7e5c4..ca3e6fd2 100644
--- a/modules-available/systemstatus/templates/_page.html
+++ b/modules-available/systemstatus/templates/_page.html
@@ -1,3 +1,5 @@
+<h1>{{lang_moduleHeading}}</h1>
+
{{#rebootTask}}
<div data-tm-id="{{rebootTask}}" data-tm-log="messages">Reboot...</div>
{{/rebootTask}}
@@ -84,9 +86,23 @@
<form class="form-adduser" action="?do=SystemStatus" method="post">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="reboot">
- <div>Server Reboot</div>
- <label><input type="checkbox" name="confirm" value="yep"> {{lang_iAmSure}}</label>
- <button class="btn btn-warning btn-xs" type="submit">Reboot</button>
+ <button class="btn btn-warning" type="button" data-toggle="modal" data-target="#rebootServerModal"><span class="glyphicon glyphicon-repeat"></span> {{lang_serverReboot}}</button>
+
+
+ <div class ="modal fade" id="rebootServerModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
+ <div class="modal-dialog" style="width: 400px" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ {{lang_areYouSureNoUndo}}
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button>
+ <button type="submit" class="btn btn-sm btn-warning"><span class="glyphicon glyphicon-repeat"></span> {{lang_serverReboot}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
</form>
<div id="dmsd-users"></div>
</div>
diff --git a/modules-available/translation/lang/de/template-tags.json b/modules-available/translation/lang/de/template-tags.json
index 99ec6cea..cb10d3b4 100644
--- a/modules-available/translation/lang/de/template-tags.json
+++ b/modules-available/translation/lang/de/template-tags.json
@@ -1,5 +1,6 @@
{
"lang_createTag": "Tag erstellen",
+ "lang_clear": "Läutern",
"lang_global": "Global",
"lang_globalTooltip": "Dieser Tag ist global verf\u00fcgbar und braucht normalerweise nicht explizit f\u00fcr dieses Modul \u00fcbersetzt zu werden",
"lang_menuCategories": "Men\u00fckategorien",
@@ -7,6 +8,7 @@
"lang_missing": "Fehlend",
"lang_missingDeps": "Fehlende Abh\u00e4ngigkeiten",
"lang_module": "Modul",
+ "lang_modullist": "Liste der Module",
"lang_otherStrings": "Andere Texte",
"lang_sample": "Beispiel",
"lang_status": "Status",
@@ -16,7 +18,7 @@
"lang_templateHint": "Hinweis: Gelbe Linien zeigen an, dass eine \u00dcbersetzung fehlt, rote Linien, dass ein Tag nicht von dem jeweiligen Template verwendet wird.",
"lang_templates": "Templates",
"lang_translation": "\u00dcbersetzung",
- "lang_translationHeading": "Verwalten der \u00dcbersetzungen",
+ "lang_translationHeading": "Verwaltung der \u00dcbersetzungen",
"lang_unused": "Ungenutzt",
"lang_unusedUnreliableHint": "Die Erkennung ungenutzter Tags bezieht nur aktivierte Module mit ein. Es k\u00f6nnte sein, dass ein ungenutzt gemeldeter Tag in einem nicht aktivierten Modul verwendet wird."
} \ No newline at end of file
diff --git a/modules-available/translation/lang/en/template-tags.json b/modules-available/translation/lang/en/template-tags.json
index 9f0795b1..e7365ca6 100644
--- a/modules-available/translation/lang/en/template-tags.json
+++ b/modules-available/translation/lang/en/template-tags.json
@@ -1,5 +1,6 @@
{
"lang_createTag": "Create Tag",
+ "lang_clear": "Clear",
"lang_global": "Global",
"lang_globalTooltip": "This tag is global; usually there is no need to translate it explicitly for this module",
"lang_menuCategories": "Menu categories",
@@ -7,6 +8,7 @@
"lang_missing": "Missing",
"lang_missingDeps": "Missing dependencies",
"lang_module": "Module",
+ "lang_modullist": "List of Modules",
"lang_otherStrings": "Other strings",
"lang_sample": "Sample",
"lang_status": "Status",
@@ -16,7 +18,7 @@
"lang_templateHint": "Hint: Yellow lines indicate a translation is missing and red lines indicate a tag is not being used by the template.",
"lang_templates": "Templates",
"lang_translation": "Translation",
- "lang_translationHeading": "Manage translations",
+ "lang_translationHeading": "Translation Management",
"lang_unused": "Unused",
"lang_unusedUnreliableHint": "Detection of unused tags only includes currently activated modules. It's possible that a tag marked \"unused\" is actually refered to in a module not activated."
} \ No newline at end of file
diff --git a/modules-available/translation/templates/edit.html b/modules-available/translation/templates/edit.html
index 082e2cb5..3c66aef6 100644
--- a/modules-available/translation/templates/edit.html
+++ b/modules-available/translation/templates/edit.html
@@ -1,21 +1,90 @@
-<div class="panel panel-default">
- <div class="panel-heading">
- {{module}} / {{section}}
+<h1>{{lang_translationHeading}}: {{module}} / {{section}}</h1>
+
+<div class="alert alert-info">
+ {{lang_templateHint}}
+</div>
+
+<form action="?do=Translation" method="post" class="slx-visible-rows">
+ <table id="moduleTable" class="table table-condensed table-hover stupidtable">
+ <thead>
+ <tr>
+ <th>{{lang_tag}}</th>
+ <th>{{lang_translation}} (<b>{{language}}</b>)</th>
+ <th class="hidden-xs">{{lang_sample}}</th>
+ <th style="text-align: center;">{{lang_clear}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#tags}}
+ <tr>
+ <td class="col-sm-3">
+ <div>
+ {{#unused}}
+ <span class="label label-danger">{{lang_unused}}</span>
+ {{/unused}}
+ {{#missing}}
+ <span class="label label-warning">{{lang_missing}}</span>
+ {{/missing}}
+ {{#isglobal}}
+ <span class="label label-success" title="{{lang_globalTooltip}}">{{lang_global}}</span>
+ {{/isglobal}}
+ {{tag}}
+ <div class="slx-notebox">{{{notes}}}</div>
+ </div>
+ </td>
+
+ <td class="col-sm-4" id="tagid-{{tagid}}">
+ {{^big}}
+ <input type="text" class="form-control switchable" value="{{translation}}" ondblclick="slxMb(this)" name="lang#!#{{tag}}" placeholder="{{placeholder}}">
+ {{/big}}
+ {{#big}}
+ <textarea rows="3" class="form-control" name="lang#!#{{tag}}" placeholder="{{placeholder}}">{{translation}}</textarea>
+ {{/big}}
+ </td>
+
+ <td class="hidden-xs col-sm-4">
+ <div class="badge">{{samplelang}}</div>
+ {{sampletext}}
+ </td>
+
+ <td class="col-sm-1" style="text-align:center; vertical-align: middle;">
+ <button type="button" class="btn btn-danger btn-xs" onclick="slxDelTag({{tagid}})" tabindex="-1">
+ <span class="glyphicon glyphicon-remove"></span>
+ </button>
+ </td>
+ </tr>
+ {{/tags}}
+ </tbody>
+ </table>
+
+
+ <input type="hidden" name="module" value="{{module}}">
+ <input type="hidden" name="destlang" value="{{destlang}}">
+ <input type="hidden" name="section" value="{{section}}">
+ <input type="hidden" name="subsection" value="{{subsection}}">
+ <input type="hidden" name="token" value="{{token}}">
+ <div class="text-right">
+ <a class="btn btn-default" href='?do=Translation' >{{lang_back}}</a>
+ <button type="submit" class="btn btn-primary" name="update" value="true">
+ <span class="glyphicon glyphicon-floppy-disk"></span>
+ {{lang_save}}
+ </button>
+ <button class="btn btn-success" type="button" onclick="slxAddTag()" >
+ <span class="glyphicon glyphicon-plus"></span>
+ {{lang_createTag}}
+ </button>
</div>
- <div class="panel-body">
- <p>{{lang_templateAdminHelp}}</p>
- <div class="alert alert-info">
- {{lang_templateHint}}
- </div>
+</form>
+<br/>
+
+<!-- vorherige Version der "Tabelle" geregelt über Divisions
+
<form action="?do=Translation" method="post" class="slx-visible-rows">
<input type="hidden" name="module" value="{{module}}">
<input type="hidden" name="destlang" value="{{destlang}}">
<input type="hidden" name="section" value="{{section}}">
<input type="hidden" name="subsection" value="{{subsection}}">
<input type="hidden" name="token" value="{{token}}">
- <a class="btn btn-primary" href='?do=Translation' >{{lang_back}}</a>
- <button class="btn btn-primary" type="button" onclick="slxAddTag()" >{{lang_createTag}}</button>
- <button type="submit" class="btn btn-primary" name="update" value="true">{{lang_save}}</button>
<div class="row">
<div class="col-xs-4 col-sm-3">{{lang_tag}}</div>
<div class="col-xs-6 col-sm-4">{{lang_translation}} (<b>{{language}}</b>)</div>
@@ -26,7 +95,7 @@
<div class="row">
<div class="col-xs-4 col-sm-3">
{{#unused}}
- <span class="label label-info">{{lang_unused}}</span>
+ <span class="label label-danger">{{lang_unused}}</span>
{{/unused}}
{{#missing}}
<span class="label label-warning">{{lang_missing}}</span>
@@ -53,23 +122,25 @@
</div>
<div class="col-xs-2 col-sm-2 col-lg-1">
<button type="button" class="btn btn-danger btn-xs" onclick="slxDelTag({{tagid}})" tabindex="-1">
- <span class="glyphicon glyphicon-remove"></span>
+ <span class="glyphicon glyphicon-trash"></span>
<span class="hidden-xs">{{lang_delete}}</span>
</button>
</div>
</div>
{{/tags}}
<div id="newTag"></div>
- <a class="btn btn-primary" href='?do=Translation' >{{lang_back}}</a>
- <button class="btn btn-primary" type="button" onclick="slxAddTag()" >{{lang_createTag}}</button>
- <button type="submit" class="btn btn-primary" name="update" value="true">{{lang_save}}</button>
+ <br/>
+ <div class="text-right">
+ <a class="btn btn-default" href='?do=Translation' >{{lang_back}}</a>
+ <button class="btn btn-success" type="button" onclick="slxAddTag()" >{{lang_createTag}}</button>
+ <button type="submit" class="btn btn-primary" name="update" value="true">{{lang_save}}</button>
+ </div>
</form>
- </div>
-</div>
-<script type="text/javascript">
- var slxNewTagCounter = 0;
- function slxAddTag()
- {
+
+
+
+
+Function:
$('#newTag').before(
'<div class="row" id="new-delete-' + slxNewTagCounter + '">' +
' <div class="col-xs-4 col-sm-3">' +
@@ -79,14 +150,42 @@
' <input type="text" class="form-control" name="new-text[' + slxNewTagCounter + ']">' +
' </div>' +
' <div class="hidden-xs col-sm-4">' +
- ' </div>' +
+ ' </div>' +
' <div class="col-xs-2 col-sm-1">' +
' <button type="button" class="btn btn-danger btn-xs" onclick="slxDelNew(' + slxNewTagCounter + ')" tabindex="-1"><span class="glyphicon glyphicon-remove"></span> {{lang_delete}}</button>' +
' </div>' +
'</div>'
);
+
+
+
+-->
+
+<script type="text/javascript">
+ var slxNewTagCounter = 0;
+ function slxAddTag()
+ {
+ $('#moduleTable tr:last').after(
+ '<tr id="new-delete-' + slxNewTagCounter + '">' +
+ ' <td class="col-sm-3">' +
+ ' <input type="text" name="new-id[' + slxNewTagCounter + ']" class="form-control">' +
+ ' </td>' +
+ ' <td class="col-sm-4">' +
+ ' <input type="text" class="form-control" name="new-text[' + slxNewTagCounter + ']">' +
+ ' </td>' +
+ ' <td class="hidden-xs col-sm-4"></td>' +
+ ' <td class="col-sm-1" style="text-align:center; vertical-align: middle;">' +
+ ' <button type="button" class="btn btn-danger btn-xs" onclick="slxDelNew(' + slxNewTagCounter + ')" tabindex="-1">' +
+ ' <span class="glyphicon glyphicon-remove"></span> ' +
+ ' </button>' +
+ ' </td>' +
+ '</tr>'
+ );
+
slxNewTagCounter++;
+
}
+
function slxDelNew(id)
{
diff --git a/modules-available/translation/templates/module-heading.html b/modules-available/translation/templates/module-heading.html
index 540828e9..8e87e22f 100644
--- a/modules-available/translation/templates/module-heading.html
+++ b/modules-available/translation/templates/module-heading.html
@@ -1 +1 @@
-<h1>{{moduleName}} ({{module}})</h1> \ No newline at end of file
+<h1>{{lang_translationHeading}}: {{module}}</h1> \ No newline at end of file
diff --git a/modules-available/translation/templates/module-list.html b/modules-available/translation/templates/module-list.html
index 026e17e9..c0af6a9c 100644
--- a/modules-available/translation/templates/module-list.html
+++ b/modules-available/translation/templates/module-list.html
@@ -1,25 +1,30 @@
<h1>{{lang_translationHeading}}</h1>
<div class="panel panel-default">
- <table class="table">
- <thead>
- <tr>
- <th>{{lang_module}}</th>
- <th>{{lang_status}}</th>
- <tr>
- </thead>
- <tbody>
- {{#table}}
+ <div class="panel-heading">
+ {{lang_modullist}}
+ </div>
+ <div class="panel-body">
+ <table class="table">
+ <thead>
<tr>
- <td>
- {{#depfail}}
- <div class="pull-right"><span class="red glyphicon glyphicon-exclamation-sign" title="{{lang_missingDeps}}"></span></div>
- {{/depfail}}
- <a href="?do=Translation&amp;module={{module}}">{{module}}</a>
- </td>
- <td>{{{status}}}</td>
- </tr>
- {{/table}}
- </tbody>
- </table>
+ <th>{{lang_module}}</th>
+ <th>{{lang_status}}</th>
+ <tr>
+ </thead>
+ <tbody>
+ {{#table}}
+ <tr>
+ <td>
+ {{#depfail}}
+ <div class="pull-right"><span class="red glyphicon glyphicon-exclamation-sign" title="{{lang_missingDeps}}"></span></div>
+ {{/depfail}}
+ <a href="?do=Translation&amp;module={{module}}">{{module}}</a>
+ </td>
+ <td>{{{status}}}</td>
+ </tr>
+ {{/table}}
+ </tbody>
+ </table>
+ </div>
</div>
diff --git a/modules-available/vmstore/lang/en/module.json b/modules-available/vmstore/lang/en/module.json
index 95b2e66d..a424640e 100644
--- a/modules-available/vmstore/lang/en/module.json
+++ b/modules-available/vmstore/lang/en/module.json
@@ -1,4 +1,4 @@
{
- "module_name": "VM storage location",
- "page_title": "Setting VM storage location"
+ "module_name": "VM Storage Location",
+ "page_title": "Setting VM Storage Location"
} \ No newline at end of file
diff --git a/modules-available/vmstore/lang/en/template-tags.json b/modules-available/vmstore/lang/en/template-tags.json
index 38047e09..b56cdd23 100644
--- a/modules-available/vmstore/lang/en/template-tags.json
+++ b/modules-available/vmstore/lang/en/template-tags.json
@@ -8,7 +8,7 @@
"lang_readOnly": "Read-only Access",
"lang_readWrite": "Read\/Write Access",
"lang_username": "Username",
- "lang_vmLocation": "VM Location",
+ "lang_vmLocation": "VM Storage Location",
"lang_vmLocationChoose": "Please choose where the images of virtual machines will be stored.",
"lang_vmLocationConfiguration": "VM location is configured",
"lang_vmLocationHelp1": "For test purposes, the VMs can be stored directly on the Satellite server. However, if you operate the delivered satellite vmdk please remember that you have only about 100GB of memory.",
diff --git a/modules-available/vmstore/templates/page-vmstore.html b/modules-available/vmstore/templates/page-vmstore.html
index c1ab2472..293b8aad 100644
--- a/modules-available/vmstore/templates/page-vmstore.html
+++ b/modules-available/vmstore/templates/page-vmstore.html
@@ -3,72 +3,87 @@
<input type="password" name="password_fake" id="password_fake" value="" style="position:absolute;top:-2000px" tabindex="-1">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="action" value="setstore">
+
+ <h1>{{lang_vmLocation}}</h1>
+
+ <p>{{lang_vmLocationChoose}} <a class="btn btn-default" data-toggle="modal" data-target="#help-store"><span class="glyphicon glyphicon-question-sign"></span></a></p>
+
+
<div class="panel panel-default">
<div class="panel-heading">
- {{lang_vmLocation}} <a class="btn btn-default" data-toggle="modal" data-target="#help-store"><span class="glyphicon glyphicon-question-sign"></span></a>
+ <div class="radio">
+ <input type="radio" name="storetype" value="internal" {{pre-internal}}>
+ <label>{{lang_intern}}</label>
+ </div>
+ </div>
+ <div class="panel-body">
+ {{lang_noAdditionalInformation}}
</div>
- <div class="panel-body slx-md-width">
- <p>{{lang_vmLocationChoose}}</p>
- <div class="panel panel-default">
- <div class="panel-heading">
- <input type="radio" name="storetype" value="internal" {{pre-internal}}> {{lang_intern}}
- </div>
- <div class="panel-body">
- {{lang_noAdditionalInformation}}
- </div>
+ </div>
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="radio radio-inline">
+ <input type="radio" name="storetype" value="nfs" {{pre-nfs}}>
+ <label>NFS</label>
</div>
- <div class="panel panel-default">
- <div class="panel-heading">
- <input type="radio" name="storetype" value="nfs" {{pre-nfs}}> NFS
- <a class="btn btn-default btn-sm" data-toggle="modal" data-target="#help-nfs"><span class="glyphicon glyphicon-question-sign"></span></a>
- </div>
- <div class="panel-body">
- <label for="nfsaddr">NFS-Export</label>
- <input type="text" class="form-control" name="nfsaddr" value="{{nfsaddr}}" placeholder="1.2.3.4:/export/bwlp" id="nfsaddr">
- </div>
+ <a class="btn btn-default btn-sm" data-toggle="modal" data-target="#help-nfs"><span class="glyphicon glyphicon-question-sign"></span></a>
+ </div>
+ <div class="panel-body">
+ <label for="nfsaddr">NFS-Export</label>
+ <input type="text" class="form-control" name="nfsaddr" value="{{nfsaddr}}" placeholder="1.2.3.4:/export/bwlp" id="nfsaddr">
+ </div>
+ </div>
+
+
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="radio">
+ <input type="radio" name="storetype" value="cifs" {{pre-cifs}}>
+ <label>CIFS</label>
</div>
- <div class="panel panel-default">
- <div class="panel-heading">
- <input type="radio" name="storetype" value="cifs" {{pre-cifs}}> CIFS
- </div>
- <div class="panel-body">
- <label for="cifsaddr">UNC-Pfad</label>
- <input type="text" class="form-control" name="cifsaddr" value="{{cifsaddr}}" placeholder="\\samba.server.example.com\bwlp" id="cifsaddr">
- <br>
- <label for="cifsuser">{{lang_readWrite}}</label>
- <div class="input-group">
- <span class="input-group-addon slx-ga">
- {{lang_username}}
- </span>
- <input type="text" class="form-control" name="cifsuser" value="{{cifsuser}}" placeholder="{{lang_username}}" id="cifsuser">
- <span class="input-group-addon">
- {{lang_password}}
- </span>
- <input type="{{password_type}}" class="form-control" name="cifspasswd" value="{{cifspasswd}}" placeholder="{{lang_password}}">
- </div>
- <br>
- <label for="cifsuserro">{{lang_readOnly}}</label>
- <div class="input-group">
- <span class="input-group-addon slx-ga">
- {{lang_username}}
- </span>
- <input type="text" class="form-control" name="cifsuserro" value="{{cifsuserro}}" placeholder="{{lang_username}}" id="cifsuserro">
- <span class="input-group-addon">
- {{lang_password}}
- </span>
- <input type="{{password_type}}" class="form-control" name="cifspasswdro" value="{{cifspasswdro}}" placeholder="{{lang_password}}">
- </div>
- </div>
+ </div>
+ <div class="panel-body">
+ <label for="cifsaddr">UNC-Pfad</label>
+ <input type="text" class="form-control" name="cifsaddr" value="{{cifsaddr}}" placeholder="\\samba.server.example.com\bwlp" id="cifsaddr">
+ <br>
+ <label for="cifsuser">{{lang_readWrite}}</label>
+ <div class="input-group">
+ <span class="input-group-addon slx-ga">
+ {{lang_username}}
+ </span>
+ <input type="text" class="form-control" name="cifsuser" value="{{cifsuser}}" placeholder="{{lang_username}}" id="cifsuser">
+ <span class="input-group-addon">
+ {{lang_password}}
+ </span>
+ <input type="{{password_type}}" class="form-control" name="cifspasswd" value="{{cifspasswd}}" placeholder="{{lang_password}}">
+ </div>
+ <br>
+ <label for="cifsuserro">{{lang_readOnly}}</label>
+ <div class="input-group">
+ <span class="input-group-addon slx-ga">
+ {{lang_username}}
+ </span>
+ <input type="text" class="form-control" name="cifsuserro" value="{{cifsuserro}}" placeholder="{{lang_username}}" id="cifsuserro">
+ <span class="input-group-addon">
+ {{lang_password}}
+ </span>
+ <input type="{{password_type}}" class="form-control" name="cifspasswdro" value="{{cifspasswdro}}" placeholder="{{lang_password}}">
</div>
- <button class="btn btn-primary" type="submit">{{lang_save}}</button>
</div>
</div>
+ <button class="btn btn-primary pull-right" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+
</form>
<div class="modal fade" id="help-store" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">{{lang_vmLocation}}</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ {{lang_vmLocation}}
+ </div>
<div class="modal-body">
<p>
{{lang_vmLocationHelp1}}
@@ -80,7 +95,6 @@
{{lang_vmLocationHelp3}}
</p>
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
@@ -88,7 +102,10 @@
<div class="modal fade" id="help-nfs" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
- <div class="modal-header">NFS</div>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ NFS
+ </div>
<div class="modal-body">
<p>
{{lang_nfsHelp1}}
@@ -105,7 +122,6 @@
/mnt/images *(ro,async)
</pre>
</div>
- <div class="modal-footer"><a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a></div>
</div>
</div>
</div>
diff --git a/modules-available/webinterface/lang/de/template-tags.json b/modules-available/webinterface/lang/de/template-tags.json
index 64ba84d0..e193938d 100644
--- a/modules-available/webinterface/lang/de/template-tags.json
+++ b/modules-available/webinterface/lang/de/template-tags.json
@@ -12,6 +12,7 @@
"lang_httpsSettings": "HTTPS-Konfiguration",
"lang_installAndRestart": "Zertifikat installieren und Webserver neustarten",
"lang_logoBackground": "Hintergrundfarbe des Logos",
+ "lang_moduleHeading": "Web-Schnittstelle",
"lang_noHttps": "HTTPS wieder deaktivieren, aktuelles Zertifikat l\u00f6schen",
"lang_offSelected": "HTTPS ist derzeit deaktiviert.",
"lang_pageTitlePrefix": "Pr\u00e4fix f\u00fcr den Seitentitel",
diff --git a/modules-available/webinterface/lang/en/template-tags.json b/modules-available/webinterface/lang/en/template-tags.json
index 0fb4cc96..28129e64 100644
--- a/modules-available/webinterface/lang/en/template-tags.json
+++ b/modules-available/webinterface/lang/en/template-tags.json
@@ -12,6 +12,7 @@
"lang_httpsSettings": "HTTPS settings",
"lang_installAndRestart": "Installing certificate and restarting web server",
"lang_logoBackground": "Logo background color",
+ "lang_moduleHeading": "Web Interface",
"lang_noHttps": "Disable HTTPS, delete current certificate",
"lang_offSelected": "HTTPS is currently disabled.",
"lang_pageTitlePrefix": "Page title prefix",
diff --git a/modules-available/webinterface/page.inc.php b/modules-available/webinterface/page.inc.php
index e576807e..6dfc9faa 100644
--- a/modules-available/webinterface/page.inc.php
+++ b/modules-available/webinterface/page.inc.php
@@ -73,6 +73,7 @@ class Page_WebInterface extends Page
protected function doRender()
{
+ Render::addTemplate("heading");
//
// HTTPS
//
diff --git a/modules-available/webinterface/templates/customization.html b/modules-available/webinterface/templates/customization.html
index 7949f95b..c949c1f2 100644
--- a/modules-available/webinterface/templates/customization.html
+++ b/modules-available/webinterface/templates/customization.html
@@ -23,7 +23,7 @@
</label>
</div>
<div class="pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</div>
</div>
diff --git a/modules-available/webinterface/templates/heading.html b/modules-available/webinterface/templates/heading.html
new file mode 100644
index 00000000..d68360f1
--- /dev/null
+++ b/modules-available/webinterface/templates/heading.html
@@ -0,0 +1 @@
+<h1>{{lang_moduleHeading}}</h1> \ No newline at end of file
diff --git a/modules-available/webinterface/templates/https.html b/modules-available/webinterface/templates/https.html
index ecfe5f5d..365e2fee 100644
--- a/modules-available/webinterface/templates/https.html
+++ b/modules-available/webinterface/templates/https.html
@@ -28,7 +28,12 @@
{{#httpsEnabled}}
<div class="input-group" onclick="$('#moff').prop('checked', true);
$('#wcustom').hide()">
- <span class="input-group-addon"><input id="moff" type="radio" name="mode" value="off"></span>
+ <span class="input-group-addon">
+ <div class="radio" style="margin: 0; line-height: normal; text-align: left">
+ <input id="moff" type="radio" name="mode" value="off">
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control">
{{lang_noHttps}}
</span>
@@ -36,14 +41,24 @@
{{/httpsEnabled}}
<div class="input-group" onclick="$('#mrandom').prop('checked', true);
$('#wcustom').hide()">
- <span class="input-group-addon"><input id="mrandom" type="radio" name="mode" value="random"></span>
+ <span class="input-group-addon">
+ <div class="radio" style="margin: 0; line-height: normal; text-align: left">
+ <input id="mrandom" type="radio" name="mode" value="random">
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control">
{{lang_randomCert}}
</span>
</div>
<div class="input-group" onclick="$('#mcustom').prop('checked', true);
$('#wcustom').show()">
- <span class="input-group-addon"><input id="mcustom" type="radio" name="mode" value="custom"></span>
+ <span class="input-group-addon">
+ <div class="radio" style="margin: 0; line-height: normal; text-align: left">
+ <input id="mcustom" type="radio" name="mode" value="custom">
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control">
{{lang_customCert}}
</span>
@@ -73,13 +88,23 @@ MIIFfTCCA...
<br>
<div class="input-group">
- <span class="input-group-addon"><input id="httpsredirect" type="checkbox" name="httpsredirect" value="on" {{redirect_checked}}></span>
+ <span class="input-group-addon">
+ <div class="checkbox" style="margin: 0; line-height: normal; text-align: left">
+ <input id="httpsredirect" type="checkbox" name="httpsredirect" value="on" {{redirect_checked}}>
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control" onclick="$('#httpsredirect').prop('checked', !$('#httpsredirect').prop('checked'))">
{{lang_httpsRedirect}}
</span>
</div>
<div class="input-group">
- <span class="input-group-addon"><input id="usehsts" type="checkbox" name="usehsts" value="on" {{hsts_checked}}></span>
+ <span class="input-group-addon">
+ <div class="checkbox" style="margin: 0; line-height: normal; text-align: left">
+ <input id="usehsts" type="checkbox" name="usehsts" value="on" {{hsts_checked}}>
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control" onclick="$('#usehsts').prop('checked', !$('#usehsts').prop('checked'))">
{{lang_useHsts}}
</span>
@@ -87,7 +112,7 @@ MIIFfTCCA...
<br>
<div class="pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</div>
</div>
diff --git a/modules-available/webinterface/templates/passwords.html b/modules-available/webinterface/templates/passwords.html
index 8481d884..b9ff5550 100644
--- a/modules-available/webinterface/templates/passwords.html
+++ b/modules-available/webinterface/templates/passwords.html
@@ -6,20 +6,30 @@
<div class="panel-body">
<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="input-group-addon">
+ <div class="radio" style="margin: 0; line-height: normal; text-align: left">
+ <input id="pmshow" type="radio" name="mode" value="show" {{selected_show}}>
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control">
{{lang_showPasswords}}
</span>
</div>
<div class="input-group" onclick="$('#pmhide').prop('checked', true)">
- <span class="input-group-addon"><input id="pmhide" type="radio" name="mode" value="hide" {{selected_hide}}></span>
+ <span class="input-group-addon">
+ <div class="radio" style="margin: 0; line-height: normal; text-align: left">
+ <input id="pmhide" type="radio" name="mode" value="hide" {{selected_hide}}>
+ <label style="padding: 0"></label>
+ </div>
+ </span>
<span class="form-control">
{{lang_hidePasswords}}
</span>
</div>
<br>
<div class="pull-right">
- <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
</div>
</div>
diff --git a/style/default.css b/style/default.css
index a6614965..9f8b4091 100644
--- a/style/default.css
+++ b/style/default.css
@@ -479,24 +479,20 @@ nav.navbar.sidebar {
/* this is based on https://github.com/flatlogic/awesome-bootstrap-checkbox
and "fixes" the style of radio buttons and check boxes.
-it only applies if they're in a container that has the checkbox/radio class */
+it only applies if they're in a container that has the checkbox class */
-.checkbox,
-.radio {
+.checkbox {
padding-left: 20px;
margin-top: 5px;
margin-bottom: 2px;
}
-.checkbox label,
-.radio label {
+.checkbox label {
display: inline-block;
vertical-align: middle;
position: relative;
padding-left: 5px;
- margin-right: 20px;
}
-.checkbox label::before,
-.radio label::before {
+.checkbox label::before {
top: 1px;
content: "";
display: inline-block;
@@ -512,11 +508,7 @@ it only applies if they're in a container that has the checkbox/radio class */
-o-transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
}
-.radio label::before {
- border-radius: 8px;
-}
-.checkbox label::after,
-.radio label::after {
+.checkbox label::after {
display: inline-block;
position: absolute;
width: 16px;
@@ -530,7 +522,7 @@ it only applies if they're in a container that has the checkbox/radio class */
color: #555555;
}
.checkbox input[type="checkbox"],
-.radio input[type="radio"] {
+.checkbox input[type="radio"] {
opacity: 0;
z-index: 1;
top: -3px;
@@ -540,20 +532,92 @@ it only applies if they're in a container that has the checkbox/radio class */
.checkbox input[type="checkbox"]:focus + label::before,
-.radio input[type="radio"]:focus + label::before {
+.checkbox input[type="radio"]:focus + label::before {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.checkbox input[type="checkbox"]:checked + label::after,
-.radio input[type="radio"]:checked + label::after {
+.checkbox input[type="radio"]:checked + label::after {
font-family: "Glyphicons Halflings";
content: "\E013";
}
+
+.radio {
+ padding-left: 20px;
+}
+.radio label {
+ display: inline-block;
+ vertical-align: middle;
+ position: relative;
+ padding-left: 5px;
+}
+.radio label::before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ width: 17px;
+ height: 17px;
+ left: 0;
+ margin-left: -20px;
+ border: 1px solid #cccccc;
+ border-radius: 50%;
+ background-color: #fff;
+ -webkit-transition: border 0.15s ease-in-out;
+ -o-transition: border 0.15s ease-in-out;
+ transition: border 0.15s ease-in-out;
+}
+.radio label::after {
+ display: inline-block;
+ position: absolute;
+ content: " ";
+ width: 11px;
+ height: 11px;
+ left: 3px;
+ top: 3px;
+ margin-left: -20px;
+ border-radius: 50%;
+ background-color: #555555;
+ -webkit-transform: scale(0, 0);
+ -ms-transform: scale(0, 0);
+ -o-transform: scale(0, 0);
+ transform: scale(0, 0);
+ -webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ -moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ -o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+}
+.radio input[type="radio"] {
+ opacity: 0;
+ z-index: 1;
+ cursor: pointer;
+}
+.radio input[type="radio"]:focus + label::before {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
.radio input[type="radio"]:checked + label::after {
- content: "\002a";
+ -webkit-transform: scale(1, 1);
+ -ms-transform: scale(1, 1);
+ -o-transform: scale(1, 1);
+ transform: scale(1, 1);
}
+.radio input[type="radio"]:disabled {
+ cursor: not-allowed;
+}
+.radio input[type="radio"]:disabled + label {
+ opacity: 0.65;
+}
+.radio input[type="radio"]:disabled + label::before {
+ cursor: not-allowed;
+}
+.radio.radio-inline {
+ margin-top: 0;
+}
+
+
/* Hack to get ellipsis in containers without absolute width */
/* Use: <table class="slx-ellipsis"><tr><td>my text bla bla</td></tr></table> */