Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 71
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
FixDefaultJsonContentPages
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 4
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getUpdateKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doDBUpdates
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
12
 handleRow
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * Fix instances of pre-existing JSON pages
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Maintenance
22 */
23
24use MediaWiki\Content\JsonContent;
25use MediaWiki\Revision\RevisionRecord;
26use MediaWiki\Revision\SlotRecord;
27use MediaWiki\Title\Title;
28use Wikimedia\Rdbms\IExpression;
29use Wikimedia\Rdbms\LikeValue;
30
31require_once __DIR__ . '/Maintenance.php';
32
33/**
34 * Usage:
35 *  fixDefaultJsonContentPages.php
36 *
37 * It is automatically run by update.php
38 */
39class FixDefaultJsonContentPages extends LoggedUpdateMaintenance {
40    public function __construct() {
41        parent::__construct();
42        $this->addDescription(
43            'Fix instances of JSON pages prior to them being the ContentHandler default' );
44        $this->setBatchSize( 100 );
45    }
46
47    protected function getUpdateKey() {
48        return __CLASS__;
49    }
50
51    protected function doDBUpdates() {
52        $dbr = $this->getReplicaDB();
53        $namespaces = [
54            NS_MEDIAWIKI => $dbr->expr(
55                'page_title',
56                IExpression::LIKE,
57                new LikeValue( $dbr->anyString(), '.json' )
58            ),
59            NS_USER => $dbr->expr(
60                'page_title',
61                IExpression::LIKE,
62                new LikeValue( $dbr->anyString(), '/', $dbr->anyString(), '.json' )
63            ),
64        ];
65        foreach ( $namespaces as $ns => $likeExpr ) {
66            $lastPage = 0;
67            do {
68                $rows = $dbr->newSelectQueryBuilder()
69                    ->select( [ 'page_id', 'page_title', 'page_namespace', 'page_content_model' ] )
70                    ->from( 'page' )
71                    ->where( [
72                        'page_namespace' => $ns,
73                        $likeExpr,
74                        $dbr->expr( 'page_id', '>', $lastPage ),
75                    ] )
76                    ->orderBy( 'page_id' )
77                    ->limit( $this->getBatchSize() )
78                    ->caller( __METHOD__ )->fetchResultSet();
79                foreach ( $rows as $row ) {
80                    $this->handleRow( $row );
81                    $lastPage = $row->page_id;
82                }
83            } while ( $rows->numRows() >= $this->getBatchSize() );
84        }
85
86        return true;
87    }
88
89    protected function handleRow( stdClass $row ) {
90        $title = Title::makeTitle( $row->page_namespace, $row->page_title );
91        $this->output( "Processing {$title} ({$row->page_id})...\n" );
92        $rev = $this->getServiceContainer()
93            ->getRevisionLookup()
94            ->getRevisionByTitle( $title );
95        $content = $rev->getContent( SlotRecord::MAIN, RevisionRecord::RAW );
96        $dbw = $this->getPrimaryDB();
97        if ( $content instanceof JsonContent ) {
98            if ( $content->isValid() ) {
99                // Yay, actually JSON. We need to just change the
100                // page_content_model because revision will automatically
101                // use the default, which is *now* JSON.
102                $this->output( "Setting page_content_model to json..." );
103                $dbw->newUpdateQueryBuilder()
104                    ->update( 'page' )
105                    ->set( [ 'page_content_model' => CONTENT_MODEL_JSON ] )
106                    ->where( [ 'page_id' => $row->page_id ] )
107                    ->caller( __METHOD__ )->execute();
108
109                $this->output( "done.\n" );
110                $this->waitForReplication();
111            } else {
112                // Not JSON...force it to wikitext. We need to update the
113                // revision table so that these revisions are always processed
114                // as wikitext in the future. page_content_model is already
115                // set to "wikitext".
116                $this->output( "Setting rev_content_model to wikitext..." );
117                // Grab all the ids for batching
118                $ids = $dbw->newSelectQueryBuilder()
119                    ->select( 'rev_id' )
120                    ->from( 'revision' )
121                    ->where( [ 'rev_page' => $row->page_id ] )
122                    ->caller( __METHOD__ )->fetchFieldValues();
123                foreach ( array_chunk( $ids, 50 ) as $chunk ) {
124                    $dbw->newUpdateQueryBuilder()
125                        ->update( 'revision' )
126                        ->set( [ 'rev_content_model' => CONTENT_MODEL_WIKITEXT ] )
127                        ->where( [ 'rev_page' => $row->page_id, 'rev_id' => $chunk ] )
128                        ->caller( __METHOD__ )->execute();
129
130                    $this->waitForReplication();
131                }
132                $this->output( "done.\n" );
133            }
134        } else {
135            $this->output( "not a JSON page? Skipping\n" );
136        }
137    }
138}
139
140$maintClass = FixDefaultJsonContentPages::class;
141require_once RUN_MAINTENANCE_IF_MAIN;