Skip to content

Commit

Permalink
Use the FormBuilder to create/edit captcha questions
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyperghost committed Nov 14, 2024
1 parent 0eefa53 commit 27532b5
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 336 deletions.
61 changes: 1 addition & 60 deletions wcfsetup/install/files/acp/templates/captchaQuestionAdd.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,65 +14,6 @@
</nav>
</header>

{include file='shared_formNotice'}

<form id="adForm" method="post" action="{if $action == 'add'}{link controller='CaptchaQuestionAdd'}{/link}{else}{link controller='CaptchaQuestionEdit' id=$captchaQuestion->questionID}{/link}{/if}">
<div class="section">
<dl{if $errorField == 'question'} class="formError"{/if}>
<dt><label for="question">{lang}wcf.acp.captcha.question.question{/lang}</label></dt>
<dd>
<input type="text" id="question" name="question" value="{$i18nPlainValues[question]}" required autofocus class="long">
{if $errorField == 'question'}
<small class="innerError">
{if $errorType == 'empty'}
{lang}wcf.global.form.error.empty{/lang}
{elseif $errorType == 'multilingual'}
{lang}wcf.global.form.error.multilingual{/lang}
{else}
{lang}wcf.acp.captcha.question.question.error.{$errorType}{/lang}
{/if}
</small>
{/if}
</dd>
</dl>
{include file='shared_multipleLanguageInputJavascript' elementIdentifier='question' forceSelection=false}

<dl{if $errorField == 'answers'} class="formError"{/if}>
<dt><label for="answers">{lang}wcf.acp.captcha.question.answers{/lang}</label></dt>
<dd>
<textarea id="answers" name="answers" cols="40" rows="10">{$i18nPlainValues[answers]}</textarea>
<small>{lang}wcf.acp.captcha.question.answers.description{/lang}</small>
{if $errorField == 'answers'}
<small class="innerError">
{if $errorType == 'empty'}
{lang}wcf.global.form.error.empty{/lang}
{elseif $errorType == 'multilingual'}
{lang}wcf.global.form.error.multilingual{/lang}
{else}
{lang}wcf.acp.captcha.question.answers.error.{$errorType}{/lang}
{/if}
</small>
{/if}
</dd>
</dl>
{include file='shared_multipleLanguageInputJavascript' elementIdentifier='answers' forceSelection=false}

<dl>
<dt></dt>
<dd>
<label><input type="checkbox" name="isDisabled" value="1"{if $isDisabled} checked{/if}> {lang}wcf.acp.captcha.question.isDisabled{/lang}</label>
</dd>
</dl>

{event name='dataFields'}
</div>

{event name='sections'}

<div class="formSubmit">
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
{csrfToken}
</div>
</form>
{unsafe:$form->getHtml()}

{include file='footer'}
236 changes: 75 additions & 161 deletions wcfsetup/install/files/lib/acp/form/CaptchaQuestionAddForm.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,35 @@

namespace wcf\acp\form;

use wcf\data\captcha\question\CaptchaQuestion;
use wcf\data\captcha\question\CaptchaQuestionAction;
use wcf\data\captcha\question\CaptchaQuestionEditor;
use wcf\form\AbstractForm;
use wcf\system\exception\UserInputException;
use wcf\system\language\I18nHandler;
use wcf\data\language\Language;
use wcf\form\AbstractFormBuilderForm;
use wcf\system\form\builder\container\FormContainer;
use wcf\system\form\builder\field\BooleanFormField;
use wcf\system\form\builder\field\MultilineTextFormField;
use wcf\system\form\builder\field\TextFormField;
use wcf\system\form\builder\field\validation\FormFieldValidationError;
use wcf\system\form\builder\field\validation\FormFieldValidator;
use wcf\system\language\LanguageFactory;
use wcf\system\Regex;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
use wcf\util\StringUtil;

/**
* Shows the form to create a new captcha question.
*
* @author Matthias Schmidt
* @copyright 2001-2019 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @author Olaf Braun, Matthias Schmidt
* @copyright 2001-2024 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
*
* @property CaptchaQuestion $formObject
*/
class CaptchaQuestionAddForm extends AbstractForm
class CaptchaQuestionAddForm extends AbstractFormBuilderForm
{
/**
* @inheritDoc
*/
public $activeMenuItem = 'wcf.acp.menu.link.captcha.question.add';

/**
* invalid regex in answers
* @var string
*/
public $invalidRegex = '';

/**
* 1 if the question is disabled
* @var int
*/
public $isDisabled = 0;

/**
* @inheritDoc
*/
Expand All @@ -46,155 +39,76 @@ class CaptchaQuestionAddForm extends AbstractForm
/**
* @inheritDoc
*/
public function assignVariables()
{
parent::assignVariables();

I18nHandler::getInstance()->assignVariables();

WCF::getTPL()->assign([
'action' => 'add',
'isDisabled' => $this->isDisabled,
'invalidRegex' => $this->invalidRegex,
]);
}

/**
* @inheritDoc
*/
public function readFormParameters()
{
parent::readFormParameters();

I18nHandler::getInstance()->readValues();

if (isset($_POST['isDisabled'])) {
$this->isDisabled = 1;
}
}
public $objectActionClass = CaptchaQuestionAction::class;

/**
* @inheritDoc
*/
public function readParameters()
{
parent::readParameters();

I18nHandler::getInstance()->register('question');
I18nHandler::getInstance()->register('answers');
}
public $objectEditLinkController = CaptchaQuestionEditForm::class;

/**
* @inheritDoc
*/
public function save()
#[\Override]
protected function createForm()
{
parent::save();

$this->objectAction = new CaptchaQuestionAction([], 'create', [
'data' => \array_merge($this->additionalFields, [
'answers' => I18nHandler::getInstance()->isPlainValue('answers') ? I18nHandler::getInstance()->getValue('answers') : '',
'isDisabled' => $this->isDisabled,
'question' => I18nHandler::getInstance()->isPlainValue('question') ? I18nHandler::getInstance()->getValue('question') : '',
]),
]);
$returnValues = $this->objectAction->executeAction();
$questionID = $returnValues['returnValues']->questionID;

// set i18n values
$questionUpdates = [];
if (!I18nHandler::getInstance()->isPlainValue('question')) {
I18nHandler::getInstance()->save(
'question',
'wcf.captcha.question.question.question' . $questionID,
'wcf.captcha.question',
1
);

$questionUpdates['question'] = 'wcf.captcha.question.question.question' . $questionID;
}
if (!I18nHandler::getInstance()->isPlainValue('answers')) {
I18nHandler::getInstance()->save(
'answers',
'wcf.captcha.question.answers.question' . $questionID,
'wcf.captcha.question',
1
);

$questionUpdates['answers'] = 'wcf.captcha.question.answers.question' . $questionID;
}

if (!empty($questionUpdates)) {
$questionEditor = new CaptchaQuestionEditor($returnValues['returnValues']);
$questionEditor->update($questionUpdates);
}

$this->saved();

// reset values
I18nHandler::getInstance()->reset();
$this->isDisabled = 0;

// show success message
WCF::getTPL()->assign([
'success' => true,
'objectEditLink' => LinkHandler::getInstance()->getControllerLink(
CaptchaQuestionEditForm::class,
['id' => $questionID]
),
parent::createForm();

$this->form->appendChildren([
FormContainer::create('general')
->appendChildren([
TextFormField::create('question')
->label('wcf.acp.captcha.question.question')
->i18n()
->languageItemPattern('wcf.captcha.question.question.question\d+')
->required(),
MultilineTextFormField::create('answers')
->label('wcf.acp.captcha.question.answers')
->i18n()
->languageItemPattern('wcf.captcha.question.answers.question\d+')
->required()
->addValidator(
new FormFieldValidator('regexValidator', function (MultilineTextFormField $formField) {
$value = $formField->getValue();

if ($formField->hasPlainValue()) {
$this->validateAnswer($value, $formField);
} else {
foreach ($value as $languageID => $languageValue) {
$this->validateAnswer(
$languageValue,
$formField,
LanguageFactory::getInstance()->getLanguage($languageID)
);
}
}
})
),
BooleanFormField::create('isDisabled')
->label('wcf.acp.captcha.question.isDisabled')
->value(false)
])
]);
}

/**
* @inheritDoc
*/
public function validate()
{
parent::validate();

// validate question
if (!I18nHandler::getInstance()->validateValue('question')) {
if (I18nHandler::getInstance()->isPlainValue('question')) {
throw new UserInputException('question');
} else {
throw new UserInputException('question', 'multilingual');
}
protected function validateAnswer(
string $answer,
MultilineTextFormField $formField,
?Language $language = null
): void {
if (!\str_starts_with('~', $answer) || !\str_ends_with('~', $answer)) {
return;
}

// validate answers
if (!I18nHandler::getInstance()->validateValue('answers')) {
if (I18nHandler::getInstance()->isPlainValue('answers')) {
throw new UserInputException('answers');
} else {
throw new UserInputException('answers', 'multilingual');
}
}

if (I18nHandler::getInstance()->isPlainValue('answers')) {
$answers = \explode("\n", StringUtil::unifyNewlines(I18nHandler::getInstance()->getValue('answers')));
foreach ($answers as $answer) {
if (\mb_substr($answer, 0, 1) == '~' && \mb_substr($answer, -1, 1) == '~') {
$regexLength = \mb_strlen($answer) - 2;
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
$this->invalidRegex = $answer;

throw new UserInputException('answers', 'invalidRegex');
}
}
}
}
foreach (I18nHandler::getInstance()->getValues('answers') as $languageAnswers) {
$answers = \explode("\n", StringUtil::unifyNewlines($languageAnswers));
foreach ($answers as $answer) {
if (\mb_substr($answer, 0, 1) == '~' && \mb_substr($answer, -1, 1) == '~') {
$regexLength = \mb_strlen($answer) - 2;
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
$this->invalidRegex = $answer;

throw new UserInputException('answers', 'invalidRegex');
}
}
}
$regexLength = \mb_strlen($answer) - 2;
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
$formField->addValidationError(
new FormFieldValidationError(
'invalidRegex',
'wcf.acp.captcha.question.answers.error.invalidRegex',
[
'invalidRegex' => $answer,
'language' => $language
]
)
);
}
}
}
Loading

0 comments on commit 27532b5

Please sign in to comment.