3 * Makes the required database updates for Special:ProtectedPages
4 * to show all protected pages, even ones before the page restrictions
5 * schema change. All remaining page_restriction column values are moved
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
24 * @ingroup Maintenance
27 use MediaWiki\Maintenance\Maintenance
;
29 // @codeCoverageIgnoreStart
30 require_once __DIR__
. '/Maintenance.php';
31 // @codeCoverageIgnoreEnd
34 * Maintenance script that updates page_restrictions table from
35 * old page_restriction column.
37 * @ingroup Maintenance
39 class UpdateRestrictions
extends Maintenance
{
40 public function __construct() {
41 parent
::__construct();
42 $this->addDescription( 'Updates page_restrictions table from old page_restriction column' );
43 $this->setBatchSize( 1000 );
46 public function execute() {
47 $dbw = $this->getDB( DB_PRIMARY
);
48 $batchSize = $this->getBatchSize();
50 if ( !$dbw->tableExists( 'page_restrictions', __METHOD__
) ) {
51 $this->fatalError( "page_restrictions table does not exist" );
54 if ( !$dbw->fieldExists( 'page', 'page_restrictions', __METHOD__
) ) {
55 $this->output( "Migration is not needed.\n" );
59 $encodedExpiry = $dbw->getInfinity();
61 $maxPageId = $dbw->newSelectQueryBuilder()
62 ->select( 'MAX(page_id)' )
64 ->caller( __METHOD__
)->fetchField();
69 $batchMaxPageId = $batchMinPageId +
$batchSize;
71 $this->output( "...processing page IDs from $batchMinPageId to $batchMaxPageId.\n" );
73 $res = $dbw->newSelectQueryBuilder()
74 ->select( [ 'page_id', 'page_restrictions' ] )
77 $dbw->expr( 'page_restrictions', '!=', '' ),
78 $dbw->expr( 'page_id', '>', $batchMinPageId ),
79 $dbw->expr( 'page_id', '<=', $batchMaxPageId ),
81 ->caller( __METHOD__
)->fetchResultSet();
83 // No pages have legacy protection settings in the current batch
84 if ( !$res->numRows() ) {
85 $batchMinPageId = $batchMaxPageId;
92 foreach ( $res as $row ) {
93 $pageIds[] = $row->page_id
;
95 $restrictionsByAction = $this->mapLegacyRestrictionBlob( $row->page_restrictions
);
97 # Update restrictions table
98 foreach ( $restrictionsByAction as $action => $restrictions ) {
100 'pr_page' => $row->page_id
,
101 'pr_type' => $action,
102 'pr_level' => $restrictions,
104 'pr_expiry' => $encodedExpiry
109 $this->beginTransaction( $dbw, __METHOD__
);
111 // Insert new format protection settings for the pages in the current batch.
112 // Use INSERT IGNORE to ignore conflicts with new format settings that might exist for the page
113 $dbw->newInsertQueryBuilder()
114 ->insertInto( 'page_restrictions' )
117 ->caller( __METHOD__
)->execute();
119 // Clear out the legacy page.page_restrictions blob for this batch
120 $dbw->newUpdateQueryBuilder()
122 ->set( [ 'page_restrictions' => '' ] )
123 ->where( [ 'page_id' => $pageIds ] )
124 ->caller( __METHOD__
)
127 $this->commitTransaction( $dbw, __METHOD__
);
129 $batchMinPageId = $batchMaxPageId;
130 } while ( $batchMaxPageId < $maxPageId );
132 $this->output( "...Done!\n" );
137 * Convert a legacy restriction specification from the page.page_restrictions blob to
138 * a map of action names to restriction levels.
140 * @param string $legacyBlob Legacy page.page_restrictions blob,
141 * e.g. "sysop" or "edit=sysop:move=autoconfirmed"
142 * @return string[] array of restriction levels keyed by action names
144 private function mapLegacyRestrictionBlob( $legacyBlob ) {
145 $oldRestrictions = [];
147 foreach ( explode( ':', trim( $legacyBlob ) ) as $restrict ) {
148 $temp = explode( '=', trim( $restrict ) );
150 // Treat old old format without action name as edit/move restriction
151 if ( count( $temp ) == 1 ) {
152 $level = trim( $temp[0] );
154 $oldRestrictions['edit'] = $level;
155 $oldRestrictions['move'] = $level;
157 $restriction = trim( $temp[1] );
158 // Some old entries are empty
159 if ( $restriction != '' ) {
160 $oldRestrictions[$temp[0]] = $restriction;
165 return $oldRestrictions;
169 // @codeCoverageIgnoreStart
170 $maintClass = UpdateRestrictions
::class;
171 require_once RUN_MAINTENANCE_IF_MAIN
;
172 // @codeCoverageIgnoreEnd