Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 109
FlagProtectToSemiProtect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 3
462
0.00% covered (danger)
0.00%
0 / 101
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 7
 execute
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 16
 flagToSemiProtect
0.00% covered (danger)
0.00%
0 / 1
272
0.00% covered (danger)
0.00%
0 / 78
<?php
/**
 * @ingroup Maintenance
 */
use MediaWiki\MediaWikiServices;
if ( getenv( 'MW_INSTALL_PATH' ) ) {
    $IP = getenv( 'MW_INSTALL_PATH' );
} else {
    $IP = __DIR__ . '/../../..';
}
require_once "$IP/maintenance/Maintenance.php";
class FlagProtectToSemiProtect extends Maintenance {
    public function __construct() {
        parent::__construct();
        $this->addDescription( 'Convert flag-protected pages to semi-protection.' );
        $this->addOption( 'user', 'The name of the admin user to use as the "protector"', true, true );
        $this->addOption( 'reason', 'The reason for the conversion', false, true );
        $this->setBatchSize( 500 );
        $this->requireExtension( 'FlaggedRevs' );
    }
    /**
     * @inheritDoc
     */
    public function execute() {
        global $wgFlaggedRevsProtection;
        if ( !$wgFlaggedRevsProtection ) {
            $this->output( "\$wgFlaggedRevsProtection not enabled.\n" );
            return;
        }
        $user = User::newFromName( $this->getOption( 'user' ) );
        if ( !$user || !$user->isRegistered() ) {
            $this->fatalError( "Invalid user specified!" );
        }
        $reason = $this->getOption( 'reason',
            "Converting flagged protection settings to edit protection settings." );
        $this->output( "Protecter username: \"" . $user->getName() . "\"\n" );
        $this->output( "Running in 5 seconds...Press ctrl-c to abort.\n" );
        sleep( 5 );
        $this->flagToSemiProtect( $user, $reason );
    }
    /**
     * @param User $user
     * @param string $reason
     */
    private function flagToSemiProtect( User $user, $reason ) {
        global $wgFlaggedRevsNamespaces;
        $this->output( "Semi-protecting all flag-protected pages...\n" );
        if ( !$wgFlaggedRevsNamespaces ) {
            $this->output( "\$wgFlaggedRevsNamespaces is empty.\n" );
            return;
        }
        $db = wfGetDB( DB_PRIMARY );
        $start = $db->selectField( 'flaggedpage_config', 'MIN(fpc_page_id)', false, __METHOD__ );
        $end = $db->selectField( 'flaggedpage_config', 'MAX(fpc_page_id)', false, __METHOD__ );
        if ( $start === null || $end === null ) {
            $this->output( "...flaggedpage_config table seems to be empty.\n" );
            return;
        }
        # Do remaining chunk
        $end += $this->mBatchSize - 1;
        $blockStart = (int)$start;
        $blockEnd = (int)( $start + $this->mBatchSize - 1 );
        $count = 0;
        $services = MediaWikiServices::getInstance();
        $lbFactory = $services->getDBLoadBalancerFactory();
        $restrictionStore = $services->getRestrictionStore();
        while ( $blockEnd <= $end ) {
            $this->output( "...doing fpc_page_id from $blockStart to $blockEnd\n" );
            $res = $db->select(
                [ 'flaggedpage_config', 'page' ],
                [ 'fpc_page_id', 'fpc_level', 'fpc_expiry' ],
                [ "fpc_page_id BETWEEN $blockStart AND $blockEnd",
                    'page_namespace' => $wgFlaggedRevsNamespaces,
                    'page_id = fpc_page_id',
                    "fpc_level != ''" ],
                __METHOD__
            );
            # Go through and protect each page...
            foreach ( $res as $row ) {
                $title = Title::newFromID( $row->fpc_page_id );
                if ( $restrictionStore->isProtected( $title, 'edit' ) ) {
                    continue; // page already has edit protection - skip it
                }
                # Flagged protection settings
                $frLimit = trim( $row->fpc_level );
                $frExpiry = ( $row->fpc_expiry === $db->getInfinity() )
                    ? 'infinity'
                    : wfTimestamp( TS_MW, $row->fpc_expiry );
                # Build the new protection settings
                $cascade = false;
                $limit = [];
                $expiry = [];
                foreach ( $restrictionStore->listApplicableRestrictionTypes( $title ) as $type ) {
                    # Get existing restrictions for this action
                    $oldLimit = $restrictionStore->getRestrictions( $title, $type ); // array
                    $oldExpiry = $restrictionStore->getRestrictionExpiry( $title, $type ); // MW_TS
                    # Move or Edit rights - take highest of (flag,type) settings
                    if ( $type == 'edit' || $type == 'move' ) {
                        # Sysop flag-protect -> full protect
                        if ( $frLimit == 'sysop' || in_array( 'sysop', $oldLimit ) ) {
                            $newLimit = 'sysop';
                        # Reviewer/autoconfirmed flag-protect -> semi-protect
                        } else {
                            $newLimit = 'autoconfirmed';
                        }
                        # Take highest expiry of (flag,type) settings
                        $newExpiry = ( !$oldLimit || $frExpiry >= $oldExpiry )
                            ? $frExpiry // note: 'infinity' > '99999999999999'
                            : $oldExpiry;
                    # Otherwise - maintain original limits
                    } else {
                        $newLimit = $oldLimit;
                        $newExpiry = $oldExpiry;
                    }
                    $limit[$type] = $newLimit;
                    $expiry[$type] = $newExpiry;
                }
                $db->begin( __METHOD__ );
                $wikiPage = WikiPage::factory( $title );
                $ok = $wikiPage->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $user );
                if ( $ok ) {
                    $count++;
                } else {
                    $this->output( "Could not protect: " . $title->getPrefixedText() . "\n" );
                }
                $db->commit( __METHOD__ );
            }
            $blockStart += $this->mBatchSize - 1;
            $blockEnd += $this->mBatchSize - 1;
            $lbFactory->waitForReplication( [ 'ifWritesSince' => 5 ] );
        }
        $this->output( "Protection of all flag-protected pages complete ... {$count} pages\n" );
    }
}
$maintClass = FlagProtectToSemiProtect::class;
require_once RUN_MAINTENANCE_IF_MAIN;