2014-07-18 03:58:21 +00:00
|
|
|
<?php
|
|
|
|
|
2022-11-02 20:47:04 +00:00
|
|
|
namespace MediaWiki\Extension\Notifications\Mapper;
|
|
|
|
|
|
|
|
use BatchRowIterator;
|
|
|
|
use Exception;
|
2023-06-09 00:21:09 +00:00
|
|
|
use InvalidArgumentException;
|
2023-12-11 15:33:08 +00:00
|
|
|
use MediaWiki\Deferred\AtomicSectionUpdate;
|
|
|
|
use MediaWiki\Deferred\DeferredUpdates;
|
2022-11-02 21:34:17 +00:00
|
|
|
use MediaWiki\Extension\Notifications\Model\Notification;
|
2018-06-28 18:15:04 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2023-08-19 04:14:59 +00:00
|
|
|
use MediaWiki\Title\Title;
|
2021-06-29 05:50:13 +00:00
|
|
|
use MediaWiki\User\UserIdentity;
|
2022-11-02 20:47:04 +00:00
|
|
|
use MWExceptionHandler;
|
2017-12-22 22:20:13 +00:00
|
|
|
use Wikimedia\Rdbms\IDatabase;
|
2024-04-27 21:37:18 +00:00
|
|
|
use Wikimedia\Rdbms\SelectQueryBuilder;
|
2017-12-22 22:20:13 +00:00
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
/**
|
2022-11-02 21:34:17 +00:00
|
|
|
* Database mapper for Notification model
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
2022-11-02 20:47:04 +00:00
|
|
|
class NotificationMapper extends AbstractMapper {
|
2014-07-18 03:58:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Insert a notification record
|
2022-11-02 21:34:17 +00:00
|
|
|
* @param Notification $notification
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
2022-11-02 21:34:17 +00:00
|
|
|
public function insert( Notification $notification ) {
|
2021-05-03 07:28:02 +00:00
|
|
|
$dbw = $this->dbFactory->getEchoDb( DB_PRIMARY );
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2014-08-07 19:10:37 +00:00
|
|
|
$listeners = $this->getMethodListeners( __FUNCTION__ );
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2016-09-07 17:38:12 +00:00
|
|
|
$row = $notification->toDbArray();
|
2016-07-22 06:43:21 +00:00
|
|
|
DeferredUpdates::addUpdate( new AtomicSectionUpdate(
|
|
|
|
$dbw,
|
|
|
|
__METHOD__,
|
2021-05-04 16:06:42 +00:00
|
|
|
static function ( IDatabase $dbw, $fname ) use ( $row, $listeners ) {
|
2016-07-22 06:43:21 +00:00
|
|
|
$row['notification_timestamp'] =
|
|
|
|
$dbw->timestamp( $row['notification_timestamp'] );
|
2022-03-23 21:09:19 +00:00
|
|
|
$row['notification_read_timestamp'] =
|
|
|
|
$dbw->timestampOrNull( $row['notification_read_timestamp'] );
|
2024-04-13 18:33:56 +00:00
|
|
|
$dbw->newInsertQueryBuilder()
|
|
|
|
->insertInto( 'echo_notification' )
|
|
|
|
->row( $row )
|
|
|
|
->caller( $fname )
|
|
|
|
->execute();
|
2018-10-26 21:36:39 +00:00
|
|
|
foreach ( $listeners as $listener ) {
|
2020-06-07 00:59:39 +00:00
|
|
|
$dbw->onTransactionCommitOrIdle( $listener, $fname );
|
2014-08-07 19:10:37 +00:00
|
|
|
}
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
2016-07-22 06:43:21 +00:00
|
|
|
) );
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the offset used for notification list
|
2019-12-21 05:45:14 +00:00
|
|
|
* @param string|null $continue String Used for offset
|
2014-07-18 03:58:21 +00:00
|
|
|
* @return int[]
|
|
|
|
*/
|
|
|
|
protected function extractQueryOffset( $continue ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
$offset = [
|
2014-07-18 03:58:21 +00:00
|
|
|
'timestamp' => 0,
|
|
|
|
'offset' => 0,
|
2016-12-05 18:51:07 +00:00
|
|
|
];
|
2014-07-18 03:58:21 +00:00
|
|
|
if ( $continue ) {
|
|
|
|
$values = explode( '|', $continue, 3 );
|
|
|
|
if ( count( $values ) !== 2 ) {
|
2023-06-09 00:21:09 +00:00
|
|
|
throw new InvalidArgumentException( 'Invalid continue param: ' . $continue );
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
$offset['timestamp'] = (int)$values[0];
|
|
|
|
$offset['offset'] = (int)$values[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $offset;
|
|
|
|
}
|
|
|
|
|
2014-08-14 18:46:26 +00:00
|
|
|
/**
|
2014-09-03 20:56:12 +00:00
|
|
|
* Get unread notifications by user in the amount specified by limit order by
|
|
|
|
* notification timestamp in descending order. We have an index to retrieve
|
2022-11-02 20:47:04 +00:00
|
|
|
* unread notifications, but it's not optimized for ordering by timestamp. The
|
2014-09-03 20:56:12 +00:00
|
|
|
* descending order is only allowed if we keep the notification in low volume,
|
|
|
|
* which is done via a deleteJob
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity
|
2014-08-14 18:46:26 +00:00
|
|
|
* @param int $limit
|
2019-12-21 05:45:14 +00:00
|
|
|
* @param string|null $continue Used for offset
|
2014-08-14 18:46:26 +00:00
|
|
|
* @param string[] $eventTypes
|
2018-04-04 15:11:39 +00:00
|
|
|
* @param Title[]|null $titles If set, only return notifications for these pages.
|
2016-06-23 22:32:18 +00:00
|
|
|
* To find notifications not associated with any page, add null as an element to this array.
|
2021-05-13 00:04:54 +00:00
|
|
|
* @param int $dbSource Use primary database or replica database
|
2022-11-02 21:34:17 +00:00
|
|
|
* @return Notification[]
|
2014-08-14 18:46:26 +00:00
|
|
|
*/
|
2018-08-25 10:51:14 +00:00
|
|
|
public function fetchUnreadByUser(
|
2021-06-29 05:50:13 +00:00
|
|
|
UserIdentity $userIdentity,
|
2018-08-25 10:51:14 +00:00
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
array $eventTypes = [],
|
2024-10-26 13:05:00 +00:00
|
|
|
?array $titles = null,
|
2018-08-25 10:51:14 +00:00
|
|
|
$dbSource = DB_REPLICA
|
|
|
|
) {
|
2019-03-11 13:25:18 +00:00
|
|
|
$conds = [ 'notification_read_timestamp' => null ];
|
2016-06-07 18:48:33 +00:00
|
|
|
if ( $titles ) {
|
|
|
|
$conds['event_page_id'] = $this->getIdsForTitles( $titles );
|
|
|
|
if ( !$conds['event_page_id'] ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
return [];
|
2016-06-07 18:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-29 05:50:13 +00:00
|
|
|
return $this->fetchByUserInternal(
|
|
|
|
$userIdentity,
|
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
$eventTypes,
|
|
|
|
$conds,
|
|
|
|
$dbSource
|
|
|
|
);
|
2014-08-14 18:46:26 +00:00
|
|
|
}
|
|
|
|
|
2015-12-10 16:18:30 +00:00
|
|
|
/**
|
|
|
|
* Get read notifications by user in the amount specified by limit order by
|
|
|
|
* notification timestamp in descending order. We have an index to retrieve
|
|
|
|
* unread notifications but it's not optimized for ordering by timestamp. The
|
|
|
|
* descending order is only allowed if we keep the notification in low volume,
|
|
|
|
* which is done via a deleteJob
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity
|
2015-12-10 16:18:30 +00:00
|
|
|
* @param int $limit
|
2019-12-21 05:45:14 +00:00
|
|
|
* @param string|null $continue Used for offset
|
2015-12-10 16:18:30 +00:00
|
|
|
* @param string[] $eventTypes
|
2018-04-04 15:11:39 +00:00
|
|
|
* @param Title[]|null $titles If set, only return notifications for these pages.
|
2016-06-23 22:32:18 +00:00
|
|
|
* To find notifications not associated with any page, add null as an element to this array.
|
2021-05-13 00:04:54 +00:00
|
|
|
* @param int $dbSource Use primary database or replica database
|
2022-11-02 21:34:17 +00:00
|
|
|
* @return Notification[]
|
2015-12-10 16:18:30 +00:00
|
|
|
*/
|
2018-08-25 10:51:14 +00:00
|
|
|
public function fetchReadByUser(
|
2021-06-29 05:50:13 +00:00
|
|
|
UserIdentity $userIdentity,
|
2018-08-25 10:51:14 +00:00
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
array $eventTypes = [],
|
2024-10-26 13:05:00 +00:00
|
|
|
?array $titles = null,
|
2018-08-25 10:51:14 +00:00
|
|
|
$dbSource = DB_REPLICA
|
|
|
|
) {
|
2024-07-21 20:52:17 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( $dbSource );
|
|
|
|
$conds = [ $dbr->expr( 'notification_read_timestamp', '!=', null ) ];
|
2016-06-07 18:48:33 +00:00
|
|
|
if ( $titles ) {
|
|
|
|
$conds['event_page_id'] = $this->getIdsForTitles( $titles );
|
|
|
|
if ( !$conds['event_page_id'] ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
return [];
|
2016-06-07 18:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-29 05:50:13 +00:00
|
|
|
return $this->fetchByUserInternal(
|
|
|
|
$userIdentity,
|
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
$eventTypes,
|
|
|
|
$conds,
|
|
|
|
$dbSource
|
|
|
|
);
|
2015-12-10 16:18:30 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
/**
|
|
|
|
* Get Notification by user in batch along with limit, offset etc
|
2014-09-23 00:24:03 +00:00
|
|
|
*
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity the user to get notifications for
|
2014-09-23 00:24:03 +00:00
|
|
|
* @param int $limit The maximum number of notifications to return
|
2019-12-21 05:45:14 +00:00
|
|
|
* @param string|null $continue Used for offset
|
2014-09-23 00:24:03 +00:00
|
|
|
* @param array $eventTypes Event types to load
|
|
|
|
* @param array $excludeEventIds Event id's to exclude.
|
2018-04-04 15:11:39 +00:00
|
|
|
* @param Title[]|null $titles If set, only return notifications for these pages.
|
2016-06-23 22:32:18 +00:00
|
|
|
* To find notifications not associated with any page, add null as an element to this array.
|
2022-11-02 21:34:17 +00:00
|
|
|
* @return Notification[]
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
2018-08-25 10:51:14 +00:00
|
|
|
public function fetchByUser(
|
2021-06-29 05:50:13 +00:00
|
|
|
UserIdentity $userIdentity,
|
2018-08-25 10:51:14 +00:00
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
array $eventTypes = [],
|
|
|
|
array $excludeEventIds = [],
|
2024-10-26 13:05:00 +00:00
|
|
|
?array $titles = null
|
2018-08-25 10:51:14 +00:00
|
|
|
) {
|
2017-09-24 05:23:47 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( DB_REPLICA );
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2016-12-05 18:51:07 +00:00
|
|
|
$conds = [];
|
2015-12-09 17:00:15 +00:00
|
|
|
if ( $excludeEventIds ) {
|
2024-04-27 21:37:18 +00:00
|
|
|
$conds[] = $dbr->expr( 'event_id', '!=', $excludeEventIds );
|
2015-12-09 17:00:15 +00:00
|
|
|
}
|
2016-06-07 18:48:33 +00:00
|
|
|
if ( $titles ) {
|
|
|
|
$conds['event_page_id'] = $this->getIdsForTitles( $titles );
|
|
|
|
if ( !$conds['event_page_id'] ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
return [];
|
2016-06-07 18:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-09 17:00:15 +00:00
|
|
|
|
2021-06-29 05:50:13 +00:00
|
|
|
return $this->fetchByUserInternal(
|
|
|
|
$userIdentity,
|
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
$eventTypes,
|
|
|
|
$conds
|
|
|
|
);
|
2015-12-09 17:00:15 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 18:48:33 +00:00
|
|
|
protected function getIdsForTitles( array $titles ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
$ids = [];
|
2016-06-07 18:48:33 +00:00
|
|
|
foreach ( $titles as $title ) {
|
2016-06-23 22:32:18 +00:00
|
|
|
if ( $title === null ) {
|
|
|
|
$ids[] = null;
|
|
|
|
} elseif ( $title->exists() ) {
|
2016-06-07 18:48:33 +00:00
|
|
|
$ids[] = $title->getArticleId();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $ids;
|
|
|
|
}
|
|
|
|
|
2015-12-09 17:00:15 +00:00
|
|
|
/**
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity the user to get notifications for
|
2015-12-09 17:00:15 +00:00
|
|
|
* @param int $limit The maximum number of notifications to return
|
2019-12-21 05:45:14 +00:00
|
|
|
* @param string|null $continue Used for offset
|
2015-12-09 17:00:15 +00:00
|
|
|
* @param array $eventTypes Event types to load
|
|
|
|
* @param array $conds Additional query conditions.
|
2021-05-13 00:04:54 +00:00
|
|
|
* @param int $dbSource Use primary database or replica database
|
2022-11-02 21:34:17 +00:00
|
|
|
* @return Notification[]
|
2015-12-09 17:00:15 +00:00
|
|
|
*/
|
2018-08-25 10:51:14 +00:00
|
|
|
protected function fetchByUserInternal(
|
2021-06-29 05:50:13 +00:00
|
|
|
UserIdentity $userIdentity,
|
2018-08-25 10:51:14 +00:00
|
|
|
$limit,
|
|
|
|
$continue,
|
|
|
|
array $eventTypes = [],
|
|
|
|
array $conds = [],
|
|
|
|
$dbSource = DB_REPLICA
|
|
|
|
) {
|
2015-12-09 17:00:15 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( $dbSource );
|
|
|
|
|
2014-08-14 18:46:26 +00:00
|
|
|
if ( !$eventTypes ) {
|
2016-12-05 18:51:07 +00:00
|
|
|
return [];
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
// There is a problem with querying by event type, if a user has only one or none
|
2015-12-09 17:00:15 +00:00
|
|
|
// flow notification and huge amount other notifications, the lookup of only flow
|
2014-07-22 21:33:22 +00:00
|
|
|
// notification will result in a slow query. Luckily users won't have that many
|
|
|
|
// notifications. We should have some cron job to remove old notifications so
|
|
|
|
// the notification volume is in a reasonable amount for such case. The other option
|
|
|
|
// is to denormalize notification table with event_type and lookup index.
|
2016-12-05 18:51:07 +00:00
|
|
|
$conds = [
|
2021-06-29 05:50:13 +00:00
|
|
|
'notification_user' => $userIdentity->getId(),
|
2014-08-14 18:46:26 +00:00
|
|
|
'event_type' => $eventTypes,
|
2016-03-04 19:23:02 +00:00
|
|
|
'event_deleted' => 0,
|
2016-12-05 18:51:07 +00:00
|
|
|
] + $conds;
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2015-12-09 18:41:40 +00:00
|
|
|
$offset = $this->extractQueryOffset( $continue );
|
|
|
|
|
|
|
|
// Start points are specified
|
|
|
|
if ( $offset['timestamp'] && $offset['offset'] ) {
|
|
|
|
// The offset and timestamp are those of the first notification we want to return
|
2022-11-15 10:43:24 +00:00
|
|
|
$conds[] = $dbr->buildComparison( '<=', [
|
|
|
|
'notification_timestamp' => $dbr->timestamp( $offset['timestamp'] ),
|
|
|
|
'notification_event' => $offset['offset'],
|
|
|
|
] );
|
2015-12-09 18:41:40 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 21:37:18 +00:00
|
|
|
$res = $dbr->newSelectQueryBuilder()
|
|
|
|
->select( Notification::selectFields() )
|
|
|
|
->from( 'echo_notification' )
|
|
|
|
->leftJoin( 'echo_event', null, 'notification_event=event_id' )
|
|
|
|
->where( $conds )
|
|
|
|
->orderBy( [ 'notification_timestamp', 'notification_event' ], SelectQueryBuilder::SORT_DESC )
|
|
|
|
->limit( $limit )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchResultSet();
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2022-11-02 21:34:17 +00:00
|
|
|
/** @var Notification[] $allNotifications */
|
2016-12-05 18:51:07 +00:00
|
|
|
$allNotifications = [];
|
2015-03-16 15:47:13 +00:00
|
|
|
foreach ( $res as $row ) {
|
|
|
|
try {
|
2022-11-02 21:34:17 +00:00
|
|
|
$notification = Notification::newFromRow( $row );
|
2016-03-04 19:23:02 +00:00
|
|
|
if ( $notification ) {
|
|
|
|
$allNotifications[] = $notification;
|
2016-05-13 23:39:17 +00:00
|
|
|
}
|
2015-03-16 15:47:13 +00:00
|
|
|
} catch ( Exception $e ) {
|
2019-03-12 20:04:00 +00:00
|
|
|
$id = $row->event_id ?? 'unknown event';
|
2015-03-16 15:47:13 +00:00
|
|
|
wfDebugLog( 'Echo', __METHOD__ . ": Failed initializing event: $id" );
|
|
|
|
MWExceptionHandler::logException( $e );
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2016-12-05 18:51:07 +00:00
|
|
|
$data = [];
|
2016-03-04 19:23:02 +00:00
|
|
|
foreach ( $allNotifications as $notification ) {
|
|
|
|
$data[ $notification->getEvent()->getId() ] = $notification;
|
|
|
|
}
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2016-05-03 01:56:13 +00:00
|
|
|
/**
|
2022-11-02 21:34:17 +00:00
|
|
|
* Fetch Notifications by user and event IDs.
|
2016-05-03 01:56:13 +00:00
|
|
|
*
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity
|
2016-06-13 20:41:12 +00:00
|
|
|
* @param int[] $eventIds
|
2024-04-18 19:54:01 +00:00
|
|
|
* @return Notification[]
|
2016-05-03 01:56:13 +00:00
|
|
|
*/
|
2021-06-29 05:50:13 +00:00
|
|
|
public function fetchByUserEvents( UserIdentity $userIdentity, array $eventIds ) {
|
2017-09-24 05:23:47 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( DB_REPLICA );
|
2016-05-03 01:56:13 +00:00
|
|
|
|
2024-04-27 21:37:18 +00:00
|
|
|
$result = $dbr->newSelectQueryBuilder()
|
|
|
|
->select( Notification::selectFields() )
|
|
|
|
->from( 'echo_notification' )
|
|
|
|
->join( 'echo_event', null, 'notification_event=event_id' )
|
|
|
|
->where( [
|
2021-06-29 05:50:13 +00:00
|
|
|
'notification_user' => $userIdentity->getId(),
|
2016-06-13 20:41:12 +00:00
|
|
|
'notification_event' => $eventIds
|
2024-04-27 21:37:18 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchResultSet();
|
2016-05-03 01:56:13 +00:00
|
|
|
|
2024-04-18 19:54:01 +00:00
|
|
|
$notifications = [];
|
|
|
|
foreach ( $result as $row ) {
|
|
|
|
$notifications[] = Notification::newFromRow( $row );
|
2016-05-03 01:56:13 +00:00
|
|
|
}
|
2024-04-18 19:54:01 +00:00
|
|
|
return $notifications;
|
2016-05-03 01:56:13 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 22:11:53 +00:00
|
|
|
/**
|
|
|
|
* Fetch a notification by user in the specified offset. The caller should
|
|
|
|
* know that passing a big number for offset is NOT going to work
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity
|
2014-09-09 22:11:53 +00:00
|
|
|
* @param int $offset
|
2022-11-02 21:34:17 +00:00
|
|
|
* @return Notification|false
|
2014-09-09 22:11:53 +00:00
|
|
|
*/
|
2021-06-29 05:50:13 +00:00
|
|
|
public function fetchByUserOffset( UserIdentity $userIdentity, $offset ) {
|
2017-09-24 05:23:47 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( DB_REPLICA );
|
2024-04-27 21:37:18 +00:00
|
|
|
$row = $dbr->newSelectQueryBuilder()
|
|
|
|
->select( Notification::selectFields() )
|
|
|
|
->from( 'echo_notification' )
|
|
|
|
->leftJoin( 'echo_event', null, 'notification_event=event_id' )
|
|
|
|
->where( [
|
2021-06-29 05:50:13 +00:00
|
|
|
'notification_user' => $userIdentity->getId(),
|
2016-03-04 19:23:02 +00:00
|
|
|
'event_deleted' => 0,
|
2024-04-27 21:37:18 +00:00
|
|
|
] )
|
|
|
|
->orderBy( [ 'notification_timestamp', 'notification_event' ], SelectQueryBuilder::SORT_DESC )
|
|
|
|
->offset( $offset )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchRow();
|
2014-09-09 22:11:53 +00:00
|
|
|
|
|
|
|
if ( $row ) {
|
2022-11-02 21:34:17 +00:00
|
|
|
return Notification::newFromRow( $row );
|
2014-09-09 22:11:53 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Batch delete notifications by user and eventId offset
|
2021-06-29 05:50:13 +00:00
|
|
|
* @param UserIdentity $userIdentity
|
2014-09-09 22:11:53 +00:00
|
|
|
* @param int $eventId
|
2017-07-26 19:34:44 +00:00
|
|
|
* @return bool
|
2014-09-09 22:11:53 +00:00
|
|
|
*/
|
2021-06-29 05:50:13 +00:00
|
|
|
public function deleteByUserEventOffset( UserIdentity $userIdentity, $eventId ) {
|
2018-06-28 18:15:04 +00:00
|
|
|
global $wgUpdateRowsPerQuery;
|
2022-11-02 20:47:04 +00:00
|
|
|
$eventMapper = new EventMapper( $this->dbFactory );
|
2021-06-29 05:50:13 +00:00
|
|
|
$userId = $userIdentity->getId();
|
2021-05-03 07:28:02 +00:00
|
|
|
$dbw = $this->dbFactory->getEchoDb( DB_PRIMARY );
|
2019-04-23 00:16:21 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( DB_REPLICA );
|
2018-06-28 18:15:04 +00:00
|
|
|
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
|
|
|
|
$ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
|
2019-06-11 21:43:05 +00:00
|
|
|
$domainId = $dbw->getDomainID();
|
2018-06-28 18:15:04 +00:00
|
|
|
|
2019-04-23 00:16:21 +00:00
|
|
|
$iterator = new BatchRowIterator(
|
|
|
|
$dbr,
|
2014-09-09 22:11:53 +00:00
|
|
|
'echo_notification',
|
2018-06-28 18:15:04 +00:00
|
|
|
'notification_event',
|
2019-04-23 00:16:21 +00:00
|
|
|
$wgUpdateRowsPerQuery
|
2014-09-09 22:11:53 +00:00
|
|
|
);
|
2019-04-23 00:16:21 +00:00
|
|
|
$iterator->addConditions( [
|
|
|
|
'notification_user' => $userId,
|
2024-07-21 20:52:17 +00:00
|
|
|
$dbw->expr( 'notification_event', '<', (int)$eventId ),
|
2019-04-23 00:16:21 +00:00
|
|
|
] );
|
2020-09-05 02:02:17 +00:00
|
|
|
$iterator->setCaller( __METHOD__ );
|
2019-04-23 00:16:21 +00:00
|
|
|
|
|
|
|
foreach ( $iterator as $batch ) {
|
|
|
|
$eventIds = [];
|
|
|
|
foreach ( $batch as $row ) {
|
|
|
|
$eventIds[] = $row->notification_event;
|
|
|
|
}
|
2024-04-12 19:50:43 +00:00
|
|
|
$dbw->newDeleteQueryBuilder()
|
|
|
|
->deleteFrom( 'echo_notification' )
|
|
|
|
->where( [
|
2018-06-28 18:15:04 +00:00
|
|
|
'notification_user' => $userId,
|
2019-04-23 00:16:21 +00:00
|
|
|
'notification_event' => $eventIds,
|
2024-04-12 19:50:43 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->execute();
|
2019-04-23 00:16:21 +00:00
|
|
|
|
|
|
|
// Find out which events are now orphaned, i.e. no longer referenced in echo_notifications
|
|
|
|
// (besides the rows we just deleted) or in echo_email_batch, and delete them
|
|
|
|
$eventMapper->deleteOrphanedEvents( $eventIds, $userId, 'echo_notification' );
|
|
|
|
|
2018-06-28 18:15:04 +00:00
|
|
|
$lbFactory->commitAndWaitForReplication(
|
|
|
|
__METHOD__, $ticket, [ 'domain' => $domainId ] );
|
|
|
|
}
|
2018-10-26 22:25:15 +00:00
|
|
|
return true;
|
2014-09-09 22:11:53 +00:00
|
|
|
}
|
|
|
|
|
2016-03-04 19:23:02 +00:00
|
|
|
/**
|
|
|
|
* Fetch ids of users that have notifications for certain events
|
|
|
|
*
|
|
|
|
* @param int[] $eventIds
|
2024-04-18 19:54:01 +00:00
|
|
|
* @return int[]
|
2016-03-04 19:23:02 +00:00
|
|
|
*/
|
2019-10-23 10:44:35 +00:00
|
|
|
public function fetchUsersWithNotificationsForEvents( array $eventIds ) {
|
2017-09-24 05:23:47 +00:00
|
|
|
$dbr = $this->dbFactory->getEchoDb( DB_REPLICA );
|
2016-03-04 19:23:02 +00:00
|
|
|
|
2024-04-27 21:37:18 +00:00
|
|
|
return $dbr->newSelectQueryBuilder()
|
|
|
|
->select( 'notification_user' )
|
|
|
|
->distinct()
|
|
|
|
->from( 'echo_notification' )
|
|
|
|
->where( [
|
2016-03-04 19:23:02 +00:00
|
|
|
'notification_event' => $eventIds
|
2024-04-27 21:37:18 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchFieldValues();
|
2016-03-04 19:23:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
2022-11-02 20:47:04 +00:00
|
|
|
|
|
|
|
class_alias( NotificationMapper::class, 'EchoNotificationMapper' );
|