Skip to content

Commit d707370

Browse files
authored
Merge pull request #6213 from WoltLab/6.2-UserAuthenticationFailureListPage-to-grid-view
Migrate `UserAuthenticationFailureListPage` to grid view
2 parents ff9e03e + fe1ba6c commit d707370

File tree

5 files changed

+169
-258
lines changed

5 files changed

+169
-258
lines changed

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

Lines changed: 4 additions & 138 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.user.authentication.failure.list{/lang}{if $items} <span class="badge badgeInverse">{#$items}</span>{/if}</h1>
5+
<h1 class="contentTitle">{lang}wcf.acp.user.authentication.failure.list{/lang} <span class="badge badgeInverse">{#$gridView->countRows()}</span></h1>
66
</div>
77

88
{hascontent}
@@ -14,142 +14,8 @@
1414
{/hascontent}
1515
</header>
1616

17-
<form method="post" action="{link controller='UserAuthenticationFailureList'}{/link}">
18-
<section class="section">
19-
<h2 class="sectionTitle">{lang}wcf.global.filter{/lang}</h2>
20-
21-
<div class="row rowColGap formGrid">
22-
<dl class="col-xs-12 col-md-4">
23-
<dt></dt>
24-
<dd>
25-
<select name="filter[environment]" id="environment">
26-
<option value="">{lang}wcf.acp.user.authentication.failure.environment{/lang}</option>
27-
<option value="admin"{if $filter[environment] === 'admin'} selected{/if}>{lang}wcf.acp.user.authentication.failure.environment.admin{/lang}</option>
28-
<option value="user"{if $filter[environment] === 'user'} selected{/if}>{lang}wcf.acp.user.authentication.failure.environment.user{/lang}</option>
29-
</select>
30-
</dd>
31-
</dl>
32-
33-
<dl class="col-xs-12 col-md-4">
34-
<dt></dt>
35-
<dd>
36-
<input type="text" id="username" name="filter[username]" value="{$filter[username]}" placeholder="{lang}wcf.user.username{/lang}" class="long">
37-
</dd>
38-
</dl>
39-
40-
<dl class="col-xs-12 col-md-4">
41-
<dt></dt>
42-
<dd>
43-
<select name="filter[validationError]" id="validationError">
44-
<option value="">{lang}wcf.acp.user.authentication.failure.validationError{/lang}</option>
45-
<option value="invalidPassword"{if $filter[validationError] === 'invalidPassword'} selected{/if}>{lang}wcf.acp.user.authentication.failure.validationError.invalidPassword{/lang}</option>
46-
<option value="invalidUsername"{if $filter[validationError] === 'invalidUsername'} selected{/if}>{lang}wcf.acp.user.authentication.failure.validationError.invalidUsername{/lang}</option>
47-
{event name='validationErrorFilterOptions'}
48-
</select>
49-
</dd>
50-
</dl>
51-
52-
<dl class="col-xs-12 col-md-4">
53-
<dt></dt>
54-
<dd>
55-
<input type="date" id="startDate" name="filter[startDate]" value="{$filter[startDate]}" data-placeholder="{lang}wcf.acp.user.authentication.failure.time.start{/lang}">
56-
</dd>
57-
</dl>
58-
59-
<dl class="col-xs-12 col-md-4">
60-
<dt></dt>
61-
<dd>
62-
<input type="date" id="endDate" name="filter[endDate]" value="{$filter[endDate]}" data-placeholder="{lang}wcf.acp.user.authentication.failure.time.end{/lang}">
63-
</dd>
64-
</dl>
65-
66-
<dl class="col-xs-12 col-md-4">
67-
<dt></dt>
68-
<dd>
69-
<input type="text" id="userAgent" name="filter[userAgent]" value="{$filter[userAgent]}" placeholder="{lang}wcf.user.userAgent{/lang}" class="long">
70-
</dd>
71-
</dl>
72-
73-
{event name='filterFields'}
74-
</div>
75-
76-
<div class="formSubmit">
77-
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
78-
{csrfToken}
79-
</div>
80-
</section>
81-
</form>
82-
83-
{hascontent}
84-
<div class="paginationTop">
85-
{content}
86-
{pages print=true assign=pagesLinks controller='UserAuthenticationFailureList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$filterLinkParameters"}
87-
{/content}
88-
</div>
89-
{/hascontent}
90-
91-
{if $objects|count}
92-
<div class="section tabularBox">
93-
<table class="table">
94-
<thead>
95-
<tr>
96-
<th class="columnID columnFailureID{if $sortField == 'failureID'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=failureID&sortOrder={if $sortField == 'failureID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
97-
<th class="columnText columnEnvironment{if $sortField == 'environment'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=environment&sortOrder={if $sortField == 'environment' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.user.authentication.failure.environment{/lang}</a></th>
98-
<th class="columnTitle columnUsername{if $sortField == 'username'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=username&sortOrder={if $sortField == 'username' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.user.username{/lang}</a></th>
99-
<th class="columnDate columnTime{if $sortField == 'time'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=time&sortOrder={if $sortField == 'time' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.user.authentication.failure.time{/lang}</a></th>
100-
<th class="columnText columnValidationError{if $sortField === 'validationError'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=validationError&sortOrder={if $sortField === 'validationError' && $sortOrder === 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.user.authentication.failure.validationError{/lang}</a></th>
101-
<th class="columnURL columnIpAddress{if $sortField == 'ipAddress'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=ipAddress&sortOrder={if $sortField == 'ipAddress' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.user.ipAddress{/lang}</a></th>
102-
<th class="columnText columnUserAgent{if $sortField == 'userAgent'} active {@$sortOrder}{/if}"><a href="{link controller='UserAuthenticationFailureList'}pageNo={@$pageNo}&sortField=userAgent&sortOrder={if $sortField == 'userAgent' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.user.userAgent{/lang}</a></th>
103-
104-
{event name='columnHeads'}
105-
</tr>
106-
</thead>
107-
108-
<tbody>
109-
{foreach from=$objects item='authenticationFailure'}
110-
<tr>
111-
<td class="columnID columnFailureID">{@$authenticationFailure->failureID}</td>
112-
<td class="columnText columnEnvironment">{lang}wcf.acp.user.authentication.failure.environment.{@$authenticationFailure->environment}{/lang}</td>
113-
<td class="columnTitle columnUsername">
114-
{if $authenticationFailure->userID}
115-
<a href="{link controller='UserEdit' id=$authenticationFailure->userID}{/link}">{$authenticationFailure->username}</a>
116-
{else}
117-
{$authenticationFailure->username}
118-
{/if}
119-
</td>
120-
<td class="columnDate columnTime">{@$authenticationFailure->time|time}</td>
121-
<td class="columnSmallText columnValidationError">
122-
{if $authenticationFailure->validationError}
123-
{lang}wcf.acp.user.authentication.failure.validationError.{$authenticationFailure->validationError}{/lang}
124-
{/if}
125-
</td>
126-
<td class="columnSmallText columnIpAddress">{$authenticationFailure->getIpAddress()}</td>
127-
<td class="columnSmallText columnUserAgent" title="{$authenticationFailure->userAgent}">{$authenticationFailure->userAgent|truncate:75|tableWordwrap}</td>
128-
129-
{event name='columns'}
130-
</tr>
131-
{/foreach}
132-
</tbody>
133-
</table>
134-
</div>
135-
136-
<footer class="contentFooter">
137-
{hascontent}
138-
<div class="paginationBottom">
139-
{content}{@$pagesLinks}{/content}
140-
</div>
141-
{/hascontent}
142-
143-
{hascontent}
144-
<nav class="contentFooterNavigation">
145-
<ul>
146-
{content}{event name='contentFooterNavigation'}{/content}
147-
</ul>
148-
</nav>
149-
{/hascontent}
150-
</footer>
151-
{else}
152-
<woltlab-core-notice type="info">{lang}wcf.global.noItems{/lang}</woltlab-core-notice>
153-
{/if}
17+
<div class="section">
18+
{unsafe:$gridView->render()}
19+
</div>
15420

15521
{include file='footer'}

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

Lines changed: 11 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
namespace wcf\acp\page;
44

5-
use wcf\data\user\authentication\failure\UserAuthenticationFailureList;
6-
use wcf\page\SortablePage;
7-
use wcf\system\WCF;
5+
use wcf\page\AbstractGridViewPage;
6+
use wcf\system\gridView\AbstractGridView;
7+
use wcf\system\gridView\admin\UserAuthenticationFailureGridView;
88

99
/**
1010
* Shows a list of user authentication failures.
1111
*
12-
* @author Marcel Werk
13-
* @copyright 2001-2019 WoltLab GmbH
14-
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
12+
* @author Olaf Braun, Marcel Werk
13+
* @copyright 2001-2025 WoltLab GmbH
14+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
1515
*
16-
* @property UserAuthenticationFailureList $objectList
16+
* @property UserAuthenticationFailureGridView $gridView
1717
*/
18-
class UserAuthenticationFailureListPage extends SortablePage
18+
class UserAuthenticationFailureListPage extends AbstractGridViewPage
1919
{
2020
/**
2121
* @inheritDoc
@@ -32,118 +32,9 @@ class UserAuthenticationFailureListPage extends SortablePage
3232
*/
3333
public $neededModules = ['ENABLE_USER_AUTHENTICATION_FAILURE'];
3434

35-
/**
36-
* @inheritDoc
37-
*/
38-
public $defaultSortField = 'time';
39-
40-
/**
41-
* @inheritDoc
42-
*/
43-
public $defaultSortOrder = 'DESC';
44-
45-
/**
46-
* @inheritDoc
47-
*/
48-
public $validSortFields = ['failureID', 'environment', 'userID', 'username', 'time', 'ipAddress', 'userAgent', 'validationError'];
49-
50-
/**
51-
* @inheritDoc
52-
*/
53-
public $objectListClassName = UserAuthenticationFailureList::class;
54-
55-
/**
56-
* @var string[]
57-
* @since 5.4
58-
*/
59-
public $filter = [
60-
'environment' => '',
61-
'endDate' => '',
62-
'startDate' => '',
63-
'username' => '',
64-
'userAgent' => '',
65-
'validationError' => '',
66-
];
67-
68-
/**
69-
* @inheritDoc
70-
*/
71-
public function readParameters()
72-
{
73-
parent::readParameters();
74-
75-
if (isset($_REQUEST['filter']) && \is_array($_REQUEST['filter'])) {
76-
foreach ($_REQUEST['filter'] as $key => $value) {
77-
if (\array_key_exists($key, $this->filter)) {
78-
$this->filter[$key] = $value;
79-
}
80-
}
81-
}
82-
}
83-
84-
/**
85-
* @inheritDoc
86-
*/
87-
protected function initObjectList()
35+
#[\Override]
36+
protected function createGridViewController(): AbstractGridView
8837
{
89-
parent::initObjectList();
90-
91-
if ($this->filter['environment'] !== '') {
92-
$this->objectList->getConditionBuilder()->add(
93-
'user_authentication_failure.environment = ?',
94-
[$this->filter['environment']]
95-
);
96-
}
97-
if ($this->filter['endDate'] !== '') {
98-
$endDate = @\strtotime($this->filter['endDate']);
99-
if ($endDate > 0) {
100-
$this->objectList->getConditionBuilder()->add(
101-
'user_authentication_failure.time <= ?',
102-
[$endDate]
103-
);
104-
}
105-
}
106-
if ($this->filter['startDate'] !== '') {
107-
$startDate = @\strtotime($this->filter['startDate']);
108-
if ($startDate > 0) {
109-
$this->objectList->getConditionBuilder()->add(
110-
'user_authentication_failure.time >= ?',
111-
[$startDate]
112-
);
113-
}
114-
}
115-
if ($this->filter['username'] !== '') {
116-
$this->objectList->getConditionBuilder()->add(
117-
'user_authentication_failure.username LIKE ?',
118-
['%' . \addcslashes($this->filter['username'], '_%') . '%']
119-
);
120-
}
121-
if ($this->filter['userAgent'] !== '') {
122-
$this->objectList->getConditionBuilder()->add(
123-
'user_authentication_failure.userAgent LIKE ?',
124-
['%' . \addcslashes($this->filter['userAgent'], '_%') . '%']
125-
);
126-
}
127-
if ($this->filter['validationError'] !== '') {
128-
$this->objectList->getConditionBuilder()->add(
129-
'user_authentication_failure.validationError = ?',
130-
[$this->filter['validationError']]
131-
);
132-
}
133-
}
134-
135-
/**
136-
* @inheritDoc
137-
*/
138-
public function assignVariables()
139-
{
140-
parent::assignVariables();
141-
142-
$filterLinkParameters = \http_build_query(['filter' => \array_filter($this->filter)], '', '&');
143-
144-
WCF::getTPL()->assign([
145-
'filter' => $this->filter,
146-
'filterLinkParameters' => $filterLinkParameters ? '&' . $filterLinkParameters : '',
147-
]);
38+
return new UserAuthenticationFailureGridView();
14839
}
14940
}

wcfsetup/install/files/lib/data/user/authentication/failure/UserAuthenticationFailure.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* @property-read int $time timestamp at which the user authentication failure has occurred
2121
* @property-read string $ipAddress ip address of the user trying to login in
2222
* @property-read string $userAgent user agent of the user trying to login in
23+
* @property-read string $validationError
2324
*/
2425
class UserAuthenticationFailure extends DatabaseObject
2526
{
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\UserAuthenticationFailureGridView;
7+
8+
/**
9+
* Indicates that the user authentication failure 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 UserAuthenticationFailureGridViewInitialized implements IPsr14Event
17+
{
18+
public function __construct(public readonly UserAuthenticationFailureGridView $param)
19+
{
20+
}
21+
}

0 commit comments

Comments
 (0)