X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2Fspecials%2FSpecialDeletedContributions.php;h=76dc7ada61b698c990d61490c6123ab204ad1678;hb=03d1d295b99713bbe4657d26448bb7fc2b57d013;hp=6256bbf21a166150158ea98439d8d5d25ba3b7fe;hpb=a1bf5109f122fc3928d834141558e25a08a989ab;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php index 6256bbf21a..76dc7ada61 100644 --- a/includes/specials/SpecialDeletedContributions.php +++ b/includes/specials/SpecialDeletedContributions.php @@ -25,341 +25,12 @@ * Implements Special:DeletedContributions to display archived revisions * @ingroup SpecialPage */ -class DeletedContribsPager extends IndexPager { - public $mDefaultDirection = IndexPager::DIR_DESCENDING; - public $messages; - public $target; - public $namespace = ''; - public $mDb; - - /** - * @var string Navigation bar with paging links. - */ - protected $mNavigationBar; - - function __construct( IContextSource $context, $target, $namespace = false ) { - parent::__construct( $context ); - $msgs = [ 'deletionlog', 'undeleteviewlink', 'diff' ]; - foreach ( $msgs as $msg ) { - $this->messages[$msg] = $this->msg( $msg )->escaped(); - } - $this->target = $target; - $this->namespace = $namespace; - $this->mDb = wfGetDB( DB_SLAVE, 'contributions' ); - } - - function getDefaultQuery() { - $query = parent::getDefaultQuery(); - $query['target'] = $this->target; - - return $query; - } - - function getQueryInfo() { - list( $index, $userCond ) = $this->getUserCond(); - $conds = array_merge( $userCond, $this->getNamespaceCond() ); - $user = $this->getUser(); - // Paranoia: avoid brute force searches (bug 17792) - if ( !$user->isAllowed( 'deletedhistory' ) ) { - $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0'; - } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { - $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) . - ' != ' . Revision::SUPPRESSED_USER; - } - - return [ - 'tables' => [ 'archive' ], - 'fields' => [ - 'ar_rev_id', 'ar_namespace', 'ar_title', 'ar_timestamp', 'ar_comment', - 'ar_minor_edit', 'ar_user', 'ar_user_text', 'ar_deleted' - ], - 'conds' => $conds, - 'options' => [ 'USE INDEX' => $index ] - ]; - } - - /** - * This method basically executes the exact same code as the parent class, though with - * a hook added, to allow extensions to add additional queries. - * - * @param string $offset Index offset, inclusive - * @param int $limit Exact query limit - * @param bool $descending Query direction, false for ascending, true for descending - * @return ResultWrapper - */ - function reallyDoQuery( $offset, $limit, $descending ) { - $data = [ parent::reallyDoQuery( $offset, $limit, $descending ) ]; - - // This hook will allow extensions to add in additional queries, nearly - // identical to ContribsPager::reallyDoQuery. - Hooks::run( - 'DeletedContribsPager::reallyDoQuery', - [ &$data, $this, $offset, $limit, $descending ] - ); - - $result = []; - - // loop all results and collect them in an array - foreach ( $data as $query ) { - foreach ( $query as $i => $row ) { - // use index column as key, allowing us to easily sort in PHP - $result[$row->{$this->getIndexField()} . "-$i"] = $row; - } - } - - // sort results - if ( $descending ) { - ksort( $result ); - } else { - krsort( $result ); - } - - // enforce limit - $result = array_slice( $result, 0, $limit ); - - // get rid of array keys - $result = array_values( $result ); - - return new FakeResultWrapper( $result ); - } - - function getUserCond() { - $condition = []; - - $condition['ar_user_text'] = $this->target; - $index = 'usertext_timestamp'; - - return [ $index, $condition ]; - } - - function getIndexField() { - return 'ar_timestamp'; - } - - function getStartBody() { - return "\n"; - } - - function getNavigationBar() { - if ( isset( $this->mNavigationBar ) ) { - return $this->mNavigationBar; - } - - $linkTexts = [ - 'prev' => $this->msg( 'pager-newer-n' )->numParams( $this->mLimit )->escaped(), - 'next' => $this->msg( 'pager-older-n' )->numParams( $this->mLimit )->escaped(), - 'first' => $this->msg( 'histlast' )->escaped(), - 'last' => $this->msg( 'histfirst' )->escaped() - ]; - - $pagingLinks = $this->getPagingLinks( $linkTexts ); - $limitLinks = $this->getLimitLinks(); - $lang = $this->getLanguage(); - $limits = $lang->pipeList( $limitLinks ); - - $firstLast = $lang->pipeList( [ $pagingLinks['first'], $pagingLinks['last'] ] ); - $firstLast = $this->msg( 'parentheses' )->rawParams( $firstLast )->escaped(); - $prevNext = $this->msg( 'viewprevnext' ) - ->rawParams( - $pagingLinks['prev'], - $pagingLinks['next'], - $limits - )->escaped(); - $separator = $this->msg( 'word-separator' )->escaped(); - $this->mNavigationBar = $firstLast . $separator . $prevNext; - - return $this->mNavigationBar; - } - - function getNamespaceCond() { - if ( $this->namespace !== '' ) { - return [ 'ar_namespace' => (int)$this->namespace ]; - } else { - return []; - } - } - - /** - * Generates each row in the contributions list. - * - * @todo This would probably look a lot nicer in a table. - * @param stdClass $row - * @return string - */ - function formatRow( $row ) { - $ret = ''; - $classes = []; - - /* - * There may be more than just revision rows. To make sure that we'll only be processing - * revisions here, let's _try_ to build a revision out of our row (without displaying - * notices though) and then trying to grab data from the built object. If we succeed, - * we're definitely dealing with revision data and we may proceed, if not, we'll leave it - * to extensions to subscribe to the hook to parse the row. - */ - MediaWiki\suppressWarnings(); - try { - $rev = Revision::newFromArchiveRow( $row ); - $validRevision = (bool)$rev->getId(); - } catch ( Exception $e ) { - $validRevision = false; - } - MediaWiki\restoreWarnings(); - - if ( $validRevision ) { - $ret = $this->formatRevisionRow( $row ); - } - - // Let extensions add data - Hooks::run( 'DeletedContributionsLineEnding', [ $this, &$ret, $row, &$classes ] ); - - if ( $classes === [] && $ret === '' ) { - wfDebug( "Dropping Special:DeletedContribution row that could not be formatted\n" ); - $ret = "\n"; - } else { - $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n"; - } - - return $ret; - } - - /** - * Generates each row in the contributions list for archive entries. - * - * Contributions which are marked "top" are currently on top of the history. - * For these contributions, a [rollback] link is shown for users with sysop - * privileges. The rollback link restores the most recent version that was not - * written by the target user. - * - * @todo This would probably look a lot nicer in a table. - * @param stdClass $row - * @return string - */ - function formatRevisionRow( $row ) { - $page = Title::makeTitle( $row->ar_namespace, $row->ar_title ); - - $rev = new Revision( [ - 'title' => $page, - 'id' => $row->ar_rev_id, - 'comment' => $row->ar_comment, - 'user' => $row->ar_user, - 'user_text' => $row->ar_user_text, - 'timestamp' => $row->ar_timestamp, - 'minor_edit' => $row->ar_minor_edit, - 'deleted' => $row->ar_deleted, - ] ); - - $undelete = SpecialPage::getTitleFor( 'Undelete' ); - - $logs = SpecialPage::getTitleFor( 'Log' ); - $dellog = Linker::linkKnown( - $logs, - $this->messages['deletionlog'], - [], - [ - 'type' => 'delete', - 'page' => $page->getPrefixedText() - ] - ); - - $reviewlink = Linker::linkKnown( - SpecialPage::getTitleFor( 'Undelete', $page->getPrefixedDBkey() ), - $this->messages['undeleteviewlink'] - ); - - $user = $this->getUser(); - - if ( $user->isAllowed( 'deletedtext' ) ) { - $last = Linker::linkKnown( - $undelete, - $this->messages['diff'], - [], - [ - 'target' => $page->getPrefixedText(), - 'timestamp' => $rev->getTimestamp(), - 'diff' => 'prev' - ] - ); - } else { - $last = $this->messages['diff']; - } - - $comment = Linker::revComment( $rev ); - $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $user ); - $date = htmlspecialchars( $date ); - - if ( !$user->isAllowed( 'undelete' ) || !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { - $link = $date; // unusable link - } else { - $link = Linker::linkKnown( - $undelete, - $date, - [ 'class' => 'mw-changeslist-date' ], - [ - 'target' => $page->getPrefixedText(), - 'timestamp' => $rev->getTimestamp() - ] - ); - } - // Style deleted items - if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { - $link = '' . $link . ''; - } - - $pagelink = Linker::link( - $page, - null, - [ 'class' => 'mw-changeslist-title' ] - ); - - if ( $rev->isMinor() ) { - $mflag = ChangesList::flag( 'minor' ); - } else { - $mflag = ''; - } - - // Revision delete link - $del = Linker::getRevDeleteLink( $user, $rev, $page ); - if ( $del ) { - $del .= ' '; - } - - $tools = Html::rawElement( - 'span', - [ 'class' => 'mw-deletedcontribs-tools' ], - $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( - [ $last, $dellog, $reviewlink ] ) )->escaped() - ); - - $separator = '. .'; - $ret = "{$del}{$link} {$tools} {$separator} {$mflag} {$pagelink} {$comment}"; - - # Denote if username is redacted for this edit - if ( $rev->isDeleted( Revision::DELETED_USER ) ) { - $ret .= " " . $this->msg( 'rev-deleted-user-contribs' )->escaped() . ""; - } - - return $ret; - } - - /** - * Get the Database object in use - * - * @return IDatabase - */ - public function getDatabase() { - return $this->mDb; - } -} - class DeletedContributionsPage extends SpecialPage { + /** @var FormOptions */ + protected $mOpts; + function __construct() { - parent::__construct( 'DeletedContributions', 'deletedhistory', - /*listed*/true, /*function*/false, /*file*/false ); + parent::__construct( 'DeletedContributions', 'deletedhistory' ); } /** @@ -371,40 +42,43 @@ class DeletedContributionsPage extends SpecialPage { function execute( $par ) { $this->setHeaders(); $this->outputHeader(); + $this->checkPermissions(); $user = $this->getUser(); - if ( !$this->userCanExecute( $user ) ) { - $this->displayRestrictionError(); - - return; - } - - $request = $this->getRequest(); $out = $this->getOutput(); $out->setPageTitle( $this->msg( 'deletedcontributions-title' ) ); - $options = []; + $opts = new FormOptions(); + + $opts->add( 'target', '' ); + $opts->add( 'namespace', '' ); + $opts->add( 'limit', 20 ); + + $opts->fetchValuesFromRequest( $this->getRequest() ); + $opts->validateIntBounds( 'limit', 0, $this->getConfig()->get( 'QueryPageDefaultLimit' ) ); if ( $par !== null ) { - $target = $par; - } else { - $target = $request->getVal( 'target' ); + $opts->setValue( 'target', $par ); } + $ns = $opts->getValue( 'namespace' ); + if ( $ns !== null && $ns !== '' ) { + $opts->setValue( 'namespace', intval( $ns ) ); + } + + $this->mOpts = $opts; + + $target = $opts->getValue( 'target' ); if ( !strlen( $target ) ) { - $out->addHTML( $this->getForm( '' ) ); + $this->getForm(); return; } - $options['limit'] = $request->getInt( 'limit', - $this->getConfig()->get( 'QueryPageDefaultLimit' ) ); - $options['target'] = $target; - $userObj = User::newFromName( $target, false ); if ( !$userObj ) { - $out->addHTML( $this->getForm( '' ) ); + $this->getForm(); return; } @@ -413,16 +87,9 @@ class DeletedContributionsPage extends SpecialPage { $target = $userObj->getName(); $out->addSubtitle( $this->getSubTitle( $userObj ) ); - $ns = $request->getVal( 'namespace', null ); - if ( $ns !== null && $ns !== '' ) { - $options['namespace'] = intval( $ns ); - } else { - $options['namespace'] = ''; - } - - $out->addHTML( $this->getForm( $options ) ); + $this->getForm(); - $pager = new DeletedContribsPager( $this->getContext(), $target, $options['namespace'] ); + $pager = new DeletedContribsPager( $this->getContext(), $target, $opts->getValue( 'namespace' ) ); if ( !$pager->getNumRows() ) { $out->addWikiMsg( 'nocontribs' ); @@ -586,76 +253,35 @@ class DeletedContributionsPage extends SpecialPage { /** * Generates the namespace selector form with hidden attributes. - * @param array $options The options to be included. - * @return string */ - function getForm( $options ) { - $options['title'] = $this->getPageTitle()->getPrefixedText(); - if ( !isset( $options['target'] ) ) { - $options['target'] = ''; - } else { - $options['target'] = str_replace( '_', ' ', $options['target'] ); - } - - if ( !isset( $options['namespace'] ) ) { - $options['namespace'] = ''; - } - - if ( !isset( $options['contribs'] ) ) { - $options['contribs'] = 'user'; - } - - if ( $options['contribs'] == 'newbie' ) { - $options['target'] = ''; - } - - $f = Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] ); - - foreach ( $options as $name => $value ) { - if ( in_array( $name, [ 'namespace', 'target', 'contribs' ] ) ) { - continue; - } - $f .= "\t" . Html::hidden( $name, $value ) . "\n"; - } + function getForm() { + $opts = $this->mOpts; + + $formDescriptor = [ + 'target' => [ + 'type' => 'user', + 'name' => 'target', + 'label-message' => 'sp-contributions-username', + 'default' => $opts->getValue( 'target' ), + 'ipallowed' => true, + ], - $this->getOutput()->addModules( 'mediawiki.userSuggest' ); - - $f .= Xml::openElement( 'fieldset' ); - $f .= Xml::element( 'legend', [], $this->msg( 'sp-contributions-search' )->text() ); - $f .= Xml::tags( - 'label', - [ 'for' => 'target' ], - $this->msg( 'sp-contributions-username' )->parse() - ) . ' '; - $f .= Html::input( - 'target', - $options['target'], - 'text', - [ - 'size' => '20', - 'required' => '', - 'class' => [ - 'mw-autocomplete-user', // used by mediawiki.userSuggest - ], - ] + ( $options['target'] ? [] : [ 'autofocus' ] ) - ) . ' '; - $f .= Html::namespaceSelector( - [ - 'selected' => $options['namespace'], + 'namespace' => [ + 'type' => 'namespaceselect', + 'name' => 'namespace', + 'label-message' => 'namespace', 'all' => '', - 'label' => $this->msg( 'namespace' )->text() ], - [ - 'name' => 'namespace', - 'id' => 'namespace', - 'class' => 'namespaceselector', - ] - ) . ' '; - $f .= Xml::submitButton( $this->msg( 'sp-contributions-submit' )->text() ); - $f .= Xml::closeElement( 'fieldset' ); - $f .= Xml::closeElement( 'form' ); - - return $f; + ]; + + $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ) + ->setWrapperLegendMsg( 'sp-contributions-search' ) + ->setSubmitTextMsg( 'sp-contributions-submit' ) + // prevent setting subpage and 'target' parameter at the same time + ->setAction( $this->getPageTitle()->getLocalURL() ) + ->setMethod( 'get' ) + ->prepareForm() + ->displayForm( false ); } /**