summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2018-12-10 15:43:07 +0100
committerSimon Rettberg2018-12-10 15:43:07 +0100
commitb98119be9411ad73b989fdf29284ad59b8340e4e (patch)
treeb3f3c1b6a4474681af9acd74ac66397f5800c321
parent[runmode] Simple back/cancel button (diff)
downloadslx-admin-b98119be9411ad73b989fdf29284ad59b8340e4e.tar.gz
slx-admin-b98119be9411ad73b989fdf29284ad59b8340e4e.tar.xz
slx-admin-b98119be9411ad73b989fdf29284ad59b8340e4e.zip
[dozmod] Add editor for predefined run scripts
Assigning scripts to certain locations only is currently not possible. Whether this is required is to be discussed, since predefined scripts selectable by bwLehrpool-Suite users would almost cover this use case. Refs #3145
-rw-r--r--modules-available/dozmod/lang/de/messages.json2
-rw-r--r--modules-available/dozmod/lang/de/module.json1
-rw-r--r--modules-available/dozmod/lang/de/permissions.json2
-rw-r--r--modules-available/dozmod/lang/de/template-tags.json18
-rw-r--r--modules-available/dozmod/page.inc.php3
-rw-r--r--modules-available/dozmod/pages/runscripts.inc.php133
-rw-r--r--modules-available/dozmod/permissions/permissions.json6
-rw-r--r--modules-available/dozmod/style.css20
-rw-r--r--modules-available/dozmod/templates/runscripts-edit.html89
-rw-r--r--modules-available/dozmod/templates/runscripts-list.html89
10 files changed, 362 insertions, 1 deletions
diff --git a/modules-available/dozmod/lang/de/messages.json b/modules-available/dozmod/lang/de/messages.json
index f74c3eab..4a4be923 100644
--- a/modules-available/dozmod/lang/de/messages.json
+++ b/modules-available/dozmod/lang/de/messages.json
@@ -18,6 +18,8 @@
"networkshare-saved": "Netzlaufwerk gespeichert",
"no-expired-images": "Keine Abgelaufenen VM-Versionen",
"nothing-submitted": "Es wurde nichts \u00fcbermittelt",
+ "runscript-invalid-id": "Ung\u00fcltige Script-ID: {{0}}",
+ "runscript-saved": "Script gespeichert",
"runtimelimits-config-saved": "Einstellungen gespeichert",
"templates-saved": "Templates wurden gespeichert",
"timeout": "Zeit\u00fcberschreitung",
diff --git a/modules-available/dozmod/lang/de/module.json b/modules-available/dozmod/lang/de/module.json
index b2746b81..de8b10f7 100644
--- a/modules-available/dozmod/lang/de/module.json
+++ b/modules-available/dozmod/lang/de/module.json
@@ -6,6 +6,7 @@
"submenu_ldapfilters": "LDAP Filter",
"submenu_mailconfig": "Email-Konfiguration",
"submenu_networkshares": "Netzlaufwerke",
+ "submenu_runscripts": "Startscripte",
"submenu_runtimeconfig": "Limits und Standardwerte",
"submenu_templates": "Textbausteine f\u00fcr E-Mails",
"submenu_users": "Benutzer und Berechtigungen"
diff --git a/modules-available/dozmod/lang/de/permissions.json b/modules-available/dozmod/lang/de/permissions.json
index 845be3b9..a1675148 100644
--- a/modules-available/dozmod/lang/de/permissions.json
+++ b/modules-available/dozmod/lang/de/permissions.json
@@ -6,6 +6,8 @@
"mailconfig.save": "\u00c4nderungen an der SMTP-Konfiguration zum Versenden von Mails speichern.",
"networkshares.save": "Netzlaufwerke einsehen.",
"networkshares.view": "\u00c4nderungen an den Netzlaufwerken speichern.",
+ "runscripts.save": "Startkripte erstellen\/bearbeiten",
+ "runscripts.view": "Startscripte auflisten",
"runtimeconfig.save": "\u00c4nderungen an der Laufzeit-Konfiguration speichern.",
"templates.reset": "E-Mail Templates zur\u00fccksetzen.",
"templates.save": "E-Mail Templates speichern.",
diff --git a/modules-available/dozmod/lang/de/template-tags.json b/modules-available/dozmod/lang/de/template-tags.json
index 99756995..ef775a16 100644
--- a/modules-available/dozmod/lang/de/template-tags.json
+++ b/modules-available/dozmod/lang/de/template-tags.json
@@ -25,6 +25,7 @@
"lang_description_delete_images": "Diese Liste zeigt VMs, die entweder abgelaufen sind, oder deren Datei besch\u00e4digt, verschoben oder gel\u00f6scht wurde. Diese Images sind zur Zeit im Lehrpool nicht verf\u00fcgbar, ihre endg\u00fcltige L\u00f6schung muss aber manuell best\u00e4tigt werden, um gr\u00f6\u00dfere Katastrophen durch Softwarefehler, verstellte Systemuhren etc. zu vermeiden.",
"lang_dozmodLogHeading": "bwLehrpool-Suite Aktionslog",
"lang_editNetworkshare": "Netzlaufwerk bearbeiten",
+ "lang_editScript": "Startscript bearbeiten",
"lang_email": "EMail",
"lang_emailNotifications": "EMail-Benachrichtigungen aktiviert",
"lang_error": "Fehler",
@@ -34,6 +35,7 @@
"lang_hasNewer": "Neuere Version existiert",
"lang_hash": "Hash",
"lang_heading": "Zu l\u00f6schende VM-Versionen",
+ "lang_hidden": "Versteckt",
"lang_host": "Host",
"lang_image": "VM",
"lang_lastEditor": "Zuletzt bearbeitet von",
@@ -60,12 +62,14 @@
"lang_maxLectureVisibility": "Sp\u00e4testes Enddatum einer Veranstaltung (Tage in der Zukunft)",
"lang_maxLocationsPerLecture": "Max. explizite Orte pro Veranstaltung",
"lang_maxTransfers": "Maximale Zahl gleichzeitiger Up-\/Downloads pro Benutzer",
+ "lang_minimized": "Minimiert",
"lang_miscOptions": "Verschiedene Einstellungen",
"lang_modified": "Modifiziert",
"lang_name": "Name",
"lang_networkshares": "Netzlaufwerke",
"lang_networksharesIntro": "Hier k\u00f6nnen Sie vordefinierte Netzlaufwerke anlegen, die den Nutzern der bwLehrpool-Suite zur Auswahl gestellt werden. Es ist den Nutzern der bwLehrpool-Suite weiterhin m\u00f6glich, komplett eigene Netzwerkfreigaben zu definieren. Die Angaben hier sollen lediglich das Hinzuf\u00fcgen h\u00e4ufig genutzter Laufwerke vereinfachen, bzw. das \u00c4ndern eines Netzwerkpfades vereinfachen, da in diesem Fall nur der Zentrale Eintrag hier angepasst werden muss, und nicht mehr wie zuvor jede Veranstaltung einzeln.",
"lang_none": "(Keiner)",
+ "lang_normal": "Normal",
"lang_organization": "Einrichtung",
"lang_organizationListHeader": "Nutzungsrechte f\u00fcr den Satelliten festlegen",
"lang_os": "Betriebssystem",
@@ -78,8 +82,22 @@
"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",
+ "lang_runScriptAdd": "Script hinzuf\u00fcgen",
+ "lang_runScriptDeleteConfirmation": "Script wirklich l\u00f6schen?",
"lang_runtimeConfig": "Laufzeit-Konfiguration",
"lang_runtimeConfigLimits": "Beschr\u00e4nkungen",
+ "lang_scriptContent": "Scriptinhalt",
+ "lang_scriptExtension": "Dateinamenerweiterung",
+ "lang_scriptExtensionHead": "Erweiterung",
+ "lang_scriptIsGlobal": "Script ist global, wird in jeder Veranstaltung ausgef\u00fchrt",
+ "lang_scriptIsGlobalHead": "Global",
+ "lang_scriptIsPredefined": "Script ist ein vordefiniertes Script, das in der bwLehrpool-Suite zur Auswahl steht",
+ "lang_scriptPassCredentials": "Benutzername\/Passwort an dieses Script \u00fcbergeben",
+ "lang_scriptPassCredentialsHead": "User\/Pass",
+ "lang_scriptVisibility": "Anzeigemodus",
+ "lang_scriptVisibilityHead": "Anzeige",
+ "lang_scriptsHead": "Startscripte f\u00fcr Virtuelle Umgebungen",
+ "lang_scriptsIntro": "Hier k\u00f6nnen Sie Startskripte definieren, die entweder global bei jedem Start einer Veranstaltung ausgef\u00fchrt werden, oder den Nutzerinnen der bwLehrpool-Suite zur Vorauswahl zur Verf\u00fcgung gestellt werden.",
"lang_senderAddress": "Absenderadresse",
"lang_senderName": "Absender Anzeigename",
"lang_shareDeleteConfirm": "Willst du dieses Netzlaufwerk wirklich l\u00f6schen?",
diff --git a/modules-available/dozmod/page.inc.php b/modules-available/dozmod/page.inc.php
index cdb347ab..776109cf 100644
--- a/modules-available/dozmod/page.inc.php
+++ b/modules-available/dozmod/page.inc.php
@@ -5,7 +5,7 @@ class Page_DozMod extends Page
/** @var bool true if we have a proper subpage */
private $haveSubPage = false;
- private $validSections = ['expiredimages', 'mailconfig', 'templates', 'runtimeconfig', 'users', 'actionlog', 'networkshares', 'ldapfilters'];
+ private $validSections = ['expiredimages', 'mailconfig', 'templates', 'runtimeconfig', 'users', 'actionlog', 'networkshares', 'ldapfilters', 'runscripts'];
private $section;
@@ -62,6 +62,7 @@ class Page_DozMod extends Page
Dictionary::translate('submenu_actionlog', true);
Dictionary::translate('submenu_networkshares', true);
Dictionary::translate('submenu_ldapfilters', true);
+ Dictionary::translate('submenu_runscripts', true);
*/
/* add sub-menus */
diff --git a/modules-available/dozmod/pages/runscripts.inc.php b/modules-available/dozmod/pages/runscripts.inc.php
new file mode 100644
index 00000000..c6566c13
--- /dev/null
+++ b/modules-available/dozmod/pages/runscripts.inc.php
@@ -0,0 +1,133 @@
+<?php
+
+class SubPage
+{
+
+ public static function doPreprocess()
+ {
+ /* execute actions */
+ $action = Request::post('action', false, 'string');
+
+ if ($action === 'save') {
+ User::assertPermission("runscripts.save");
+ self::saveScript();
+ }
+
+ if (Request::isPost()) {
+ Util::redirect('?do=dozmod&section=runscripts');
+ }
+ User::assertPermission('runscripts.view');
+ }
+
+ private static function saveScript()
+ {
+ $id = Request::post('runscriptid', false, 'int');
+ $scriptname = Request::post('scriptname', '', 'string');
+ if ($id === false) {
+ Message::addError('main.parameter-missing', 'runscriptid');
+ return;
+ }
+ $data = [
+ 'scriptname' => $scriptname,
+ 'content' => Request::post('content', '', 'string'),
+ 'visibility' => Request::post('visibility', 1, 'int'),
+ 'extension' => preg_replace('/[^a-z0-9_\-~\!\$\=]/i', '', Request::post('extension', '', 'string')),
+ 'passcreds' => Request::post('passcreds', 0, 'int') !== 0,
+ 'isglobal' => Request::post('isglobal', 0, 'int') !== 0,
+ ];
+ if ($id === 0) {
+ // New entry
+ $ret = Database::exec('INSERT INTO sat.presetrunscript
+ (scriptname, content, extension, visibility, passcreds, isglobal) VALUES
+ (:scriptname, :content, :extension, :visibility, :passcreds, :isglobal)', $data);
+ $id = Database::lastInsertId();
+ } else {
+ // Edit entry
+ $data['id'] = $id;
+ Database::exec('UPDATE sat.presetrunscript SET
+ scriptname = :scriptname, content = :content, extension = :extension, visibility = :visibility,
+ passcreds = :passcreds, isglobal = :isglobal
+ WHERE runscriptid = :id', $data);
+ }
+ $oslist = Request::post('osid', false, 'array');
+ if (is_array($oslist)) {
+ $oslist = array_filter($oslist, 'is_numeric');
+ $query = Database::prepare('INSERT INTO sat.presetrunscript_x_operatingsystem
+ (runscriptid, osid) VALUES (:id, :osid)');
+ foreach ($oslist as $osid) {
+ $query->execute(['id' => $id, 'osid' => $osid]);
+ }
+ $query->closeCursor();
+ Database::exec('DELETE FROM sat.presetrunscript_x_operatingsystem
+ WHERE runscriptid = :id AND osid NOT IN (:oslist)', ['id' => $id, 'oslist' => $oslist]);
+ }
+ Message::addSuccess('runscript-saved');
+ }
+
+ public static function doRender()
+ {
+ $show = Request::get('show', 'list', 'string');
+ if ($show === 'list') {
+ $res = Database::simpleQuery('SELECT runscriptid, scriptname, extension, visibility, passcreds, isglobal
+ FROM sat.presetrunscript
+ ORDER BY scriptname ASC');
+ $rows = [];
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if ($row['visibility'] == 0) {
+ $row['visibility'] = 'eye-close';
+ } elseif ($row['visibility'] == 1) {
+ $row['visibility'] = 'eye-open';
+ } else {
+ $row['visibility'] = 'arrow-down';
+ }
+ $rows[] = $row;
+ }
+ Render::addTemplate('runscripts-list', ['list' => $rows, 'hasEditPermission' => User::hasPermission('runscripts.save')]);
+ } elseif ($show === 'edit') {
+ // Edit
+ $id = Request::get('runscriptid', false, 'int');
+ if ($id === false) {
+ Message::addError('main.parameter-missing', 'runscriptid');
+ Util::redirect('?do=dozmod&section=runscripts');
+ }
+ if ($id === 0) {
+ $row = [
+ 'runscriptid' => 0,
+ 'visibility_1_checked' => 'checked',
+ 'isglobal_1_checked' => 'checked',
+ ];
+ } else {
+ $row = Database::queryFirst('SELECT runscriptid, scriptname, content, extension, visibility, passcreds, isglobal
+ FROM sat.presetrunscript
+ WHERE runscriptid = :runscriptid', ['runscriptid' => $id]);
+ $row['visibility_' . $row['visibility'] . '_selected'] = 'selected';
+ $row['passcreds_checked'] = $row['passcreds'] ? 'checked' : '';
+ $row['isglobal_' . $row['isglobal'] . '_checked'] = 'checked';
+ if ($row === false) {
+ Message::addError('runscript-invalid-id', $id);
+ Util::redirect('?do=dozmod&section=runscripts');
+ }
+ }
+ // Get OS
+ $row['oslist'] = [];
+ $res = Database::simpleQuery('SELECT o.osid, o.displayname, pxo.osid AS isvalid FROM sat.operatingsystem o
+ LEFT JOIN sat.presetrunscript_x_operatingsystem pxo ON (o.osid = pxo.osid AND pxo.runscriptid = :runscriptid)
+ ORDER BY o.displayname ASC', ['runscriptid' => $id]);
+ while ($osrow = $res->fetch(PDO::FETCH_ASSOC)) {
+ $row['oslist'][] = [
+ 'osid' => $osrow['osid'],
+ 'displayname' => $osrow['displayname'],
+ 'checked' => $osrow['isvalid'] ? 'checked' : '',
+ ];
+ }
+ // Output
+ Render::addTemplate('runscripts-edit', $row);
+ }
+ }
+
+ public static function doAjax()
+ {
+
+ }
+
+}
diff --git a/modules-available/dozmod/permissions/permissions.json b/modules-available/dozmod/permissions/permissions.json
index 4496b771..3f9cd604 100644
--- a/modules-available/dozmod/permissions/permissions.json
+++ b/modules-available/dozmod/permissions/permissions.json
@@ -23,6 +23,12 @@
"runtimeconfig.save": {
"location-aware": false
},
+ "runscripts.view": {
+ "location-aware": false
+ },
+ "runscripts.save": {
+ "location-aware": false
+ },
"templates.reset": {
"location-aware": false
},
diff --git a/modules-available/dozmod/style.css b/modules-available/dozmod/style.css
index 23dd121e..4cec715a 100644
--- a/modules-available/dozmod/style.css
+++ b/modules-available/dozmod/style.css
@@ -48,4 +48,24 @@
.table > tbody > tr > td > div {
display: inline-block;
+}
+
+/* number of columns in tree view depending on screen size */
+.column-list {
+ column-gap: 20px;
+ column-count: 2;
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+@media (min-width: 768px) {
+ .column-list {
+ column-count: 3;
+ }
+}
+
+@media (min-width: 992px) {
+ .column-list {
+ column-count: 4;
+ }
} \ No newline at end of file
diff --git a/modules-available/dozmod/templates/runscripts-edit.html b/modules-available/dozmod/templates/runscripts-edit.html
new file mode 100644
index 00000000..8d81b33c
--- /dev/null
+++ b/modules-available/dozmod/templates/runscripts-edit.html
@@ -0,0 +1,89 @@
+<h1>{{lang_scriptsHead}}</h1>
+
+<form method="post" action="?do=dozmod&section=runscripts">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" id="runscriptid" name="runscriptid" value="{{runscriptid}}">
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_editScript}}
+ </div>
+ <div class="panel-body">
+ <div class="input-group">
+ <label class="input-group-addon" for="scriptname">{{lang_name}}</label>
+ <input type="text" name="scriptname" id="scriptname" class="form-control"
+ value="{{scriptname}}" required>
+ </div>
+ <div class="input-group">
+ <label class="input-group-addon" for="extension">{{lang_scriptExtension}}</label>
+ <input type="text" name="extension" id="extension" class="form-control" value="{{extension}}"
+ list="default-exts">
+ <datalist id="default-exts">
+ <option value="bat">
+ <option value="ps">
+ <option value="py">
+ <option value="sh">
+ </datalist>
+ </div>
+ <div class="input-group">
+ <label class="input-group-addon" for="visibility">{{lang_scriptVisibility}}</label>
+ <select type="text" name="visibility" id="visibility" class="form-control" required>
+ <option value="0" {{visibility_0_selected}}>{{lang_hidden}}</option>
+ <option value="1" {{visibility_1_selected}}>{{lang_normal}}</option>
+ <option value="2" {{visibility_2_selected}}>{{lang_minimized}}</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <div class="checkbox">
+ <input type="checkbox" name="passcreds" value="1" {{passcreds_checked}} id="passcreds"
+ class="form-control">
+ <label for="passcreds">
+ {{lang_scriptPassCredentials}}
+ </label>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="radio">
+ <input type="radio" name="isglobal" value="1" {{isglobal_1_checked}} id="isglobal1" class="form-control">
+ <label for="isglobal1">
+ {{lang_scriptIsGlobal}}
+ </label>
+ </div>
+ <div class="radio">
+ <input type="radio" name="isglobal" value="0" {{isglobal_0_checked}} id="isglobal0" class="form-control">
+ <label for="isglobal0">
+ {{lang_scriptIsPredefined}}
+ </label>
+ </div>
+ </div>
+ <div>
+ <label for="content">{{lang_scriptContent}}</label>
+ <textarea name="content" id="content" rows="20" cols="80" class="form-control">{{content}}</textarea>
+ </div>
+
+ <div class="panel panel-body column-list">
+ {{#oslist}}
+ <div class="checkbox">
+ <input type="checkbox" name="osid[]" value="{{osid}}" {{checked}} id="osid{{osid}}" class="form-control">
+ <label for="osid{{osid}}">
+ {{displayname}}
+ </label>
+ </div>
+ {{/oslist}}
+ </div>
+
+ <div class="text-right" style="margin-top: 20px;">
+ <a type="button" class="btn btn-default" href="?do=dozmod&section=runscripts">{{lang_cancel}}</a>
+ <button class="btn btn-primary" type="submit" name="action" value="save">
+ <span class="glyphicon glyphicon-floppy-disk"></span>
+ {{lang_save}}
+ </button>
+ </div>
+
+ </div>
+ </div>
+
+</form>
+
+<script type="text/javascript">
+</script>
diff --git a/modules-available/dozmod/templates/runscripts-list.html b/modules-available/dozmod/templates/runscripts-list.html
new file mode 100644
index 00000000..4d519afb
--- /dev/null
+++ b/modules-available/dozmod/templates/runscripts-list.html
@@ -0,0 +1,89 @@
+<h1>{{lang_scriptsHead}}</h1>
+
+<p>
+ {{lang_scriptsIntro}}
+</p>
+
+<table class="table">
+ <thead>
+ <tr>
+ <th>{{lang_name}}</th>
+ <th class="slx-smallcol">{{lang_scriptExtensionHead}}</th>
+ <th class="slx-smallcol">{{lang_scriptVisibilityHead}}</th>
+ <th class="slx-smallcol">{{lang_scriptPassCredentialsHead}}</th>
+ <th class="slx-smallcol">{{lang_scriptIsGlobalHead}}</th>
+ {{#hasEditPermission}}
+ <th class="slx-smallcol">{{lang_edit}}</th>
+ <th class="slx-smallcol">{{lang_delete}}</th>
+ {{/hasEditPermission}}
+ </tr>
+ </thead>
+ <tbody>
+ {{#list}}
+ <tr>
+ <td>{{scriptname}}</td>
+ <td>.{{extension}}</td>
+ <td><span class="glyphicon glyphicon-{{visibility}}"></span></td>
+ <td>
+ {{#passcreds}}
+ <span class="glyphicon glyphicon-ok"></span>
+ {{/passcreds}}
+ </td>
+ <td>
+ {{#isglobal}}
+ <span class="glyphicon glyphicon-ok"></span>
+ {{/isglobal}}
+ </td>
+ {{#hasEditPermission}}
+ <td class="text-center">
+ <a class="btn btn-xs btn-primary" href="?do=dozmod&amp;section=runscripts&amp;show=edit&amp;runscriptid={{runscriptid}}">
+ <span class="glyphicon glyphicon-edit"></span>
+ </a>
+ </td>
+ <td class="text-center">
+ <button type="button" class="btn btn-xs btn-danger" data-toggle="modal" data-target="#deleteModal" onclick="setDeleteId('{{runscriptid}}')">
+ <span class="glyphicon glyphicon-trash"></span>
+ </button>
+ </td>
+ {{/hasEditPermission}}
+ </tr>
+ {{/list}}
+ </tbody>
+</table>
+
+{{#hasEditPermission}}
+ <div class="text-right">
+ <a class="btn btn-sm btn-success" href="?do=dozmod&amp;section=runscripts&amp;show=edit&amp;runscriptid=0">
+ <span class="glyphicon glyphicon-plus"></span>
+ {{lang_runScriptAdd}}
+ </a>
+ </div>
+{{/hasEditPermission}}
+
+<form method="post" action="?do=dozmod&amp;section=runscripts">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" id="deleteAction" name="runscriptid" value="">
+ <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">
+ <p>{{lang_runScriptDeleteConfirmation}}</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="delete" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span> {{lang_delete}}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+</form>
+
+<script type="text/javascript">
+ function setDeleteId(id) {
+ $('#deleteAction').val(id)
+ }
+</script>