Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 95
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 / 89
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 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 updateTreeRevision
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
30
 updateRevision
0.00% covered (danger)
0.00%
0 / 34
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 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 = static function ( $callback ) use ( $dbf, $dbw, $storage, $fname ) {
61            $continue = "\0";
62            do {
63                $dbw->begin( $fname );
64                $continue = $callback( $dbw, $continue );
65                $dbw->commit( $fname );
66                $dbf->waitForReplicas();
67                $storage->clear();
68            } while ( $continue !== null );
69        };
70
71        $runUpdate( [ $this, 'updateTreeRevision' ] );
72        foreach ( [ 'rev_user', 'rev_mod_user', 'rev_edit_user' ] as $prefix ) {
73            $runUpdate( function ( $dbw, $continue ) use ( $prefix ) {
74                return $this->updateRevision( $prefix, $dbw, $continue );
75            } );
76        }
77
78        return true;
79    }
80
81    public function updateTreeRevision( IDatabase $dbw, $continue = null ) {
82        $rows = $dbw->select(
83            /* table */'flow_tree_revision',
84            /* select */[ 'tree_rev_id' ],
85            [
86                'tree_rev_id > ' . $dbw->addQuotes( $continue ),
87                'tree_orig_user_ip IS NOT NULL',
88                'tree_orig_user_id > 0',
89            ],
90            __METHOD__,
91            /* options */[ 'LIMIT' => $this->getBatchSize(), 'ORDER BY' => 'tree_rev_id' ]
92        );
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->update(
110            /* table */'flow_tree_revision',
111            /* update */[ 'tree_orig_user_ip' => null ],
112            /* conditions */[ 'tree_rev_id' => $ids ],
113            __METHOD__
114        );
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->select(
126            /* table */'flow_revision',
127            /* select */[ 'rev_id', 'rev_type' ],
128            /* conditions */ [
129                'rev_id > ' . $dbw->addQuotes( $continue ),
130                "{$columnPrefix}_id > 0",
131                "{$columnPrefix}_ip IS NOT NULL",
132            ],
133            __METHOD__,
134            /* options */[ 'LIMIT' => $this->getBatchSize(), 'ORDER BY' => 'rev_id' ]
135        );
136
137        $ids = $objs = [];
138        foreach ( $rows as $row ) {
139            $id = UUID::create( $row->rev_id );
140            $type = self::TYPES[$row->rev_type];
141            $om = $this->storage->getStorage( $type );
142            $obj = $om->get( $id );
143            if ( $obj ) {
144                $om->merge( $obj );
145                $ids[] = $row->rev_id;
146                $objs[] = $obj;
147            } else {
148                $this->error( __METHOD__ . ": Failed loading $type" . $id->getAlphadecimal() );
149            }
150        }
151        if ( !$ids ) {
152            return null;
153        }
154
155        $dbw->update(
156            /* table */ 'flow_revision',
157            /* update */ [ "{$columnPrefix}_ip" => null ],
158            /* conditions */ [ 'rev_id' => $ids ],
159            __METHOD__
160        );
161
162        foreach ( $objs as $obj ) {
163            $this->storage->cachePurge( $obj );
164        }
165
166        $this->completeCount += count( $ids );
167
168        return end( $ids );
169    }
170
171    /**
172     * Get the update key name to go in the update log table
173     *
174     * @return string
175     */
176    protected function getUpdateKey() {
177        return 'FlowFixUserIp';
178    }
179}
180
181$maintClass = FlowFixUserIp::class;
182require_once RUN_MAINTENANCE_IF_MAIN;