diff --git a/extension.json b/extension.json index 31fc57cd8..48ad89131 100644 --- a/extension.json +++ b/extension.json @@ -1009,6 +1009,7 @@ "NotificationPager": "includes/special/NotificationPager.php", "NotificationsTest": "tests/phpunit/NotificationsTest.php", "ProcessEchoEmailBatch": "maintenance/processEchoEmailBatch.php", + "RecomputeNotifCounts": "maintenance/recomputeNotifCounts.php", "RemoveInvalidNotification": "maintenance/removeInvalidNotification.php", "RemoveOrphanedEvents": "maintenance/removeOrphanedEvents.php", "ResourceLoaderEchoImageModule": "includes/ResourceLoaderEchoImageModule.php", diff --git a/maintenance/recomputeNotifCounts.php b/maintenance/recomputeNotifCounts.php new file mode 100644 index 000000000..36a0fcc2f --- /dev/null +++ b/maintenance/recomputeNotifCounts.php @@ -0,0 +1,87 @@ +addDescription( 'Recompute notification counts for all users.' ); + $this->addOption( 'user-ids', 'Comma-separated list of users to recompute notification counts for', false, true ); + $this->addOption( 'notif-types', 'Recompute counts for all users who have unread notifications of one of these types (comma-separated)', + false, true ); + + $this->setBatchSize( 500 ); + + $this->requireExtension( 'Echo' ); + } + + public function execute() { + $dbFactory = MWEchoDbFactory::newFromDefault(); + $dbwEcho = $dbFactory->getEchoDb( DB_MASTER ); + $dbrEcho = $dbFactory->getEchoDb( DB_REPLICA ); + $dbr = wfGetDB( DB_REPLICA ); + + $userIDs = $this->getOption( 'user-ids' ); + $userIDs = $userIDs ? explode( ',', $userIDs ) : null; + $notifTypes = $this->getOption( 'notif-types' ); + $notifTypes = $notifTypes ? explode( ',', $notifTypes ) : null; + + if ( $userIDs ) { + $userIterator = array_chunk( $userIDs, $this->getBatchSize() ); + } elseif ( $notifTypes ) { + $userIterator = new BatchRowIterator( + $dbrEcho, + [ 'echo_event', 'echo_notification' ], + 'notification_user', + $this->getBatchSize() + ); + $userIterator->addJoinConditions( [ + 'echo_notification' => [ 'INNER JOIN', 'notification_event=event_id' ] + ] ); + $userIterator->addConditions( [ + 'event_type' => $notifTypes, + 'notification_read_timestamp' => null + ] ); + $userIterator->addOptions( [ + 'GROUP BY' => 'notification_user' + ] ); + } else { + $userQuery = User::getQueryInfo(); + $userIterator = new BatchRowIterator( $dbr, $userQuery['tables'], 'user_id', $this->getBatchSize() ); + $userIterator->setFetchColumns( $userQuery['fields'] ); + $userIterator->addJoinConditions( $userQuery['joins'] ); + } + + $count = 0; + foreach ( $userIterator as $batch ) { + foreach ( $batch as $rowOrID ) { + if ( is_object( $rowOrID ) && isset( $rowOrID->user_id ) ) { + $user = User::newFromRow( $rowOrID ); + } else { + $user = User::newFromId( is_object( $rowOrID ) ? $rowOrID->notification_user : $rowOrID ); + } + $notifUser = MWEchoNotifUser::newFromUser( $user ); + $notifUser->resetNotificationCount(); + } + $count += count( $batch ); + $this->output( "$count users' counts recomputed.\n" ); + $dbFactory->waitForSlaves(); + } + } +} + +$maintClass = RecomputeNotifCounts::class; +require_once RUN_MAINTENANCE_IF_MAIN;