Skip to content

Commit 9f91c1d

Browse files
authored
Merge pull request #6074 from WoltLab/6.2-captcha
Use FormBuilder for captcha questions
2 parents 9daf8a9 + 4e03021 commit 9f91c1d

File tree

7 files changed

+158
-335
lines changed

7 files changed

+158
-335
lines changed

wcfsetup/install/files/acp/templates/captchaQuestionAdd.tpl

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,65 +14,6 @@
1414
</nav>
1515
</header>
1616

17-
{include file='shared_formNotice'}
18-
19-
<form id="adForm" method="post" action="{if $action == 'add'}{link controller='CaptchaQuestionAdd'}{/link}{else}{link controller='CaptchaQuestionEdit' id=$captchaQuestion->questionID}{/link}{/if}">
20-
<div class="section">
21-
<dl{if $errorField == 'question'} class="formError"{/if}>
22-
<dt><label for="question">{lang}wcf.acp.captcha.question.question{/lang}</label></dt>
23-
<dd>
24-
<input type="text" id="question" name="question" value="{$i18nPlainValues[question]}" required autofocus class="long">
25-
{if $errorField == 'question'}
26-
<small class="innerError">
27-
{if $errorType == 'empty'}
28-
{lang}wcf.global.form.error.empty{/lang}
29-
{elseif $errorType == 'multilingual'}
30-
{lang}wcf.global.form.error.multilingual{/lang}
31-
{else}
32-
{lang}wcf.acp.captcha.question.question.error.{$errorType}{/lang}
33-
{/if}
34-
</small>
35-
{/if}
36-
</dd>
37-
</dl>
38-
{include file='shared_multipleLanguageInputJavascript' elementIdentifier='question' forceSelection=false}
39-
40-
<dl{if $errorField == 'answers'} class="formError"{/if}>
41-
<dt><label for="answers">{lang}wcf.acp.captcha.question.answers{/lang}</label></dt>
42-
<dd>
43-
<textarea id="answers" name="answers" cols="40" rows="10">{$i18nPlainValues[answers]}</textarea>
44-
<small>{lang}wcf.acp.captcha.question.answers.description{/lang}</small>
45-
{if $errorField == 'answers'}
46-
<small class="innerError">
47-
{if $errorType == 'empty'}
48-
{lang}wcf.global.form.error.empty{/lang}
49-
{elseif $errorType == 'multilingual'}
50-
{lang}wcf.global.form.error.multilingual{/lang}
51-
{else}
52-
{lang}wcf.acp.captcha.question.answers.error.{$errorType}{/lang}
53-
{/if}
54-
</small>
55-
{/if}
56-
</dd>
57-
</dl>
58-
{include file='shared_multipleLanguageInputJavascript' elementIdentifier='answers' forceSelection=false}
59-
60-
<dl>
61-
<dt></dt>
62-
<dd>
63-
<label><input type="checkbox" name="isDisabled" value="1"{if $isDisabled} checked{/if}> {lang}wcf.acp.captcha.question.isDisabled{/lang}</label>
64-
</dd>
65-
</dl>
66-
67-
{event name='dataFields'}
68-
</div>
69-
70-
{event name='sections'}
71-
72-
<div class="formSubmit">
73-
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
74-
{csrfToken}
75-
</div>
76-
</form>
17+
{unsafe:$form->getHtml()}
7718

7819
{include file='footer'}

wcfsetup/install/files/lib/acp/form/CaptchaQuestionAddForm.class.php

Lines changed: 75 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,35 @@
22

33
namespace wcf\acp\form;
44

5+
use wcf\data\captcha\question\CaptchaQuestion;
56
use wcf\data\captcha\question\CaptchaQuestionAction;
6-
use wcf\data\captcha\question\CaptchaQuestionEditor;
7-
use wcf\form\AbstractForm;
8-
use wcf\system\exception\UserInputException;
9-
use wcf\system\language\I18nHandler;
7+
use wcf\data\language\Language;
8+
use wcf\form\AbstractFormBuilderForm;
9+
use wcf\system\form\builder\container\FormContainer;
10+
use wcf\system\form\builder\field\BooleanFormField;
11+
use wcf\system\form\builder\field\MultilineTextFormField;
12+
use wcf\system\form\builder\field\TextFormField;
13+
use wcf\system\form\builder\field\validation\FormFieldValidationError;
14+
use wcf\system\form\builder\field\validation\FormFieldValidator;
15+
use wcf\system\language\LanguageFactory;
1016
use wcf\system\Regex;
11-
use wcf\system\request\LinkHandler;
12-
use wcf\system\WCF;
13-
use wcf\util\StringUtil;
1417

1518
/**
1619
* Shows the form to create a new captcha question.
1720
*
18-
* @author Matthias Schmidt
19-
* @copyright 2001-2019 WoltLab GmbH
20-
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
21+
* @author Olaf Braun, Matthias Schmidt
22+
* @copyright 2001-2024 WoltLab GmbH
23+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
24+
*
25+
* @property CaptchaQuestion $formObject
2126
*/
22-
class CaptchaQuestionAddForm extends AbstractForm
27+
class CaptchaQuestionAddForm extends AbstractFormBuilderForm
2328
{
2429
/**
2530
* @inheritDoc
2631
*/
2732
public $activeMenuItem = 'wcf.acp.menu.link.captcha.question.add';
2833

29-
/**
30-
* invalid regex in answers
31-
* @var string
32-
*/
33-
public $invalidRegex = '';
34-
35-
/**
36-
* 1 if the question is disabled
37-
* @var int
38-
*/
39-
public $isDisabled = 0;
40-
4134
/**
4235
* @inheritDoc
4336
*/
@@ -46,155 +39,76 @@ class CaptchaQuestionAddForm extends AbstractForm
4639
/**
4740
* @inheritDoc
4841
*/
49-
public function assignVariables()
50-
{
51-
parent::assignVariables();
52-
53-
I18nHandler::getInstance()->assignVariables();
54-
55-
WCF::getTPL()->assign([
56-
'action' => 'add',
57-
'isDisabled' => $this->isDisabled,
58-
'invalidRegex' => $this->invalidRegex,
59-
]);
60-
}
61-
62-
/**
63-
* @inheritDoc
64-
*/
65-
public function readFormParameters()
66-
{
67-
parent::readFormParameters();
68-
69-
I18nHandler::getInstance()->readValues();
70-
71-
if (isset($_POST['isDisabled'])) {
72-
$this->isDisabled = 1;
73-
}
74-
}
42+
public $objectActionClass = CaptchaQuestionAction::class;
7543

7644
/**
7745
* @inheritDoc
7846
*/
79-
public function readParameters()
80-
{
81-
parent::readParameters();
82-
83-
I18nHandler::getInstance()->register('question');
84-
I18nHandler::getInstance()->register('answers');
85-
}
47+
public $objectEditLinkController = CaptchaQuestionEditForm::class;
8648

87-
/**
88-
* @inheritDoc
89-
*/
90-
public function save()
49+
#[\Override]
50+
protected function createForm()
9151
{
92-
parent::save();
93-
94-
$this->objectAction = new CaptchaQuestionAction([], 'create', [
95-
'data' => \array_merge($this->additionalFields, [
96-
'answers' => I18nHandler::getInstance()->isPlainValue('answers') ? I18nHandler::getInstance()->getValue('answers') : '',
97-
'isDisabled' => $this->isDisabled,
98-
'question' => I18nHandler::getInstance()->isPlainValue('question') ? I18nHandler::getInstance()->getValue('question') : '',
99-
]),
100-
]);
101-
$returnValues = $this->objectAction->executeAction();
102-
$questionID = $returnValues['returnValues']->questionID;
103-
104-
// set i18n values
105-
$questionUpdates = [];
106-
if (!I18nHandler::getInstance()->isPlainValue('question')) {
107-
I18nHandler::getInstance()->save(
108-
'question',
109-
'wcf.captcha.question.question.question' . $questionID,
110-
'wcf.captcha.question',
111-
1
112-
);
113-
114-
$questionUpdates['question'] = 'wcf.captcha.question.question.question' . $questionID;
115-
}
116-
if (!I18nHandler::getInstance()->isPlainValue('answers')) {
117-
I18nHandler::getInstance()->save(
118-
'answers',
119-
'wcf.captcha.question.answers.question' . $questionID,
120-
'wcf.captcha.question',
121-
1
122-
);
123-
124-
$questionUpdates['answers'] = 'wcf.captcha.question.answers.question' . $questionID;
125-
}
126-
127-
if (!empty($questionUpdates)) {
128-
$questionEditor = new CaptchaQuestionEditor($returnValues['returnValues']);
129-
$questionEditor->update($questionUpdates);
130-
}
131-
132-
$this->saved();
133-
134-
// reset values
135-
I18nHandler::getInstance()->reset();
136-
$this->isDisabled = 0;
137-
138-
// show success message
139-
WCF::getTPL()->assign([
140-
'success' => true,
141-
'objectEditLink' => LinkHandler::getInstance()->getControllerLink(
142-
CaptchaQuestionEditForm::class,
143-
['id' => $questionID]
144-
),
52+
parent::createForm();
53+
54+
$this->form->appendChildren([
55+
FormContainer::create('general')
56+
->appendChildren([
57+
TextFormField::create('question')
58+
->label('wcf.acp.captcha.question.question')
59+
->i18n()
60+
->languageItemPattern('wcf.captcha.question.question.question\d+')
61+
->required(),
62+
MultilineTextFormField::create('answers')
63+
->label('wcf.acp.captcha.question.answers')
64+
->i18n()
65+
->languageItemPattern('wcf.captcha.question.answers.question\d+')
66+
->required()
67+
->addValidator(
68+
new FormFieldValidator('regexValidator', function (MultilineTextFormField $formField) {
69+
$value = $formField->getValue();
70+
71+
if ($formField->hasPlainValue()) {
72+
$this->validateAnswer($value, $formField);
73+
} else {
74+
foreach ($value as $languageID => $languageValue) {
75+
$this->validateAnswer(
76+
$languageValue,
77+
$formField,
78+
LanguageFactory::getInstance()->getLanguage($languageID)
79+
);
80+
}
81+
}
82+
})
83+
),
84+
BooleanFormField::create('isDisabled')
85+
->label('wcf.acp.captcha.question.isDisabled')
86+
->value(false)
87+
])
14588
]);
14689
}
14790

148-
/**
149-
* @inheritDoc
150-
*/
151-
public function validate()
152-
{
153-
parent::validate();
154-
155-
// validate question
156-
if (!I18nHandler::getInstance()->validateValue('question')) {
157-
if (I18nHandler::getInstance()->isPlainValue('question')) {
158-
throw new UserInputException('question');
159-
} else {
160-
throw new UserInputException('question', 'multilingual');
161-
}
91+
protected function validateAnswer(
92+
string $answer,
93+
MultilineTextFormField $formField,
94+
?Language $language = null
95+
): void {
96+
if (!\str_starts_with('~', $answer) || !\str_ends_with('~', $answer)) {
97+
return;
16298
}
16399

164-
// validate answers
165-
if (!I18nHandler::getInstance()->validateValue('answers')) {
166-
if (I18nHandler::getInstance()->isPlainValue('answers')) {
167-
throw new UserInputException('answers');
168-
} else {
169-
throw new UserInputException('answers', 'multilingual');
170-
}
171-
}
172-
173-
if (I18nHandler::getInstance()->isPlainValue('answers')) {
174-
$answers = \explode("\n", StringUtil::unifyNewlines(I18nHandler::getInstance()->getValue('answers')));
175-
foreach ($answers as $answer) {
176-
if (\mb_substr($answer, 0, 1) == '~' && \mb_substr($answer, -1, 1) == '~') {
177-
$regexLength = \mb_strlen($answer) - 2;
178-
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
179-
$this->invalidRegex = $answer;
180-
181-
throw new UserInputException('answers', 'invalidRegex');
182-
}
183-
}
184-
}
185-
}
186-
foreach (I18nHandler::getInstance()->getValues('answers') as $languageAnswers) {
187-
$answers = \explode("\n", StringUtil::unifyNewlines($languageAnswers));
188-
foreach ($answers as $answer) {
189-
if (\mb_substr($answer, 0, 1) == '~' && \mb_substr($answer, -1, 1) == '~') {
190-
$regexLength = \mb_strlen($answer) - 2;
191-
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
192-
$this->invalidRegex = $answer;
193-
194-
throw new UserInputException('answers', 'invalidRegex');
195-
}
196-
}
197-
}
100+
$regexLength = \mb_strlen($answer) - 2;
101+
if (!$regexLength || !Regex::compile(\mb_substr($answer, 1, $regexLength))->isValid()) {
102+
$formField->addValidationError(
103+
new FormFieldValidationError(
104+
'invalidRegex',
105+
'wcf.acp.captcha.question.answers.error.invalidRegex',
106+
[
107+
'invalidRegex' => $answer,
108+
'language' => $language
109+
]
110+
)
111+
);
198112
}
199113
}
200114
}

0 commit comments

Comments
 (0)