Extend plugin config with a grouping class

This commit is contained in:
the-djmaze 2022-02-09 17:48:05 +01:00
parent 05f1d62041
commit e0ebc999d5
10 changed files with 162 additions and 129 deletions

View file

@ -21,11 +21,11 @@ class PluginPopupView extends AbstractViewPopup {
readme: ''
});
this.configures = ko.observableArray();
this.config = ko.observableArray();
this.addComputables({
hasReadme: () => !!this.readme(),
hasConfiguration: () => 0 < this.configures().length
hasConfiguration: () => 0 < this.config().length
});
this.bDisabeCloseOnEsc = true;
@ -44,7 +44,7 @@ class PluginPopupView extends AbstractViewPopup {
Settings: {}
};
this.configures.forEach(oItem => {
this.config.forEach(oItem => {
let value = oItem.value();
if (false === value || true === value) {
value = value ? 1 : 0;
@ -64,7 +64,7 @@ class PluginPopupView extends AbstractViewPopup {
this.id('');
this.name('');
this.readme('');
this.configures([]);
this.config([]);
if (oPlugin) {
this.id(oPlugin.Id);
@ -73,16 +73,11 @@ class PluginPopupView extends AbstractViewPopup {
const config = oPlugin.Config;
if (arrayLength(config)) {
this.configures(
config.map(item => ({
value: ko.observable(item[0]),
placeholder: ko.observable(item[6]),
Name: item[1],
Type: item[2],
Label: item[3],
Default: item[4],
Desc: item[5]
}))
this.config(
config.map(item => {
item.value = ko.observable(item.value);
return item;
})
);
}
}

View file

@ -6,9 +6,9 @@ class ChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Change Password',
VERSION = '2.9',
RELEASE = '2021-07-20',
REQUIRED = '2.9.1',
VERSION = '2.12',
RELEASE = '2022-02-10',
REQUIRED = '2.12.0',
CATEGORY = 'Security',
DESCRIPTION = 'Extension to allow users to change their passwords';
@ -96,17 +96,21 @@ class ChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
->SetDefaultValue(70),
];
foreach ($this->getSupportedDrivers(true) as $name => $class) {
$result[] = \RainLoop\Plugins\Property::NewInstance("driver_{$name}_enabled")
->SetLabel('Enable ' . $class::NAME)
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
->SetDescription($class::DESCRIPTION)
->SetDefaultValue(false);
$result[] = \RainLoop\Plugins\Property::NewInstance("driver_{$name}_allowed_emails")
->SetLabel('Allowed emails')
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@example.net user2@example1.net *@example2.net')
->SetDefaultValue('*');
$result = \array_merge($result, \call_user_func("{$class}::configMapping"));
$group = new \RainLoop\Plugins\PropertyCollection($name);
$props = [
\RainLoop\Plugins\Property::NewInstance("driver_{$name}_enabled")
->SetLabel('Enable ' . $class::NAME)
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
->SetDescription($class::DESCRIPTION)
->SetDefaultValue(false),
\RainLoop\Plugins\Property::NewInstance("driver_{$name}_allowed_emails")
->SetLabel('Allowed emails')
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@example.net user2@example1.net *@example2.net')
->SetDefaultValue('*')
];
$group->exchangeArray(\array_merge($props, \call_user_func("{$class}::configMapping")));
$result[] = $group;
}
return $result;
}

View file

@ -791,34 +791,41 @@ trait Admin
$mResult = false;
$sId = (string) $this->GetActionParam('Id', '');
if (!empty($sId))
{
if (!empty($sId)) {
$oPlugin = $this->Plugins()->CreatePluginByName($sId);
if ($oPlugin)
{
if ($oPlugin) {
$mResult = array(
'Id' => $sId,
'Name' => $oPlugin->Name(),
'Readme' => $oPlugin->Description(),
'Config' => array()
'@Object' => 'Object/Plugin',
'Id' => $sId,
'Name' => $oPlugin->Name(),
'Readme' => $oPlugin->Description(),
'Config' => array()
);
$aMap = $oPlugin->ConfigMap();
$oConfig = $oPlugin->Config();
if (is_array($aMap))
{
foreach ($aMap as $oItem)
{
if ($oItem && ($oItem instanceof \RainLoop\Plugins\Property))
{
$aItem = $oItem->ToArray();
$aItem[0] = $oConfig->Get('plugin', $oItem->Name(), '');
if (PluginPropertyType::PASSWORD === $oItem->Type())
{
$aItem[0] = APP_DUMMY;
if (\is_array($aMap)) {
$oConfig = $oPlugin->Config();
foreach ($aMap as $oItem) {
if ($oItem) {
if ($oItem instanceof \RainLoop\Plugins\Property) {
if (PluginPropertyType::PASSWORD === $oItem->Type()) {
$oItem->SetValue(APP_DUMMY);
} else {
$oItem->SetValue($oConfig->Get('plugin', $oItem->Name(), ''));
}
$mResult['Config'][] = $oItem;
} else if ($oItem instanceof \RainLoop\Plugins\PropertyCollection) {
foreach ($oItem as $oSubItem) {
if ($oSubItem && $oSubItem instanceof \RainLoop\Plugins\Property) {
if (PluginPropertyType::PASSWORD === $oSubItem->Type()) {
$oSubItem->SetValue(APP_DUMMY);
} else {
$oSubItem->SetValue($oConfig->Get('plugin', $oSubItem->Name(), ''));
}
}
}
$mResult['Config'][] = $oItem;
}
$mResult['Config'][] = $aItem;
}
}
}
@ -841,7 +848,7 @@ trait Admin
if ($oPlugin)
{
$oConfig = $oPlugin->Config();
$aMap = $oPlugin->ConfigMap();
$aMap = $oPlugin->ConfigMap(true);
if (is_array($aMap))
{
$aSettings = (array) $this->GetActionParam('Settings', []);

View file

@ -7,39 +7,28 @@ class Plugin extends \RainLoop\Config\AbstractConfig
/**
* @var array
*/
private $aMap;
private $aMap = array();
public function __construct(string $sPluginName, array $aMap = array())
{
$this->aMap = is_array($aMap) ? $this->convertConfigMap($aMap) : array();
parent::__construct('plugin-'.$sPluginName.'.ini', '; SnappyMail plugin ('.$sPluginName.')');
}
private function convertConfigMap(array $aMap) : array
{
if (\count($aMap))
{
if (\count($aMap)) {
$aResultMap = array();
foreach ($aMap as /* @var $oProperty \RainLoop\Plugins\Property */ $oProperty)
{
if ($oProperty)
{
foreach ($aMap as /* @var $oProperty \RainLoop\Plugins\Property */ $oProperty) {
if ($oProperty) {
$mValue = $oProperty->DefaultValue();
$sValue = \is_array($mValue) && isset($mValue[0]) ? $mValue[0] : $mValue;
$aResultMap[$oProperty->Name()] = array($sValue, '');
}
}
if (\count($aResultMap))
{
return array(
if (\count($aResultMap)) {
$this->aMap = array(
'plugin' => $aResultMap
);
}
}
return array();
parent::__construct('plugin-'.$sPluginName.'.ini', '; SnappyMail plugin ('.$sPluginName.')');
}
protected function defaultValues() : array

View file

@ -5,6 +5,7 @@ namespace RainLoop\Enumerations;
class PluginPropertyType
{
const
GROUP = 7,
STRING = 0,
INT = 1,
STRING_TEXT = 2,

View file

@ -111,13 +111,31 @@ abstract class AbstractPlugin
return $this->sPath;
}
final public function ConfigMap() : array
final public function ConfigMap(bool $flatten = false) : array
{
if (null === $this->aConfigMap)
{
$this->aConfigMap = $this->configMapping();
}
if ($flatten) {
$result = [];
foreach ($this->aConfigMap as $oItem) {
if ($oItem) {
if ($oItem instanceof \RainLoop\Plugins\Property) {
$result[] = $oItem;
} else if ($oItem instanceof \RainLoop\Plugins\PropertyCollection) {
foreach ($oItem as $oSubItem) {
if ($oSubItem && $oSubItem instanceof \RainLoop\Plugins\Property) {
$result[] = $oSubItem;
}
}
}
}
}
return $result;
}
return $this->aConfigMap;
}

View file

@ -82,7 +82,7 @@ class Manager
->SetName($sName)
->SetPath(static::getPluginPath($sName))
->SetPluginManager($this)
->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap()))
->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap(true)))
;
}
@ -223,7 +223,7 @@ class Manager
if ($oPlugin)
{
$aConfig = array();
$aMap = $oPlugin->ConfigMap();
$aMap = $oPlugin->ConfigMap(true);
if (\is_array($aMap))
{
foreach ($aMap as /* @var $oPluginProperty \RainLoop\Plugins\Property */ $oPluginProperty)
@ -468,16 +468,15 @@ class Manager
return false;
}
public function ReadLang(string $sLang, array &$aLang) : self
public function ReadLang(string $sLang, array &$aLang) : void
{
if ($this->bIsEnabled)
{
foreach ($this->aPlugins as $oPlugin)
{
if ($oPlugin->UseLangs())
{
if ($this->bIsEnabled) {
foreach ($this->aPlugins as $oPlugin) {
if ($oPlugin->UseLangs()) {
$sPath = $oPlugin->Path().'/langs/';
$aPLang = [];
// First get english
if (\is_file("{$sPath}en.ini")) {
$aPLang = \parse_ini_file("{$sPath}en.ini", true);
} else if (\is_file("{$sPath}en.json")) {
@ -487,8 +486,8 @@ class Manager
$aLang = \array_replace_recursive($aLang, $aPLang);
}
if ('en' !== $sLang)
{
// Now get native
if ('en' !== $sLang) {
$aPLang = [];
if (\is_file("{$sPath}{$sLang}.ini")) {
$aPLang = \parse_ini_file("{$sPath}{$sLang}.ini", true);
@ -504,8 +503,6 @@ class Manager
}
}
}
return $this;
}
public function IsEnabled() : bool

View file

@ -2,13 +2,18 @@
namespace RainLoop\Plugins;
class Property
class Property implements \JsonSerializable
{
/**
* @var string
*/
private $sName;
/**
* @var mixed
*/
private $mValue;
/**
* @var string
*/
@ -62,6 +67,14 @@ class Property
return $this;
}
/**
* @param mixed $mValue
*/
public function SetValue($mValue) : void
{
$this->mValue = $mValue;
}
/**
* @param mixed $mDefaultValue
*/
@ -138,16 +151,17 @@ class Property
return $this->sPlaceholder;
}
public function ToArray() : array
public function jsonSerialize()
{
return array(
'',
$this->sName,
$this->iType,
$this->sLabel,
$this->mDefaultValue,
$this->sDesc,
$this->sPlaceholder
'@Object' => 'Object/PluginProperty',
'value' => $this->mValue,
'placeholder' => $this->sPlaceholder,
'Name' => $this->sName,
'Type' => $this->iType,
'Label' => $this->sLabel,
'Default' => $this->mDefaultValue,
'Desc' => $this->sDesc
);
}
}

View file

@ -1,37 +1,35 @@
<label data-bind="text: Label, visible: 5 !== Type"></label>
<div>
<!-- ko if: 0 === Type -->
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 1 === Type -->
<input type="number" step="1"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 3 === Type -->
<input type="password" autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 2 === Type -->
<div data-bind="component: {
name: 'TextArea',
params: { value: value, placeholder: placeholder }
}"></div>
<!-- /ko -->
<!-- ko if: 4 === Type -->
<select data-bind="options: Default, value: value"></select>
<!-- /ko -->
<!-- ko if: 5 === Type -->
<div data-bind="component: {
name: 'Checkbox',
params: { value: value, label: Label }
}"></div>
<!-- /ko -->
<!-- ko if: 6 === Type -->
<input type="url"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: '' !== Desc -->
<span tabindex="0" class="help-block"><span data-bind="text: Desc"></span></span>
<!-- /ko -->
</div>
<!-- ko if: 0 === Type -->
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 1 === Type -->
<input type="number" step="1"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 3 === Type -->
<input type="password" autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: 2 === Type -->
<div data-bind="component: {
name: 'TextArea',
params: { value: value, placeholder: placeholder }
}"></div>
<!-- /ko -->
<!-- ko if: 4 === Type -->
<select data-bind="options: Default, value: value"></select>
<!-- /ko -->
<!-- ko if: 5 === Type -->
<div data-bind="component: {
name: 'Checkbox',
params: { value: value, label: Label }
}"></div>
<!-- /ko -->
<!-- ko if: 6 === Type -->
<input type="url"
data-bind="value: value, attr: {placeholder: placeholder}" />
<!-- /ko -->
<!-- ko if: '' !== Desc -->
<span tabindex="0" class="help-block"><span data-bind="text: Desc"></span></span>
<!-- /ko -->

View file

@ -14,8 +14,18 @@
<a href="#" class="close" data-bind="click: function () { saveError('') }">×</a>
<span data-bind="text: saveError"></span>
</div>
<div data-bind="foreach: configures, visible: hasConfiguration">
<div data-bind="foreach: config, visible: hasConfiguration">
<!-- ko if: 7 == Type -->
<details open="">
<summary class="legend" data-bind="text: Label"></summary>
<div data-bind="foreach: config">
<div class="control-group" data-bind="template: { name: 'AdminSettingsPluginProperty' }"></div>
</div>
</details>
<!-- /ko -->
<!-- ko if: 7 != Type -->
<div class="control-group" data-bind="template: { name: 'AdminSettingsPluginProperty' }"></div>
<!-- /ko -->
</div>
</form>
</div>