parent::validate();
if (empty($this->getValidationErrors()) && is_array($this->getValue()) && !empty($this->getValue())) {
+ // ignore `module_attachment`, see https://github.com/WoltLab/WCF/issues/2531
+ $options = $this->getValue();
+ if (($index = array_search('module_attachment', $options)) !== false) {
+ unset($options[$index]);
+ }
+
+ if (empty($options)) {
+ return;
+ }
+
$conditionBuilder = new PreparedStatementConditionBuilder();
- $conditionBuilder->add('optionName IN (?)', [$this->getValue()]);
+ $conditionBuilder->add('optionName IN (?)', [$options]);
if (!empty($this->getPackageIDs())) {
$conditionBuilder->add('packageID IN (?)', [$this->getPackageIDs()]);
}
$statement->execute($conditionBuilder->getParameters());
$availableOptions = $statement->fetchAll(\PDO::FETCH_COLUMN);
- $unknownOptions = array_diff($this->getValue(), $availableOptions);
+ $unknownOptions = array_diff($options, $availableOptions);
if (!empty($unknownOptions)) {
$this->addValidationError(
break;
case 'options':
+ $classnamePieces = explode('\\', get_class($this));
+ $pipPrefix = str_replace('PackageInstallationPlugin', '', array_pop($classnamePieces));
+
$dataContainer->appendChildren([
TextFormField::create('optionName')
->objectProperty('name')
->label('wcf.acp.pip.abstractOption.options.optionName')
- ->description('wcf.acp.pip.abstractOption.categories.options.description')
+ ->description('wcf.acp.pip.abstractOption.options.optionName.description')
->required(),
SingleSelectionFormField::create('categoryName')
SingleSelectionFormField::create('optionType')
->objectProperty('optiontype')
->label('wcf.acp.pip.abstractOption.options.optionType')
- ->description('wcf.acp.pip.' . $this->tagName . '.options.optionType.description')
+ ->description('wcf.acp.pip.' . lcfirst($pipPrefix) . '.options.optionType.description')
->required()
->options(function(): array {
$classnamePieces = explode('\\', get_class());
throw new \LogicException('Unreachable');
}
+ if ($saveData) {
+ $lowercaseData = [
+ 'packageID' => $this->installation->getPackage()->packageID
+ ];
+
+ $lowercaseFields = [
+ 'categoryName',
+ 'optionName',
+ 'optionType',
+ 'defaultValue',
+ 'enableOptions',
+ 'validationPattern',
+ 'showOrder',
+ 'parentCategoryName',
+ 'showOrder'
+ ];
+
+ foreach ($lowercaseFields as $name) {
+ if (isset($data[$name])) {
+ $lowercaseData[strtolower($name)] = $data[$name];
+ }
+ }
+
+ return $lowercaseData;
+ }
+
return $data;
}
case 'options':
$optionData = $this->getElementData($newElement, true);
- $this->saveOption($optionData, $optionData['categoryName']);
+ $this->saveOption($optionData, $optionData['categoryname']);
break;
}
'options' => '',
'permissions' => '',
- // object-type specific elements
+ // option type-specific elements
'minvalue' => null,
'maxvalue' => null,
'suffix' => '',
];
foreach ($fields as $field => $defaultValue) {
if (isset($formData[$field]) && $formData[$field] !== $defaultValue) {
- $option->appendChild($document->createElement($field, (string) $formData[$field]));
+ $option->appendChild($document->createElement($field, StringUtil::unifyNewlines((string) $formData[$field])));
}
}
<?php
namespace wcf\system\package\plugin;
+use wcf\data\option\category\OptionCategory;
+use wcf\data\option\Option;
use wcf\data\user\group\option\UserGroupOption;
use wcf\data\user\group\option\UserGroupOptionEditor;
use wcf\data\user\group\UserGroup;
-use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin;
+use wcf\system\devtools\pip\IGuiPackageInstallationPlugin;
use wcf\system\exception\SystemException;
+use wcf\system\form\builder\container\IFormContainer;
+use wcf\system\form\builder\field\BooleanFormField;
+use wcf\system\form\builder\field\dependency\ValueFormFieldDependency;
+use wcf\system\form\builder\field\MultilineTextFormField;
+use wcf\system\form\builder\field\SingleSelectionFormField;
+use wcf\system\form\builder\field\TextFormField;
+use wcf\system\form\builder\IFormDocument;
+use wcf\system\option\user\group\UserGroupOptionHandler;
use wcf\system\WCF;
use wcf\util\StringUtil;
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package WoltLabSuite\Core\System\Package\Plugin
*/
-class UserGroupOptionPackageInstallationPlugin extends AbstractOptionPackageInstallationPlugin implements IIdempotentPackageInstallationPlugin {
+class UserGroupOptionPackageInstallationPlugin extends AbstractOptionPackageInstallationPlugin implements IGuiPackageInstallationPlugin {
/**
* list of group ids by type
* @var integer[][]
*/
public $tableName = 'user_group_option';
+ /**
+ * @inheritDoc
+ */
+ public $tagName = 'option';
+
/**
* list of names of tags which aren't considered as additional data
* @var string[]
return $this->groupIDs;
}
+
+ /**
+ * @inheritDoc
+ * @since 3.2
+ */
+ public function addFormFields(IFormDocument $form) {
+ parent::addFormFields($form);
+
+ if ($this->entryType === 'options') {
+ /** @var IFormContainer $dataContainer */
+ $dataContainer = $form->getNodeById('data');
+
+ /** @var SingleSelectionFormField $optionType */
+ $optionType = $form->getNodeById('optionType');
+
+ $dataContainer->appendChildren([
+ MultilineTextFormField::create('adminDefaultValue')
+ ->objectProperty('admindefaultvalue')
+ ->label('wcf.acp.pip.userGroupOption.options.adminDefaultValue')
+ ->description('wcf.acp.pip.userGroupOption.options.adminDefaultValue.description')
+ ->rows(5),
+
+ MultilineTextFormField::create('modDefaultValue')
+ ->objectProperty('moddefaultvalue')
+ ->label('wcf.acp.pip.userGroupOption.options.modDefaultValue')
+ ->description('wcf.acp.pip.userGroupOption.options.modDefaultValue.description')
+ ->rows(5),
+
+ BooleanFormField::create('usersOnly')
+ ->objectProperty('usersonly')
+ ->label('wcf.acp.pip.userGroupOption.options.usersOnly')
+ ->description('wcf.acp.pip.userGroupOption.options.usersOnly.description'),
+
+ BooleanFormField::create('excludedInTinyBuild')
+ ->label('wcf.acp.pip.userGroupOption.options.excludedInTinyBuild')
+ ->description('wcf.acp.pip.userGroupOption.options.excludedInTinyBuild.description'),
+
+ TextFormField::create('wildcard')
+ ->label('wcf.acp.pip.userGroupOption.options.wildcard')
+ ->description('wcf.acp.pip.userGroupOption.options.wildcard.description')
+ ->addDependency(
+ ValueFormFieldDependency::create('optionType')
+ ->field($optionType)
+ ->values(['textarea'])
+ )
+ ]);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ * @since 3.2
+ */
+ protected function getElementData(\DOMElement $element, $saveData = false) {
+ $data = parent::getElementData($element, $saveData);
+
+ switch ($this->entryType) {
+ case 'options':
+ foreach (['adminDefaultValue', 'modDefaultValue', 'usersOnly', 'excludedInTinyBuild', 'wildcard'] as $optionalPropertyName) {
+ $optionalProperty = $element->getElementsByTagName(strtolower($optionalPropertyName))->item(0);
+ if ($optionalProperty !== null) {
+ if ($saveData && $optionalPropertyName !== 'excludedInTinyBuild') {
+ $data[strtolower($optionalPropertyName)] = $optionalProperty->nodeValue;
+ }
+ else {
+ $data[$optionalPropertyName] = $optionalProperty->nodeValue;
+ }
+ }
+ }
+
+ break;
+ }
+
+ return $data;
+ }
+
+ /**
+ * @inheritDoc
+ * @since 3.2
+ */
+ protected function getSortOptionHandler() {
+ // reuse UserGroupOptionHandler
+ return new class(true) extends UserGroupOptionHandler {
+ /**
+ * @inheritDoc
+ */
+ protected function checkCategory(OptionCategory $category) {
+ // we do not care for category checks here
+ return true;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function checkOption(Option $option) {
+ // we do not care for option checks here
+ return true;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCategoryOptions($categoryName = '', $inherit = true) {
+ // we just need to ensure that the category is not empty
+ return [new Option(null, [])];
+ }
+ };
+ }
+
+ /**
+ * @inheritDoc
+ * @since 3.2
+ */
+ protected function writeEntry(\DOMDocument $document, IFormDocument $form) {
+ $option = parent::writeEntry($document, $form);
+
+ $formData = $form->getData()['data'];
+
+ switch ($this->entryType) {
+ case 'options':
+ $fields = [
+ 'admindefaultvalue' => '',
+ 'moddefaultvalue' => '',
+ 'usersonly' => 0,
+ 'excludedInTinyBuild' => 0,
+ 'wildcard' => ''
+ ];
+
+ foreach ($fields as $field => $defaultValue) {
+ if (isset($formData[$field]) && $formData[$field] !== $defaultValue) {
+ $option->appendChild($document->createElement($field, (string) $formData[$field]));
+ }
+ }
+
+ break;
+ }
+
+ return $option;
+ }
}
<item name="wcf.acp.pip.option.options.supportI18n.description"><![CDATA[If selected, the option supports different values for each available language.]]></item>
<item name="wcf.acp.pip.option.options.requireI18n"><![CDATA[Require Multilingual Input]]></item>
<item name="wcf.acp.pip.option.options.requireI18n.description"><![CDATA[If selected, the option’s value must be explicitly set for each available language.]]></item>
- <item name="wcf.acp.pip.option.options.optionType.description"><![CDATA[The option types determine the interface with which the value of the option is set and which (types of) values the option may have.]]></item>
+ <item name="wcf.acp.pip.option.options.optionType.description"><![CDATA[The option type determines the interface with which the value of the option is set and which (types of) values the option may have.]]></item>
<item name="wcf.acp.pip.abstractOption.options.optionType.select.allowEmptyValue"><![CDATA[Allow Empty Value]]></item>
<item name="wcf.acp.pip.abstractOption.options.optionType.select.allowEmptyValue.description"><![CDATA[If selected, the value of the option may be empty.]]></item>
<item name="wcf.acp.pip.abstractOption.options.optionType.useroptions.isSortable"><![CDATA[User Options Are Sortable]]></item>
<item name="wcf.acp.pip.smiley.smileyPath.error.fileDoesNotExist"><![CDATA[The entered file does not exist.]]></item>
<item name="wcf.acp.pip.smiley.smileyPath2x"><![CDATA[HD Smiley Path]]></item>
<item name="wcf.acp.pip.smiley.smileyPath2x.description"><![CDATA[The entered path has to be relative to <code>{'WCF_DIR'|constant}</code>.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.usersOnly"><![CDATA[Members Only]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.usersOnly.description"><![CDATA[The user group option is only available for registered members-only user groups.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.optionType.description"><![CDATA[The option type determines the interface with which the value of the user group option is set and which (types of) values the option may have. Additionally, the option type also determines how the final option value is determined if a user is in multiple user groups with different option values.]]></item>
+ <item name="wcf.acp.pip.abstractOption.options.optionName.description"><![CDATA[The option name is used to update options and to identify options in PHP code.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.adminDefaultValue"><![CDATA[Administrator Default Value]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.adminDefaultValue.description"><![CDATA[The administrator default value is used for administrator user groups. Administrator user groups are user groups that can edit every user group.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.modDefaultValue"><![CDATA[Moderator Default Value]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.modDefaultValue.description"><![CDATA[The moderator default value is used for moderator user groups. Moderator user groups are user groups that can access the moderation.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.usersOnly"><![CDATA[Members Only]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.usersOnly.description"><![CDATA[The user group option value cannot be set for the guests user group.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.excludedInTinyBuild"><![CDATA[Disable for Accelerated Guest View]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.excludedInTinyBuild.description"><![CDATA[If the accelared guest view is enabled, the user group option’s value is “Never” for guests regardless of the actual value set for the guests user group.]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.wildcard"><![CDATA[Wildcard]]></item>
+ <item name="wcf.acp.pip.userGroupOption.options.wildcard.description"><![CDATA[If a wildcard is specified and if one line of the user group option value only contains this wildcare, the entire option value will be replaced by the wildcard.]]></item>
</category>
<category name="wcf.acp.reactionType">