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 Flow\Container;
6use Flow\DbFactory;
7use Flow\Model\AbstractRevision;
8use Flow\Model\UUID;
9use MediaWiki\Maintenance\LoggedUpdateMaintenance;
10use MediaWiki\Utils\BatchRowIterator;
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        // phpcs:disable Generic.Files.LineLength
30        $this->addDescription( 'Backfills missing moderation logs from flow_revision.  Must be run separately for each affected wiki.' );
31
32        $this->addOption( 'start', 'rev_id of last moderation revision that was logged correctly before regression.', true, true );
33        $this->addOption( 'stop', 'rev_id of first revision that was logged correctly after moderation logging fix.', true, true );
34        // phpcs:enable
35
36        $this->setBatchSize( 300 );
37
38        $this->requireExtension( 'Flow' );
39    }
40
41    protected function getUpdateKey() {
42        return 'FlowAddMissingModerationLogs';
43    }
44
45    protected function doDBUpdates() {
46        $container = Container::getContainer();
47
48        /** @var DbFactory $dbFactory */
49        $dbFactory = $container['db.factory'];
50        $dbw = $dbFactory->getDB( DB_PRIMARY );
51
52        $storage = $container['storage'];
53
54        $moderationLoggingListener = $container['storage.post.listeners.moderation_logging'];
55
56        $rowIterator = new BatchRowIterator(
57            $dbw,
58            /* table = */'flow_revision',
59            /* primary key = */'rev_id',
60            $this->getBatchSize()
61        );
62
63        $rowIterator->setFetchColumns( [
64            'rev_id',
65            'rev_type',
66        ] );
67
68        // Fetch rows that are a moderation action
69        $rowIterator->addConditions( [
70            'rev_change_type' => AbstractRevision::getModerationChangeTypes(),
71            'rev_user_wiki' => WikiMap::getCurrentWikiId(),
72        ] );
73
74        $start = $this->getOption( 'start' );
75        $startId = UUID::create( $start );
76        $rowIterator->addConditions( [
77            $dbw->expr( 'rev_id', '>', $startId->getBinary() ),
78        ] );
79
80        $stop = $this->getOption( 'stop' );
81        $stopId = UUID::create( $stop );
82        $rowIterator->addConditions( [
83            $dbw->expr( 'rev_id', '<', $stopId->getBinary() ),
84        ] );
85
86        $rowIterator->setCaller( __METHOD__ );
87
88        $total = $fail = 0;
89        foreach ( $rowIterator as $batch ) {
90            $this->beginTransaction( $dbw, __METHOD__ );
91            foreach ( $batch as $row ) {
92                $total++;
93                $objectManager = $storage->getStorage( $row->rev_type );
94                $revId = UUID::create( $row->rev_id );
95                $obj = $objectManager->get( $revId );
96                if ( !$obj ) {
97                    $this->error( 'Could not load revision: ' . $revId->getAlphadecimal() );
98                    $fail++;
99                    continue;
100                }
101
102                $workflow = $obj->getCollection()->getWorkflow();
103                $moderationLoggingListener->onAfterInsert( $obj, [], [
104                    'workflow' => $workflow,
105                ] );
106            }
107
108            $this->commitTransaction( $dbw, __METHOD__ );
109            $storage->clear();
110            $dbFactory->waitForReplicas();
111        }
112
113        $this->output( "Processed a total of $total moderation revisions.\n" );
114        if ( $fail !== 0 ) {
115            $this->error( "Errors were encountered while processing $fail of them.\n" );
116        }
117
118        return true;
119    }
120}
121
122$maintClass = FlowAddMissingModerationLogs::class;
123require_once RUN_MAINTENANCE_IF_MAIN;