3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
22 namespace MediaWiki\Pager
;
26 use MediaWiki\Cache\LinkBatchFactory
;
27 use MediaWiki\CommentFormatter\RowCommentFormatter
;
28 use MediaWiki\CommentStore\CommentStore
;
29 use MediaWiki\Context\IContextSource
;
30 use MediaWiki\Html\Html
;
31 use MediaWiki\Linker\Linker
;
32 use MediaWiki\Linker\LinkRenderer
;
33 use MediaWiki\Title\Title
;
34 use UnexpectedValueException
;
35 use Wikimedia\Rdbms\FakeResultWrapper
;
36 use Wikimedia\Rdbms\IConnectionProvider
;
38 class ProtectedPagesPager
extends TablePager
{
57 private CommentStore
$commentStore;
58 private LinkBatchFactory
$linkBatchFactory;
59 private RowCommentFormatter
$rowCommentFormatter;
62 private $formattedComments = [];
65 * @param IContextSource $context
66 * @param CommentStore $commentStore
67 * @param LinkBatchFactory $linkBatchFactory
68 * @param LinkRenderer $linkRenderer
69 * @param IConnectionProvider $dbProvider
70 * @param RowCommentFormatter $rowCommentFormatter
72 * @param string $level
73 * @param int|null $namespace
74 * @param string $sizetype
75 * @param int|null $size
76 * @param bool $indefonly
77 * @param bool $cascadeonly
78 * @param bool $noredirect
80 public function __construct(
81 IContextSource
$context,
82 CommentStore
$commentStore,
83 LinkBatchFactory
$linkBatchFactory,
84 LinkRenderer
$linkRenderer,
85 IConnectionProvider
$dbProvider,
86 RowCommentFormatter
$rowCommentFormatter,
96 // Set database before parent constructor to avoid setting it there
97 $this->mDb
= $dbProvider->getReplicaDatabase();
98 parent
::__construct( $context, $linkRenderer );
99 $this->commentStore
= $commentStore;
100 $this->linkBatchFactory
= $linkBatchFactory;
101 $this->rowCommentFormatter
= $rowCommentFormatter;
102 $this->type
= $type ?
: 'edit';
103 $this->level
= $level;
104 $this->namespace = $namespace;
105 $this->sizetype
= $sizetype;
106 $this->size
= intval( $size );
107 $this->indefonly
= (bool)$indefonly;
108 $this->cascadeonly
= (bool)$cascadeonly;
109 $this->noredirect
= (bool)$noredirect;
112 public function preprocessResults( $result ) {
113 # Do a link batch query
114 $lb = $this->linkBatchFactory
->newLinkBatch();
115 $rowsWithComments = [];
117 foreach ( $result as $row ) {
118 $lb->add( $row->page_namespace
, $row->page_title
);
119 // for old protection rows, user and comment are missing
120 if ( $row->actor_name
!== null ) {
121 $lb->add( NS_USER
, $row->actor_name
);
122 $lb->add( NS_USER_TALK
, $row->actor_name
);
124 if ( $row->log_timestamp
!== null ) {
125 $rowsWithComments[] = $row;
131 // Format the comments
132 $this->formattedComments
= $this->rowCommentFormatter
->formatRows(
133 new FakeResultWrapper( $rowsWithComments ),
141 protected function getFieldNames() {
142 static $headers = null;
144 if ( $headers === null ) {
146 'log_timestamp' => 'protectedpages-timestamp',
147 'pr_page' => 'protectedpages-page',
148 'pr_expiry' => 'protectedpages-expiry',
149 'actor_user' => 'protectedpages-performer',
150 'pr_params' => 'protectedpages-params',
151 'log_comment' => 'protectedpages-reason',
153 foreach ( $headers as $key => $val ) {
154 $headers[$key] = $this->msg( $val )->text();
162 * @param string $field
163 * @param string|null $value
164 * @return string HTML
166 public function formatValue( $field, $value ) {
167 /** @var stdClass $row */
168 $row = $this->mCurrentRow
;
169 $linkRenderer = $this->getLinkRenderer();
172 case 'log_timestamp':
173 // when timestamp is null, this is a old protection row
174 if ( $value === null ) {
175 $formatted = Html
::rawElement(
177 [ 'class' => 'mw-protectedpages-unknown' ],
178 $this->msg( 'protectedpages-unknown-timestamp' )->escaped()
181 $formatted = htmlspecialchars( $this->getLanguage()->userTimeAndDate(
182 $value, $this->getUser() ) );
187 $title = Title
::makeTitleSafe( $row->page_namespace
, $row->page_title
);
189 $formatted = Html
::element(
191 [ 'class' => 'mw-invalidtitle' ],
192 Linker
::getInvalidTitleDescription(
194 $row->page_namespace
,
199 $formatted = $linkRenderer->makeLink( $title );
201 $formatted = Html
::rawElement( 'bdi', [
202 'dir' => $this->getLanguage()->getDir()
204 if ( $row->page_len
!== null ) {
205 $formatted .= ' ' . Html
::rawElement(
207 [ 'class' => 'mw-protectedpages-length' ],
208 Linker
::formatRevisionSize( $row->page_len
)
214 $formatted = htmlspecialchars( $this->getLanguage()->formatExpiry(
215 $value, /* User preference timezone */true, 'infinity', $this->getUser() ) );
216 $title = Title
::makeTitleSafe( $row->page_namespace
, $row->page_title
);
217 if ( $title && $this->getAuthority()->isAllowed( 'protect' ) ) {
218 $changeProtection = $linkRenderer->makeKnownLink(
220 $this->msg( 'protect_change' )->text(),
222 [ 'action' => 'unprotect' ]
224 $formatted .= ' ' . Html
::rawElement(
226 [ 'class' => 'mw-protectedpages-actions' ],
227 $this->msg( 'parentheses' )->rawParams( $changeProtection )->escaped()
233 // when timestamp is null, this is a old protection row
234 if ( $row->log_timestamp
=== null ) {
235 $formatted = Html
::rawElement(
237 [ 'class' => 'mw-protectedpages-unknown' ],
238 $this->msg( 'protectedpages-unknown-performer' )->escaped()
241 $username = $row->actor_name
;
242 if ( LogEventsList
::userCanBitfield(
244 LogPage
::DELETED_USER
,
245 $this->getAuthority()
247 $formatted = Linker
::userLink( (int)$value, $username )
248 . Linker
::userToolLinks( (int)$value, $username );
250 $formatted = $this->msg( 'rev-deleted-user' )->escaped();
252 if ( LogEventsList
::isDeleted( $row, LogPage
::DELETED_USER
) ) {
253 $formatted = '<span class="history-deleted">' . $formatted . '</span>';
260 // Messages: restriction-level-sysop, restriction-level-autoconfirmed
261 $params[] = $this->msg( 'restriction-level-' . $row->pr_level
)->escaped();
262 if ( $row->pr_cascade
) {
263 $params[] = $this->msg( 'protect-summary-cascade' )->escaped();
265 $formatted = $this->getLanguage()->commaList( $params );
269 // when timestamp is null, this is an old protection row
270 if ( $row->log_timestamp
=== null ) {
271 $formatted = Html
::rawElement(
273 [ 'class' => 'mw-protectedpages-unknown' ],
274 $this->msg( 'protectedpages-unknown-reason' )->escaped()
277 if ( LogEventsList
::userCanBitfield(
279 LogPage
::DELETED_COMMENT
,
280 $this->getAuthority()
282 $formatted = $this->formattedComments
[$row->pr_id
];
284 $formatted = $this->msg( 'rev-deleted-comment' )->escaped();
286 if ( LogEventsList
::isDeleted( $row, LogPage
::DELETED_COMMENT
) ) {
287 $formatted = '<span class="history-deleted">' . $formatted . '</span>';
293 throw new UnexpectedValueException( "Unknown field '$field'" );
299 public function getQueryInfo() {
300 $dbr = $this->getDatabase();
302 $dbr->expr( 'pr_expiry', '>', $dbr->timestamp() )
303 ->or( 'pr_expiry', '=', null ),
305 $dbr->expr( 'pr_type', '=', $this->type
),
308 if ( $this->sizetype
== 'min' ) {
309 $conds[] = 'page_len>=' . $this->size
;
310 } elseif ( $this->sizetype
== 'max' ) {
311 $conds[] = 'page_len<=' . $this->size
;
314 if ( $this->indefonly
) {
315 $conds['pr_expiry'] = [ $dbr->getInfinity(), null ];
317 if ( $this->cascadeonly
) {
318 $conds['pr_cascade'] = 1;
320 if ( $this->noredirect
) {
321 $conds['page_is_redirect'] = 0;
324 if ( $this->level
) {
325 $conds[] = $dbr->expr( 'pr_level', '=', $this->level
);
327 if ( $this->namespace !== null ) {
328 $conds[] = $dbr->expr( 'page_namespace', '=', $this->namespace );
331 $commentQuery = $this->commentStore
->getJoin( 'log_comment' );
335 'page', 'page_restrictions', 'log_search',
336 'logparen' => [ 'logging', 'actor' ] +
$commentQuery['tables'],
351 ] +
$commentQuery['fields'],
356 'ls_field' => 'pr_id', 'ls_value = ' . $dbr->buildStringCast( 'pr_id' )
369 ] +
$commentQuery['joins']
373 protected function getTableClass() {
374 return parent
::getTableClass() . ' mw-protectedpages';
377 public function getIndexField() {
381 public function getDefaultSort() {
385 protected function isFieldSortable( $field ) {
386 // no index for sorting exists
392 * Retain the old class name for backwards compatibility.
393 * @deprecated since 1.41
395 class_alias( ProtectedPagesPager
::class, 'ProtectedPagesPager' );