Skip to content

Commit 35c5ec4

Browse files
authored
Merge pull request #6192 from WoltLab/6.2-captcha-question-to-grid-view
Migrate `CaptchaQuestionListPage` to grid view
2 parents 8d6376b + b806fd5 commit 35c5ec4

File tree

13 files changed

+420
-84
lines changed

13 files changed

+420
-84
lines changed

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

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<header class="contentHeader">
44
<div class="contentHeaderTitle">
5-
<h1 class="contentTitle">{lang}wcf.acp.captcha.question.list{/lang}{if $items} <span class="badge badgeInverse">{#$items}</span>{/if}</h1>
5+
<h1 class="contentTitle">{lang}wcf.acp.captcha.question.list{/lang}</h1>
66
</div>
77

88
<nav class="contentHeaderNavigation">
@@ -14,68 +14,9 @@
1414
</nav>
1515
</header>
1616

17-
{hascontent}
18-
<div class="paginationTop">
19-
{content}{pages print=true assign=pagesLinks controller="CaptchaQuestionList" link="pageNo=%d"}{/content}
20-
</div>
21-
{/hascontent}
22-
23-
{if $objects|count}
24-
<div id="captchaQuestionTabelContainer" class="section tabularBox">
25-
<table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\captcha\question\CaptchaQuestionAction">
26-
<thead>
27-
<tr>
28-
<th class="columnID columnQuestionID active ASC" colspan="2">{lang}wcf.global.objectID{/lang}</th>
29-
<th class="columnText columnQuestion">{lang}wcf.acp.captcha.question.question{/lang}</th>
30-
<th class="columnDigits columnViews">{lang}wcf.acp.captcha.question.views{/lang}</th>
31-
<th class="columnDigits columnCorrectSubmissions">{lang}wcf.acp.captcha.question.correctSubmissions{/lang}</th>
32-
<th class="columnDigits columnIncorrectSubmissions">{lang}wcf.acp.captcha.question.incorrectSubmissions{/lang}</th>
33-
34-
{event name='columnHeads'}
35-
</tr>
36-
</thead>
37-
38-
<tbody class="jsReloadPageWhenEmpty">
39-
{foreach from=$objects item='question'}
40-
<tr class="jsQuestionRow jsObjectActionObject" data-object-id="{@$question->getObjectID()}">
41-
<td class="columnIcon">
42-
{objectAction action="toggle" isDisabled=$question->isDisabled}
43-
<a href="{link controller='CaptchaQuestionEdit' id=$question->questionID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
44-
{objectAction action="delete" objectTitle=$question->getQuestion()}
45-
46-
{event name='rowButtons'}
47-
</td>
48-
<td class="columnID columnQuestionID">{$question->questionID}</td>
49-
<td class="columnText columnQuestion"><a href="{link controller='CaptchaQuestionEdit' id=$question->questionID}{/link}">{$question->getQuestion()}</a></td>
50-
<td class="columnDigits columnViews">{#$question->views}</td>
51-
<td class="columnDigits columnCorrectSubmissions">{#$question->correctSubmissions}</td>
52-
<td class="columnDigits columnIncorrectSubmissions">{#$question->incorrectSubmissions}</td>
53-
54-
{event name='columns'}
55-
</tr>
56-
{/foreach}
57-
</tbody>
58-
</table>
59-
</div>
60-
61-
<footer class="contentFooter">
62-
{hascontent}
63-
<div class="paginationBottom">
64-
{content}{@$pagesLinks}{/content}
65-
</div>
66-
{/hascontent}
67-
68-
<nav class="contentFooterNavigation">
69-
<ul>
70-
<li><a href="{link controller='CaptchaQuestionAdd'}{/link}" class="button">{icon name='plus'} <span>{lang}wcf.acp.captcha.question.add{/lang}</span></a></li>
71-
72-
{event name='contentFooterNavigation'}
73-
</ul>
74-
</nav>
75-
</footer>
76-
{else}
77-
<woltlab-core-notice type="info">{lang}wcf.global.noItems{/lang}</woltlab-core-notice>
78-
{/if}
17+
<div class="section">
18+
{unsafe:$gridView->render()}
19+
</div>
7920

8021
{include file='footer'}
8122

wcfsetup/install/files/lib/acp/page/CaptchaQuestionListPage.class.php

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
namespace wcf\acp\page;
44

5-
use wcf\data\captcha\question\CaptchaQuestionList;
6-
use wcf\page\MultipleLinkPage;
5+
use wcf\page\AbstractGridViewPage;
6+
use wcf\system\gridView\AbstractGridView;
7+
use wcf\system\gridView\admin\CaptchaQuestionGridView;
78

89
/**
910
* Lists the available captcha questions.
1011
*
11-
* @author Matthias Schmidt
12-
* @copyright 2001-2019 WoltLab GmbH
13-
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
12+
* @author Olaf Braun, Matthias Schmidt
13+
* @copyright 2001-2025 WoltLab GmbH
14+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
1415
*
15-
* @property CaptchaQuestionList $objectList
16+
* @property CaptchaQuestionGridView $gridView
1617
*/
17-
class CaptchaQuestionListPage extends MultipleLinkPage
18+
class CaptchaQuestionListPage extends AbstractGridViewPage
1819
{
1920
/**
2021
* @inheritDoc
@@ -26,18 +27,9 @@ class CaptchaQuestionListPage extends MultipleLinkPage
2627
*/
2728
public $neededPermissions = ['admin.captcha.canManageCaptchaQuestion'];
2829

29-
/**
30-
* @inheritDoc
31-
*/
32-
public $objectListClassName = CaptchaQuestionList::class;
33-
34-
/**
35-
* @inheritDoc
36-
*/
37-
public $sortField = 'questionID';
38-
39-
/**
40-
* @inheritDoc
41-
*/
42-
public $sortOrder = 'ASC';
30+
#[\Override]
31+
protected function createGridViewController(): AbstractGridView
32+
{
33+
return new CaptchaQuestionGridView();
34+
}
4335
}

wcfsetup/install/files/lib/bootstrap/com.woltlab.wcf.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ static function (\wcf\event\endpoint\ControllerCollecting $event) {
166166
$event->register(new \wcf\system\endpoint\controller\core\cronjobs\DisableCronjob());
167167
$event->register(new \wcf\system\endpoint\controller\core\cronjobs\DeleteCronjob());
168168
$event->register(new \wcf\system\endpoint\controller\core\cronjobs\ExecuteCronjob());
169+
$event->register(new \wcf\system\endpoint\controller\core\captchas\questions\EnableQuestion());
170+
$event->register(new \wcf\system\endpoint\controller\core\captchas\questions\DisableQuestion());
171+
$event->register(new \wcf\system\endpoint\controller\core\captchas\questions\DeleteQuestion());
169172
}
170173
);
171174

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace wcf\data\captcha\question;
4+
5+
use wcf\data\I18nDatabaseObjectList;
6+
7+
/**
8+
* I18n implementation of captcha question list.
9+
*
10+
* @author Olaf Brain
11+
* @copyright 2001-2025 WoltLab GmbH
12+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
13+
* @since 6.2
14+
*
15+
* @method CaptchaQuestion current()
16+
* @method CaptchaQuestion[] getObjects()
17+
* @method CaptchaQuestion|null getSingleObject()
18+
* @method CaptchaQuestion|null search($objectID)
19+
* @property CaptchaQuestion[] $objects
20+
*/
21+
class I18nCaptchaQuestionList extends I18nDatabaseObjectList
22+
{
23+
/**
24+
* @inheritDoc
25+
*/
26+
public $i18nFields = ['question' => 'questionI18n'];
27+
28+
/**
29+
* @inheritDoc
30+
*/
31+
public $className = CaptchaQuestion::class;
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\gridView\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\gridView\admin\CaptchaQuestionGridView;
7+
8+
/**
9+
* Indicates that the acp captcha question grid view has been initialized.
10+
*
11+
* @author Olaf Braun
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.2
15+
*/
16+
final class CaptchaQuestionGridViewInitialized implements IPsr14Event
17+
{
18+
public function __construct(public readonly CaptchaQuestionGridView $gridView)
19+
{
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\interaction\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\interaction\admin\CaptchaQuestionInteractions;
7+
8+
/**
9+
* Indicates that the provider for captcha question interactions is collecting interactions.
10+
*
11+
* @author Olaf Braun
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.2
15+
*/
16+
final class CaptchaQuestionInteractionCollecting implements IPsr14Event
17+
{
18+
public function __construct(public readonly CaptchaQuestionInteractions $provider)
19+
{
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace wcf\event\interaction\bulk\admin;
4+
5+
use wcf\event\IPsr14Event;
6+
use wcf\system\interaction\bulk\admin\CaptchaQuestionBulkInteractions;
7+
8+
/**
9+
* Indicates that the provider for captcha question bulk interactions is collecting interactions.
10+
*
11+
* @author Olaf Braun
12+
* @copyright 2001-2025 WoltLab GmbH
13+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14+
* @since 6.2
15+
*/
16+
final class CaptchaQuestionBulkInteractionCollecting implements IPsr14Event
17+
{
18+
public function __construct(public readonly CaptchaQuestionBulkInteractions $provider)
19+
{
20+
}
21+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace wcf\system\endpoint\controller\core\captchas\questions;
4+
5+
use Laminas\Diactoros\Response\JsonResponse;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use wcf\data\captcha\question\CaptchaQuestion;
9+
use wcf\data\captcha\question\CaptchaQuestionAction;
10+
use wcf\http\Helper;
11+
use wcf\system\endpoint\DeleteRequest;
12+
use wcf\system\endpoint\IController;
13+
use wcf\system\WCF;
14+
15+
/**
16+
* API endpoint for deleting captcha questions.
17+
*
18+
* @author Olaf Braun
19+
* @copyright 2001-2025 WoltLab GmbH
20+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
21+
* @since 6.2
22+
*/
23+
#[DeleteRequest('/core/captchas/questions/{id:\d+}')]
24+
final class DeleteQuestion implements IController
25+
{
26+
#[\Override]
27+
public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
28+
{
29+
$question = Helper::fetchObjectFromRequestParameter($variables['id'], CaptchaQuestion::class);
30+
31+
$this->assertQuestionCanBeDeleted();
32+
33+
(new CaptchaQuestionAction([$question], 'delete'))->executeAction();
34+
35+
return new JsonResponse([]);
36+
}
37+
38+
private function assertQuestionCanBeDeleted(): void
39+
{
40+
WCF::getSession()->checkPermissions(['admin.captcha.canManageCaptchaQuestion']);
41+
}
42+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace wcf\system\endpoint\controller\core\captchas\questions;
4+
5+
use Laminas\Diactoros\Response\JsonResponse;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use wcf\data\captcha\question\CaptchaQuestion;
9+
use wcf\data\captcha\question\CaptchaQuestionAction;
10+
use wcf\http\Helper;
11+
use wcf\system\endpoint\IController;
12+
use wcf\system\endpoint\PostRequest;
13+
use wcf\system\exception\PermissionDeniedException;
14+
use wcf\system\WCF;
15+
16+
/**
17+
* API endpoint for disabling captcha questions.
18+
*
19+
* @author Olaf Braun
20+
* @copyright 2001-2025 WoltLab GmbH
21+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
22+
* @since 6.2
23+
*/
24+
#[PostRequest('/core/captchas/questions/{id:\d+}/disable')]
25+
final class DisableQuestion implements IController
26+
{
27+
#[\Override]
28+
public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
29+
{
30+
$question = Helper::fetchObjectFromRequestParameter($variables['id'], CaptchaQuestion::class);
31+
32+
$this->assertQuestionCanBeDisabled($question);
33+
34+
(new CaptchaQuestionAction([$question], 'toggle'))->executeAction();
35+
36+
return new JsonResponse([]);
37+
}
38+
39+
private function assertQuestionCanBeDisabled(CaptchaQuestion $question): void
40+
{
41+
WCF::getSession()->checkPermissions(['admin.captcha.canManageCaptchaQuestion']);
42+
43+
if ($question->isDisabled) {
44+
throw new PermissionDeniedException();
45+
}
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace wcf\system\endpoint\controller\core\captchas\questions;
4+
5+
use Laminas\Diactoros\Response\JsonResponse;
6+
use Psr\Http\Message\ResponseInterface;
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use wcf\data\captcha\question\CaptchaQuestion;
9+
use wcf\data\captcha\question\CaptchaQuestionAction;
10+
use wcf\http\Helper;
11+
use wcf\system\endpoint\IController;
12+
use wcf\system\endpoint\PostRequest;
13+
use wcf\system\exception\PermissionDeniedException;
14+
use wcf\system\WCF;
15+
16+
/**
17+
* API endpoint for enabling captcha questions.
18+
*
19+
* @author Olaf Braun
20+
* @copyright 2001-2025 WoltLab GmbH
21+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
22+
* @since 6.2
23+
*/
24+
#[PostRequest('/core/captchas/questions/{id:\d+}/enable')]
25+
final class EnableQuestion implements IController
26+
{
27+
#[\Override]
28+
public function __invoke(ServerRequestInterface $request, array $variables): ResponseInterface
29+
{
30+
$question = Helper::fetchObjectFromRequestParameter($variables['id'], CaptchaQuestion::class);
31+
32+
$this->assertQuestionCanBeEnabled($question);
33+
34+
(new CaptchaQuestionAction([$question], 'toggle'))->executeAction();
35+
36+
return new JsonResponse([]);
37+
}
38+
39+
private function assertQuestionCanBeEnabled(CaptchaQuestion $question): void
40+
{
41+
WCF::getSession()->checkPermissions(['admin.captcha.canManageCaptchaQuestion']);
42+
43+
if (!$question->isDisabled) {
44+
throw new PermissionDeniedException();
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)