Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 88 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
MigrateCentralWikiLogs | |
0.00% |
0 / 82 |
|
0.00% |
0 / 2 |
132 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 77 |
|
0.00% |
0 / 1 |
110 |
1 | <?php |
2 | /** |
3 | * This script should be run as part of migrating to a new central OAuth wiki in your |
4 | * cluster. See the notes in migrateCentralWikiLogs.php for the complete process. |
5 | * This script is intended to be run on the new central wiki after the tables have already |
6 | * been migrated. This will fill in the logs from newest to oldest, and tries to do sane |
7 | * things if you need to stop it and restart it later. |
8 | * |
9 | * @ingroup Maintenance |
10 | */ |
11 | if ( getenv( 'MW_INSTALL_PATH' ) ) { |
12 | $IP = getenv( 'MW_INSTALL_PATH' ); |
13 | } else { |
14 | $IP = __DIR__ . '/../../..'; |
15 | } |
16 | |
17 | require_once "$IP/maintenance/Maintenance.php"; |
18 | |
19 | use MediaWiki\MediaWikiServices; |
20 | use MediaWiki\Title\Title; |
21 | use MediaWiki\WikiMap\WikiMap; |
22 | use Wikimedia\Rdbms\SelectQueryBuilder; |
23 | |
24 | class MigrateCentralWikiLogs extends Maintenance { |
25 | public function __construct() { |
26 | parent::__construct(); |
27 | $this->addDescription( "Import central wiki logs to this wiki" ); |
28 | $this->addOption( 'old', 'Previous central wiki', true, true ); |
29 | $this->setBatchSize( 200 ); |
30 | $this->requireExtension( "OAuth" ); |
31 | } |
32 | |
33 | public function execute() { |
34 | $oldWiki = $this->getOption( 'old' ); |
35 | $targetWiki = WikiMap::getCurrentWikiId(); |
36 | |
37 | $this->output( "Moving OAuth logs from '$oldWiki' to '$targetWiki'\n" ); |
38 | |
39 | // We only read from $oldDb, but we do want to make sure we get the most recent logs. |
40 | $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); |
41 | $oldDb = $lbFactory->getMainLB( $oldWiki )->getConnection( DB_PRIMARY, [], $oldWiki ); |
42 | $targetDb = $lbFactory->getMainLB( $targetWiki ) |
43 | ->getConnection( DB_PRIMARY, [], $targetWiki ); |
44 | |
45 | $targetMinTS = $targetDb->newSelectQueryBuilder() |
46 | ->select( 'MIN(log_timestamp)' ) |
47 | ->from( 'logging' ) |
48 | ->where( [ 'log_type' => 'mwoauthconsumer' ] ) |
49 | ->caller( __METHOD__ ) |
50 | ->fetchField(); |
51 | |
52 | $lastMinTimestamp = null; |
53 | if ( $targetMinTS !== false ) { |
54 | $lastMinTimestamp = $targetMinTS; |
55 | } |
56 | |
57 | $commentStore = MediaWikiServices::getInstance()->getCommentStore(); |
58 | $commentQuery = $commentStore->getJoin( 'log_comment' ); |
59 | |
60 | do { |
61 | $conds = [ 'log_type' => 'mwoauthconsumer' ]; |
62 | |
63 | // This assumes that we don't have more than mBatchSize oauth log entries |
64 | // with the same timestamp. Otherwise this will go into an infinite loop. |
65 | if ( $lastMinTimestamp !== null ) { |
66 | $conds[] = $oldDb->expr( 'log_timestamp', '<', $oldDb->timestamp( $lastMinTimestamp ) ); |
67 | } |
68 | |
69 | $oldLoggs = $oldDb->newSelectQueryBuilder() |
70 | ->select( [ |
71 | 'log_id', 'log_action', 'log_timestamp', 'log_params', 'log_deleted', |
72 | 'actor_id', 'actor_name', 'actor_user' |
73 | ] ) |
74 | ->from( 'logging' ) |
75 | ->join( 'actor', null, 'actor_id=log_actor' ) |
76 | ->where( $conds ) |
77 | ->queryInfo( $commentQuery ) |
78 | ->orderBy( 'log_timestamp', SelectQueryBuilder::SORT_DESC ) |
79 | ->limit( $this->mBatchSize + 1 ) |
80 | ->caller( __METHOD__ ) |
81 | ->fetchResultSet(); |
82 | |
83 | $rowCount = $oldLoggs->numRows(); |
84 | |
85 | if ( $rowCount == $this->mBatchSize + 1 ) { |
86 | $first = $oldLoggs->fetchObject(); |
87 | $oldLoggs->seek( $rowCount - 2 ); |
88 | $last = $oldLoggs->fetchObject(); |
89 | if ( $first->log_timestamp === $last->log_timestamp ) { |
90 | $this->fatalError( "Batch size too low to avoid infinite loop.\n" ); |
91 | } |
92 | $extra = $oldLoggs->fetchObject(); |
93 | if ( $last->log_timestamp === $extra->log_timestamp ) { |
94 | $this->fatalError( "We hit an edge case. Please increase the batch " . |
95 | " size and restart the transfer.\n" ); |
96 | } |
97 | $oldLoggs->rewind(); |
98 | } |
99 | |
100 | $targetDb->begin( __METHOD__ ); |
101 | foreach ( $oldLoggs as $key => $row ) { |
102 | // Skip if this is the extra row we selected |
103 | if ( $key > $this->mBatchSize ) { |
104 | continue; |
105 | } |
106 | |
107 | $lastMinTimestamp = $row->log_timestamp; |
108 | |
109 | $this->output( "Migrating log {$row->log_id}...\n" ); |
110 | if ( !$row->actor_user ) { |
111 | $this->output( |
112 | "Cannot transfer log_id: {$row->log_id}, the log user doesn't exist" |
113 | ); |
114 | continue; |
115 | } |
116 | $logUser = MediaWikiServices::getInstance()->getActorNormalization() |
117 | ->newActorFromRow( $row ); |
118 | $params = LogEntryBase::extractParams( $row->log_params ); |
119 | if ( !isset( $params['4:consumer'] ) ) { |
120 | $this->output( "Cannot transfer log_id: {$row->log_id}, param isn't correct" ); |
121 | continue; |
122 | } |
123 | $logEntry = new ManualLogEntry( 'mwoauthconsumer', $row->log_action ); |
124 | $logEntry->setPerformer( $logUser ); |
125 | $logEntry->setTarget( Title::makeTitleSafe( NS_USER, $row->actor_name ) ); |
126 | $logEntry->setComment( $commentStore->getComment( 'log_comment', $row )->text ); |
127 | $logEntry->setParameters( $params ); |
128 | $logEntry->setRelations( [ |
129 | 'OAuthConsumer' => [ $params['4:consumer'] ] |
130 | ] ); |
131 | // ManualLogEntry::insert() calls $dbw->timestamp on the value |
132 | $logEntry->setTimestamp( $row->log_timestamp ); |
133 | // @TODO: Maybe this will do something some day. Sigh. |
134 | $logEntry->setDeleted( $row->log_deleted ); |
135 | $logEntry->insert( $targetDb ); |
136 | } |
137 | $targetDb->commit( __METHOD__ ); |
138 | |
139 | $this->waitForReplication(); |
140 | |
141 | } while ( $rowCount ); |
142 | } |
143 | |
144 | } |
145 | |
146 | $maintClass = MigrateCentralWikiLogs::class; |
147 | require_once RUN_MAINTENANCE_IF_MAIN; |