1<?php 2/** 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. 7 * 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. 12 * 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 17 * 18 * @file 19 * @ingroup Pager 20 */ 21 22use MediaWiki\Cache\LinkBatchFactory; 23use MediaWiki\HookContainer\HookContainer; 24use MediaWiki\HookContainer\HookRunner; 25use MediaWiki\Permissions\PermissionManager; 26use MediaWiki\User\UserFactory; 27use Wikimedia\Rdbms\ILoadBalancer; 28 29/** 30 * @ingroup Pager 31 */ 32class NewPagesPager extends ReverseChronologicalPager { 33 34 /** 35 * @var FormOptions 36 */ 37 protected $opts; 38 39 /** 40 * @var SpecialNewpages 41 */ 42 protected $mForm; 43 44 /** @var LinkBatchFactory */ 45 private $linkBatchFactory; 46 47 /** @var HookRunner */ 48 private $hookRunner; 49 50 /** @var PermissionManager */ 51 private $permissionManager; 52 53 /** @var NamespaceInfo */ 54 private $namespaceInfo; 55 56 /** @var ActorMigration */ 57 private $actorMigration; 58 59 /** @var UserFactory */ 60 private $userFactory; 61 62 /** 63 * @param SpecialNewpages $form 64 * @param FormOptions $opts 65 * @param LinkBatchFactory $linkBatchFactory 66 * @param HookContainer $hookContainer 67 * @param PermissionManager $permissionManager 68 * @param ILoadBalancer $loadBalancer 69 * @param NamespaceInfo $namespaceInfo 70 * @param ActorMigration $actorMigration 71 * @param UserFactory $userFactory 72 */ 73 public function __construct( 74 $form, 75 FormOptions $opts, 76 LinkBatchFactory $linkBatchFactory, 77 HookContainer $hookContainer, 78 PermissionManager $permissionManager, 79 ILoadBalancer $loadBalancer, 80 NamespaceInfo $namespaceInfo, 81 ActorMigration $actorMigration, 82 UserFactory $userFactory 83 ) { 84 // Set database before parent constructor to avoid setting it there with wfGetDB 85 $this->mDb = $loadBalancer->getConnectionRef( ILoadBalancer::DB_REPLICA ); 86 parent::__construct( $form->getContext() ); 87 $this->mForm = $form; 88 $this->opts = $opts; 89 $this->linkBatchFactory = $linkBatchFactory; 90 $this->hookRunner = new HookRunner( $hookContainer ); 91 $this->permissionManager = $permissionManager; 92 $this->namespaceInfo = $namespaceInfo; 93 $this->actorMigration = $actorMigration; 94 $this->userFactory = $userFactory; 95 } 96 97 public function getQueryInfo() { 98 $rcQuery = RecentChange::getQueryInfo(); 99 100 $conds = []; 101 $conds['rc_new'] = 1; 102 103 $username = $this->opts->getValue( 'username' ); 104 $user = Title::makeTitleSafe( NS_USER, $username ); 105 106 $size = abs( intval( $this->opts->getValue( 'size' ) ) ); 107 if ( $size > 0 ) { 108 if ( $this->opts->getValue( 'size-mode' ) === 'max' ) { 109 $conds[] = 'page_len <= ' . $size; 110 } else { 111 $conds[] = 'page_len >= ' . $size; 112 } 113 } 114 115 if ( $user ) { 116 $userObj = $this->userFactory->newFromName( $user->getText(), UserFactory::RIGOR_NONE ); 117 $conds[] = $this->actorMigration->getWhere( 118 $this->getDatabase(), 'rc_user', $userObj, false 119 )['conds']; 120 } elseif ( $this->canAnonymousUsersCreatePages() && $this->opts->getValue( 'hideliu' ) ) { 121 # If anons cannot make new pages, don't "exclude logged in users"! 122 $conds[] = $this->actorMigration->isAnon( $rcQuery['fields']['rc_user'] ); 123 } 124 125 $conds = array_merge( $conds, $this->getNamespaceCond() ); 126 127 # If this user cannot see patrolled edits or they are off, don't do dumb queries! 128 if ( $this->opts->getValue( 'hidepatrolled' ) && $this->getUser()->useNPPatrol() ) { 129 $conds['rc_patrolled'] = RecentChange::PRC_UNPATROLLED; 130 } 131 132 if ( $this->opts->getValue( 'hidebots' ) ) { 133 $conds['rc_bot'] = 0; 134 } 135 136 if ( $this->opts->getValue( 'hideredirs' ) ) { 137 $conds['page_is_redirect'] = 0; 138 } 139 140 // Allow changes to the New Pages query 141 $tables = array_merge( $rcQuery['tables'], [ 'page' ] ); 142 $fields = array_merge( $rcQuery['fields'], [ 143 'length' => 'page_len', 'rev_id' => 'page_latest', 'page_namespace', 'page_title', 144 'page_content_model', 145 ] ); 146 $join_conds = [ 'page' => [ 'JOIN', 'page_id=rc_cur_id' ] ] + $rcQuery['joins']; 147 148 $this->hookRunner->onSpecialNewpagesConditions( 149 $this, $this->opts, $conds, $tables, $fields, $join_conds ); 150 151 $info = [ 152 'tables' => $tables, 153 'fields' => $fields, 154 'conds' => $conds, 155 'options' => [], 156 'join_conds' => $join_conds 157 ]; 158 159 // Modify query for tags 160 ChangeTags::modifyDisplayQuery( 161 $info['tables'], 162 $info['fields'], 163 $info['conds'], 164 $info['join_conds'], 165 $info['options'], 166 $this->opts['tagfilter'] 167 ); 168 169 return $info; 170 } 171 172 private function canAnonymousUsersCreatePages() { 173 return $this->permissionManager->groupHasPermission( '*', 'createpage' ) || 174 $this->permissionManager->groupHasPermission( '*', 'createtalk' ); 175 } 176 177 // Based on ContribsPager.php 178 private function getNamespaceCond() { 179 $namespace = $this->opts->getValue( 'namespace' ); 180 if ( $namespace === 'all' || $namespace === '' ) { 181 return []; 182 } 183 184 $namespace = intval( $namespace ); 185 if ( $namespace < NS_MAIN ) { 186 // Negative namespaces are invalid 187 return []; 188 } 189 190 $invert = $this->opts->getValue( 'invert' ); 191 $associated = $this->opts->getValue( 'associated' ); 192 193 $eq_op = $invert ? '!=' : '='; 194 $bool_op = $invert ? 'AND' : 'OR'; 195 196 $dbr = $this->getDatabase(); 197 $selectedNS = $dbr->addQuotes( $namespace ); 198 if ( !$associated ) { 199 return [ "rc_namespace $eq_op $selectedNS" ]; 200 } 201 202 $associatedNS = $dbr->addQuotes( 203 $this->namespaceInfo->getAssociated( $namespace ) 204 ); 205 return [ 206 "rc_namespace $eq_op $selectedNS " . 207 $bool_op . 208 " rc_namespace $eq_op $associatedNS" 209 ]; 210 } 211 212 public function getIndexField() { 213 return 'rc_timestamp'; 214 } 215 216 public function formatRow( $row ) { 217 return $this->mForm->formatRow( $row ); 218 } 219 220 protected function getStartBody() { 221 # Do a batch existence check on pages 222 $linkBatch = $this->linkBatchFactory->newLinkBatch(); 223 foreach ( $this->mResult as $row ) { 224 $linkBatch->add( NS_USER, $row->rc_user_text ); 225 $linkBatch->add( NS_USER_TALK, $row->rc_user_text ); 226 $linkBatch->add( $row->page_namespace, $row->page_title ); 227 } 228 $linkBatch->execute(); 229 230 return '<ul>'; 231 } 232 233 protected function getEndBody() { 234 return '</ul>'; 235 } 236} 237