SpecialManageGroups.php

Go to the documentation of this file.
00001 <?php
00022 class SpecialManageGroups extends SpecialPage {
00023     const CHANGEFILE = 'translate_messagechanges.cdb';
00024     const RIGHT = 'translate-manage';
00025 
00029     protected $diff;
00030 
00031     public function __construct() {
00032         // Anyone is allowed to see, but actions are restricted
00033         parent::__construct( 'ManageMessageGroups' );
00034     }
00035 
00036     public function execute( $par ) {
00037         $this->setHeaders();
00038         $out = $this->getOutput();
00039         $out->addModules( 'ext.translate.special.managegroups' );
00040         TranslateUtils::addSpecialHelpLink( $out, 'Help:Extension:Translate/Group_management' );
00041 
00042         $changefile = TranslateUtils::cacheFile( self::CHANGEFILE );
00043         if ( !file_exists( $changefile ) ) {
00044             // @todo Tell them when changes was last checked/process
00045             // or how to initiate recheck.
00046             $out->addWikiMsg( 'translate-smg-nochanges' );
00047 
00048             return;
00049         }
00050 
00051         $user = $this->getUser();
00052         $allowed = $user->isAllowed( self::RIGHT );
00053 
00054         $req = $this->getRequest();
00055         if ( !$req->wasPosted() ) {
00056             $this->showChanges( $allowed, $this->getLimit() );
00057 
00058             return;
00059         }
00060 
00061         $token = $req->getVal( 'token' );
00062         if ( !$allowed || !$user->matchEditToken( $token ) ) {
00063             throw new PermissionsError( self::RIGHT );
00064         }
00065 
00066         $this->processSubmit();
00067     }
00068 
00073     protected function getLimit() {
00074         $limits = array(
00075             1000, // Default max
00076             ini_get( 'max_input_vars' ),
00077             ini_get( 'suhosin.post.max_vars' ),
00078             ini_get( 'suhosin.request.max_vars' )
00079         );
00080         // Ignore things not set
00081         $limits = array_filter( $limits );
00082         return min( $limits );
00083     }
00084 
00085     protected function getLegend() {
00086         $text = $this->diff->addHeader(
00087             '',
00088             $this->msg( 'translate-smg-left' )->escaped(),
00089             $this->msg( 'translate-smg-right' )->escaped()
00090         );
00091 
00092         return Html::rawElement( 'div', array( 'class' => "mw-translate-smg-header" ), $text );
00093     }
00094 
00095     protected function showChanges( $allowed, $limit ) {
00096         global $wgContLang;
00097 
00098         $diff = new DifferenceEngine( $this->getContext() );
00099         $diff->showDiffStyle();
00100         $diff->setReducedLineNumbers();
00101         $this->diff = $diff;
00102 
00103         $out = $this->getOutput();
00104         $out->addHtml(
00105             '' .
00106                 Html::openElement( 'form', array( 'method' => 'post' ) ) .
00107                 Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
00108                 Html::hidden( 'token', $this->getUser()->getEditToken() ) .
00109                 $this->getLegend()
00110         );
00111 
00112         // The above count as two
00113         $limit = $limit - 2;
00114 
00115         $changefile = TranslateUtils::cacheFile( self::CHANGEFILE );
00116         $reader = CdbReader::open( $changefile );
00117         $groups = unserialize( $reader->get( '#keys' ) );
00118         foreach ( $groups as $id ) {
00119             $group = MessageGroups::getGroup( $id );
00120             if ( !$group ) {
00121                 continue;
00122             }
00123 
00124             $changes = unserialize( $reader->get( $id ) );
00125             $out->addHtml( Html::element( 'h2', array(), $group->getLabel() ) );
00126 
00127             // Reduce page existance queries to one per group
00128             $lb = new LinkBatch();
00129             $ns = $group->getNamespace();
00130             $isCap = MWNamespace::isCapitalized( $ns );
00131             foreach ( $changes as $code => $subchanges ) {
00132                 foreach ( $subchanges as $messages ) {
00133                     foreach ( $messages as $params ) {
00134                         // Constructing title objects is way slower
00135                         $key = $params['key'];
00136                         if ( $isCap ) {
00137                             $key = $wgContLang->ucfirst( $key );
00138                         }
00139                         $lb->add( $ns, "$key/$code" );
00140                     }
00141                 }
00142             }
00143             $lb->execute();
00144 
00145             foreach ( $changes as $code => $subchanges ) {
00146                 foreach ( $subchanges as $type => $messages ) {
00147                     foreach ( $messages as $params ) {
00148                         $change = $this->formatChange( $group, $code, $type, $params, $limit );
00149                         $out->addHtml( $change );
00150 
00151                         if ( $limit <= 0 ) {
00152                             // We need to restrict the changes per page per form submission
00153                             // limitations as well as performance.
00154                             $out->wrapWikiMsg( "<div class=warning>\n$1\n</div>", 'translate-smg-more' );
00155                             break 4;
00156                         }
00157                     }
00158                 }
00159             }
00160         }
00161 
00162         $attribs = array( 'type' => 'submit', 'class' => 'mw-translate-smg-submit' );
00163         if ( !$allowed ) {
00164             $attribs['disabled'] = 'disabled';
00165             $attribs['title'] = $this->msg( 'translate-smg-notallowed' )->text();
00166         }
00167         $button = Html::element( 'button', $attribs, $this->msg( 'translate-smg-submit' )->text() );
00168         $out->addHtml( $button );
00169         $out->addHtml( Html::closeElement( 'form' ) );
00170     }
00171 
00179     protected function formatChange( MessageGroup $group, $code, $type, $params, &$limit ) {
00180         $key = $params['key'];
00181         $title = Title::makeTitleSafe( $group->getNamespace(), "$key/$code" );
00182         $id = self::changeId( $group->getId(), $code, $type, $key );
00183 
00184         if ( $title && $title->exists() && $type === 'addition' ) {
00185             // The message has for some reason dropped out from cache
00186             // or perhaps it is being reused. In any case treat it
00187             // as a change for display, so the admin can see if
00188             // action is needed and let the message be processed.
00189             // Otherwise it will end up in the postponed category
00190             // forever and will prevent rebuilding the cache, which
00191             // leads to many other annoying problems.
00192             $type = 'change';
00193         } elseif ( $title && !$title->exists() && ( $type === 'deletion' || $type === 'change' ) ) {
00194             return '';
00195         }
00196 
00197         $text = '';
00198         if ( $type === 'deletion' ) {
00199             $wiki = Revision::newFromTitle( $title )->getText();
00200             $this->diff->setText( $wiki, '' );
00201             $text = $this->diff->getDiff( Linker::link( $title ), '' );
00202         } elseif ( $type === 'addition' ) {
00203             $this->diff->setText( '', $params['content'] );
00204             $text = $this->diff->getDiff( '', Linker::link( $title ) );
00205         } elseif ( $type === 'change' ) {
00206             $wiki = Revision::newFromTitle( $title )->getText();
00207             $handle = new MessageHandle( $title );
00208             if ( $handle->isFuzzy() ) {
00209                 $wiki = '!!FUZZY!!' . str_replace( TRANSLATE_FUZZY, '', $wiki );
00210             }
00211 
00212             $label = $this->msg( 'translate-manage-action-ignore' )->text();
00213             $actions = Xml::checkLabel( $label, "i/$id", "i/$id" );
00214             $limit--;
00215 
00216             if ( $group->getSourceLanguage() === $code ) {
00217                 $label = $this->msg( 'translate-manage-action-fuzzy' )->text();
00218                 $actions .= ' ' . Xml::checkLabel( $label, "f/$id", "f/$id" );
00219                 $limit--;
00220             }
00221 
00222             $this->diff->setText( $wiki, $params['content'] );
00223             $text .= $this->diff->getDiff( Linker::link( $title ), $actions );
00224         }
00225 
00226         $hidden = Html::hidden( $id, 1 );
00227         $limit--;
00228         $text .= $hidden;
00229         $classes = "mw-translate-smg-change smg-change-$type";
00230 
00231         if ( $limit < 0 ) {
00232             // Don't add if one of the fields might get dropped of at submission
00233             return '';
00234         }
00235 
00236         return Html::rawElement( 'div', array( 'class' => $classes ), $text );
00237     }
00238 
00239     protected function processSubmit() {
00240         $req = $this->getRequest();
00241         $out = $this->getOutput();
00242 
00243         $jobs = array();
00244         $jobs[] = MessageIndexRebuildJob::newJob();
00245 
00246         $changefile = TranslateUtils::cacheFile( self::CHANGEFILE );
00247         $reader = CdbReader::open( $changefile );
00248         $groups = unserialize( $reader->get( '#keys' ) );
00249 
00250         $postponed = array();
00251 
00252         foreach ( $groups as $groupId ) {
00253             $group = MessageGroups::getGroup( $groupId );
00254             $changes = unserialize( $reader->get( $groupId ) );
00255 
00256             foreach ( $changes as $code => $subchanges ) {
00257                 foreach ( $subchanges as $type => $messages ) {
00258                     foreach ( $messages as $index => $params ) {
00259                         $id = self::changeId( $groupId, $code, $type, $params['key'] );
00260                         if ( $req->getVal( $id ) === null ) {
00261                             // We probably hit the limit with number of post parameters.
00262                             $postponed[$groupId][$code][$type][$index] = $params;
00263                             continue;
00264                         }
00265 
00266                         if ( $type === 'deletion' || $req->getCheck( "i/$id" ) ) {
00267                             continue;
00268                         }
00269 
00270                         $fuzzy = $req->getCheck( "f/$id" ) ? 'fuzzy' : false;
00271                         $key = $params['key'];
00272                         $title = Title::makeTitleSafe( $group->getNamespace(), "$key/$code" );
00273                         $jobs[] = MessageUpdateJob::newJob( $title, $params['content'], $fuzzy );
00274                     }
00275                 }
00276 
00277                 if ( !isset( $postponed[$groupId][$code] ) ) {
00278                     $cache = new MessageGroupCache( $groupId, $code );
00279                     $cache->create();
00280                 }
00281             }
00282         }
00283 
00284         Job::batchInsert( $jobs );
00285 
00286         $reader->close();
00287         rename( $changefile, $changefile . '-' . wfTimestamp() );
00288 
00289         if ( count( $postponed ) ) {
00290             $changefile = TranslateUtils::cacheFile( self::CHANGEFILE );
00291             $writer = CdbWriter::open( $changefile );
00292             $keys = array_keys( $postponed );
00293             $writer->set( '#keys', serialize( $keys ) );
00294             foreach ( $postponed as $groupId => $changes ) {
00295                 $writer->set( $groupId, serialize( $changes ) );
00296             }
00297             $writer->close();
00298             $this->showChanges( true, $this->getLimit() );
00299         } else {
00300             $out->addWikiMsg( 'translate-smg-submitted' );
00301         }
00302     }
00303 
00304     protected static function changeId( $groupId, $code, $type, $key ) {
00305         return 'smg/' . substr( sha1( "$groupId/$code/$type/$key" ), 0, 7 );
00306     }
00307 
00313     static function tabify( Skin $skin, array &$tabs ) {
00314         $title = $skin->getTitle();
00315         list( $alias, ) = SpecialPageFactory::resolveAlias( $title->getText() );
00316 
00317         $pagesInGroup = array(
00318             'ManageMessageGroups' => 'namespaces',
00319             'AggregateGroups' => 'namespaces',
00320             'SupportedLanguages' => 'views',
00321             'TranslationStats' => 'views',
00322         );
00323         if ( !isset( $pagesInGroup[$alias] ) ) {
00324             return true;
00325         }
00326 
00327         $skin->getOutput()->addModules( 'ext.translate.tabgroup' );
00328 
00329         $tabs['namespaces'] = array();
00330         foreach ( $pagesInGroup as $spName => $section ) {
00331             $spClass = SpecialPageFactory::getPage( $spName );
00332             if ( $spClass === null ) {
00333                 continue; // Page explicitly disabled
00334             }
00335             $spTitle = $spClass->getTitle();
00336 
00337             $tabs[$section][strtolower( $spName )] = array(
00338                 'text' => $spClass->getDescription(),
00339                 'href' => $spTitle->getLocalUrl(),
00340                 'class' => $alias === $spName ? 'selected' : '',
00341             );
00342         }
00343 
00344         return true;
00345     }
00346 }
Generated on Tue Oct 29 00:00:24 2013 for MediaWiki Translate Extension by  doxygen 1.6.3