summaryrefslogtreecommitdiffstats
path: root/modules-available/sysconfig
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/sysconfig')
-rw-r--r--modules-available/sysconfig/addconfig.inc.php54
-rw-r--r--modules-available/sysconfig/addmodule.inc.php58
-rw-r--r--modules-available/sysconfig/addmodule_adauth.inc.php57
-rw-r--r--modules-available/sysconfig/addmodule_branding.inc.php83
-rw-r--r--modules-available/sysconfig/addmodule_custommodule.inc.php73
-rw-r--r--modules-available/sysconfig/addmodule_ldapauth.inc.php42
-rw-r--r--modules-available/sysconfig/addmodule_screensaver.inc.php64
-rw-r--r--modules-available/sysconfig/addmodule_sshconfig.inc.php23
-rw-r--r--modules-available/sysconfig/addmodule_sshkey.inc.php12
-rw-r--r--modules-available/sysconfig/api.inc.php8
-rw-r--r--modules-available/sysconfig/hooks/bootup.inc.php3
-rw-r--r--modules-available/sysconfig/hooks/locations-column.inc.php57
-rw-r--r--modules-available/sysconfig/inc/configmodule.inc.php228
-rw-r--r--modules-available/sysconfig/inc/configmodule/branding.inc.php20
-rw-r--r--modules-available/sysconfig/inc/configmodule/customodule.inc.php36
-rw-r--r--modules-available/sysconfig/inc/configmodule/ldapauth.inc.php2
-rw-r--r--modules-available/sysconfig/inc/configmodule/screensaver.inc.php29
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshconfig.inc.php8
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshkey.inc.php8
-rw-r--r--modules-available/sysconfig/inc/configmodulebaseldap.inc.php35
-rw-r--r--modules-available/sysconfig/inc/configtgz.inc.php188
-rw-r--r--modules-available/sysconfig/inc/ldap.inc.php2
-rw-r--r--modules-available/sysconfig/inc/ppd.inc.php249
-rw-r--r--modules-available/sysconfig/inc/sysconfig.inc.php31
-rw-r--r--modules-available/sysconfig/install.inc.php37
-rw-r--r--modules-available/sysconfig/lang/de/module.json17
-rw-r--r--modules-available/sysconfig/lang/de/template-tags.json6
-rw-r--r--modules-available/sysconfig/lang/en/module.json17
-rw-r--r--modules-available/sysconfig/lang/en/template-tags.json4
-rw-r--r--modules-available/sysconfig/page.inc.php43
-rw-r--r--modules-available/sysconfig/templates/ad-selfsearch.html2
-rw-r--r--modules-available/sysconfig/templates/ad-start.html12
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-checkconnection.html2
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-checkcredentials.html3
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-homedir.html1
-rw-r--r--modules-available/sysconfig/templates/branding-check.html2
-rw-r--r--modules-available/sysconfig/templates/branding-start.html2
-rw-r--r--modules-available/sysconfig/templates/cfg-start.html2
-rw-r--r--modules-available/sysconfig/templates/custom-filelist.html18
-rw-r--r--modules-available/sysconfig/templates/custom-fileselect.html36
-rw-r--r--modules-available/sysconfig/templates/ldap-finish.html1
-rw-r--r--modules-available/sysconfig/templates/ldap-start.html12
-rw-r--r--modules-available/sysconfig/templates/sshconfig-start.html5
-rw-r--r--modules-available/sysconfig/templates/sshkey-start.html5
44 files changed, 835 insertions, 762 deletions
diff --git a/modules-available/sysconfig/addconfig.inc.php b/modules-available/sysconfig/addconfig.inc.php
index a22cdc46..27af31e8 100644
--- a/modules-available/sysconfig/addconfig.inc.php
+++ b/modules-available/sysconfig/addconfig.inc.php
@@ -9,21 +9,17 @@ abstract class AddConfig_Base
/**
* Holds the instance for the currently executing step
- * @var \AddConfig_Base
+ * @var AddConfig_Base
*/
- private static $instance = false;
+ private static $instance = null;
/**
* Config being edited (if any)
- * @var \ConfigTgz
+ * @var ?ConfigTgz
*/
- protected $edit = false;
+ protected $edit = null;
- /**
- *
- * @param string $step
- */
- public static function setStep($step)
+ public static function setStep(string $step)
{
if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddConfig_Base') {
Message::addError('invalid-action', $step);
@@ -32,18 +28,12 @@ abstract class AddConfig_Base
self::$instance = new $step();
if (($editId = Request::any('edit', 0, 'int')) !== 0) {
self::$instance->edit = ConfigTgz::get($editId);
- if (self::$instance->edit === false)
- Util::traceError('Invalid config id for editing');
+ if (self::$instance->edit === null)
+ ErrorHandler::traceError('Invalid config id for editing');
Util::addRedirectParam('edit', self::$instance->edit->id());
}
}
- protected function tmError()
- {
- Message::addError('main.taskmanager-error');
- Util::redirect('?do=SysConfig');
- }
-
/**
* Called before any HTML rendering happens, so you can
* prepare stuff, validate input, and optionally redirect
@@ -73,25 +63,25 @@ abstract class AddConfig_Base
public static function preprocess()
{
- if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ if (self::$instance === null) {
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->preprocessInternal();
}
public static function render()
{
- if (self::$instance === false)
- Util::traceError('No step instance yet');
- if (self::$instance->edit !== false)
+ if (self::$instance === null)
+ ErrorHandler::traceError('No step instance yet');
+ if (self::$instance->edit !== null)
Message::addInfo('replacing-config', self::$instance->edit->title());
self::$instance->renderInternal();
}
public static function ajax()
{
- if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ if (self::$instance === null) {
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->ajaxInternal();
}
@@ -110,7 +100,7 @@ class AddConfig_Start extends AddConfig_Base
$mods = ConfigModule::getList();
$res = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath FROM configtgz_module"
. " ORDER BY title ASC"); // Move to ConfigModule
- if ($this->edit === false) {
+ if ($this->edit === null) {
$active = array();
} else {
$active = $this->edit->getModuleIds();
@@ -122,7 +112,7 @@ class AddConfig_Start extends AddConfig_Base
$modGroups[$mod['group']] =& $mod;
}
unset($mod);
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
if (!isset($mods[$row['moduletype']])) {
$mods[$row['moduletype']] = array(
'unique' => false,
@@ -140,7 +130,7 @@ class AddConfig_Start extends AddConfig_Base
$row['active'] = in_array($row['moduleid'], $active);
$group['modules'][] = $row;
}
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
$title = $this->edit->title();
} else {
$title = Request::any('title', '', 'string');
@@ -162,7 +152,7 @@ class AddConfig_Start extends AddConfig_Base
'step' => 'AddConfig_Finish',
'groups' => array_values($modGroups),
'title' => $title,
- 'edit' => ($this->edit !== false ? $this->edit->id() : false)
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
));
}
@@ -174,9 +164,9 @@ class AddConfig_Start extends AddConfig_Base
class AddConfig_Finish extends AddConfig_Base
{
/**
- * @var ConfigTgz
+ * @var ?ConfigTgz
*/
- private $config = false;
+ private $config = null;
protected function preprocessInternal()
{
@@ -186,13 +176,13 @@ class AddConfig_Finish extends AddConfig_Base
Message::addError('missing-file');
Util::redirect('?do=SysConfig&action=addconfig');
}
- if ($this->edit === false) {
+ if ($this->edit === null) {
$this->config = ConfigTgz::insert($title, $modules);
} else {
$this->edit->update($title, $modules);
$this->config = $this->edit;
}
- if ($this->config === false || $this->config->generate(true, 150) === false) {
+ if ($this->config->generate(true, 150) === false) {
Message::addError('unsuccessful-action');
Util::redirect('?do=SysConfig&action=addconfig');
}
diff --git a/modules-available/sysconfig/addmodule.inc.php b/modules-available/sysconfig/addmodule.inc.php
index 91fee45d..4564537e 100644
--- a/modules-available/sysconfig/addmodule.inc.php
+++ b/modules-available/sysconfig/addmodule.inc.php
@@ -9,34 +9,39 @@ abstract class AddModule_Base
/**
* Holds the instance for the currently executing step
- * @var \AddModule_Base
+ *
+ * @var AddModule_Base
*/
private static $instance = false;
/**
* Instance of ConfigModule we're editing. False if not editing but creating.
- * @var \ConfigModule
+ *
+ * @var ?ConfigModule
*/
- protected $edit = false;
+ protected $edit = null;
/**
*
* @param string $step name of class representing the current step
* @param int $editId (optional) overwrite for the request parameter 'edit'
*/
- public static function setStep($step, $editId = false)
+ public static function setStep(string $step, int $editId = null): void
{
if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddModule_Base') {
Message::addError('invalid-action', $step);
Util::redirect('?do=SysConfig');
}
self::$instance = new $step();
- if ($editId = $editId ? $editId : Request::any('edit')) {
+ if ($editId === null) {
+ $editId = Request::any('edit', 0, 'int');
+ }
+ if ($editId !== 0) {
self::$instance->edit = ConfigModule::get($editId);
- if (self::$instance->edit === false)
- Util::traceError('Invalid module id for editing');
+ if (self::$instance->edit === null)
+ ErrorHandler::traceError('Invalid module id for editing');
if ($step !== 'AddModule_Assign' && !preg_match('/^' . self::$instance->edit->moduleType() . '_/', $step))
- Util::traceError('Module to edit is of different type!');
+ ErrorHandler::traceError('Module to edit is of different type!');
Util::addRedirectParam('edit', self::$instance->edit->id());
}
}
@@ -90,7 +95,7 @@ abstract class AddModule_Base
public static function preprocess()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->preprocessInternal();
}
@@ -98,9 +103,9 @@ abstract class AddModule_Base
public static function render()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
- if (get_class(self::$instance) !== 'AddModule_Assign' && self::$instance->edit !== false) {
+ if (get_class(self::$instance) !== 'AddModule_Assign' && self::$instance->edit !== null) {
Message::addInfo('replacing-module', self::$instance->edit->title());
}
self::$instance->renderInternal();
@@ -109,7 +114,7 @@ abstract class AddModule_Base
public static function ajax()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->ajaxInternal();
}
@@ -155,7 +160,7 @@ class AddModule_Assign extends AddModule_Base
if (ConfigModule::getList()[$moduleType]['unique']) {
$moduleIds = [];
- foreach (ConfigModule::getAll($moduleType) as $module) {
+ foreach (ConfigModule::getAll($moduleType) ?? [] as $module) {
$moduleIds[] = $module->id();
}
@@ -209,41 +214,26 @@ class AddModule_Assign extends AddModule_Base
* Helper functions to set/get a batch of vars from/to post variables or a module
*/
-/**
- *
- * @param \ConfigModule $module
- * @param array $array
- * @param array $keys
- */
-function moduleToArray($module, &$array, $keys)
+function moduleToArray(ConfigModule $module, array &$array, array $keys): void
{
foreach ($keys as $key) {
$array[$key] = $module->getData($key);
}
}
-/**
- *
- * @param \ConfigModule $module
- * @param array $array
- * @param array $keys
- */
-function arrayToModule($module, $array, $keys)
+function arrayToModule(ConfigModule $module, array $array, array $keys): void
{
foreach ($keys as $key) {
$module->setData($key, $array[$key]);
}
}
-/**
- *
- * @param array $array
- * @param array $keys
- */
-function postToArray(&$array, $keys, $ignoreMissing = false)
+
+function postToArray(array &$array, array $keys, $ignoreMissing = false): void
{
foreach ($keys as $key) {
$val = Request::post($key, '--not-in-post');
- if ($ignoreMissing && $val === '--not-in-post') continue;
+ if ($ignoreMissing && $val === '--not-in-post')
+ continue;
$array[$key] = $val;
}
}
diff --git a/modules-available/sysconfig/addmodule_adauth.inc.php b/modules-available/sysconfig/addmodule_adauth.inc.php
index 583844d0..42187171 100644
--- a/modules-available/sysconfig/addmodule_adauth.inc.php
+++ b/modules-available/sysconfig/addmodule_adauth.inc.php
@@ -13,15 +13,12 @@ class AdAuth_Start extends AddModule_Base
protected function renderInternal()
{
- $ADAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'fixnumeric', 'genuid', 'certificate', 'mapping', 'nohomewarn');
+ $ADAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'genuid', 'certificate', 'mapping', 'nohomewarn');
$data = array();
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
moduleToArray($this->edit, $data, $ADAUTH_COMMON_FIELDS);
$data['title'] = $this->edit->title();
$data['edit'] = $this->edit->id();
- if (!isset($data['fixnumeric']) || $data['fixnumeric'] === false) {
- $data['fixnumeric'] = 's';
- }
} else {
$data['ssl'] = true;
}
@@ -38,7 +35,7 @@ class AdAuth_Start extends AddModule_Base
}
$data['step'] = 'AdAuth_CheckConnection';
$data['map_empty'] = true;
- $data['mapping'] = ConfigModuleBaseLdap::getMapping(isset($data['mapping']) ? $data['mapping'] : false, $data['map_empty']);
+ $data['mapping'] = ConfigModuleBaseLdap::getMapping($data['mapping'] ?? null, $data['map_empty']);
Render::addDialog(Dictionary::translateFile('config-module', 'adAuth_title'), false, 'ad-start', $data);
}
@@ -92,13 +89,12 @@ class AdAuth_CheckConnection extends AddModule_Base
));
if (!isset($this->scanTask['id'])) {
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
- return;
}
}
protected function renderInternal()
{
- $mapping = Request::post('mapping', false, 'array');
+ $mapping = Request::post('mapping', null, 'array');
$data = array(
'edit' => Request::post('edit'),
'title' => Request::post('title'),
@@ -108,7 +104,6 @@ class AdAuth_CheckConnection extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl'),
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'certificate' => Request::post('certificate', ''),
'taskid' => $this->scanTask['id'],
@@ -135,7 +130,7 @@ class AdAuth_SelfSearch extends AddModule_Base
protected function preprocessInternal()
{
- $server = $binddn = $port = null;
+ $server = $binddn = null;
$searchbase = Request::post('searchbase', '');
$bindpw = Request::post('bindpw');
$ssl = Request::post('ssl', 'off') === 'on';
@@ -144,14 +139,8 @@ class AdAuth_SelfSearch extends AddModule_Base
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
return;
}
- foreach (['server', 'binddn', 'port'] as $var) {
- $$var = Request::post($var, null);
- if (empty($$var)) {
- Message::addError('main.parameter-empty', $var);
- AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
- return;
- }
- }
+ $server = Request::post('server', Request::REQUIRED, 'string');
+ $binddn = Request::post('binddn', Request::REQUIRED, 'string');
$this->originalBindDn = '';
// Fix bindDN if short name given
//
@@ -199,7 +188,7 @@ class AdAuth_SelfSearch extends AddModule_Base
protected function renderInternal()
{
- $mapping = Request::post('mapping', false, 'array');
+ $mapping = Request::post('mapping', null, 'array');
$data = array(
'edit' => Request::post('edit'),
'title' => Request::post('title'),
@@ -210,7 +199,6 @@ class AdAuth_SelfSearch extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
@@ -288,13 +276,12 @@ class AdAuth_HomeAttrCheck extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
'tryHomeAttr' => true,
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_CheckCredentials'
))
@@ -361,12 +348,11 @@ class AdAuth_CheckCredentials extends AddModule_Base
'home' => Request::post('home'),
'homeattr' => Request::post('homeattr'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_HomeDir'
))
@@ -426,16 +412,15 @@ class AdAuth_HomeDir extends AddModule_Base
'home' => Request::post('home'),
'homeattr' => Request::post('homeattr'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_Finish'
);
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
foreach (self::getAttributes() as $key) {
if ($this->edit->getData($key)) {
$data[$key . '_c'] = 'checked="checked"';
@@ -456,13 +441,13 @@ class AdAuth_HomeDir extends AddModule_Base
foreach (range('D', 'Z') as $l) {
$data['drives'][] = array(
'drive' => $l . ':',
- 'selected' => (strtoupper($letter{0}) === $l) ? 'selected="selected"' : ''
+ 'selected' => (strtoupper($letter[0]) === $l) ? 'selected="selected"' : ''
);
}
Render::addDialog(Dictionary::translateFile('config-module', 'adAuth_title'), false, 'ad_ldap-homedir', $data);
}
- public static function getAttributes()
+ public static function getAttributes(): array
{
return array('shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop',
'shareMedia', 'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough');
@@ -480,12 +465,13 @@ class AdAuth_Finish extends AddModule_Base
$title = Request::post('title');
if (empty($title))
$title = 'AD: ' . Request::post('server');
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('AdAuth');
- else
+ } else {
$module = $this->edit;
+ }
$ssl = Request::post('ssl', 'off') === 'on';
- foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'homeattr', 'certificate', 'fixnumeric', 'genuid',
+ foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'homeattr', 'certificate', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts'] as $key) {
$module->setData($key, Request::post($key, '', 'string'));
}
@@ -507,7 +493,7 @@ class AdAuth_Finish extends AddModule_Base
} else {
$module->setData('fingerprint', '');
}
- if ($this->edit !== false)
+ if ($this->edit !== null)
$ret = $module->update($title);
else
$ret = $module->insert($title);
@@ -515,7 +501,7 @@ class AdAuth_Finish extends AddModule_Base
Message::addError('main.value-invalid', 'any', 'any');
$tgz = false;
} else {
- $tgz = $module->generate($this->edit === false);
+ $tgz = $module->generate($this->edit === null);
}
if ($tgz === false) {
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
@@ -525,9 +511,8 @@ class AdAuth_Finish extends AddModule_Base
'tm-config' => $tgz,
);
- if ($this->edit === false) {
+ if ($this->edit === null) {
AddModule_Base::setStep('AddModule_Assign', $module->id());
- return;
}
}
diff --git a/modules-available/sysconfig/addmodule_branding.inc.php b/modules-available/sysconfig/addmodule_branding.inc.php
index d941a7a7..54b2ad57 100644
--- a/modules-available/sysconfig/addmodule_branding.inc.php
+++ b/modules-available/sysconfig/addmodule_branding.inc.php
@@ -11,7 +11,7 @@ class Branding_Start extends AddModule_Base
{
Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-start', array(
'step' => 'Branding_ProcessFile',
- 'edit' => $this->edit ? $this->edit->id() : false
+ 'edit' => $this->edit == null ? null : $this->edit->id(),
));
}
@@ -22,7 +22,6 @@ class Branding_ProcessFile extends AddModule_Base
private $task;
private $svgFile;
- private $tarFile;
protected function preprocessInternal()
{
@@ -48,14 +47,16 @@ class Branding_ProcessFile extends AddModule_Base
if (strpos($url, '://') === false)
$url = "http://$url";
$title = false;
- if (!$this->downloadSvg($this->svgFile, $url, $title))
+ if (!Branding_ProcessFile::downloadSvg($this->svgFile, $url, $title)) {
+ @unlink($this->svgFile);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
+ }
Session::set('logo_name', $title);
}
chmod($this->svgFile, 0644);
- $this->tarFile = '/tmp/bwlp-' . time() . '-' . mt_rand() . '.tgz';
+ $tarFile = '/tmp/bwlp-' . time() . '-' . mt_rand() . '.tgz';
$this->task = Taskmanager::submit('BrandingGenerator', array(
- 'tarFile' => $this->tarFile,
+ 'tarFile' => $tarFile,
'svgFile' => $this->svgFile
));
$this->task = Taskmanager::waitComplete($this->task, 5000);
@@ -64,8 +65,7 @@ class Branding_ProcessFile extends AddModule_Base
Taskmanager::addErrorMessage($this->task);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
- Session::set('logo_tgz', $this->tarFile);
- Session::save();
+ Session::set('logo_tgz', $tarFile);
}
protected function renderInternal()
@@ -75,13 +75,13 @@ class Branding_ProcessFile extends AddModule_Base
$png = base64_encode(file_get_contents($this->task['data']['pngFile']));
if (filesize($this->svgFile) < 1000000)
$svg = base64_encode(file_get_contents($this->svgFile));
- Render::addDialog(Dictionary::translate('config-module', 'branding_title'), false, 'branding-check', array(
+ Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-check', array(
'png' => $png,
'svg' => $svg,
- 'error' => $this->task['data']['error'],
+ 'error' => $this->task['data']['error'] ?? $this->task['statusCode'],
'step' => 'Branding_Finish',
- 'edit' => $this->edit ? $this->edit->id() : false,
- 'title' => $this->edit ? $this->edit->title() : false
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
+ 'title' => $this->edit === null ? null : $this->edit->title(),
)
);
@unlink($this->svgFile);
@@ -96,39 +96,56 @@ class Branding_ProcessFile extends AddModule_Base
* @return boolean true of download succeeded, false on download error (also returns true if downloaded file doesn't
* seem to be svg!)
*/
- private function downloadSvg($svgName, $url, &$title)
+ private static function downloadSvg(string $svgName, string $url, &$title): bool
{
$title = false;
- // [wikipedia] Did someone paste a link to a thumbnail of the svg? Let's fix that...
- if (preg_match('#^(.*)/thumb/(.*\.svg)/.*\.svg#', $url, $out)) {
- $url = $out[1] . '/' . $out[2];
- }
for ($i = 0; $i < 5; ++$i) {
+ // [wikipedia] Did someone paste a link to a thumbnail of the svg? Let's fix that...
+ if (preg_match('#^(.*)/thumb/(.*\.svg)/.*\.svg#', $url, $out)) {
+ $url = $out[1] . '/' . $out[2];
+ }
$code = 400;
if (!Download::toFile($svgName, $url, 3, $code) || $code < 200 || $code > 299) {
Message::addError('remote-timeout', $url, $code);
return false;
}
- $content = FileUtil::readFile($svgName, 25000);
+ $content = FileUtil::readFile($svgName, 250000);
// Is svg file?
if (strpos($content, '<svg') !== false)
return true; // Found an svg tag - don't try to find links to the actual image
// [wikipedia] Try to be nice and detect links that might give a hint where the svg can be found
- if (preg_match_all('#href="([^"]*upload.wikimedia.org/[^"]*/[^"]*/[^"]*\.svg|[^"]+/[^"]+:[^"]+\.svg[^"]*)"#', $content, $out, PREG_PATTERN_ORDER)) {
+ $out1 = $out2 = $out3 = null;
+ if (preg_match_all('#href="([^"]*upload.wikimedia.org/[^"]*/[^"]*/[^"]*\.svg)"#', $content, $out1, PREG_PATTERN_ORDER)
+ || preg_match_all('#src="([^"]*upload.wikimedia.org/[^"]*/thumb/[^"]*\.svg/[^"]+\.svg[^"]*)"#', $content, $out2, PREG_PATTERN_ORDER)
+ || preg_match_all('#href="([^"]+/[^"]+:[^"]+\.svg)"#', $content, $out3, PREG_PATTERN_ORDER)) {
if ($title === false && preg_match('#<title>([^<]*)</title>#i', $content, $tout)) {
$title = trim(preg_replace('/\W*Wikipedia.*/', '', $tout[1]));
}
$new = false;
- foreach ($out[1] as $res) {
+ $out = [];
+ if (isset($out1[1])) {
+ $out += $out1[1];
+ }
+ if (isset($out2[1])) {
+ $out += $out2[1];
+ }
+ if (isset($out3[1])) {
+ $out += $out3[1];
+ }
+ foreach ($out as $res) {
+ error_log("Match '$res'");
+ if (!preg_match('/hochschule|univers|logo|siegel/i', $res))
+ continue;
if (strpos($res, 'action=edit') !== false)
continue;
- $new = $this->internetCombineUrl($url, html_entity_decode($res, ENT_COMPAT, 'UTF-8'));
+ $new = Branding_ProcessFile::internetCombineUrl($url, html_entity_decode($res, ENT_COMPAT, 'UTF-8'));
if ($new !== $url)
break;
}
if ($new === $url || $new === false)
break;
+ error_log("New: '$new'");
$url = $new;
continue;
}
@@ -145,7 +162,7 @@ class Branding_ProcessFile extends AddModule_Base
* @param string $relative relative url that will be converted to an absolute url
* @return string combined absolute url
*/
- private function internetCombineUrl($absolute, $relative)
+ private static function internetCombineUrl(string $absolute, string $relative): string
{
$p = parse_url($relative);
if (!empty($p["scheme"]))
@@ -154,8 +171,8 @@ class Branding_ProcessFile extends AddModule_Base
$parsed = parse_url($absolute);
$path = dirname($parsed['path']);
- if ($relative{0} === '/') {
- if ($relative{1} === '/')
+ if ($relative[0] === '/') {
+ if ($relative[1] === '/')
return "{$parsed['scheme']}:$relative";
$cparts = array_filter(explode("/", $relative));
} else {
@@ -197,9 +214,9 @@ class Branding_Finish extends AddModule_Base
protected function preprocessInternal()
{
$title = Request::post('title');
- if ($title === false || empty($title))
+ if (empty($title))
$title = Session::get('logo_name');
- if ($title === false || empty($title)) {
+ if (empty($title)) {
Message::addError('missing-title'); // TODO: Ask for title again instead of starting over
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
@@ -208,30 +225,26 @@ class Branding_Finish extends AddModule_Base
Message::addError('main.error-read', $tgz);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('Branding');
- else
+ } else {
$module = $this->edit;
- if ($module === false) {
- Message::addError('main.error-read', 'branding.inc.php');
- Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
$module->setData('tmpFile', $tgz);
- if ($this->edit !== false)
+ if ($this->edit !== null)
$ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
- elseif ($module->generate($this->edit === false, NULL, 200) === false)
+ elseif ($module->generate($this->edit === null, NULL, 200) === false)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
Session::set('logo_tgz', false);
Session::set('logo_name', false);
- Session::save();
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_custommodule.inc.php b/modules-available/sysconfig/addmodule_custommodule.inc.php
index 0c3c299d..3afdad0a 100644
--- a/modules-available/sysconfig/addmodule_custommodule.inc.php
+++ b/modules-available/sysconfig/addmodule_custommodule.inc.php
@@ -14,7 +14,7 @@ class CustomModule_Start extends AddModule_Base
Session::set('mod_temp', false);
Render::addDialog(Dictionary::translateFile('config-module', 'custom_title'), false, 'custom-upload', array(
'step' => 'CustomModule_ProcessUpload',
- 'edit' => $this->edit ? $this->edit->id() : false
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
));
}
@@ -55,8 +55,9 @@ class CustomModule_ProcessUpload extends AddModule_Base
protected function renderInternal()
{
- $status = Taskmanager::waitComplete($this->taskId);
+ $status = Taskmanager::waitComplete($this->taskId, 7500);
Taskmanager::release($this->taskId);
+ $userGroupWarn = false;
$tempfile = Session::get('mod_temp');
if (!isset($status['statusCode'])) {
unlink($tempfile);
@@ -66,47 +67,29 @@ class CustomModule_ProcessUpload extends AddModule_Base
unlink($tempfile);
$this->taskError($status);
}
- // Sort files for better display
- $dirs = array();
- foreach ($status['data']['entries'] as $file) {
- if ($file['isdir']) continue;
- $dirs[dirname($file['name'])][] = $file;
- }
- ksort($dirs);
- $list = array();
- foreach ($dirs as $dir => $files) {
- $list[] = array(
- 'name' => $dir,
- 'isdir' => true
- );
- sort($files);
- foreach ($files as $file) {
- $file['size'] = Util::readableFileSize($file['size']);
- $list[] = $file;
- }
- }
- if ($this->edit !== false)
+ $list = SysConfig::archiveContentsFromTask($status, $userGroupWarn);
+
+ if ($this->edit !== null) {
$title = $this->edit->title();
- elseif (isset($_FILES['modulefile']['name']))
+ } else if (isset($_FILES['modulefile']['name'])) {
$title = basename($_FILES['modulefile']['name']);
- else
+ } else {
$title = '';
- Render::addDialog(Dictionary::translate('config-module', 'custom_title'), false, 'custom-fileselect', array(
+ }
+ Render::addDialog(Dictionary::translateFile('config-module', 'custom_title'), false, 'custom-fileselect', array(
'step' => 'CustomModule_CompressModule',
'files' => $list,
- 'edit' => $this->edit ? $this->edit->id() : false,
- 'title' => $title
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
+ 'title' => $title,
+ 'userGroupWarn' => $userGroupWarn,
));
- Session::save();
}
}
class CustomModule_CompressModule extends AddModule_Base
{
-
- private $taskId = false;
-
+
protected function preprocessInternal()
{
$title = Request::post('title');
@@ -116,14 +99,15 @@ class CustomModule_CompressModule extends AddModule_Base
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
}
// Recompress using task manager
- $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true);
+ $taskId = 'tgzmod' . mt_rand() . '-' . microtime(true);
$destFile = tempnam(sys_get_temp_dir(), 'bwlp-') . '.tgz';
Taskmanager::submit('RecompressArchive', array(
- 'id' => $this->taskId,
+ 'id' => $taskId,
'inputFiles' => [$tempfile => false],
- 'outputFile' => $destFile
+ 'outputFile' => $destFile,
+ 'forceRoot' => Request::post('force-owner', 0, 'int') !== 0,
), true);
- $status = Taskmanager::waitComplete($this->taskId, 5000);
+ $status = Taskmanager::waitComplete($taskId, 10000);
unlink($tempfile);
if (!isset($status['statusCode'])) {
$this->tmError();
@@ -132,29 +116,26 @@ class CustomModule_CompressModule extends AddModule_Base
$this->taskError($status);
}
// Seems ok, create entry
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('CustomModule');
- else
+ } else {
$module = $this->edit;
- if ($module === false) {
- Message::addError('main.error-read', 'custommodule.inc.php');
- Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
}
$module->setData('tmpFile', $destFile);
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
+ }
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
- elseif (!$module->generate($this->edit === false, NULL, 200))
+ elseif (!$module->generate($this->edit === null, NULL, 200))
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
Session::set('mod_temp', false);
- Session::save();
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_ldapauth.inc.php b/modules-available/sysconfig/addmodule_ldapauth.inc.php
index 98f98c6d..6a385d9c 100644
--- a/modules-available/sysconfig/addmodule_ldapauth.inc.php
+++ b/modules-available/sysconfig/addmodule_ldapauth.inc.php
@@ -9,15 +9,12 @@ class LdapAuth_Start extends AddModule_Base
protected function renderInternal()
{
- $LDAPAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'fixnumeric', 'genuid', 'certificate', 'mapping', 'nohomewarn');
+ $LDAPAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'genuid', 'certificate', 'mapping', 'nohomewarn');
$data = array();
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
moduleToArray($this->edit, $data, $LDAPAUTH_COMMON_FIELDS);
$data['title'] = $this->edit->title();
$data['edit'] = $this->edit->id();
- if (!isset($data['fixnumeric']) || $data['fixnumeric'] === false) {
- $data['fixnumeric'] = 's';
- }
} else {
$data['ssl'] = true;
}
@@ -30,7 +27,7 @@ class LdapAuth_Start extends AddModule_Base
}
$data['step'] = 'LdapAuth_CheckConnection';
$data['map_empty'] = true;
- $data['mapping'] = ConfigModuleBaseLdap::getMapping(isset($data['mapping']) ? $data['mapping'] : false, $data['map_empty']);
+ $data['mapping'] = ConfigModuleBaseLdap::getMapping($data['mapping'] ?? null, $data['map_empty']);
Render::addDialog(Dictionary::translateFile('config-module', 'ldapAuth_title'), false, 'ldap-start', $data);
}
@@ -67,7 +64,6 @@ class LdapAuth_CheckConnection extends AddModule_Base
));
if (!isset($this->scanTask['id'])) {
AddModule_Base::setStep('LdapAuth_Start'); // Continues with LdapAuth_Start for render()
- return;
}
}
@@ -82,11 +78,10 @@ class LdapAuth_CheckConnection extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl'),
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'certificate' => Request::post('certificate', ''),
'taskid' => $this->scanTask['id'],
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
);
$data['prev'] = 'LdapAuth_Start';
$data['next'] = 'LdapAuth_CheckCredentials';
@@ -154,11 +149,10 @@ class LdapAuth_CheckCredentials extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'LdapAuth_Start',
'next' => 'LdapAuth_HomeDir',
))
@@ -195,16 +189,15 @@ class LdapAuth_HomeDir extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'LdapAuth_Start',
'next' => 'LdapAuth_Finish',
);
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
foreach (self::getAttributes() as $key) {
if ($this->edit->getData($key)) {
$data[$key . '_c'] = 'checked="checked"';
@@ -225,13 +218,13 @@ class LdapAuth_HomeDir extends AddModule_Base
foreach (range('D', 'Z') as $l) {
$data['drives'][] = array(
'drive' => $l . ':',
- 'selected' => (strtoupper($letter{0}) === $l) ? 'selected="selected"' : ''
+ 'selected' => (strtoupper($letter[0]) === $l) ? 'selected="selected"' : ''
);
}
Render::addDialog(Dictionary::translateFile('config-module', 'ldapAuth_title'), false, 'ad_ldap-homedir', $data);
}
- public static function getAttributes()
+ public static function getAttributes(): array
{
return array('shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop',
'shareMedia', 'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough');
@@ -249,12 +242,13 @@ class LdapAuth_Finish extends AddModule_Base
$title = Request::post('title');
if (empty($title))
$title = 'LDAP: ' . Request::post('server');
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('LdapAuth');
- else
+ } else {
$module = $this->edit;
+ }
$ssl = Request::post('ssl', 'off') === 'on';
- foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'certificate', 'fixnumeric', 'genuid',
+ foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'certificate', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts'] as $key) {
$module->setData($key, Request::post($key, '', 'string'));
}
@@ -276,15 +270,16 @@ class LdapAuth_Finish extends AddModule_Base
} else {
$module->setData('fingerprint', '');
}
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
+ }
if (!$ret) {
Message::addError('main.value-invalid', 'any', 'any');
$tgz = false;
} else {
- $tgz = $module->generate($this->edit === false);
+ $tgz = $module->generate($this->edit === null);
}
if ($tgz === false) {
AddModule_Base::setStep('LdapAuth_Start'); // Continues with LdapAuth_Start for render()
@@ -294,9 +289,8 @@ class LdapAuth_Finish extends AddModule_Base
'tm-config' => $tgz,
);
- if ($this->edit === false) {
+ if ($this->edit === null) {
AddModule_Base::setStep('AddModule_Assign', $module->id());
- return;
}
}
diff --git a/modules-available/sysconfig/addmodule_screensaver.inc.php b/modules-available/sysconfig/addmodule_screensaver.inc.php
index d8c189f7..7b6d0afb 100644
--- a/modules-available/sysconfig/addmodule_screensaver.inc.php
+++ b/modules-available/sysconfig/addmodule_screensaver.inc.php
@@ -6,7 +6,6 @@
class Screensaver_Start extends AddModule_Base
{
- private $hasSummernote = false;
private $session_data;
protected function preprocessInternal()
@@ -15,7 +14,7 @@ class Screensaver_Start extends AddModule_Base
if (Request::get('back', 'false', 'string') !== 'false')
/* If coming via the back button, load the session data */
$this->session_data = Session::get('data');
- elseif ($this->edit !== false) {
+ elseif ($this->edit !== null) {
$this->session_data = array(
'title' => $this->edit->title(),
'qss' => $this->edit->getData('qss'),
@@ -25,22 +24,22 @@ class Screensaver_Start extends AddModule_Base
} else {
$this->session_data = array(
'title' => '',
- 'qss' => Dictionary::translate('saver_QssDefault', true),
+ 'qss' => Dictionary::translate('saver_QssDefault'),
'messages' => array(
'General' => array(
- 'shutdown' => Dictionary::translate('saver_MessageDefaultShutdown', true),
- 'shutdown-locked' => Dictionary::translate('saver_MessageDefaultShutdownLocked', true),
- 'idle-kill' => Dictionary::translate('saver_MessageDefaultIdleKill', true),
- 'idle-kill-locked' => Dictionary::translate('saver_MessageDefaultIdleKillLocked', true),
- 'no-timeout' => Dictionary::translate('saver_MessageDefaultNoTimeout', true),
- 'no-timeout-locked' => Dictionary::translate('saver_MessageDefaultNoTimeoutLocked', true),
+ 'shutdown' => Dictionary::translate('saver_MessageDefaultShutdown'),
+ 'shutdown-locked' => Dictionary::translate('saver_MessageDefaultShutdownLocked'),
+ 'idle-kill' => Dictionary::translate('saver_MessageDefaultIdleKill'),
+ 'idle-kill-locked' => Dictionary::translate('saver_MessageDefaultIdleKillLocked'),
+ 'no-timeout' => Dictionary::translate('saver_MessageDefaultNoTimeout'),
+ 'no-timeout-locked' => Dictionary::translate('saver_MessageDefaultNoTimeoutLocked'),
)
),
'texts' => array(
- 'text-shutdown' => Dictionary::translate('saver_TextDefaultShutdown', true),
+ 'text-shutdown' => Dictionary::translate('saver_TextDefaultShutdown'),
'text-shutdown-locked' => '',
- 'text-idle-kill' => Dictionary::translate('saver_TextDefaultIdleKill', true),
- 'text-idle-kill-locked' => Dictionary::translate('saver_TextDefaultIdleKillLocked', true),
+ 'text-idle-kill' => Dictionary::translate('saver_TextDefaultIdleKill'),
+ 'text-idle-kill-locked' => Dictionary::translate('saver_TextDefaultIdleKillLocked'),
'text-no-timeout' => '',
'text-no-timeout-locked' => '',
),
@@ -48,18 +47,16 @@ class Screensaver_Start extends AddModule_Base
}
$this->session_data['next'] = 'idle-kill';
Session::set('data', $this->session_data);
- Session::save();
}
protected function renderInternal()
{
/* Load summernote module if available */
- $this->hasSummernote = Module::isAvailable('summernote');
-
+ Module::isAvailable('summernote');
Render::addDialog(Dictionary::translateFile('config-module', 'screensaver_title'), false, 'screensaver-start', array(
'step' => 'Screensaver_Text',
'next' => 'idle-kill',
- 'edit' => $this->edit ? $this->edit->id() : 0,
+ 'edit' => $this->edit !== null ? $this->edit->id() : 0,
'id' => 'start',
'title' => $this->session_data['title'],
'qss' => $this->session_data['qss'],
@@ -69,26 +66,23 @@ class Screensaver_Start extends AddModule_Base
class Screensaver_Text extends AddModule_Base
{
- private $hasSummernote = false;
private $session_data;
- private $id;
protected function preprocessInternal()
{
/* Load session data */
$this->session_data = Session::get('data');
- $this->id = Request::post('id', '', 'string');
+ $id = Request::post('id', '', 'string');
- if ($this->id === 'start') {
+ if ($id === 'start') {
Screensaver_Helper::processQssData($this->session_data);
- } elseif ($this->id !== '') {
- Screensaver_Helper::processScreensaverText($this->session_data, $this->id);
+ } elseif ($id !== '') {
+ Screensaver_Helper::processScreensaverText($this->session_data, $id);
}
$next = Request::post('next', $this->session_data['next'], 'string');
$this->session_data['next'] = $next;
Session::set('data', $this->session_data);
- Session::save();
if ($next === 'finish')
@@ -100,11 +94,11 @@ class Screensaver_Text extends AddModule_Base
protected function renderInternal()
{
/* Load summernote module if available */
- $this->hasSummernote = Module::isAvailable('summernote');
+ Module::isAvailable('summernote');
$next = $this->session_data['next'];
$data = array(
- 'edit' => $this->edit ? $this->edit->id() : 0,
+ 'edit' => $this->edit !== null ? $this->edit->id() : 0,
);
/* Prepare and translate labels for the frontend */
@@ -120,8 +114,8 @@ class Screensaver_Text extends AddModule_Base
* Dictionary::translate('saver_TitleShutdown');
* Dictionary::translate('saver_DescriptionShutdown');
*/
- $data['title'] = Dictionary::translate('saver_Title' . $tag, true);
- $data['description'] = Dictionary::translate('saver_Description' . $tag, true);;
+ $data['title'] = Dictionary::translate('saver_Title' . $tag);
+ $data['description'] = Dictionary::translate('saver_Description' . $tag);
$data['msg_value'] = $this->session_data['messages']['General'][$next];
$data['msg_locked_value'] = $this->session_data['messages']['General'][$next . '-locked'];
$data['text_value'] = $this->session_data['texts']['text-' . $next];
@@ -156,14 +150,14 @@ class Screensaver_Finish extends AddModule_Base
if (empty($session_data['title'])) {
Message::addError('missing-title');
Util::redirect('?do=SysConfig');
- return;
}
/* Only create an instance, if it's a new one */
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$module = $this->edit;
- else
+ } else {
$module = ConfigModule::getInstance('Screensaver');
+ }
/* Set all the data to the module instance */
$module->setData('qss', $session_data['qss']);
@@ -171,15 +165,16 @@ class Screensaver_Finish extends AddModule_Base
$module->setData('texts', $session_data['texts']);
/* Insert or update database entries */
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$module->update($session_data['title']);
- else
+ } else {
$module->insert($session_data['title']);
+ }
- $task = $module->generate($this->edit === false);
+ $task = $module->generate($this->edit === null);
// Yay
- if ($task !== false && $this->edit !== false)
+ if ($task !== false && $this->edit !== null)
Message::addSuccess('module-edited');
elseif ($task !== false) {
Message::addSuccess('module-added');
@@ -198,7 +193,6 @@ class Screensaver_Helper
if (empty($session_data['title'])) {
Message::addError('missing-title');
Util::redirect('?do=SysConfig');
- return;
}
$session_data['qss'] = Request::post('qss', $session_data['qss'], 'string');
$helperMode = Request::post('helper_mode', 'false', 'string');
diff --git a/modules-available/sysconfig/addmodule_sshconfig.inc.php b/modules-available/sysconfig/addmodule_sshconfig.inc.php
index 4a75d77e..2447f9be 100644
--- a/modules-available/sysconfig/addmodule_sshconfig.inc.php
+++ b/modules-available/sysconfig/addmodule_sshconfig.inc.php
@@ -9,8 +9,8 @@ class SshConfig_Start extends AddModule_Base
protected function renderInternal()
{
- if ($this->edit !== false) {
- $data = $this->edit->getData(false) + array(
+ if ($this->edit !== null) {
+ $data = $this->edit->getData(null) + array(
'title' => $this->edit->title(),
'edit' => $this->edit->id(),
'PWD_' . strtoupper($this->edit->getData('allowPasswordLogin')) . '_selected' => 'selected',
@@ -40,10 +40,11 @@ class SshConfig_Finish extends AddModule_Base
return;
}
// Seems ok, create entry
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('SshConfig');
- else
+ } else {
$module = $this->edit;
+ }
if ($module === false) {
Message::addError('main.error-read', 'sshconfig.inc.php');
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
@@ -59,18 +60,20 @@ class SshConfig_Finish extends AddModule_Base
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
}
$module->setData('publicKey', false);
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
- if (!$ret)
+ }
+ if (!$ret) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
- elseif (!$module->generate($this->edit === false, NULL, 200))
+ } elseif (!$module->generate($this->edit === null, NULL, 200)) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ }
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_sshkey.inc.php b/modules-available/sysconfig/addmodule_sshkey.inc.php
index b5ab4ad6..9f5bd1d3 100644
--- a/modules-available/sysconfig/addmodule_sshkey.inc.php
+++ b/modules-available/sysconfig/addmodule_sshkey.inc.php
@@ -9,8 +9,8 @@ class SshKey_Start extends AddModule_Base
protected function renderInternal()
{
- if ($this->edit !== false) {
- $data = $this->edit->getData(false) + array(
+ if ($this->edit !== null) {
+ $data = $this->edit->getData(null) + array(
'title' => $this->edit->title(),
'edit' => $this->edit->id(),
);
@@ -35,7 +35,7 @@ class SshKey_Finish extends AddModule_Base
return;
}
// Seems ok, create entry
- if ($this->edit === false) {
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('SshKey');
} else {
$module = $this->edit;
@@ -48,18 +48,18 @@ class SshKey_Finish extends AddModule_Base
Message::addError('main.value-invalid', 'pubkey', Request::post('publicKey'));
Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
}
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
$ret = $module->update($title);
} else {
$ret = $module->insert($title);
}
if (!$ret) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
- } elseif (!$module->generate($this->edit === false, NULL, 200)) {
+ } elseif (!$module->generate($this->edit === null, NULL, 200)) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
}
// Yay
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
} else {
Message::addSuccess('module-added');
diff --git a/modules-available/sysconfig/api.inc.php b/modules-available/sysconfig/api.inc.php
index 983c6dcb..e7be3029 100644
--- a/modules-available/sysconfig/api.inc.php
+++ b/modules-available/sysconfig/api.inc.php
@@ -11,9 +11,9 @@ if (substr($ip, 0, 7) === '::ffff:') {
$ip = substr($ip, 7);
}
-$uuid = Request::any('uuid', false, 'string');
-if ($uuid !== false && strlen($uuid) !== 36) {
- $uuid = false;
+$uuid = Request::any('uuid', null, 'string');
+if ($uuid !== null && strlen($uuid) !== 36) {
+ $uuid = null;
}
// What we do if we can't supply the requested config
@@ -46,7 +46,7 @@ $res = Database::simpleQuery("SELECT c.title, c.filepath, c.status, cl.locationi
$best = 1000;
$row = false;
-while ($r = $res->fetch(PDO::FETCH_ASSOC)) {
+foreach ($res as $r) {
settype($r['locationid'], 'int');
$index = array_search($r['locationid'], $locationChain);
if ($index === false || $index > $best)
diff --git a/modules-available/sysconfig/hooks/bootup.inc.php b/modules-available/sysconfig/hooks/bootup.inc.php
new file mode 100644
index 00000000..8e445dc4
--- /dev/null
+++ b/modules-available/sysconfig/hooks/bootup.inc.php
@@ -0,0 +1,3 @@
+<?php
+
+ConfigModuleBaseLdap::ldadp(); \ No newline at end of file
diff --git a/modules-available/sysconfig/hooks/locations-column.inc.php b/modules-available/sysconfig/hooks/locations-column.inc.php
new file mode 100644
index 00000000..8042b51c
--- /dev/null
+++ b/modules-available/sysconfig/hooks/locations-column.inc.php
@@ -0,0 +1,57 @@
+<?php
+
+if (!User::hasPermission('.sysconfig.config.*') || !Module::isAvailable('sysconfig'))
+ return null;
+
+class SysconfigLocationColumn extends AbstractLocationColumn
+{
+
+ private $lookup = [];
+
+ public function __construct()
+ {
+ $confs = SysConfig::getAll();
+ foreach ($confs as $conf) {
+ if (!isset($conf['locs']) || strlen($conf['locs']) === 0)
+ continue;
+ $confLocs = explode(',', $conf['locs']);
+ foreach ($confLocs as $locId) {
+ $this->lookup[$locId] = $conf['title'];
+ }
+ }
+ }
+
+ public function getColumnHtml(int $locationId): string
+ {
+ return htmlspecialchars($this->lookup[$locationId] ?? '');
+ }
+
+ public function getEditUrl(int $locationId): string
+ {
+ if (!User::hasPermission('.sysconfig.config.assign', $locationId))
+ return '';
+ return '?do=sysconfig&locationid=' . $locationId;
+ }
+
+ public function header(): string
+ {
+ return Dictionary::translateFileModule('sysconfig', 'module', 'location-column-header');
+ }
+
+ public function priority(): int
+ {
+ return 2000;
+ }
+
+ public function propagateColumn(): bool
+ {
+ return true;
+ }
+
+ public function propagateDefaultHtml(): string
+ {
+ return htmlspecialchars($this->lookup[0] ?? '');
+ }
+}
+
+return new SysconfigLocationColumn(); \ No newline at end of file
diff --git a/modules-available/sysconfig/inc/configmodule.inc.php b/modules-available/sysconfig/inc/configmodule.inc.php
index f3906378..729cb959 100644
--- a/modules-available/sysconfig/inc/configmodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule.inc.php
@@ -7,18 +7,23 @@ abstract class ConfigModule
{
/**
- * @var array list of known module types
+ * @var ?array{'title': string,
+ * 'description': string,
+ * 'group': string,
+ * 'unique': bool,
+ * 'sortOrder': int,
+ * 'moduleClass': string,
+ * 'wizardClass': string}[] list of known module types
*/
- private static $moduleTypes = false;
+ private static $moduleTypes = null;
private $moduleId = 0;
- private $moduleArchive = false;
- private $moduleTitle = false;
- private $moduleStatus = false;
- /**
- * @var int
- */
+ private $moduleArchive = '';
+ private $moduleTitle = '';
+ private $moduleStatus = 'MISSING';
+ /** @var int */
private $dateline = 0;
+ /** @var int */
private $currentVersion = 0;
/**
* @var false|array Data of module, false if not initialized
@@ -33,9 +38,9 @@ abstract class ConfigModule
*/
public static function loadDb()
{
- if (self::$moduleTypes !== false)
+ if (self::$moduleTypes !== null)
return;
- self::$moduleTypes = array();
+ self::$moduleTypes = [];
Module::isAvailable('sysconfig');
foreach (glob(dirname(__FILE__) . '/configmodule/*.inc.php', GLOB_NOSORT) as $file) {
require_once $file;
@@ -44,10 +49,16 @@ abstract class ConfigModule
/**
* Get all known config module types.
- *
- * @return array list of modules
+ * @return array{'title': string,
+ * 'description': string,
+ * 'group': string,
+ * 'unique': bool,
+ * 'sortOrder': int,
+ * 'moduleClass': string,
+ * 'wizardClass': string}[] list of known module types
+ * /
*/
- public static function getList()
+ public static function getList(): array
{
self::loadDb();
return self::$moduleTypes;
@@ -63,20 +74,20 @@ abstract class ConfigModule
* @param string $description Description for this module type
* @param string $group Title for group this module type belongs to
* @param bool $unique Can only one such module be added to a config?
- * @param int $sortOrder Lower comes first, alphabetical ordering otherwiese
+ * @param int $sortOrder Lower comes first, alphabetical ordering otherwise
*/
- public static function registerModule($id, $title, $description, $group, $unique, $sortOrder = 0)
+ public static function registerModule(string $id, string $title, string $description, string $group, bool $unique, int $sortOrder = 0): void
{
if (isset(self::$moduleTypes[$id])) {
- Util::traceError("Config Module $id already registered!");
+ ErrorHandler::traceError("Config Module $id already registered!");
}
$moduleClass = 'ConfigModule_' . $id;
$wizardClass = $id . '_Start';
if (!class_exists($moduleClass)) {
- Util::traceError("Class $moduleClass does not exist!");
+ ErrorHandler::traceError("Class $moduleClass does not exist!");
}
if (!is_subclass_of($moduleClass, 'ConfigModule')) {
- Util::traceError("$moduleClass does not have ConfigModule as its parent!");
+ ErrorHandler::traceError("$moduleClass does not have ConfigModule as its parent!");
}
self::$moduleTypes[$id] = array(
'title' => $title,
@@ -93,21 +104,33 @@ abstract class ConfigModule
* Get fresh instance of ConfigModule subclass for given module type.
*
* @param string $moduleType name of module type
- * @return false|\ConfigModule module instance
+ * @return ConfigModule module instance
*/
- public static function getInstance($moduleType)
+ public static function getInstance(string $moduleType): ConfigModule
+ {
+ $ret = self::getInstanceOrNull($moduleType);
+ if ($ret === null) {
+ Message::addError('main.error-read', $moduleType . '.inc.php');
+ Util::redirect('?do=sysconfig');
+ }
+ return $ret;
+ }
+
+ public static function getInstanceOrNull(string $moduleType): ?ConfigModule
{
self::loadDb();
if (!isset(self::$moduleTypes[$moduleType])) {
error_log('Unknown module type: ' . $moduleType);
- return false;
+ return null;
}
return new self::$moduleTypes[$moduleType]['moduleClass'];
}
- public static function instanceFromDbRow($dbRow)
+ private static function instanceFromDbRow(array $dbRow): ?ConfigModule
{
- $instance = self::getInstance($dbRow['moduletype']);
+ $instance = self::getInstanceOrNull($dbRow['moduletype']);
+ if ($instance === null)
+ return null;
$instance->currentVersion = $dbRow['version'];
$instance->moduleArchive = $dbRow['filepath'];
$instance->moduleData = json_decode($dbRow['contents'], true);
@@ -125,37 +148,37 @@ abstract class ConfigModule
* Get module instance from id.
*
* @param int $moduleId module id to get
- * @return false|\ConfigModule The requested module from DB, or false on error
+ * @return ?ConfigModule The requested module from DB, or null on error
*/
- public static function get($moduleId)
+ public static function get(int $moduleId): ?ConfigModule
{
$ret = Database::queryFirst("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module "
. " WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleId));
if ($ret === false)
- return false;
+ return null;
return self::instanceFromDbRow($ret);
}
/**
* Get module instances from module type.
*
- * @param int $moduleType module type to get
- * @return \ConfigModule[]|false The requested modules from DB, or false on error
+ * @param string $moduleType module type to get
+ * @return ?ConfigModule[] The requested modules from DB, or null on error
*/
- public static function getAll($moduleType = false)
+ public static function getAll(string $moduleType = null): ?array
{
- if ($moduleType === false) {
+ if ($moduleType === null) {
$ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module");
} else {
$ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module "
. " WHERE moduletype = :moduletype", array('moduletype' => $moduleType));
}
if ($ret === false)
- return false;
+ return null;
$list = array();
- while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($ret as $row) {
$instance = self::instanceFromDbRow($row);
- if ($instance === false)
+ if ($instance === null)
continue;
$list[] = $instance;
}
@@ -167,37 +190,37 @@ abstract class ConfigModule
*
* @return int module version
*/
- protected abstract function moduleVersion();
+ protected abstract function moduleVersion(): int;
/**
* Validate the module's configuration.
*
- * @return boolean ok or not
+ * @return bool ok or not
*/
- protected abstract function validateConfig();
+ protected abstract function validateConfig(): bool;
/**
* Set module specific data.
*
* @param string $key key, name or id of data being set
* @param mixed $value Module specific data
- * @return boolean true if data was successfully set, false otherwise (i.e. invalid data being set)
+ * @return bool true if data was successfully set, false otherwise (i.e. invalid data being set)
*/
- public abstract function setData($key, $value);
+ public abstract function setData(string $key, $value): bool;
/**
* Get module specific data.
* Can be overridden by modules.
*
- * @param string $key key, name or id of data to get, or false to get the raw moduleData array
+ * @param ?string $key key, name or id of data to get, or null to get the raw moduleData array
* @return mixed Module specific data
*/
- public function getData($key)
+ public function getData(?string $key)
{
- if ($key === false)
+ if ($key === null)
return $this->moduleData;
if (!is_array($this->moduleData) || !isset($this->moduleData[$key]))
- return false;
+ return null;
return $this->moduleData[$key];
}
@@ -205,25 +228,25 @@ abstract class ConfigModule
* Module specific version of generate.
*
* @param string $tgz File name of tgz module to write final output to
- * @param string $parent Parent task of this task
+ * @param string|null $parent Parent task of this task
* @return array|boolean true if generation is completed immediately,
* a task struct if some task needs to be run for generation,
* false on error
*/
- protected abstract function generateInternal($tgz, $parent);
+ protected abstract function generateInternal(string $tgz, ?string $parent);
- private final function createFileName()
+ private function createFileName(): string
{
return CONFIG_TGZ_LIST_DIR . '/modules/'
. $this->moduleType() . '_id-' . $this->moduleId . '__' . mt_rand() . '-' . time() . '.tgz';
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return false;
}
- public function needRebuild()
+ public function needRebuild(): bool
{
return $this->moduleStatus !== 'OK' || $this->currentVersion < $this->moduleVersion();
}
@@ -233,17 +256,15 @@ abstract class ConfigModule
*
* @return int id
*/
- public final function id()
+ public final function id(): int
{
return $this->moduleId;
}
/**
* Get module title.
- *
- * @return string
*/
- public final function title()
+ public final function title(): string
{
return $this->moduleTitle;
}
@@ -253,29 +274,33 @@ abstract class ConfigModule
*
* @return string tgz file absolute path
*/
- public final function archive()
+ public final function archive(): string
{
return $this->moduleArchive;
}
- public final function status()
+ public final function status(): string
{
return $this->moduleStatus;
}
+
+ public final function currentVersion(): int
+ {
+ return $this->currentVersion;
+ }
/**
* Get the module type.
*
* @return string module type
*/
- public final function moduleType()
+ public final function moduleType(): string
{
+ // Yes, need to pass $this, otherwise we get ConfigModule, the base class this function is part of
$name = get_class($this);
- if ($name === false)
- Util::traceError('ConfigModule::moduleType: get_class($this) returned false!');
// ConfigModule_*
if (!preg_match('/^ConfigModule_(\w+)$/', $name, $out))
- Util::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"');
+ ErrorHandler::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"');
return $out[1];
}
@@ -287,10 +312,10 @@ abstract class ConfigModule
* @param string $title display name of the module
* @return boolean true if inserted successfully, false if module config is invalid
*/
- public final function insert($title)
+ public final function insert(string $title): bool
{
if ($this->moduleId !== 0)
- Util::traceError('ConfigModule::insert called when moduleId != 0');
+ ErrorHandler::traceError('ConfigModule::insert called when moduleId != 0');
if (!$this->validateConfig())
return false;
$this->moduleTitle = $title;
@@ -306,7 +331,7 @@ abstract class ConfigModule
));
$this->moduleId = Database::lastInsertId();
if (!is_numeric($this->moduleId))
- Util::traceError('Inserting new config module into DB did not yield a numeric insert id');
+ ErrorHandler::traceError('Inserting new config module into DB did not yield a numeric insert id');
$this->moduleArchive = $this->createFileName();
Database::exec("UPDATE configtgz_module SET filepath = :path WHERE moduleid = :moduleid LIMIT 1", array(
'path' => $this->moduleArchive,
@@ -321,10 +346,10 @@ abstract class ConfigModule
*
* @return boolean true on success, false otherwise
*/
- public final function update($title = '')
+ public final function update(string $title = ''): bool
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::update called when moduleId == 0');
+ ErrorHandler::traceError('ConfigModule::update called when moduleId == 0');
if (!empty($title)) {
$this->moduleTitle = $title;
}
@@ -348,16 +373,16 @@ abstract class ConfigModule
* Updating the database etc. will happen later through a callback.
*
* @param boolean $deleteOnError if true, the db entry will be deleted if generation failed
- * @param string $parent Parent task of this task
+ * @param string|null $parent Parent task of this task
* @param int $timeoutMs maximum time in milliseconds we wait for completion
* @return string|boolean task id if deferred generation was started,
* true if generation succeeded (without using a task or within $timeoutMs)
* false on error
*/
- public final function generate($deleteOnError, $parent = NULL, $timeoutMs = 0)
+ public final function generate(bool $deleteOnError, string $parent = NULL, int $timeoutMs = 0)
{
- if ($this->moduleId === 0 || $this->moduleTitle === false)
- Util::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!');
+ if ($this->moduleId === 0 || empty($this->moduleTitle))
+ ErrorHandler::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!');
$tmpTgz = '/tmp/bwlp-id-' . $this->moduleId . '_' . mt_rand() . '_' . time() . '.tgz';
$ret = $this->generateInternal($tmpTgz, $parent);
// Wait for generation if requested
@@ -390,10 +415,10 @@ abstract class ConfigModule
/**
* Delete the module.
*/
- public final function delete()
+ public final function delete(): void
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::delete called with invalid module id!');
+ ErrorHandler::traceError('ConfigModule::delete called with invalid module id!');
$ret = Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array(
'moduleid' => $this->moduleId
), true) !== false;
@@ -405,17 +430,19 @@ abstract class ConfigModule
$this->moduleTitle = false;
$this->moduleArchive = false;
}
- return $ret;
}
- private final function markUpdated($tmpTgz)
+ /**
+ * @param ?string $tmpTgz new tar archive to use for this module, or null if the old one is still valid
+ */
+ private function markUpdated(?string $tmpTgz): bool
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::markUpdated called with invalid module id!');
- if ($this->moduleArchive === false)
+ ErrorHandler::traceError('ConfigModule::markUpdated called with invalid module id!');
+ if ($this->moduleArchive === null)
$this->moduleArchive = $this->createFileName();
// Move file
- if ($tmpTgz === false) {
+ if ($tmpTgz === null) {
if (!file_exists($this->moduleArchive)) {
EventLog::failure('ConfigModule::markUpdated for "' . $this->moduleTitle . '" called with no tmpTgz and no existing tgz!');
$this->markFailed();
@@ -455,24 +482,26 @@ abstract class ConfigModule
return $retval;
}
- private final function markFailed()
+ private function markFailed(): void
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::markFailed called with invalid module id!');
- if ($this->moduleArchive === false)
+ ErrorHandler::traceError('ConfigModule::markFailed called with invalid module id!');
+ if ($this->moduleArchive === '') {
$this->moduleArchive = $this->createFileName();
- if (!file_exists($this->moduleArchive))
+ }
+ if (!file_exists($this->moduleArchive)) {
$status = 'MISSING';
- else
+ } else {
$status = 'OUTDATED';
- return Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array(
+ }
+ Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array(
'id' => $this->moduleId,
'filename' => $this->moduleArchive,
'status' => $status
- )) !== false;
+ ));
}
- public function dateline_s()
+ public function dateline_s(): string
{
return Util::prettyTime($this->dateline);
}
@@ -484,7 +513,7 @@ abstract class ConfigModule
* Override this if you need to handle this, otherwise
* the base implementation does nothing.
*/
- public function event_serverIpChanged()
+ public function event_serverIpChanged(): void
{
// Do::Nothing()
}
@@ -495,11 +524,10 @@ abstract class ConfigModule
* Will be called if the server's IP address changes. The event will be propagated
* to all config module classes so action can be taken if appropriate.
*/
- public static function serverIpChanged()
+ public static function serverIpChanged(): void
{
self::loadDb();
- $list = self::getAll();
- foreach ($list as $mod) {
+ foreach (self::getAll() ?? [] as $mod) {
$mod->event_serverIpChanged();
}
}
@@ -508,53 +536,51 @@ abstract class ConfigModule
* Called when (re)generating a config module failed, so we can
* update the status in the DB and add a server log entry.
*
- * @param array $task
- * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz'
+ * @param array $args contains 'moduleid' and optionally 'deleteOnError'
*/
- public static function generateFailed($task, $args)
+ public static function generateFailed(array $task, array $args): void
{
if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) {
EventLog::warning('Ignoring generateFailed event as it has no moduleid assigned.');
return;
}
$module = self::get($args['moduleid']);
- if ($module === false) {
+ if ($module === null) {
EventLog::warning('generateFailed callback for module id ' . $args['moduleid'] . ', but no instance could be generated.');
return;
}
- if (isset($task['data']['error']))
+ if (isset($task['data']['error'])) {
$error = $task['data']['error'];
- elseif (isset($task['data']['messages']))
+ } elseif (isset($task['data']['messages'])) {
$error = $task['data']['messages'];
- else
+ } else {
$error = '';
+ }
EventLog::failure("Generating module '" . $module->moduleTitle . "' failed.", $error);
- if ($args['deleteOnError'])
+ if ($args['deleteOnError'] ?? false) {
$module->delete();
- else
+ } else {
$module->markFailed();
+ }
}
/**
* (Re)generating a config module succeeded. Update db entry.
*
- * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz'
+ * @param array $args contains 'moduleid' and optionally 'tmpTgz'
*/
- public static function generateSucceeded($args)
+ public static function generateSucceeded(array $args): void
{
if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) {
EventLog::warning('Ignoring generateSucceeded event as it has no moduleid assigned.');
return;
}
$module = self::get($args['moduleid']);
- if ($module === false) {
+ if ($module === null) {
EventLog::warning('generateSucceeded callback for module id ' . $args['moduleid'] . ', but no instance could be generated.');
return;
}
- if (isset($args['tmpTgz']))
- $module->markUpdated($args['tmpTgz']);
- else
- $module->markUpdated(false);
+ $module->markUpdated($args['tmpTgz'] ?? null);
}
}
diff --git a/modules-available/sysconfig/inc/configmodule/branding.inc.php b/modules-available/sysconfig/inc/configmodule/branding.inc.php
index 8990dbec..7013e3ae 100644
--- a/modules-available/sysconfig/inc/configmodule/branding.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/branding.inc.php
@@ -14,34 +14,34 @@ class ConfigModule_Branding extends ConfigModule
const MODID = 'Branding';
const VERSION = 1;
-
+
+ /** @var false|string */
private $tmpFile = false;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig()) {
- return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
+ return !empty($this->archive()) && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
}
- $task = Taskmanager::submit('MoveFile', array(
+ return Taskmanager::submit('MoveFile', array(
'source' => $this->tmpFile,
'destination' => $tgz,
'parentTask' => $parent,
'failOnParentFail' => false
));
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
return $this->tmpFile !== false && file_exists($this->tmpFile);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
if ($key !== 'tmpFile' || !is_string($value) || !file_exists($value))
return false;
@@ -49,12 +49,12 @@ class ConfigModule_Branding extends ConfigModule
return true;
}
- public function getData($key)
+ public function getData(?string $key): bool
{
return false;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return true;
}
diff --git a/modules-available/sysconfig/inc/configmodule/customodule.inc.php b/modules-available/sysconfig/inc/configmodule/customodule.inc.php
index 3c10bada..0b8e38d2 100644
--- a/modules-available/sysconfig/inc/configmodule/customodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/customodule.inc.php
@@ -12,48 +12,62 @@ ConfigModule::registerModule(
class ConfigModule_CustomModule extends ConfigModule
{
const MODID = 'CustomModule';
- const VERSION = 1;
-
+ const VERSION = 2;
+
+ /** @var false|string */
private $tmpFile = false;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig()) {
- return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
+ // No temp file given from wizard
+ // Old archive still exists? pretend it worked...
+ if ($this->archive() === '' || !file_exists($this->archive()))
+ return false;
+ if ($this->currentVersion() == 1) {
+ // Need an upgrade
+ return Taskmanager::submit('RecompressArchive', array(
+ 'inputFiles' => [$this->archive() => false],
+ 'outputFile' => $tgz,
+ 'forceRoot' => true, // Force this for old modules for backward compat
+ ));
+ }
+ // Nothing to do
+ return true;
}
- $task = Taskmanager::submit('MoveFile', array(
+ return Taskmanager::submit('MoveFile', array(
'source' => $this->tmpFile,
'destination' => $tgz,
'parentTask' => $parent,
'failOnParentFail' => false
));
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
return $this->tmpFile !== false && file_exists($this->tmpFile);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
+ // Sets the temp file from the wizard, where it stored the processed archive
if ($key !== 'tmpFile' || !file_exists($value))
return false;
$this->tmpFile = $value;
return true;
}
- public function getData($key)
+ public function getData(?string $key): bool
{
return false;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return true;
}
diff --git a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
index 7af4671e..64af4c0e 100644
--- a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
@@ -5,7 +5,7 @@ class ConfigModule_LdapAuth extends ConfigModuleBaseLdap
const MODID = 'LdapAuth';
- protected function preTaskmanagerHook(&$config)
+ protected function preTaskmanagerHook(array &$config)
{
// Just set the flag so the taskmanager job knows we're dealing with a normal ldap server,
// not AD scheme
diff --git a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
index ed97941e..1797331c 100644
--- a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
@@ -14,7 +14,7 @@ class ConfigModule_Screensaver extends ConfigModule
const MODID = 'Screensaver';
const VERSION = 1;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
/* Validate if all data are available */
if (!$this->validateConfig())
@@ -23,30 +23,27 @@ class ConfigModule_Screensaver extends ConfigModule
/* Give the Taskmanager the job and create the tgz */
$taskId = 'xscreensaver' . mt_rand() . '-' . microtime(true);
- $task = Taskmanager::submit('MakeTarball', array(
+ return Taskmanager::submit('MakeTarball', array(
'id' => $taskId,
'files' => $this->getFileArray(),
'destination' => $tgz,
), false);
-
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
- return isset($this->moduleData['qss']) &&
- isset($this->moduleData['texts']) &&
- isset($this->moduleData['texts']['text-idle-kill']) &&
- isset($this->moduleData['texts']['text-no-timeout']) &&
- isset($this->moduleData['texts']['text-shutdown']);
+ return isset($this->moduleData['texts']['text-no-timeout'])
+ && isset($this->moduleData['texts']['text-idle-kill'])
+ && isset($this->moduleData['texts']['text-shutdown'])
+ && isset($this->moduleData['qss']);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
switch ($key) {
case 'qss':
@@ -60,17 +57,15 @@ class ConfigModule_Screensaver extends ConfigModule
return true;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return false;
}
/**
* Creates a map with filepath => file content
- *
- * @return array in the form of Map<String, byte[]>
*/
- private function getFileArray()
+ private function getFileArray(): array
{
$files = array(
'/opt/openslx/xscreensaver/style.qss' => $this->moduleData['qss'],
@@ -100,7 +95,7 @@ class ConfigModule_Screensaver extends ConfigModule
return $files;
}
- private function wrapHtmlTags($text_name)
+ private function wrapHtmlTags(string $text_name): string
{
return '<html><body>' . $this->moduleData['texts'][$text_name] . '</body></html>';
}
diff --git a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
index b5ab20e4..a62d1035 100644
--- a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
@@ -14,7 +14,7 @@ class ConfigModule_SshConfig extends ConfigModule
const MODID = 'SshConfig';
const VERSION = 1;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig())
return false;
@@ -26,12 +26,12 @@ class ConfigModule_SshConfig extends ConfigModule
return Taskmanager::submit('SshdConfigGenerator', $config);
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
// UPGRADE
if (isset($this->moduleData['allowPasswordLogin']) && !isset($this->moduleData['allowedUsersLogin'])) {
@@ -45,7 +45,7 @@ class ConfigModule_SshConfig extends ConfigModule
&& isset($this->moduleData['listenPort']);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
switch ($key) {
case 'publicKey':
diff --git a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
index 2d212d25..e4a55ad7 100644
--- a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
@@ -14,7 +14,7 @@ class ConfigModule_SshKey extends ConfigModule
const MODID = 'SshKey';
const VERSION = 1;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig())
return false;
@@ -30,17 +30,17 @@ class ConfigModule_SshKey extends ConfigModule
return Taskmanager::submit('MakeTarball', $config);
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
return isset($this->moduleData['publicKey']);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
switch ($key) {
case 'publicKey':
diff --git a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
index 39f4f68e..770a40e6 100644
--- a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
+++ b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
@@ -3,15 +3,15 @@
abstract class ConfigModuleBaseLdap extends ConfigModule
{
- const VERSION = 3;
+ const VERSION = 4;
private static $REQUIRED_FIELDS = array('server', 'searchbase');
- private static $OPTIONAL_FIELDS = array('binddn', 'bindpw', 'home', 'ssl', 'fixnumeric', 'fingerprint', 'certificate', 'homeattr',
+ private static $OPTIONAL_FIELDS = array('binddn', 'bindpw', 'home', 'ssl', 'fingerprint', 'certificate', 'homeattr',
'shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop', 'shareMedia',
'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough', 'mapping', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts', 'nohomewarn');
- public static function getMapping($config = false, &$empty = true)
+ public static function getMapping(array $config = null, ?bool &$empty = true): array
{
$list = array(
['name' => 'uid', 'field' => 'uid', 'ad' => 'sAMAccountName'],
@@ -46,10 +46,10 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
*
* @param string $command start, restart, check
* @param bool|int|int[] $ids list of IDs to run command on, or false meaning "all"
- * @param string $parent if not NULL, this will be the parent task of the launch-task
+ * @param string|null $parent if not NULL, this will be the parent task of the launch-task
* @return boolean|string false on error, id of task otherwise
*/
- public static function ldadp($command = 'start', $ids = false, $parent = null)
+ public static function ldadp(string $command = 'start', $ids = false, string $parent = null)
{
if ($ids === false) {
$ids = self::getActiveModuleIds();
@@ -67,7 +67,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
return $task['id'];
}
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
$config = $this->moduleData;
if (isset($config['certificate']) && !is_string($config['certificate'])) {
@@ -95,15 +95,14 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
if (!isset($config['shareHomeDrive'])) {
$config['shareHomeDrive'] = 'H:';
}
- if (!isset($config['fixnumeric'])) {
- $config['fixnumeric'] = 's';
- }
- $config['genuid'] = isset($config['genuid']) && !empty($config['genuid']);
+ // This is now always on, as we mask it transparently in our lightdm greeter
+ $config['fixnumeric'] = 'true';
+ $config['genuid'] = !empty($config['genuid']);
$config['nohomewarn'] = isset($config['nohomewarn']) ? (int)$config['nohomewarn'] : 0;
$this->preTaskmanagerHook($config);
$task = Taskmanager::submit('CreateLdapConfig', $config);
if (is_array($task) && isset($task['id'])) {
- self::ldadp('restart', $this->id(), $task['id']); // TODO: Use --restart for this one only
+ self::ldadp('restart', $this->id(), $task['id']);
}
return $task;
}
@@ -112,25 +111,23 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
* Hook called before running CreateLdapConfig task with the
* configuration to be passed to the task. Passed by reference
* so it can be modified.
- *
- * @param array $config
*/
- protected function preTaskmanagerHook(&$config)
+ protected function preTaskmanagerHook(array &$config)
{
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
// Check if required fields are filled
- return Util::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS);
+ return ArrayUtil::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
if (!in_array($key, self::$REQUIRED_FIELDS) && !in_array($key, self::$OPTIONAL_FIELDS))
return false;
@@ -143,7 +140,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
/**
* Server IP changed - rebuild all AD modules.
*/
- public function event_serverIpChanged()
+ public function event_serverIpChanged(): void
{
$this->generate(false);
}
diff --git a/modules-available/sysconfig/inc/configtgz.inc.php b/modules-available/sysconfig/inc/configtgz.inc.php
index 98f29753..8ac87908 100644
--- a/modules-available/sysconfig/inc/configtgz.inc.php
+++ b/modules-available/sysconfig/inc/configtgz.inc.php
@@ -4,29 +4,28 @@ class ConfigTgz
{
private $configId = 0;
- private $configTitle = false;
- private $file = false;
+ private $configTitle = '';
+ private $file = '';
private $modules = array();
private function __construct()
{
- ;
}
- public function id()
+ public function id(): int
{
return $this->configId;
}
- public function title()
+ public function title(): string
{
return $this->configTitle;
}
- public function areAllModulesUpToDate()
+ public function areAllModulesUpToDate(): bool
{
if (!$this->configId > 0)
- Util::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!');
+ ErrorHandler::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!');
foreach ($this->modules as $module) {
if (!empty($module['filepath']) && file_exists($module['filepath'])) {
if ($module['status'] !== 'OK')
@@ -38,24 +37,29 @@ class ConfigTgz
return true;
}
- public function isActive()
+ public function isActive(): bool
{
return readlink(CONFIG_HTTP_DIR . '/default/config.tgz') === $this->file;
}
-
- public function getModuleIds()
+
+ /**
+ * @return int[]
+ */
+ public function getModuleIds(): array
{
- $ret = array();
+ $ret = [];
foreach ($this->modules as $module) {
- $ret[] = $module['moduleid'];
+ $ret[] = (int)$module['moduleid'];
}
return $ret;
}
-
- public function update($title, $moduleIds)
+
+ /**
+ * @param string $title New title for module
+ * @param int[] $moduleIds List of modules to include in this config
+ */
+ public function update(string $title, array $moduleIds): void
{
- if (!is_array($moduleIds))
- return false;
if (!empty($title)) {
$this->configTitle = $title;
}
@@ -69,7 +73,7 @@ class ConfigTgz
// Delete old connections
Database::exec("DELETE FROM configtgz_x_module WHERE configid = :configid", array('configid' => $this->configId));
// Make connection
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array(
'configid' => $this->configId,
'moduleid' => $row['moduleid']
@@ -83,20 +87,19 @@ class ConfigTgz
'status' => 'OUTDATED',
'now' => time(),
));
- return true;
}
/**
*
- * @param bool $deleteOnError
- * @param int $timeoutMs
- * @param string|null $parentTask parent task to order this rebuild after
+ * @param bool $deleteOnError Delete this config in case of error?
+ * @param int $timeoutMs max time to wait for completion
+ * @param string|null $parentTask parent task to order this (re)build after
* @return string|bool true=success, false=error, string=taskid, still running
*/
- public function generate($deleteOnError = false, $timeoutMs = 0, $parentTask = null)
+ public function generate(bool $deleteOnError = false, int $timeoutMs = 0, ?string $parentTask = null)
{
- if (!($this->configId > 0) || !is_array($this->modules) || $this->file === false)
- Util::traceError ('configId <= 0 or modules not array in ConfigTgz::rebuild()');
+ if (!($this->configId > 0) || empty($this->file))
+ ErrorHandler::traceError('configId <= 0 or no file in ConfigTgz::rebuild()');
$files = array();
// Get all config modules for system config
foreach ($this->modules as $module) {
@@ -134,33 +137,34 @@ class ConfigTgz
return $task['id'];
}
- public function delete()
+ public function delete(): bool
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::delete called with invalid config id!');
+ ErrorHandler::traceError('ConfigTgz::delete called with invalid config id!');
$ret = Database::exec("DELETE FROM configtgz WHERE configid = :configid LIMIT 1",
['configid' => $this->configId], true);
if ($ret !== false) {
- if ($this->file !== false)
+ if (!empty($this->file)) {
Taskmanager::submit('DeleteFile', array('file' => $this->file), true);
+ }
$this->configId = 0;
- $this->modules = false;
- $this->file = false;
+ $this->modules = [];
+ $this->file = '';
}
return $ret !== false;
}
- public function markOutdated()
+ public function markOutdated(): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markOutdated called with invalid config id!');
- return $this->mark('OUTDATED');
+ ErrorHandler::traceError('ConfigTgz::markOutdated called with invalid config id!');
+ $this->mark('OUTDATED');
}
- private function markUpdated($task)
+ private function markUpdated(array $task): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markUpdated called with invalid config id!');
+ ErrorHandler::traceError('ConfigTgz::markUpdated called with invalid config id!');
if ($this->areAllModulesUpToDate()) {
if (empty($task['data']['warnings'])) {
$warnings = '';
@@ -170,7 +174,7 @@ class ConfigTgz
// Get mapping of moduleid to module name for prettier log display
$res = Database::simpleQuery('SELECT moduleid, title FROM configtgz_module');
$mods = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$mods[$row['moduleid']] = $row['title'];
}
// Now extract module id from filename and if applicable, replace filename by module name
@@ -186,27 +190,28 @@ class ConfigTgz
'status' => 'OK',
'warnings' => $warnings,
]);
- return 'OK';
+ return;
}
- return $this->mark('OUTDATED');
+ $this->mark('OUTDATED');
}
- private function markFailed()
+ private function markFailed(): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markFailed called with invalid config id!');
- if ($this->file === false || !file_exists($this->file))
- return $this->mark('MISSING');
- return $this->mark('OUTDATED');
+ ErrorHandler::traceError('ConfigTgz::markFailed called with invalid config id!');
+ if (empty($this->file) || !file_exists($this->file)) {
+ $this->mark('MISSING');
+ } else {
+ $this->mark('OUTDATED');
+ }
}
- private function mark($status)
+ private function mark($status): void
{
Database::exec("UPDATE configtgz SET status = :status WHERE configid = :configid LIMIT 1", [
'configid' => $this->configId,
'status' => $status,
]);
- return $status;
}
/*
@@ -218,12 +223,12 @@ class ConfigTgz
* @param string $destFile where to store final result
* @return false|array taskmanager task
*/
- private static function recompress($files, $destFile, $parentTask = null)
+ private static function recompress(array $files, string $destFile, $parentTask = null)
{
// Get stuff other modules want to inject
$handler = function($hook) {
include $hook->file;
- return isset($file) ? $file : false;
+ return $file ?? false;
};
foreach (Hook::load('config-tgz') as $hook) {
$file = $handler($hook);
@@ -246,15 +251,15 @@ class ConfigTgz
* on each one. This mostly makes sense to call if a global module
* that is injected via a hook has changed.
*/
- public static function rebuildAllConfigs()
+ public static function rebuildAllConfigs(): void
{
Database::exec("UPDATE configtgz SET status = :status", array(
'status' => 'OUTDATED'
));
$res = Database::simpleQuery("SELECT configid FROM configtgz");
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$configTgz = self::get($row['configid']);
- if ($configTgz !== false) {
+ if ($configTgz !== null) {
$configTgz->generate();
}
}
@@ -263,12 +268,10 @@ class ConfigTgz
/**
* @param string $title Title of config
* @param int[] $moduleIds Modules to include in config
- * @return false|ConfigTgz The module instance, false on error
+ * @return ConfigTgz The module instance
*/
- public static function insert($title, $moduleIds)
+ public static function insert(string $title, array $moduleIds): ConfigTgz
{
- if (!is_array($moduleIds))
- return false;
$instance = new ConfigTgz;
$instance->configTitle = $title;
// Create output file name (config.tgz)
@@ -290,7 +293,7 @@ class ConfigTgz
}
$res = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_module WHERE moduleid IN ($idstr)");
// Make connection
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array(
'configid' => $instance->configId,
'moduleid' => $row['moduleid']
@@ -300,53 +303,53 @@ class ConfigTgz
return $instance;
}
- public static function get($configId)
+ /**
+ * @param array{configid: int, title: string, filepath: string} $row Input data, fields mandatory
+ */
+ private static function instanceFromRow(array $row): ConfigTgz
{
- $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array(
- 'configid' => $configId
- ));
- if ($ret === false)
- return false;
$instance = new ConfigTgz;
- $instance->configId = $ret['configid'];
- $instance->configTitle = $ret['title'];
- $instance->file = $ret['filepath'];
- $ret = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
+ $instance->configId = $row['configid'];
+ $instance->configTitle = $row['title'];
+ $instance->file = $row['filepath'];
+ $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
. " INNER JOIN configtgz_module USING (moduleid) "
. " WHERE configid = :configid", array('configid' => $instance->configId));
$instance->modules = array();
- while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
- $instance->modules[] = $row;
+ foreach ($innerRes as $innerRow) {
+ $instance->modules[] = $innerRow;
}
return $instance;
}
+ public static function get(int $configId): ?ConfigTgz
+ {
+ $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array(
+ 'configid' => $configId
+ ));
+ if ($ret === false)
+ return null;
+ return self::instanceFromRow($ret);
+ }
+
/**
* @param int $moduleId ID of config module
- * @return ConfigTgz[]|false
+ * @return ConfigTgz[]
*/
- public static function getAllForModule($moduleId)
+ public static function getAllForModule(int $moduleId): array
{
$res = Database::simpleQuery("SELECT configid, title, filepath FROM configtgz_x_module "
. " INNER JOIN configtgz USING (configid) "
. " WHERE moduleid = :moduleid", array(
'moduleid' => $moduleId
));
- if ($res === false)
- return false;
+ if ($res === false) {
+ EventLog::warning('ConfigTgz::getAllForModule failed: ' . Database::lastError());
+ return [];
+ }
$list = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $instance = new ConfigTgz;
- $instance->configId = $row['configid'];
- $instance->configTitle = $row['title'];
- $instance->file = $row['filepath'];
- $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
- . " INNER JOIN configtgz_module USING (moduleid) "
- . " WHERE configid = :configid", array('configid' => $instance->configId));
- $instance->modules = array();
- while ($innerRow = $innerRes->fetch(PDO::FETCH_ASSOC)) {
- $instance->modules[] = $innerRow;
- }
+ foreach ($res as $row) {
+ $instance = self::instanceFromRow($row);
$list[] = $instance;
}
return $list;
@@ -356,31 +359,32 @@ class ConfigTgz
* Called when (re)generating a config tgz failed, so we can
* update the status in the DB and add a server log entry.
*
- * @param array $task
* @param array $args contains 'configid' and optionally 'deleteOnError'
*/
- public static function generateFailed($task, $args)
+ public static function generateFailed(array $task, array $args): void
{
if (!isset($args['configid']) || !is_numeric($args['configid'])) {
EventLog::warning('Ignoring generateFailed event as it has no configid assigned.');
return;
}
$config = self::get($args['configid']);
- if ($config === false) {
+ if ($config === null) {
EventLog::warning('generateFailed callback for config id ' . $args['configid'] . ', but no instance could be generated.');
return;
}
- if (isset($task['data']['error']))
+ if (isset($task['data']['error'])) {
$error = $task['data']['error'];
- elseif (isset($task['data']['messages']))
+ } elseif (isset($task['data']['messages'])) {
$error = $task['data']['messages'];
- else
+ } else {
$error = '';
+ }
EventLog::failure("Generating config.tgz '" . $config->configTitle . "' failed.", $error);
- if ($args['deleteOnError'])
+ if ($args['deleteOnError']) {
$config->delete();
- else
+ } else {
$config->markFailed();
+ }
}
/**
@@ -389,14 +393,14 @@ class ConfigTgz
* @param array $task the task object
* @param array $args contains 'configid' and optionally 'deleteOnError'
*/
- public static function generateSucceeded($task, $args)
+ public static function generateSucceeded(array $task, array $args): void
{
if (!isset($args['configid']) || !is_numeric($args['configid'])) {
EventLog::warning('Ignoring generateSucceeded event as it has no configid assigned.');
return;
}
$config = self::get($args['configid']);
- if ($config === false) {
+ if ($config === null) {
EventLog::warning('generateSucceeded callback for config id ' . $args['configid'] . ', but no instance could be generated.');
return;
}
diff --git a/modules-available/sysconfig/inc/ldap.inc.php b/modules-available/sysconfig/inc/ldap.inc.php
index 349a662e..e974a8a3 100644
--- a/modules-available/sysconfig/inc/ldap.inc.php
+++ b/modules-available/sysconfig/inc/ldap.inc.php
@@ -3,7 +3,7 @@
class Ldap
{
- public static function normalizeDn($dn)
+ public static function normalizeDn(string $dn): string
{
return trim(preg_replace('/[,;]\s*/', ',', $dn));
}
diff --git a/modules-available/sysconfig/inc/ppd.inc.php b/modules-available/sysconfig/inc/ppd.inc.php
index 9bd5d171..c28e0355 100644
--- a/modules-available/sysconfig/inc/ppd.inc.php
+++ b/modules-available/sysconfig/inc/ppd.inc.php
@@ -247,8 +247,8 @@ class Ppd
private $data;
private $dataLen;
- private $error;
- private $warnings;
+ private $error = null;
+ private $warnings = [];
private $knownKeywordMalformed;
@@ -301,16 +301,16 @@ class Ppd
$this->dataLen = strlen($this->data);
$this->encoder = false;
$this->sourceEncoding = false;
- $this->error = false;
+ $this->error = null;
$this->warnings = array();
$this->knownKeywordMalformed = false;
$this->settings = array();
$this->requiredKeywords = array();
// Parse
- /* @var $rawOption \PpdOption */
- /* @var $currentBlock \PpdBlockInternal */
- $currentBlock = false;
+ /* @var PpdOption $rawOption */
+ /* @var ?PpdBlockInternal $currentBlock */
+ $currentBlock = null;
$inRawBlock = false; // True if in a multi-line InvocationValue or QuotedValue (3.6: Parsing Summary for Values)
$wantsEnd = false;
// For now we ignore values mostly while parsing. The spec says that InvocationValues must only contain printable
@@ -318,9 +318,9 @@ class Ppd
$lStart = -1;
$lEnd = -1;
$no = 0;
- while ($lStart < $this->dataLen && $lEnd !== false) {
+ while ($lStart < $this->dataLen) {
unset($mainKeyword, $optionKeyword, $optionTranslation, $option, $value, $valueTranslation);
- if ($no !== 0 && $this->data{$lEnd} === "\r" && $this->data{$lEnd + 1} === "\n") {
+ if ($no !== 0 && $this->data[$lEnd] === "\r" && $this->data[$lEnd + 1] === "\n") {
$lEnd++;
}
if ($no === 1) {
@@ -332,6 +332,8 @@ class Ppd
}
$lStart = $lEnd + 1;
$lEnd = $this->nextLineEnd($lStart);
+ if ($lEnd === null)
+ break;
$no++;
// Validate
$len = $lEnd - $lStart;
@@ -343,7 +345,7 @@ class Ppd
$this->warn($no, 'Exceeds length of 255');
}
if (!$inRawBlock && preg_match_all('/[^\x09\x0A\x0D\x20-\xFF]/', $line, $out)) {
- $chars = $this->escapeBinaryArray($out[0]);
+ $chars = self::escapeBinaryArray($out[0]);
$this->warn($no, 'Contains invalid character(s) ' . $chars);
}
// Handle
@@ -373,13 +375,13 @@ class Ppd
}
}
// 3) Handle "key [option]: value"
- if ($line{0} === '*') {
- if ($line{1} === '%') {
+ if ($line[0] === '*') {
+ if ($line[1] === '%') {
// Skip comment
continue;
}
$parts = preg_split('/\s*:\s*/', $line, 2); // TODO: UIConstrains
- if (count($parts) !== 2) {
+ if (!is_array($parts) || count($parts) !== 2) {
$this->warn($no, 'No colon found; not in "key [option]: value" format, ignoring line');
continue;
}
@@ -390,11 +392,12 @@ class Ppd
continue;
}
$mainKeyword = $out[1];
- $optionKeyword = isset($out[3]) ? $out[3] : false;
+ $optionKeyword = $out[3] ?? null;
$optionTranslation = isset($out[4]) ? $this->unhexTranslation($no, substr($out[4], 1)) : $optionKeyword; // If no translation given, fallback to option
// 3b) Handle value
+ /** @var string $value */
$value = $parts[1];
- if ($value{0} === '"') {
+ if ($value[0] === '"') {
// Start of InvocationValue or QuotedValue
if (preg_match(',^"([^"]*)"(/.*)?$,', $value, $vMatch)) {
// Single line
@@ -419,28 +422,23 @@ class Ppd
// Key-value-pair parsed, now the fun part
// Special cases for opening closing certain groups
if ($mainKeyword === 'OpenGroup') {
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$this->error = 'Line ' . $no . ': OpenGroup while other block (type=' . $currentBlock->type
. ', id=' . $currentBlock->id . ') was not closed yet';
return;
}
// TODO: Check unique
- $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', $currentBlock, $lStart);
- if ($currentBlock !== false) {
- $currentBlock->childBlocks[] = $nb;
- }
+ $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', null, $lStart);
$currentBlock = $nb;
continue;
} elseif ($mainKeyword === 'OpenSubGroup') {
- if ($currentBlock === false || $currentBlock->type !== 'Group') {
+ if ($currentBlock === null || $currentBlock->type !== 'Group') {
$this->error = 'Line ' . $no . ': OpenSubGroup with no preceding OpenGroup';
return;
}
// TODO: Check unique
$nb = new PpdBlockInternal($value, $valueTranslation, 'SubGroup', $currentBlock, $lStart);
- if ($currentBlock !== false) {
- $currentBlock->childBlocks[] = $nb;
- }
+ $currentBlock->childBlocks[] = $nb;
$currentBlock = $nb;
continue;
} elseif ($mainKeyword === 'OpenUI' || $mainKeyword === 'JCLOpenUI') {
@@ -450,23 +448,24 @@ class Ppd
} else {
$type = substr($type, 4);
}
- if ($currentBlock !== false && $currentBlock->isUi()) {
+ if ($currentBlock !== null && $currentBlock->isUi()) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' while previous ' . $type . ' "'
. $currentBlock->id . '" was not closed yet';
return;
}
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no option keyword';
return;
}
- if ($optionKeyword{0} !== '*') {
+ if ($optionKeyword[0] !== '*') {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . " with option keyword that doesn't start with asterisk (*).";
return;
}
// TODO: Check unique
- $nb = new PpdBlockInternal($optionKeyword, $optionTranslation, $type, $currentBlock, $lStart);
+ $nb = new PpdBlockInternal($optionKeyword, $optionTranslation ?? $optionKeyword,
+ $type, $currentBlock, $lStart);
$nb->value = $value;
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$currentBlock->childBlocks[] = $nb;
}
$currentBlock = $nb;
@@ -481,7 +480,7 @@ class Ppd
} else {
$type = substr($type, 5);
}
- if ($currentBlock === false) {
+ if ($currentBlock === null) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no Open' . $type;
return;
}
@@ -498,7 +497,7 @@ class Ppd
$currentBlock = $currentBlock->parent;
continue;
} elseif ($mainKeyword === 'OrderDependency') {
- if ($currentBlock === false || $currentBlock->isUi()) {
+ if ($currentBlock === null || $currentBlock->isUi()) {
$this->warn($no, 'OrderDependency outside OpenUI/CloseUI block');
}
continue;
@@ -521,9 +520,10 @@ class Ppd
$this->warn($no, 'Required keyword ' . $mainKeyword . ' declared twice, ignoring');
continue;
}
+ } else {
+ $this->requiredKeywords[$mainKeyword] = array($value);
}
- $this->requiredKeywords[$mainKeyword] = array($value);
- if (($err = $this->validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
+ if (($err = Ppd::validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
$this->warn($no, 'Required main keyword ' . $mainKeyword . ': ' . $err);
$this->knownKeywordMalformed = true;
}
@@ -531,7 +531,7 @@ class Ppd
}
// Other well known keywords
if (isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
- if (($err = $this->validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
+ if (($err = Ppd::validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
$this->warn($no, 'Known main keyword ' . $mainKeyword . ': ' . $err);
$this->knownKeywordMalformed = true;
}
@@ -541,17 +541,18 @@ class Ppd
$option = $this->getOption(substr($mainKeyword, 7), $currentBlock);
$option->default = new PpdOption($lStart, $len, $value, $valueTranslation);
continue;
- } elseif (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') {
- if ($optionKeyword === false) {
+ }
+ if (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
- } elseif ($currentBlock !== false && isset($this->settings[$optionKeyword])) {
+ } elseif ($currentBlock !== null && isset($this->settings[$optionKeyword])) {
$option = $this->getOption($optionKeyword, $currentBlock);
$option->foomatic[substr($mainKeyword, 11)] = new PpdOption($lStart, $len, $value, $valueTranslation);
} else {
$this->warn($no, 'TODO: ' . $line);
}
} elseif (substr($mainKeyword, 0, 6) === 'Custom') {
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
} elseif ($optionKeyword !== 'True') {
$this->warn($no, "$mainKeyword with option keyword other than 'True'; ignored");
@@ -560,7 +561,7 @@ class Ppd
$option->custom = new PpdOption($lStart, $len, $value, $valueTranslation);
}
} elseif (substr($mainKeyword, 0, 11) === 'ParamCustom') {
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
} elseif (substr($mainKeyword, 11) !== $optionKeyword) {
$this->warn($no, "Don't know how to handle $mainKeyword with option keyword $optionKeyword "
@@ -569,20 +570,20 @@ class Ppd
$option = $this->getOption($optionKeyword, $currentBlock);
$option->customParam = new PpdOption($lStart, $len, $value, $valueTranslation);
}
- } elseif ($mainKeyword{0} === '?') {
+ } elseif ($mainKeyword[0] === '?') {
// Ignoring option query for now
- } elseif ($optionKeyword === false && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
+ } elseif ($optionKeyword === null && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
// Must be a definition for an option
$this->warn($no, "Don't know how to handle line with main keyword '$mainKeyword', no option keyword found.");
} else {
// Some option for some option ;)
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
// We know that this is a known main keyword otherwise we would have hit the previous elseif block
$optionKeyword = $value;
$optionTranslation = $valueTranslation;
}
$option = $this->getOption($mainKeyword, $currentBlock);
- $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation);
+ $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation ?? $optionKeyword);
if ($this->binary_in_array($mainKeyword, $this->REPEATED_KEYWORDS)) {
// This can occur multiple times, just pile them up
$option->values[] = $optionInstance;
@@ -603,9 +604,9 @@ class Ppd
} elseif (strlen(trim($line)) !== 0) {
$this->warn($no, 'Invalid format; not empty and not starting with asterisk (*)');
}
- }
+ } // end while loop over ppd contents
//
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$this->error = 'Block ' . $currentBlock->id . ' (' . $currentBlock->type . ') was never closed.';
return;
}
@@ -615,11 +616,11 @@ class Ppd
$this->error = 'One or more required keywords missing';
}
}
- if ($this->error !== false) {
+ if ($this->error !== null) {
return;
}
// All required keywords exist
- if (preg_match('/utf\-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) {
+ if (preg_match('/utf-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) {
$this->sourceEncoding = false; // Would be a NOOP
} elseif (isset($this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]])) {
$this->sourceEncoding = $this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]];
@@ -669,12 +670,12 @@ class Ppd
}
}
- private function nextLineEnd($start)
+ private function nextLineEnd(int $start): ?int
{
if ($start >= $this->dataLen)
- return false;
+ return null;
while ($start < $this->dataLen) {
- $char = $this->data{$start};
+ $char = $this->data[$start];
if ($char === "\r" || $char === "\n")
return $start;
++$start;
@@ -682,27 +683,26 @@ class Ppd
return $this->dataLen;
}
- private function warn($lineNo, $message)
+ private function warn(int $lineNo, string $message): void
{
$line = 'Line ' . $lineNo . ': ' . $message;
$this->warnings[] = $line;
}
- private function escapeBinaryArray($array)
+ private static function escapeBinaryArray(array $array): string
{
- $chars = array_reduce(array_unique($array), function ($carry, $item) {
+ return array_reduce(array_unique($array), function ($carry, $item) {
return $carry . '\x' . dechex(ord($item));
}, '');
- return $chars;
}
- private function unhexTranslation($lineNo, $translation)
+ private function unhexTranslation(int $lineNo, string $translation): string
{
if (strpos($translation, '<') === false)
return $translation;
return preg_replace_callback('/<[^>]*>/', function ($match) use ($lineNo) {
if (preg_match_all('/[^a-fA-F0-9\<\>\s]/', $match[0], $out)) {
- $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . $this->escapeBinaryArray($out[0]));
+ $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . self::escapeBinaryArray($out[0]));
}
$string = preg_replace('/[^a-fA-F0-9]/', '', $match[0]);
if (strlen($string) % 2 !== 0) {
@@ -713,7 +713,7 @@ class Ppd
}, $translation);
}
- private function hexTranslation($translation)
+ private function hexTranslation(string $translation): string
{
return preg_replace_callback('/[\x00-\x1f\x7b-\xff\:\<\>]+/', function ($match) {
return '<' . unpack('H*', $match[0])[1] . '>';
@@ -724,23 +724,23 @@ class Ppd
* Get option object
*
* @param string $name option name
- * @param \PpdBlockInternal $block which block this option is defined in
- * @return \PpdSettingInternal the option object
+ * @param ?PpdBlockInternal $block which block this option is defined in
+ * @return PpdSettingInternal the option object
*/
- private function getOption($name, $block = false)
+ private function getOption(string $name, ?PpdBlockInternal $block = null): PpdSettingInternal
{
if (!isset($this->settings[$name])) {
$this->settings[$name] = new PpdSettingInternal();
$this->settings[$name]->block = $block;
- } elseif ($block !== false) {
- if ($this->settings[$name]->block === false || $block->isChildOf($this->settings[$name]->block)) {
+ } elseif ($block !== null) {
+ if ($this->settings[$name]->block === null || $block->isChildOf($this->settings[$name]->block)) {
$this->settings[$name]->block = $block;
}
}
return $this->settings[$name];
}
- private function binary_in_array($elem, $array)
+ private function binary_in_array($elem, $array): bool
{
$top = sizeof($array) - 1;
$bot = 0;
@@ -755,7 +755,7 @@ class Ppd
return false;
}
- private function validateLine($validator, $option, $value)
+ private static function validateLine($validator, ?string $option, string $value)
{
if (is_array($validator)) {
$oExp = $validator[0];
@@ -780,7 +780,7 @@ class Ppd
return true;
}
- private function getEolChar()
+ private function getEolChar(): string
{
$rn = substr_count("\r\n", $this->data);
$r = substr_count("\r", $this->data) - $rn;
@@ -799,21 +799,21 @@ class Ppd
*
*/
- public function getError()
+ public function getError(): ?string
{
return $this->error;
}
- public function getWarnings()
+ public function getWarnings(): array
{
return $this->warnings;
}
- public function getUISettings()
+ public function getUISettings(): array
{
$result = array();
foreach ($this->settings as $mk => $option) {
- $isUi = ($option->block !== false && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]);
+ $isUi = ($option->block !== null && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]);
if ($isUi) {
$result[] = $mk;
}
@@ -821,30 +821,30 @@ class Ppd
return $result;
}
- public function getSetting($name)
+ public function getSetting(string $name): ?PpdSetting
{
if (!isset($this->settings[$name]))
- return false;
+ return null;
return new PpdSetting($this->settings[$name], isset($this->UI_KEYWORDS[$name]), $this->encoder);
}
- public function removeSetting($name)
+ public function removeSetting(string $name): bool
{
if (!isset($this->settings[$name]))
return false;
$setting = $this->settings[$name];
$ranges = array();
- $this->mergeRanges($ranges, $setting->default);
- $this->mergeRanges($ranges, $setting->custom);
- $this->mergeRanges($ranges, $setting->customParam);
+ Ppd::mergeRangesFromOption($ranges, $setting->default);
+ Ppd::mergeRangesFromOption($ranges, $setting->custom);
+ Ppd::mergeRangesFromOption($ranges, $setting->customParam);
foreach ($setting->foomatic as $obj) {
- $this->mergeRanges($ranges, $obj);
+ Ppd::mergeRangesFromOption($ranges, $obj);
}
foreach ($setting->values as $obj) {
- $this->mergeRanges($ranges, $obj);
+ Ppd::mergeRangesFromOption($ranges, $obj);
}
- if ($setting->block !== false && $setting->block->isUi()) {
- $this->mergeRanges($ranges, $setting->block->start, $setting->block->end);
+ if ($setting->block !== null && $setting->block->isUi()) {
+ Ppd::mergeRanges($ranges, $setting->block->start, $setting->block->end);
}
$tmp = array_map(function ($e) { return $e[0]; }, $ranges);
array_multisort($tmp, SORT_NUMERIC, $ranges);
@@ -853,20 +853,20 @@ class Ppd
foreach ($ranges as $range) {
$new .= substr($this->data, $last, $range[0] - $last);
$last = $range[1];
- if ($this->data{$last} === "\r") {
+ if ($this->data[$last] === "\r") {
$last++;
}
- if ($this->data{$last} === "\n") {
+ if ($this->data[$last] === "\n") {
$last++;
}
}
$new .= substr($this->data, $last);
$this->data = $new;
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function addEmptyOption($settingName, $option, $translation = false, $prepend = true)
+ public function addEmptyOption(string $settingName, string $option, string $translation = null, bool $prepend = true): bool
{
if (!isset($this->settings[$settingName]))
return false;
@@ -874,15 +874,15 @@ class Ppd
$pos = false;
if (!empty($setting->values)) {
if ($prepend) {
- $pos = array_reduce($setting->values, function ($carry, $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX);
+ $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX);
} else {
- $pos = array_reduce($setting->values, function ($carry, $option) { return max($carry, $option->lineOffset); }, 0);
+ $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return max($carry, $option->lineOffset); }, 0);
}
- } elseif ($setting->default !== false) {
+ } elseif ($setting->default !== null) {
$pos = $setting->default->lineOffset;
- } elseif ($setting->block !== false && $setting->block->isUi()) {
+ } elseif ($setting->block !== null && $setting->block->isUi()) {
$pos = $this->nextLineEnd($setting->block->start);
- while ($pos !== false && $pos < $this->dataLen && ($this->data{$pos} === "\r" || $this->data{$pos} === "\n")) {
+ while ($pos !== null && $pos < $this->dataLen && ($this->data[$pos] === "\r" || $this->data[$pos] === "\n")) {
$pos++;
}
}
@@ -890,23 +890,23 @@ class Ppd
return false;
}
$line = '*' . $settingName . ' ' . $option;
- if ($translation !== false) {
+ if ($translation !== null) {
$line .= '/' . $this->hexTranslation(($this->encoder)($translation, true));
}
$eol = $this->getEolChar();
$line .= ': ""' . $eol;
$this->data = substr($this->data, 0, $pos) . $line . substr($this->data, $pos);
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function setDefaultOption($settingName, $optionName)
+ public function setDefaultOption($settingName, $optionName): bool
{
if (!isset($this->settings[$settingName]))
return false;
$setting = $this->settings[$settingName];
$line = '*Default' . $settingName . ': ' . $optionName;
- if ($setting->default !== false) {
+ if ($setting->default !== null) {
$start = $setting->default->lineOffset;
$end = $start + $setting->default->lineLen;
} elseif (empty($setting->values)) {
@@ -918,22 +918,21 @@ class Ppd
}
$this->data = substr($this->data, 0, $start) . $line . substr($this->data, $end);
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function write($file)
+ public function write(string $file)
{
return file_put_contents($file, $this->data);
}
- private function mergeRanges(&$ranges, $start, $end = false)
+ private static function mergeRangesFromOption(array &$ranges, PpdOption $option): void
+ {
+ self::mergeRanges($ranges, $option->lineOffset, $option->lineOffset + $option->lineLen);
+ }
+
+ private static function mergeRanges(array &$ranges, int $start, int $end): void
{
- if (is_object($start) && get_class($start) === 'PpdOption') {
- $end = $start->lineOffset + $start->lineLen;
- $start = $start->lineOffset;
- }
- if ($start === false || $end === false)
- return;
if ($start >= $end)
return; // Don't even bother
foreach (array_keys($ranges) as $key) {
@@ -956,7 +955,7 @@ class Ppd
// $start must lie before range start, otherwise we'd have hit the case above
$end = $ranges[$key][1];
unset($ranges[$key]);
- continue;
+ //continue;
}
}
$ranges[] = array($start, $end);
@@ -965,7 +964,7 @@ class Ppd
/**
* @return bool whether there was at least one known option with format restriction violated.
*/
- public function hasInvalidOption()
+ public function hasInvalidOption(): bool
{
return $this->knownKeywordMalformed;
}
@@ -1013,15 +1012,13 @@ class PpdSetting
/**
* PpdSetting constructor.
- *
- * @param \PpdSettingInternal $setting
*/
- public function __construct($setting, $isUi, $enc)
+ public function __construct(PpdSettingInternal $setting, bool $isUi, callable $enc)
{
- if ($setting->default !== false) {
+ if ($setting->default !== null) {
$this->default = $setting->default->option;
}
- if ($setting->block !== false && $setting->block->isUi()) {
+ if ($setting->block !== null && $setting->block->isUi()) {
$this->uiOptionType = $setting->block->value;
$this->uiOptionTranslation = $enc($setting->block->translation);
$this->isUi = true;
@@ -1055,9 +1052,9 @@ class PpdSetting
class PpdSettingInternal
{
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $default = false;
+ public $default = null;
/**
* @var \PpdOption[]
*/
@@ -1067,17 +1064,17 @@ class PpdSettingInternal
*/
public $foomatic = array();
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $custom = false;
+ public $custom = null;
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $customParam = false;
+ public $customParam = null;
/**
- * @var \PpdBlockInternal the innermost block this option resides in
+ * @var ?PpdBlockInternal the innermost block this option resides in
*/
- public $block = false;
+ public $block = null;
}
class PpdOption
@@ -1088,7 +1085,7 @@ class PpdOption
public $lineLen;
public $multiLine = false;
- public function __construct($lineOffset, $lineLen, $option, $optionTranslation)
+ public function __construct(int $lineOffset, int $lineLen, string $option, string $optionTranslation)
{
$this->option = $option;
$this->optionTranslation = $optionTranslation;
@@ -1106,13 +1103,13 @@ class PpdBlockInternal
public $translation;
public $type;
/**
- * @var \PpdBlockInternal[]
+ * @var PpdBlockInternal[]
*/
public $childBlocks = array();
/**
- * @var \PpdBlockInternal
+ * @var ?PpdBlockInternal
*/
- public $parent;
+ public $parent = null;
/**
* @var int start byte in ppd
@@ -1120,16 +1117,16 @@ class PpdBlockInternal
public $start;
/**
- * @var int|bool end byte in ppd, false if block is not closed
+ * @var ?int end byte in ppd, null if block is not closed
*/
- public $end = false;
+ public $end = null;
/**
* @var string value of opening line for block, e.g. 'PickOne' for OpenUI
*/
- public $value = false;
+ public $value = '';
- public function __construct($id, $translation, $type, $parent, $start)
+ public function __construct(string $id, string $translation, string $type, ?PpdBlockInternal $parent, int $start)
{
$this->id = $id;
$this->translation = $translation;
@@ -1141,16 +1138,16 @@ class PpdBlockInternal
/**
* @return bool true if this is a UI block
*/
- public function isUi()
+ public function isUi(): bool
{
return $this->type == 'UI' || $this->type === 'JCLUI';
}
/**
- * @param \PpdBlockInternal $block some other PpdBlock instance
+ * @param PpdBlockInternal $block some other PpdBlock instance
* @return bool true if this is a child of $block
*/
- public function isChildOf($block)
+ public function isChildOf(PpdBlockInternal $block): bool
{
$parent = $this->parent;
while ($parent !== false) {
diff --git a/modules-available/sysconfig/inc/sysconfig.inc.php b/modules-available/sysconfig/inc/sysconfig.inc.php
index 15bd4104..09860c7d 100644
--- a/modules-available/sysconfig/inc/sysconfig.inc.php
+++ b/modules-available/sysconfig/inc/sysconfig.inc.php
@@ -3,15 +3,42 @@
class SysConfig
{
- public static function getAll()
+ public static function getAll(): array
{
$res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, Group_Concat(cl.locationid) AS locs FROM configtgz c"
. " LEFT JOIN configtgz_location cl USING (configid) GROUP BY c.configid");
$ret = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$ret[] = $row;
}
return $ret;
}
+ public static function archiveContentsFromTask($status, &$userGroupWarn = null) : array
+ {
+ // Sort files for better display
+ $dirs = array();
+ foreach ($status['data']['entries'] as $file) {
+ if ($file['isdir']) continue;
+ $dirs[dirname($file['name'])][] = $file;
+ if ($file['userId'] > 0 || $file['groupId'] > 0) {
+ $userGroupWarn = true;
+ }
+ }
+ ksort($dirs);
+ $list = array();
+ foreach ($dirs as $dir => $files) {
+ $list[] = array(
+ 'name' => $dir,
+ 'isdir' => true
+ );
+ sort($files);
+ foreach ($files as $file) {
+ $file['size'] = Util::readableFileSize($file['size']);
+ $list[] = $file;
+ }
+ }
+ return $list;
+ }
+
} \ No newline at end of file
diff --git a/modules-available/sysconfig/install.inc.php b/modules-available/sysconfig/install.inc.php
index fe6a8c09..53882882 100644
--- a/modules-available/sysconfig/install.inc.php
+++ b/modules-available/sysconfig/install.inc.php
@@ -7,7 +7,7 @@ $update[] = tableCreate('configtgz', "
`title` varchar(200) NOT NULL,
`filepath` varchar(255) NOT NULL,
`status` enum('OK','OUTDATED','MISSING') NOT NULL DEFAULT 'MISSING',
- `warnings` TEXT NOT NULL DEFAULT NULL,
+ `warnings` TEXT NULL DEFAULT NULL,
`dateline` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`configid`)
");
@@ -87,7 +87,7 @@ if (!tableHasColumn('configtgz_module', 'dateline')) {
$update[] = UPDATE_DONE;
// Infer from module's filemtime
$res = Database::simpleQuery('SELECT moduleid, filepath FROM configtgz_module');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec('UPDATE configtgz_module SET dateline = :mtime WHERE moduleid = :moduleid',
['moduleid' => $row['moduleid'], 'mtime' => filemtime($row['filepath'])]);
}
@@ -102,7 +102,7 @@ if (!tableHasColumn('configtgz', 'dateline')) {
INNER JOIN configtgz_x_module cxm USING (configid)
INNER JOIN configtgz_module m USING (moduleid)
GROUP BY configid');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec('UPDATE configtgz SET dateline = :mtime WHERE configid = :configid',
['configid' => $row['configid'], 'mtime' => $row['dateline']]);
}
@@ -125,28 +125,28 @@ Module::isAvailable('sysconfig');
$list = ConfigModule::getAll();
$parentTask = null;
$configList = [];
-if ($list === false) {
+if ($list === null) {
EventLog::warning('Could not regenerate configs - please do so manually');
} else {
- foreach ($list as $ad) {
- if ($ad->moduleType() === 'SshConfig') {
+ foreach ($list as $confMod) {
+ if ($confMod->moduleType() === 'SshConfig') {
// 2020-11-12: Split SshConfig into SshConfig and SshKey
- $pubkey = $ad->getData('publicKey');
- if ($pubkey !== false && !empty($pubkey)) {
- error_log('Legacy module with pubkey ' . $ad->id());
- $key = ConfigModule::getInstance('SshKey');
- if ($key !== false) {
+ $pubkey = $confMod->getData('publicKey');
+ if (!empty($pubkey)) {
+ error_log('Legacy module with pubkey ' . $confMod->id());
+ $key = ConfigModule::getInstanceOrNull('SshKey');
+ if ($key !== null) {
$key->setData('publicKey', $pubkey);
- if ($key->insert($ad->title())) {
+ if ($key->insert($confMod->title())) {
// Insert worked, remove key from old module, add this module to the same configs
$task = $key->generate(false, $parentTask);
if ($task !== false) {
$parentTask = $task;
}
error_log('Inserted new module with id ' . $key->id());
- $ad->setData('publicKey', false);
- $ad->update();
- $configs = ConfigTgz::getAllForModule($ad->id());
+ $confMod->setData('publicKey', false);
+ $confMod->update();
+ $configs = ConfigTgz::getAllForModule($confMod->id());
foreach ($configs as $config) {
// Add newly created key-only module to all configs
$new = array_merge($config->getModuleIds(), [$key->id()]);
@@ -158,9 +158,9 @@ if ($list === false) {
}
}
}
- if ($ad->needRebuild()) {
+ if ($confMod->needRebuild()) {
$update[] = UPDATE_DONE;
- $task = $ad->generate(false, $parentTask);
+ $task = $confMod->generate(false, $parentTask);
if ($task !== false) {
$parentTask = $task;
}
@@ -171,5 +171,8 @@ if ($list === false) {
}
}
+// Start any changed services
+ConfigModuleBaseLdap::ldadp();
+
// Create response for browser
responseFromArray($update);
diff --git a/modules-available/sysconfig/lang/de/module.json b/modules-available/sysconfig/lang/de/module.json
index 1dbb268b..4bc1642f 100644
--- a/modules-available/sysconfig/lang/de/module.json
+++ b/modules-available/sysconfig/lang/de/module.json
@@ -6,8 +6,12 @@
"lang_moduleAssign": "Modul zu Systemkonfigurationen zuweisen",
"lang_noModuleFromThisGroup": "(Kein Modul dieser Gruppe)",
"lang_unknwonTaskManager": "Unbekannter Taskmanager-Fehler",
+ "location-column-header": "Lokalisierung",
"module_name": "Lokalisierung + Integration",
"page_title": "Lokalisierung + Integration",
+ "saver_DescriptionIdleKill": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der Nutzer ausgeloggt wird.",
+ "saver_DescriptionNoTimeout": "Ein Bildschirmschoner ohne Timeout.",
+ "saver_DescriptionShutdown": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der PC heruntergefahren oder neugestartet wird.",
"saver_MessageDefaultIdleKill": "Diese Sitzung wird bei Inaktivit\u00e4t in %1 beendet.",
"saver_MessageDefaultIdleKillLocked": "Diese Sitzung wird in %1 beendet, wenn sie nicht entsperrt wird.",
"saver_MessageDefaultNoTimeout": "Dieser Bildschirm wird gerade geschont.",
@@ -15,13 +19,10 @@
"saver_MessageDefaultShutdown": "Achtung: Rechner wird in %1 heruntergefahren!",
"saver_MessageDefaultShutdownLocked": "Achtung: Rechner wird in %1 heruntergefahren!",
"saver_QssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
- "saver_DescriptionIdleKill": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der Nutzer ausgeloggt wird.",
- "saver_DescriptionNoTimeout": "Ein Bildschirmschoner ohne Timeout.",
- "saver_DescriptionShutdown": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der PC heruntergefahren oder neugestartet wird.",
- "saver_TitleIdleKill": "Idle Kill",
- "saver_TitleNoTimeout": "Ohne Timeout",
- "saver_TitleShutdown": "Herunterfahren",
"saver_TextDefaultIdleKill": "<html><body>Keine Nutzeraktivit\u00e4t festgestellt. <br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn der Rechner nicht mehr verwendet wird. <br>Alle noch laufenden Programme <br>werden ohne Nachfrage geschlossen. Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit <br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
"saver_TextDefaultIdleKillLocked": "<html><body><br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn sie zuvor nicht wieder entsperrt wird. <br>Alle noch laufenden Programme werden ohne Nachfrage geschlossen. <br>Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern, bzw. die Sitzung wieder zu entsperren. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit<br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
- "saver_TextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt s\u00e4mtliche Daten abzuspeichern und die Sitzung zu verlassen.<\/body><\/html>"
-}
+ "saver_TextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt s\u00e4mtliche Daten abzuspeichern und die Sitzung zu verlassen.<\/body><\/html>",
+ "saver_TitleIdleKill": "Idle Kill",
+ "saver_TitleNoTimeout": "Ohne Timeout",
+ "saver_TitleShutdown": "Herunterfahren"
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/de/template-tags.json b/modules-available/sysconfig/lang/de/template-tags.json
index 7832d469..16b2c672 100644
--- a/modules-available/sysconfig/lang/de/template-tags.json
+++ b/modules-available/sysconfig/lang/de/template-tags.json
@@ -42,9 +42,8 @@
"lang_driveLetterNote": "WICHTIG: Bitte w\u00e4hlen Sie einen Laufwerksbuchstaben, der in den eingesetzten VMs verf\u00fcgbar ist, da ansonsten auf einen anderen Buchstaben ausgewichen werden muss.",
"lang_editLong": "Modul oder Konfiguration bearbeiten.",
"lang_editingLocationInfo": "Sie setzen die Konfiguration eines bestimmten Raums\/Orts, nicht die globale Konfiguration",
- "lang_fixNumeric": "Numerischen Account-Namen muss ein 's' vorangestellt werden",
- "lang_fixNumericDescription": "Wenn Sie diese Option aktivieren, m\u00fcssen Benutzer, deren Account-Name nur aus Ziffern besteht, diesem ein 's' voranstellen beim Login. Diese Option ist beim alten Login-Manager (KDM) zwingend erforderlich, da sonst der Loginvorgang fehlschl\u00e4gt. Mit dem neuen lightdm-basierten Login-Screen lassen sich numerische Account-Namen jedoch direkt verwenden. Wenn Sie an Ihrer Einrichtung keine numerischen Account-Namen verwenden, hat diese Option keine Auswirkung.",
"lang_folderRedirection": "Folder Redirection",
+ "lang_forceRootOwner": "Besitzrechte des Inhalts auf root:root setzen",
"lang_genUid": "uid-Nummern generieren",
"lang_genUidDescription": "Wenn aktiviert, generiert der Satellitenserver nummerische IDs f\u00fcr die Benutzer, anstatt diese aus dem LDAP\/AD zu extrahieren.",
"lang_generateModule": "Modul erzeugen",
@@ -79,6 +78,7 @@
"lang_moduleChoose": "Bitte w\u00e4hlen Sie aus, welche Art Konfigurationsmodul Sie erstellen m\u00f6chten.",
"lang_moduleConfiguration": "Konfigurationsmodule",
"lang_moduleName": "Modulname",
+ "lang_moduleOwnerWarn": "Einige Dateien oder Verzeichnisse in diesem Archiv haben als Besitzer order Gruppe etwas anderes als \"root\" gesetzt. Dies ist nur in besonderen F\u00e4llen sinnvoll bzw. erforderlich.",
"lang_moduleTitle": "Titel",
"lang_moduleUnused": "Ungenutzt",
"lang_moduleUnusedLong": "Dieses Modul ist mit keiner Systemkonfiguration verkn\u00fcpft.",
@@ -159,4 +159,4 @@
"lang_user_all": "Alle Nutzer",
"lang_user_root_only": "Nur root",
"lang_user_user_only": "Alle au\u00dfer root"
-}
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/module.json b/modules-available/sysconfig/lang/en/module.json
index b49cc1cf..dbfacdb8 100644
--- a/modules-available/sysconfig/lang/en/module.json
+++ b/modules-available/sysconfig/lang/en/module.json
@@ -6,8 +6,12 @@
"lang_moduleAssign": "Assign Module to System Configurations",
"lang_noModuleFromThisGroup": "(No module from this group)",
"lang_unknwonTaskManager": "Unknown Task Manager error",
+ "location-column-header": "SysConfig",
"module_name": "Localization",
"page_title": "Localize and integrate",
+ "saver_DescriptionIdleKill": "A screensaver with a timeout which on it's expiration will close all running applications without further requests and logout the user.",
+ "saver_DescriptionNoTimeout": "A screensaver without a timeout.",
+ "saver_DescriptionShutdown": "A screensaver with a timeout which on it's expiration the PC will shutdown or restart. All applications will be closed without further requests.",
"saver_MessageDefaultIdleKill": "This session will end in %1 when inactive.",
"saver_MessageDefaultIdleKillLocked": "This session will end in %1 if the session is not unlocked.",
"saver_MessageDefaultNoTimeout": "This screen is in saving mode.",
@@ -15,13 +19,10 @@
"saver_MessageDefaultShutdown": "Caution: Computer will shutdown in %1!",
"saver_MessageDefaultShutdownLocked": "Caution: Computer will shutdown in %1!",
"saver_QssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
- "saver_DescriptionIdleKill": "A screensaver with a timeout which on it's expiration will close all running applications without further requests and logout the user.",
- "saver_DescriptionNoTimeout": "A screensaver without a timeout.",
- "saver_DescriptionShutdown": "A screensaver with a timeout which on it's expiration the PC will shutdown or restart. All applications will be closed without further requests.",
- "saver_TitleIdleKill": "Idle Kill",
- "saver_TitleNoTimeout": "No Timeout",
- "saver_TitleShutdown": "Shutdown",
"saver_TextDefaultIdleKill": "<html><body>No user activity detected. <br>If the computer is not used until the time specified above, the session will end. <br> All running applications <br>will be closed without further requests. Make sure that all files and changes are saved <br> before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
"saver_TextDefaultIdleKillLocked": "<html><body><br>The current session will end by the time specified above if the computer isn't unlocked before. <br>All running applications will be closed without further requests. <br>Make sure that all files and changes are saved <br>or the session is unlocked before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
- "saver_TextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.<\/body><\/html>"
-}
+ "saver_TextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.<\/body><\/html>",
+ "saver_TitleIdleKill": "Idle Kill",
+ "saver_TitleNoTimeout": "No Timeout",
+ "saver_TitleShutdown": "Shutdown"
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/template-tags.json b/modules-available/sysconfig/lang/en/template-tags.json
index 0cfff576..eddd03d4 100644
--- a/modules-available/sysconfig/lang/en/template-tags.json
+++ b/modules-available/sysconfig/lang/en/template-tags.json
@@ -42,9 +42,8 @@
"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",
- "lang_fixNumeric": "Numeric account names have to be prefixed by 's'",
- "lang_fixNumericDescription": "If enabled, users with account names that consist entirely of digits have to prefix their user id by 's' when logging in. This is required with the old login manager (KDM) to prevent crashes. The new lightdm-based login manager will accept numeric account names, so you can leave this option disabled. If your organization doesn't have any numeric account names, this option will have no effect.",
"lang_folderRedirection": "Folder Redirection",
+ "lang_forceRootOwner": "Change ownership of archive content to root:root",
"lang_genUid": "Generate uid numbers",
"lang_genUidDescription": "When selected, the satellite server will generate numeric IDs for the users, instead of extracting them from AD\/LDAP.",
"lang_generateModule": "Generating module",
@@ -79,6 +78,7 @@
"lang_moduleChoose": "Please select which type of configuration module you want to create.",
"lang_moduleConfiguration": "Module Configuration",
"lang_moduleName": "Module Name",
+ "lang_moduleOwnerWarn": "Some files or directories in this archive belong to another user or group than \"root\". This is only necessary\/required in special cases.",
"lang_moduleTitle": "Title",
"lang_moduleUnused": "Unused",
"lang_moduleUnusedLong": "This module is not attached to any system configuration.",
diff --git a/modules-available/sysconfig/page.inc.php b/modules-available/sysconfig/page.inc.php
index 1ef478b3..b11f399e 100644
--- a/modules-available/sysconfig/page.inc.php
+++ b/modules-available/sysconfig/page.inc.php
@@ -152,11 +152,12 @@ class Page_SysConfig extends Page
$listid = Request::post('list', Request::REQUIRED, 'int');
$this->listConfigContents($listid);
return;
+ default:
}
Message::addError('invalid-action', $action, 'main');
}
- private function getLocationNames($locations, $ids)
+ private function getLocationNames(array $locations, array $ids): string
{
$ret = array();
foreach ($ids as $id) {
@@ -188,7 +189,7 @@ class Page_SysConfig extends Page
$locationName = false;
}
$hasDefault = false;
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
if (is_null($row['loclist'])) {
$locList = array();
} else {
@@ -236,7 +237,7 @@ class Page_SysConfig extends Page
private function listModules()
{
// Config modules
- $modules = ConfigModule::getAll();
+ $modules = ConfigModule::getAll() ?? [];
$types = array_map(function ($mod) { return $mod->moduleType(); }, $modules);
$titles = array_map(function ($mod) { return $mod->title(); }, $modules);
array_multisort($types, SORT_ASC, $titles, SORT_ASC, $modules);
@@ -267,27 +268,7 @@ class Page_SysConfig extends Page
Taskmanager::addErrorMessage($status);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
-
- // Sort files for better display
- $dirs = array();
- foreach ($status['data']['entries'] as $file) {
- if ($file['isdir'])
- continue;
- $dirs[dirname($file['name'])][] = $file;
- }
- ksort($dirs);
- $list = array();
- foreach ($dirs as $dir => $files) {
- $list[] = array(
- 'name' => $dir,
- 'isdir' => true
- );
- sort($files);
- foreach ($files as $file) {
- $file['size'] = Util::readableFileSize($file['size']);
- $list[] = $file;
- }
- }
+ $list = SysConfig::archiveContentsFromTask($status);
// render the template
Render::addDialog(Dictionary::translate('lang_contentOf') . ' ' . $row['title'], false, 'custom-filelist', array(
@@ -311,7 +292,7 @@ class Page_SysConfig extends Page
. " ORDER BY module.title ASC", array('configid' => $configid));
$modules = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$modules[] = array(
'module' => $row['moduletitle'],
'moduleid' => $row['moduleid']
@@ -356,7 +337,7 @@ class Page_SysConfig extends Page
{
$configid = Request::post('rebuild', Request::REQUIRED, 'int');
$config = ConfigTgz::get($configid);
- if ($config === false) {
+ if ($config === null) {
Message::addError('config-invalid', $configid);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
@@ -395,9 +376,9 @@ class Page_SysConfig extends Page
Message::addSuccess('module-deleted', $module['title']);
}
// Rebuild depending config.tgz
- while ($crow = $existing->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($existing as $crow) {
$config = ConfigTgz::get($crow['configid']);
- if ($config !== false) {
+ if ($config !== null) {
$config->generate();
}
}
@@ -421,11 +402,11 @@ class Page_SysConfig extends Page
{
$moduleid = Request::post('rebuild', Request::REQUIRED);
$module = ConfigModule::get($moduleid);
- if ($module === false) {
+ if ($module === null) {
Message::addError('config-invalid', $moduleid);
Util::redirect('?do=sysconfig');
}
- $ret = $module->generate(false, 250);
+ $ret = $module->generate(false, null, 500);
if ($ret === true)
Message::addSuccess('module-rebuilt', $module->title());
elseif ($ret === false)
@@ -439,7 +420,7 @@ class Page_SysConfig extends Page
{
$configid = Request::post('del', Request::REQUIRED);
$config = ConfigTgz::get($configid);
- if ($config === false) {
+ if ($config === null) {
Message::addError('config-invalid', $configid);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
diff --git a/modules-available/sysconfig/templates/ad-selfsearch.html b/modules-available/sysconfig/templates/ad-selfsearch.html
index e6a19468..0eefc372 100644
--- a/modules-available/sysconfig/templates/ad-selfsearch.html
+++ b/modules-available/sysconfig/templates/ad-selfsearch.html
@@ -42,7 +42,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -67,7 +66,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_skip}} &raquo;</button>
diff --git a/modules-available/sysconfig/templates/ad-start.html b/modules-available/sysconfig/templates/ad-start.html
index 933859fd..6dd6208a 100644
--- a/modules-available/sysconfig/templates/ad-start.html
+++ b/modules-available/sysconfig/templates/ad-start.html
@@ -21,7 +21,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon slx-ga2">{{lang_moduleTitle}}</span>
- <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" autofocus>
+ <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" autofocus required>
</div>
<div class="input-group">
<span class="input-group-addon slx-ga2">Server *</span>
@@ -77,16 +77,6 @@
<br>
<div>
<div class="checkbox">
- <input id="num-cb" type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
- <label for="num-cb"><b>{{lang_fixNumeric}}</b></label>
- </div>
- <div>
- <i>{{lang_fixNumericDescription}}</i>
- </div>
- </div>
- <br>
- <div>
- <div class="checkbox">
<input id="ssl-cb" type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
<label for="ssl-cb"><b>{{lang_ssl}}</b></label>
</div>
diff --git a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
index e686c29f..ced65650 100644
--- a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
+++ b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
@@ -30,7 +30,6 @@
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -55,7 +54,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="originalbinddn" value="{{binddn}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_next}} &raquo;</button>
diff --git a/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html b/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
index d698d994..b560eecd 100644
--- a/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
+++ b/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
@@ -25,7 +25,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -49,13 +48,13 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
<input name="originalbinddn" value="{{binddn}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_skip}} &raquo;</button>
</form>
</div>
+<div class="clearfix"></div>
<script type="text/javascript">
function ldapCb(task)
{
diff --git a/modules-available/sysconfig/templates/ad_ldap-homedir.html b/modules-available/sysconfig/templates/ad_ldap-homedir.html
index 8a6c10de..33f55c16 100644
--- a/modules-available/sysconfig/templates/ad_ldap-homedir.html
+++ b/modules-available/sysconfig/templates/ad_ldap-homedir.html
@@ -17,7 +17,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
diff --git a/modules-available/sysconfig/templates/branding-check.html b/modules-available/sysconfig/templates/branding-check.html
index d48f9631..80eb4d48 100644
--- a/modules-available/sysconfig/templates/branding-check.html
+++ b/modules-available/sysconfig/templates/branding-check.html
@@ -20,7 +20,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="form-group">
<label for="title-id">{{lang_title}}</label>
- <input type="text" name="title" value="{{title}}" id ="title-id" class="form-control" placeholder="Name des Moduls">
+ <input type="text" name="title" value="{{title}}" id ="title-id" class="form-control" placeholder="Name des Moduls" required>
</div>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule&step=Branding_Start">{{lang_cancel}}</a>
diff --git a/modules-available/sysconfig/templates/branding-start.html b/modules-available/sysconfig/templates/branding-start.html
index 0db085d9..a6346552 100644
--- a/modules-available/sysconfig/templates/branding-start.html
+++ b/modules-available/sysconfig/templates/branding-start.html
@@ -14,7 +14,7 @@
<input type="text" class="form-control" readonly placeholder="{{lang_selectFile}}">
<span class="input-group-btn">
<span class="btn btn-default btn-file">
- {{lang_browseForFile}}&hellip; <input type="file" name="file" id="input-file">
+ {{lang_browseForFile}}&hellip; <input type="file" accept="image/svg+xml" name="file" id="input-file">
</span>
</span>
</div>
diff --git a/modules-available/sysconfig/templates/cfg-start.html b/modules-available/sysconfig/templates/cfg-start.html
index b4628cba..018cf89f 100644
--- a/modules-available/sysconfig/templates/cfg-start.html
+++ b/modules-available/sysconfig/templates/cfg-start.html
@@ -3,7 +3,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_name}} *</span>
- <input type="text" name="title" value="{{title}}" class="form-control" placeholder="{{lang_configuration}}" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" placeholder="{{lang_configuration}}" autofocus="autofocus" required>
</div>
<hr>
<p>{{lang_configurationChoose}}</p>
diff --git a/modules-available/sysconfig/templates/custom-filelist.html b/modules-available/sysconfig/templates/custom-filelist.html
index 344eece3..20cedfda 100644
--- a/modules-available/sysconfig/templates/custom-filelist.html
+++ b/modules-available/sysconfig/templates/custom-filelist.html
@@ -4,11 +4,23 @@
{{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="4">{{name}}</td>
{{/isdir}}
{{^isdir}}
- <td class="fileEntry">{{name}}</td>
- <td>{{size}}</td>
+ <td class="fileEntry">
+ {{name}}
+ {{#linkTarget}}
+ -&gt;
+ <span class="text-nowrap">{{linkTarget}}</span>
+ {{/linkTarget}}
+ </td>
+ <td class="text-nowrap">{{user}}{{#user}}{{#group}}/{{/group}}{{/user}}{{group}}</td>
+ <td class="text-nowrap">{{userId}}:{{groupId}}</td>
+ <td class="text-nowrap">
+ {{^linkTarget}}
+ {{size}}
+ {{/linkTarget}}
+ </td>
{{/isdir}}
</tr>
{{/files}}
diff --git a/modules-available/sysconfig/templates/custom-fileselect.html b/modules-available/sysconfig/templates/custom-fileselect.html
index f14a6fde..5f190f08 100644
--- a/modules-available/sysconfig/templates/custom-fileselect.html
+++ b/modules-available/sysconfig/templates/custom-fileselect.html
@@ -4,7 +4,8 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_moduleName}}</span>
- <input type="text" name="title" value="{{title}}" class="form-control" placeholder="Mein Konfigurationsmodul" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" placeholder="Mein Konfigurationsmodul"
+ autofocus="autofocus" required>
</div>
<div class="pull-right">
<button type="submit" class="btn btn-primary">{{lang_next}} &raquo;</button>
@@ -12,20 +13,43 @@
<div class="clearfix"></div>
<hr>
<p>{{lang_checkFileContent}}</p>
+ {{#userGroupWarn}}
+ <div class="alert alert-warning">
+ {{lang_moduleOwnerWarn}}
+ </div>
+ <div class="checkbox">
+ <input id="force-owner" type="checkbox" name="force-owner" value="1" checked>
+ <label for="force-owner">{{lang_forceRootOwner}}</label>
+ </div>
+ <div class="slx-space"></div>
+ {{/userGroupWarn}}
<table class="table table-bordered table-condensed">
- {{#files}}
+ {{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="4">{{name}}</td>
{{/isdir}}
{{^isdir}}
- <td class="fileEntry">{{name}}</td>
- <td>{{size}}</td>
+ <td class="fileEntry">
+ {{name}}
+ {{#linkTarget}}
+ -&gt;
+ <span class="text-nowrap">{{linkTarget}}</span>
+ {{/linkTarget}}
+ </td>
+ <td class="text-nowrap">{{user}}{{#user}}{{#group}}/{{/group}}{{/user}}{{group}}</td>
+ <td class="text-nowrap">{{userId}}:{{groupId}}</td>
+ <td class="text-nowrap">
+ {{^linkTarget}}
+ {{size}}
+ {{/linkTarget}}
+ </td>
{{/isdir}}
</tr>
- {{/files}}
+ {{/files}}
</table>
<div class="pull-right">
<button type="submit" class="btn btn-primary">{{lang_next}} &raquo;</button>
</div>
+ <div class="clearfix"></div>
</form>
diff --git a/modules-available/sysconfig/templates/ldap-finish.html b/modules-available/sysconfig/templates/ldap-finish.html
index a735e792..bd998bfd 100644
--- a/modules-available/sysconfig/templates/ldap-finish.html
+++ b/modules-available/sysconfig/templates/ldap-finish.html
@@ -12,6 +12,7 @@
<div id="finish" class="pull-right" style="display:none">
<a href="?do=SysConfig" class="btn btn-primary">{{lang_toSystemConfiguration}}</a>
</div>
+<div class="clearfix"></div>
<script type="text/javascript">
function ldapCb(task)
{
diff --git a/modules-available/sysconfig/templates/ldap-start.html b/modules-available/sysconfig/templates/ldap-start.html
index 28019d9e..e6c98680 100644
--- a/modules-available/sysconfig/templates/ldap-start.html
+++ b/modules-available/sysconfig/templates/ldap-start.html
@@ -11,7 +11,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon slx-ga2">{{lang_moduleTitle}}</span>
- <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control">
+ <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" required>
</div>
<div class="input-group">
<span class="input-group-addon slx-ga2">Server *</span>
@@ -78,16 +78,6 @@
<br>
<div>
<div class="checkbox">
- <input id="num-cb" type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
- <label for="num-cb"><b>{{lang_fixNumeric}}</b></label>
- </div>
- <div>
- <i>{{lang_fixNumericDescription}}</i>
- </div>
- </div>
- <br>
- <div>
- <div class="checkbox">
<input id="ssl-cb" type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
<label for="ssl-cb"><b>{{lang_ssl}}</b></label>
</div>
diff --git a/modules-available/sysconfig/templates/sshconfig-start.html b/modules-available/sysconfig/templates/sshconfig-start.html
index df39feb0..b56be415 100644
--- a/modules-available/sysconfig/templates/sshconfig-start.html
+++ b/modules-available/sysconfig/templates/sshconfig-start.html
@@ -3,7 +3,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_moduleName}}</span>
- <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus" required>
</div>
<br>
<div class="form-group">
@@ -35,6 +35,9 @@
<input class="form-control" type="text" name="listenPort" value="{{listenPort}}" id="port" pattern="\d+" placeholder="22">
<i>{{lang_listenPortInfo}}</i>
</div>
+ <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"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
diff --git a/modules-available/sysconfig/templates/sshkey-start.html b/modules-available/sysconfig/templates/sshkey-start.html
index 52709984..8033740c 100644
--- a/modules-available/sysconfig/templates/sshkey-start.html
+++ b/modules-available/sysconfig/templates/sshkey-start.html
@@ -3,13 +3,16 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_moduleName}}</span>
- <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus" required>
</div>
<div class="form-group">
<label for="root-key">{{lang_rootKey}}</label>
<input class="form-control" type="text" name="publicKey" value="{{publicKey}}" id="root-key" required pattern="[a-z0-9\-]+ +[a-zA-Z0-9=/\+]+ +.*">
<i>{{lang_rootKeyInfo}}</i>
</div>
+ <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"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>