1<?php 2/** 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation; either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 * http://www.gnu.org/copyleft/gpl.html 17 * 18 * @file 19 * @ingroup JobQueue 20 */ 21 22use MediaWiki\MediaWikiServices; 23 24/** 25 * Job for clearing all of the "last viewed" timestamps for a user's watchlist, or setting them all 26 * to the same value. 27 * 28 * Job parameters include: 29 * - userId: affected user ID [required] 30 * - casTime: UNIX timestamp of the event that triggered this job [required] 31 * - timestamp: value to set all of the "last viewed" timestamps to [optional, defaults to null] 32 * 33 * @ingroup JobQueue 34 * @since 1.31 35 */ 36class ClearWatchlistNotificationsJob extends Job implements GenericParameterJob { 37 public function __construct( array $params ) { 38 parent::__construct( 'clearWatchlistNotifications', $params ); 39 40 static $required = [ 'userId', 'casTime' ]; 41 $missing = implode( ', ', array_diff( $required, array_keys( $this->params ) ) ); 42 if ( $missing != '' ) { 43 throw new InvalidArgumentException( "Missing parameter(s) $missing" ); 44 } 45 46 $this->removeDuplicates = true; 47 } 48 49 public function run() { 50 $services = MediaWikiServices::getInstance(); 51 $lbFactory = $services->getDBLoadBalancerFactory(); 52 $rowsPerQuery = $services->getMainConfig()->get( 'UpdateRowsPerQuery' ); 53 54 $dbw = $lbFactory->getMainLB()->getConnectionRef( DB_MASTER ); 55 $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ ); 56 $timestamp = $this->params['timestamp'] ?? null; 57 if ( $timestamp === null ) { 58 $timestampCond = 'wl_notificationtimestamp IS NOT NULL'; 59 } else { 60 $timestamp = $dbw->timestamp( $timestamp ); 61 $timestampCond = 'wl_notificationtimestamp != ' . $dbw->addQuotes( $timestamp ) . 62 ' OR wl_notificationtimestamp IS NULL'; 63 } 64 // New notifications since the reset should not be cleared 65 $casTimeCond = 'wl_notificationtimestamp < ' . 66 $dbw->addQuotes( $dbw->timestamp( $this->params['casTime'] ) ) . 67 ' OR wl_notificationtimestamp IS NULL'; 68 69 $firstBatch = true; 70 do { 71 $idsToUpdate = $dbw->selectFieldValues( 72 'watchlist', 73 'wl_id', 74 [ 75 'wl_user' => $this->params['userId'], 76 $timestampCond, 77 $casTimeCond, 78 ], 79 __METHOD__, 80 [ 'LIMIT' => $rowsPerQuery ] 81 ); 82 if ( $idsToUpdate ) { 83 $dbw->update( 84 'watchlist', 85 [ 'wl_notificationtimestamp' => $timestamp ], 86 [ 87 'wl_id' => $idsToUpdate, 88 // For paranoia, enforce the CAS time condition here too 89 $casTimeCond 90 ], 91 __METHOD__ 92 ); 93 if ( !$firstBatch ) { 94 $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket ); 95 } 96 $firstBatch = false; 97 } 98 } while ( $idsToUpdate ); 99 return true; 100 } 101} 102