2014-07-18 03:58:21 +00:00
|
|
|
<?php
|
|
|
|
|
2022-11-02 03:37:20 +00:00
|
|
|
namespace MediaWiki\Extension\Notifications\Gateway;
|
|
|
|
|
2023-12-11 15:33:08 +00:00
|
|
|
use MediaWiki\Config\Config;
|
2022-11-12 07:19:00 +00:00
|
|
|
use MediaWiki\Extension\Notifications\DbFactory;
|
2022-11-13 07:48:43 +00:00
|
|
|
use MediaWiki\Extension\Notifications\NotifUser;
|
2021-12-19 01:16:52 +00:00
|
|
|
use MediaWiki\User\UserIdentity;
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
/**
|
|
|
|
* Database gateway which handles direct database interaction with the
|
|
|
|
* echo_notification & echo_event for a user, that wouldn't require
|
|
|
|
* loading data into models
|
|
|
|
*/
|
2022-11-02 03:37:20 +00:00
|
|
|
class UserNotificationGateway {
|
2014-07-18 03:58:21 +00:00
|
|
|
|
|
|
|
/**
|
2022-11-12 07:19:00 +00:00
|
|
|
* @var DbFactory
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
|
|
|
protected $dbFactory;
|
|
|
|
|
|
|
|
/**
|
2021-12-19 01:16:52 +00:00
|
|
|
* @var UserIdentity
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
|
|
|
protected $user;
|
|
|
|
|
|
|
|
/**
|
2017-08-23 14:38:58 +00:00
|
|
|
* The tables for this gateway.
|
|
|
|
*
|
|
|
|
* @var string
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
|
|
|
protected static $eventTable = 'echo_event';
|
2017-08-23 14:38:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The tables for this gateway.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
2014-07-18 03:58:21 +00:00
|
|
|
protected static $notificationTable = 'echo_notification';
|
2022-11-02 03:37:20 +00:00
|
|
|
|
2019-08-30 20:58:41 +00:00
|
|
|
/**
|
|
|
|
* @var Config
|
|
|
|
*/
|
|
|
|
private $config;
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2022-11-12 07:19:00 +00:00
|
|
|
public function __construct( UserIdentity $user, DbFactory $dbFactory, Config $config ) {
|
2014-07-18 03:58:21 +00:00
|
|
|
$this->user = $user;
|
|
|
|
$this->dbFactory = $dbFactory;
|
2019-08-30 20:58:41 +00:00
|
|
|
$this->config = $config;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
2018-05-25 17:42:13 +00:00
|
|
|
public function getDB( $dbSource ) {
|
|
|
|
return $this->dbFactory->getEchoDb( $dbSource );
|
|
|
|
}
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
/**
|
|
|
|
* Mark notifications as read
|
2017-08-23 14:38:58 +00:00
|
|
|
* @param array $eventIDs
|
2017-10-02 23:07:31 +00:00
|
|
|
* @return bool Returns true when data has been updated in DB, false on
|
|
|
|
* failure, or when there was nothing to update
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
|
|
|
public function markRead( array $eventIDs ) {
|
|
|
|
if ( !$eventIDs ) {
|
2017-10-02 23:07:31 +00:00
|
|
|
return false;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
2021-05-03 07:28:02 +00:00
|
|
|
$dbw = $this->getDB( DB_PRIMARY );
|
2018-02-22 03:07:45 +00:00
|
|
|
if ( $dbw->isReadOnly() ) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2018-08-09 23:33:45 +00:00
|
|
|
$success = true;
|
2019-08-30 20:58:41 +00:00
|
|
|
foreach (
|
|
|
|
array_chunk( $eventIDs, $this->config->get( 'UpdateRowsPerQuery' ) ) as $batch
|
|
|
|
) {
|
2024-04-13 18:33:56 +00:00
|
|
|
$dbw->newUpdateQueryBuilder()
|
|
|
|
->update( self::$notificationTable )
|
|
|
|
->set( [ 'notification_read_timestamp' => $dbw->timestamp( wfTimestampNow() ) ] )
|
|
|
|
->where( [
|
2018-08-09 23:33:45 +00:00
|
|
|
'notification_user' => $this->user->getId(),
|
|
|
|
'notification_event' => $batch,
|
|
|
|
'notification_read_timestamp' => null,
|
2024-04-13 18:33:56 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->execute();
|
|
|
|
$success = $dbw->affectedRows() && $success;
|
2018-08-09 23:33:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $success;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
2016-03-04 22:44:22 +00:00
|
|
|
/**
|
|
|
|
* Mark notifications as unread
|
2017-08-23 14:38:58 +00:00
|
|
|
* @param array $eventIDs
|
2017-10-02 23:07:31 +00:00
|
|
|
* @return bool Returns true when data has been updated in DB, false on
|
|
|
|
* failure, or when there was nothing to update
|
2016-03-04 22:44:22 +00:00
|
|
|
*/
|
|
|
|
public function markUnRead( array $eventIDs ) {
|
|
|
|
if ( !$eventIDs ) {
|
2017-10-02 23:07:31 +00:00
|
|
|
return false;
|
2016-03-04 22:44:22 +00:00
|
|
|
}
|
|
|
|
|
2021-05-03 07:28:02 +00:00
|
|
|
$dbw = $this->getDB( DB_PRIMARY );
|
2018-08-24 10:15:12 +00:00
|
|
|
if ( $dbw->isReadOnly() ) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-04 22:44:22 +00:00
|
|
|
|
2018-08-24 10:15:12 +00:00
|
|
|
$success = true;
|
2019-08-30 20:58:41 +00:00
|
|
|
foreach (
|
|
|
|
array_chunk( $eventIDs, $this->config->get( 'UpdateRowsPerQuery' ) ) as $batch
|
|
|
|
) {
|
2024-04-13 18:33:56 +00:00
|
|
|
$dbw->newUpdateQueryBuilder()
|
|
|
|
->update( self::$notificationTable )
|
|
|
|
->set( [ 'notification_read_timestamp' => null ] )
|
|
|
|
->where( [
|
2018-08-09 23:33:45 +00:00
|
|
|
'notification_user' => $this->user->getId(),
|
|
|
|
'notification_event' => $batch,
|
2024-04-13 18:33:56 +00:00
|
|
|
$dbw->expr( 'notification_read_timestamp', '!=', null ),
|
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->execute();
|
|
|
|
$success = $dbw->affectedRows() && $success;
|
2018-08-09 23:33:45 +00:00
|
|
|
}
|
|
|
|
return $success;
|
2016-03-04 22:44:22 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
/**
|
2022-11-13 07:48:43 +00:00
|
|
|
* Mark all notification as read, use NotifUser::markAllRead() instead
|
2014-08-13 22:00:25 +00:00
|
|
|
* @deprecated may need this when running in a job or revive this when we
|
|
|
|
* have updateJoin()
|
2014-07-18 03:58:21 +00:00
|
|
|
*/
|
|
|
|
public function markAllRead() {
|
2021-05-03 07:28:02 +00:00
|
|
|
$dbw = $this->getDB( DB_PRIMARY );
|
2018-08-24 10:15:12 +00:00
|
|
|
if ( $dbw->isReadOnly() ) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2024-04-13 18:33:56 +00:00
|
|
|
$dbw->newUpdateQueryBuilder()
|
|
|
|
->update( self::$notificationTable )
|
|
|
|
->set( [ 'notification_read_timestamp' => $dbw->timestamp( wfTimestampNow() ) ] )
|
|
|
|
->where( [
|
2014-07-18 03:58:21 +00:00
|
|
|
'notification_user' => $this->user->getId(),
|
2015-10-01 13:48:52 +00:00
|
|
|
'notification_read_timestamp' => null,
|
2024-04-13 18:33:56 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->execute();
|
2018-10-26 19:40:33 +00:00
|
|
|
|
|
|
|
return true;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-07-22 21:33:22 +00:00
|
|
|
* Get notification count for the types specified
|
2021-05-13 00:04:54 +00:00
|
|
|
* @param int $dbSource use primary database or replica storage to pull count
|
2016-03-14 13:37:20 +00:00
|
|
|
* @param array $eventTypesToLoad event types to retrieve
|
|
|
|
* @param int $cap Max count
|
2014-07-18 03:58:21 +00:00
|
|
|
* @return int
|
|
|
|
*/
|
2020-06-27 10:05:03 +00:00
|
|
|
public function getCappedNotificationCount(
|
|
|
|
$dbSource,
|
|
|
|
array $eventTypesToLoad = [],
|
2022-11-13 07:48:43 +00:00
|
|
|
$cap = NotifUser::MAX_BADGE_COUNT
|
2020-06-27 10:05:03 +00:00
|
|
|
) {
|
2014-07-18 03:58:21 +00:00
|
|
|
// double check
|
2021-05-03 07:28:02 +00:00
|
|
|
if ( !in_array( $dbSource, [ DB_REPLICA, DB_PRIMARY ] ) ) {
|
2017-09-24 05:23:47 +00:00
|
|
|
$dbSource = DB_REPLICA;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( !$eventTypesToLoad ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-25 17:42:13 +00:00
|
|
|
$db = $this->getDB( $dbSource );
|
2024-04-27 21:37:18 +00:00
|
|
|
return $db->newSelectQueryBuilder()
|
|
|
|
->select( '1' )
|
|
|
|
->from( self::$notificationTable )
|
|
|
|
->leftJoin( self::$eventTable, null, 'notification_event=event_id' )
|
|
|
|
->where( [
|
2014-07-18 03:58:21 +00:00
|
|
|
'notification_user' => $this->user->getId(),
|
|
|
|
'notification_read_timestamp' => null,
|
2016-03-04 19:23:02 +00:00
|
|
|
'event_deleted' => 0,
|
2014-07-18 03:58:21 +00:00
|
|
|
'event_type' => $eventTypesToLoad,
|
2024-04-27 21:37:18 +00:00
|
|
|
] )
|
|
|
|
->limit( $cap )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchRowCount();
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IMPORTANT: should only call this function if the number of unread notification
|
|
|
|
* is reasonable, for example, unread notification count is less than the max
|
2022-11-13 07:48:43 +00:00
|
|
|
* display defined in oNotifUser::MAX_BADGE_COUNT
|
2017-08-23 14:38:58 +00:00
|
|
|
* @param string $type
|
2014-07-18 03:58:21 +00:00
|
|
|
* @return int[]
|
|
|
|
*/
|
|
|
|
public function getUnreadNotifications( $type ) {
|
2018-05-25 17:42:13 +00:00
|
|
|
$dbr = $this->getDB( DB_REPLICA );
|
2024-04-27 21:37:18 +00:00
|
|
|
$res = $dbr->newSelectQueryBuilder()
|
|
|
|
->select( 'notification_event' )
|
|
|
|
->from( self::$notificationTable )
|
|
|
|
->join( self::$eventTable, null, 'notification_event = event_id' )
|
|
|
|
->where( [
|
2014-07-18 03:58:21 +00:00
|
|
|
'notification_user' => $this->user->getId(),
|
|
|
|
'notification_read_timestamp' => null,
|
2016-03-04 19:23:02 +00:00
|
|
|
'event_deleted' => 0,
|
2014-07-18 03:58:21 +00:00
|
|
|
'event_type' => $type,
|
2024-04-27 21:37:18 +00:00
|
|
|
] )
|
|
|
|
->caller( __METHOD__ )
|
|
|
|
->fetchResultSet();
|
2014-07-18 03:58:21 +00:00
|
|
|
|
2016-12-05 18:51:07 +00:00
|
|
|
$eventIds = [];
|
2024-04-18 19:54:01 +00:00
|
|
|
foreach ( $res as $row ) {
|
|
|
|
$eventIds[$row->notification_event] = $row->notification_event;
|
2014-07-18 03:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $eventIds;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|