getRequest(); $this->mMode = $request->getVal( 'show' ); } /** * These two arrays pair mode with messages. E.g. mode "approvedpages" * is used to generate a header link with query string having "show=approvedpages" * and link text of "All pages with an approved revision" (in English). */ protected $mPageHeaderLinks = [ 'approvedrevs-notlatestpages' => '', 'approvedrevs-unapprovedpages' => 'unapproved', 'approvedrevs-approvedpages' => 'all', 'approvedrevs-invalidpages' => 'invalid', ]; protected $mFileHeaderLinks = [ 'approvedrevs-notlatestfiles' => 'notlatestfiles', 'approvedrevs-unapprovedfiles' => 'unapprovedfiles', 'approvedrevs-approvedfiles' => 'approvedfiles', 'approvedrevs-invalidfiles' => 'invalidfiles', ]; public function isExpensive() { return false; } public function isSyndicated() { return false; } protected function getPageHeader() { global $egApprovedRevsEnabledNamespaces; // Show the page approval links, with the one // corresponding to the current "mode" not being linked. $navLinks = []; foreach ( $this->mPageHeaderLinks as $msg => $mode ) { $navLinks[] = $this->createHeaderLink( $msg, $mode ); } // Also add the file approval links, but only if there have // been any file approvals. if ( isset( $egApprovedRevsEnabledNamespaces[NS_FILE] ) && $egApprovedRevsEnabledNamespaces[NS_FILE] ) { $dbr = ApprovedRevs::getReadDB(); $result = $dbr->selectField( 'approved_revs_files', 'COUNT(*)' ); if ( $result > 0 ) { foreach ( $this->mFileHeaderLinks as $msg => $mode ) { $navLinks[] = $this->createHeaderLink( $msg, $mode ); } } } $navLine = $this->msg( 'approvedrevs-view' )->escaped() . ' ' . implode( ' | ', $navLinks ); $header = Xml::tags( 'p', null, $navLine ) . "\n"; return Xml::tags( 'div', [ 'class' => 'specialapprovedrevs-header' ], $header ); } /** * Generate links for header. For current mode, generate non-link bold * text. */ public function createHeaderLink( $msg, $mode ) { if ( $this->mMode == $mode ) { return Html::element( 'strong', null, $this->msg( $msg )->text() ); } else { $approvedPagesTitle = SpecialPage::getTitleFor( $this->getName() ); $show = ( $mode == '' ) ? [] : [ 'show' => $mode ]; return Html::element( 'a', [ 'href' => $approvedPagesTitle->getLocalURL( $show ) ], $this->msg( $msg )->text() ); } } /** * Set parameters for standard navigation links. * i.e. Applies mode to next/prev links when paging through list, etc. */ protected function linkParameters() { // Optionally could validate $this->mMode against the two // link arrays. return $this->mMode == '' ? [] : [ 'show' => $this->mMode ]; } public function getQueryInfo() { // SQL for page revision approvals versus file revision approvals is // significantly different. Easier to follow if broken into two functions. if ( in_array( $this->mMode, [ 'notlatestfiles', 'unapprovedfiles', 'approvedfiles', 'invalidfiles' ] ) ) { $query = ApprovedRevs::getQueryInfoFileApprovals( $this->mMode ); } else { $query = ApprovedRevs::getQueryInfoPageApprovals( $this->mMode ); } if ( in_array( $this->mMode, [ 'all', 'approvedfiles' ] ) ) { $query['tables'] = array_merge( $query['tables'], [ 'logging', 'actor' ] ); $query['fields'] = array_merge( $query['fields'], [ 'log_user' => 'actor_user', 'log_user_name' => 'actor_name', 'log_timestamp', ] ); $query['join_conds'] += [ 'logging' => [ 'LEFT OUTER JOIN', 'p.page_id=log_page' ], 'actor' => [ 'JOIN', 'log_actor=actor_id' ], ]; $query['conds']['log_type'] = 'approval'; } return $query; } protected function getOrderFields() { return [ 'p.page_namespace', 'p.page_title' ]; } protected function sortDescending() { return false; } protected function formatResult( $skin, $result ) { // SQL for page revision approvals versus file revision approvals is // significantly different. Easier to follow if broken into two functions. if ( in_array( $this->mMode, [ 'notlatestfiles', 'unapprovedfiles', 'approvedfiles', 'invalidfiles' ] ) ) { return $this->formatResultFileApprovals( $skin, $result ); } else { return $this->formatResultPageApprovals( $skin, $result ); } } public function formatResultPageApprovals( $skin, $result ) { $title = Title::newFromId( $result->id ); if ( $title === null ) { return false; } if ( !ApprovedRevs::pageIsApprovable( $title ) && $this->mMode !== 'invalid' ) { return false; } $context = $skin->getContext(); $user = $context->getUser(); $lang = $context->getLanguage(); $linkRenderer = $this->getLinkRenderer(); // Create page link - special handling for redirects. $params = []; if ( $title->isRedirect() ) { $params['redirect'] = 'no'; } $pageLink = $linkRenderer->makeLink( $title, null, [], $params ); if ( $title->isRedirect() ) { $pageLink = "$pageLink"; } if ( $this->mMode == 'all' ) { $additionalInfo = Xml::element( 'span', [ 'class' => $result->rev_id == $result->latest_id ? 'approvedRevIsLatest' : 'approvedRevNotLatest' ], $this->msg( 'approvedrevs-revisionnumber', $result->rev_id )->text() ); if ( isset( $result->log_timestamp ) ) { $timestampInteger = wfTimestamp( TS_MW, $result->log_timestamp ); $timestamp = $lang->timeanddate( $timestampInteger, true ); $date = $lang->date( $timestampInteger, true ); $time = $lang->time( $timestampInteger, true ); $userLink = Linker::userLink( $result->log_user, $result->log_user_name ); $additionalInfo .= ', ' . $this->msg( 'approvedrevs-approvedby' ) ->rawParams( $userLink ) ->params( $timestamp, $result->log_user_name, $date, $time ) ->escaped(); } return "$pageLink ($additionalInfo)"; } elseif ( $this->mMode == 'unapproved' ) { global $egApprovedRevsShowApproveLatest; $line = $pageLink; if ( $egApprovedRevsShowApproveLatest && ApprovedRevs::checkPermission( $user, $title, 'approverevisions' ) ) { $line .= ' (' . Xml::element( 'a', [ 'href' => $title->getLocalUrl( [ 'action' => 'approve', 'oldid' => $result->latest_id ] ) ], $this->msg( 'approvedrevs-approvelatest' )->text() ) . ')'; } return $line; } elseif ( $this->mMode == 'invalid' ) { return $pageLink; } else { // approved revision is not latest $diffLink = Xml::element( 'a', [ 'href' => $title->getLocalUrl( [ 'diff' => $result->latest_id, 'oldid' => $result->rev_id ] ) ], $this->msg( 'approvedrevs-difffromlatest' )->text() ); return "$pageLink ($diffLink)"; } } public function formatResultFileApprovals( $skin, $result ) { $title = Title::makeTitle( NS_FILE, $result->title ); $pageLink = $this->getLinkRenderer()->makeLink( $title ); # # mode: unapprovedfiles # if ( $this->mMode == 'unapprovedfiles' ) { global $egApprovedRevsShowApproveLatest; if ( $egApprovedRevsShowApproveLatest && ApprovedRevs::userCanApprove( $this->getUser(), $title ) ) { $approveLink = ' (' . Xml::element( 'a', [ 'href' => $title->getLocalUrl( [ 'action' => 'approvefile', 'ts' => $result->latest_ts, 'sha1' => $result->latest_sha1 ] ) ], $this->msg( 'approvedrevs-approve' )->text() ) . ')'; } else { $approveLink = ''; } return "$pageLink$approveLink"; # # mode: invalidfiles # } elseif ( $this->mMode == 'invalidfiles' ) { if ( !ApprovedRevs::fileIsApprovable( $title ) ) { // if showing invalid files only, don't show files // that have real approvability return ''; } return $pageLink; # # mode: approvedfiles # } elseif ( $this->mMode == 'approvedfiles' ) { $additionalInfo = Html::rawElement( 'span', [ 'class' => ( $result->approved_sha1 == $result->latest_sha1 && $result->approved_ts == $result->latest_ts ) ? 'approvedRevIsLatest' : 'approvedRevNotLatest' ], $this->msg( 'approvedrevs-uploaddate', wfTimestamp( TS_RFC2822, $result->approved_ts ) )->parse() ); if ( isset( $result->log_timestamp ) ) { $lang = $this->getLanguage(); $timestampInteger = wfTimestamp( TS_MW, $result->log_timestamp ); $timestamp = $lang->timeanddate( $timestampInteger, true ); $date = $lang->date( $timestampInteger, true ); $time = $lang->time( $timestampInteger, true ); $userLink = Linker::userLink( $result->log_user, $result->log_user_name ); $additionalInfo .= ', ' . $this->msg( 'approvedrevs-approvedby' ) ->rawParams( $userLink ) ->params( $timestamp, $result->log_user_name, $date, $time ) ->escaped(); } return "$pageLink ($additionalInfo)"; # # mode: notlatestfiles # } elseif ( $this->mMode == 'notlatestfiles' ) { $repoGroup = MediaWikiServices::getInstance()->getRepoGroup(); $approved_file = $repoGroup->findFileFromKey( $result->approved_sha1, [ 'time' => $result->approved_ts ] ); $latest_file = $repoGroup->findFileFromKey( $result->latest_sha1, [ 'time' => $result->latest_ts ] ); $approvedLink = Xml::element( 'a', [ 'href' => $approved_file->getUrl() ], $this->msg( 'approvedrevs-approvedfile' )->text() ); $latestLink = Xml::element( 'a', [ 'href' => $latest_file->getUrl() ], $this->msg( 'approvedrevs-latestfile' )->text() ); return "$pageLink ($approvedLink | $latestLink)"; } } protected function getGroupName() { return 'pages'; } }