Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlowAddMissingModerationLogs
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 3
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
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 / 53
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace Flow\Maintenance;
4
5use BatchRowIterator;
6use Flow\Container;
7use Flow\DbFactory;
8use Flow\Model\AbstractRevision;
9use Flow\Model\UUID;
10use LoggedUpdateMaintenance;
11use MediaWiki\WikiMap\WikiMap;
12
13$IP = getenv( 'MW_INSTALL_PATH' );
14if ( $IP === false ) {
15    $IP = __DIR__ . '/../../..';
16}
17
18require_once "$IP/maintenance/Maintenance.php";
19
20/**
21 * Adjusts edit counts for all existing Flow data.
22 *
23 * @ingroup Maintenance
24 */
25class FlowAddMissingModerationLogs extends LoggedUpdateMaintenance {
26    public function __construct() {
27        parent::__construct();
28
29        $this->addDescription( 'Backfills missing moderation logs from flow_revision.  Must be run separately for each affected wiki.' );
30
31        $this->addOption( 'start', 'rev_id of last moderation revision that was logged correctly before regression.', true, true );
32        $this->addOption( 'stop', 'rev_id of first revision that was logged correctly after moderation logging fix.', true, true );
33
34        $this->setBatchSize( 300 );
35
36        $this->requireExtension( 'Flow' );
37    }
38
39    protected function getUpdateKey() {
40        return 'FlowAddMissingModerationLogs';
41    }
42
43    protected function doDBUpdates() {
44        $container = Container::getContainer();
45
46        /** @var DbFactory $dbFactory */
47        $dbFactory = $container['db.factory'];
48        $dbw = $dbFactory->getDB( DB_PRIMARY );
49
50        $storage = $container['storage'];
51
52        $moderationLoggingListener = $container['storage.post.listeners.moderation_logging'];
53
54        $rowIterator = new BatchRowIterator(
55            $dbw,
56            /* table = */'flow_revision',
57            /* primary key = */'rev_id',
58            $this->getBatchSize()
59        );
60
61        $rowIterator->setFetchColumns( [
62            'rev_id',
63            'rev_type',
64        ] );
65
66        // Fetch rows that are a moderation action
67        $rowIterator->addConditions( [
68            'rev_change_type' => AbstractRevision::getModerationChangeTypes(),
69            'rev_user_wiki' => WikiMap::getCurrentWikiId(),
70        ] );
71
72        $start = $this->getOption( 'start' );
73        $startId = UUID::create( $start );
74        $rowIterator->addConditions( [
75            'rev_id > ' . $dbw->addQuotes( $startId->getBinary() ),
76        ] );
77
78        $stop = $this->getOption( 'stop' );
79        $stopId = UUID::create( $stop );
80        $rowIterator->addConditions( [
81            'rev_id < ' . $dbw->addQuotes( $stopId->getBinary() ),
82        ] );
83
84        $rowIterator->setCaller( __METHOD__ );
85
86        $total = $fail = 0;
87        foreach ( $rowIterator as $batch ) {
88            $this->beginTransaction( $dbw, __METHOD__ );
89            foreach ( $batch as $row ) {
90                $total++;
91                $objectManager = $storage->getStorage( $row->rev_type );
92                $revId = UUID::create( $row->rev_id );
93                $obj = $objectManager->get( $revId );
94                if ( !$obj ) {
95                    $this->error( 'Could not load revision: ' . $revId->getAlphadecimal() );
96                    $fail++;
97                    continue;
98                }
99
100                $workflow = $obj->getCollection()->getWorkflow();
101                $moderationLoggingListener->onAfterInsert( $obj, [], [
102                    'workflow' => $workflow,
103                ] );
104            }
105
106            $this->commitTransaction( $dbw, __METHOD__ );
107            $storage->clear();
108            $dbFactory->waitForReplicas();
109        }
110
111        $this->output( "Processed a total of $total moderation revisions.\n" );
112        if ( $fail !== 0 ) {
113            $this->error( "Errors were encountered while processing $fail of them.\n" );
114        }
115
116        return true;
117    }
118}
119
120$maintClass = FlowAddMissingModerationLogs::class;
121require_once RUN_MAINTENANCE_IF_MAIN;