Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 96
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlowFixUserIp
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 5
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 doDBUpdates
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
 updateTreeRevision
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 updateRevision
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
30
 getUpdateKey
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Flow\Maintenance;
4
5use Flow\Container;
6use Flow\Data\ManagerGroup;
7use Flow\DbFactory;
8use Flow\Model\Header;
9use Flow\Model\PostRevision;
10use Flow\Model\PostSummary;
11use Flow\Model\UUID;
12use MediaWiki\Maintenance\LoggedUpdateMaintenance;
13use Wikimedia\Rdbms\IDatabase;
14
15$IP = getenv( 'MW_INSTALL_PATH' );
16if ( $IP === false ) {
17    $IP = __DIR__ . '/../../..';
18}
19
20require_once "$IP/maintenance/Maintenance.php";
21
22/**
23 * Sets *_user_ip to null when *_user_id is > 0
24 *
25 * @ingroup Maintenance
26 */
27class FlowFixUserIp extends LoggedUpdateMaintenance {
28    /**
29     * The number of entries completed
30     *
31     * @var int
32     */
33    private $completeCount = 0;
34
35    /**
36     * @var ManagerGroup
37     */
38    protected $storage;
39
40    private const TYPES = [
41        'post' => PostRevision::class,
42        'header' => Header::class,
43        'post-summary' => PostSummary::class,
44    ];
45
46    public function __construct() {
47        parent::__construct();
48
49        $this->setBatchSize( 300 );
50        $this->requireExtension( 'Flow' );
51    }
52
53    protected function doDBUpdates() {
54        $this->storage = $storage = Container::get( 'storage' );
55        /** @var DbFactory $dbf */
56        $dbf = Container::get( 'db.factory' );
57        $dbw = $dbf->getDB( DB_PRIMARY );
58        $fname = __METHOD__;
59
60        $runUpdate = function ( $callback ) use ( $dbw, $storage, $fname ) {
61            $continue = "\0";
62            do {
63                $this->beginTransaction( $dbw, $fname );
64                $continue = $callback( $dbw, $continue );
65                $this->commitTransaction( $dbw, $fname );
66                $storage->clear();
67            } while ( $continue !== null );
68        };
69
70        $runUpdate( [ $this, 'updateTreeRevision' ] );
71        foreach ( [ 'rev_user', 'rev_mod_user', 'rev_edit_user' ] as $prefix ) {
72            $runUpdate( function ( $dbw, $continue ) use ( $prefix ) {
73                return $this->updateRevision( $prefix, $dbw, $continue );
74            } );
75        }
76
77        return true;
78    }
79
80    public function updateTreeRevision( IDatabase $dbw, $continue = null ) {
81        $rows = $dbw->newSelectQueryBuilder()
82            ->select( [ 'tree_rev_id' ] )
83            ->from( 'flow_tree_revision' )
84            ->where( [
85                $dbw->expr( 'tree_rev_id', '>', $continue ),
86                $dbw->expr( 'tree_orig_user_ip', '!=', null ),
87                $dbw->expr( 'tree_orig_user_id', '>', 0 ),
88            ] )
89            ->caller( __METHOD__ )
90            ->limit( $this->getBatchSize() )
91            ->orderBy( 'tree_rev_id' )
92            ->fetchResultSet();
93
94        $om = Container::get( 'storage' )->getStorage( 'PostRevision' );
95        $objs = $ids = [];
96        foreach ( $rows as $row ) {
97            $id = UUID::create( $row->tree_rev_id );
98            $found = $om->get( $id );
99            if ( $found ) {
100                $ids[] = $row->tree_rev_id;
101                $objs[] = $found;
102            } else {
103                $this->error( __METHOD__ . ': Failed loading Flow\Model\PostRevision: ' . $id->getAlphadecimal() );
104            }
105        }
106        if ( !$ids ) {
107            return null;
108        }
109        $dbw->newUpdateQueryBuilder()
110            ->update( 'flow_tree_revision' )
111            ->set( [ 'tree_orig_user_ip' => null ] )
112            ->where( [ 'tree_rev_id' => $ids ] )
113            ->caller( __METHOD__ )
114            ->execute();
115        foreach ( $objs as $obj ) {
116            $om->cachePurge( $obj );
117        }
118
119        $this->completeCount += count( $ids );
120
121        return end( $ids );
122    }
123
124    public function updateRevision( $columnPrefix, IDatabase $dbw, $continue = null ) {
125        $rows = $dbw->newSelectQueryBuilder()
126            ->select( [ 'rev_id', 'rev_type' ] )
127            ->from( 'flow_revision' )
128            ->where( [
129                $dbw->expr( 'rev_id', '>', $continue ),
130                $dbw->expr( "{$columnPrefix}_id", '>', 0 ),
131                $dbw->expr( "{$columnPrefix}_ip", '!=', null ),
132            ] )
133            ->caller( __METHOD__ )
134            ->limit( $this->getBatchSize() )
135            ->orderBy( 'rev_id' )
136            ->fetchResultSet();
137
138        $ids = $objs = [];
139        foreach ( $rows as $row ) {
140            $id = UUID::create( $row->rev_id );
141            $type = self::TYPES[$row->rev_type];
142            $om = $this->storage->getStorage( $type );
143            $obj = $om->get( $id );
144            if ( $obj ) {
145                $om->merge( $obj );
146                $ids[] = $row->rev_id;
147                $objs[] = $obj;
148            } else {
149                $this->error( __METHOD__ . ": Failed loading $type" . $id->getAlphadecimal() );
150            }
151        }
152        if ( !$ids ) {
153            return null;
154        }
155
156        $dbw->newUpdateQueryBuilder()
157            ->update( 'flow_revision' )
158            ->set( [ "{$columnPrefix}_ip" => null ] )
159            ->where( [ 'rev_id' => $ids ] )
160            ->caller( __METHOD__ )
161            ->execute();
162
163        foreach ( $objs as $obj ) {
164            $this->storage->cachePurge( $obj );
165        }
166
167        $this->completeCount += count( $ids );
168
169        return end( $ids );
170    }
171
172    /**
173     * Get the update key name to go in the update log table
174     *
175     * @return string
176     */
177    protected function getUpdateKey() {
178        return 'FlowFixUserIp';
179    }
180}
181
182$maintClass = FlowFixUserIp::class;
183require_once RUN_MAINTENANCE_IF_MAIN;