Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
81.08% |
60 / 74 |
|
40.00% |
2 / 5 |
CRAP | |
0.00% |
0 / 1 |
UnreadWikis | |
81.08% |
60 / 74 |
|
40.00% |
2 / 5 |
20.19 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
newFromUser | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getDB | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getUnreadCounts | |
93.33% |
28 / 30 |
|
0.00% |
0 / 1 |
7.01 | |||
updateCount | |
82.86% |
29 / 35 |
|
0.00% |
0 / 1 |
7.25 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\Notifications; |
4 | |
5 | use MediaWiki\MediaWikiServices; |
6 | use MediaWiki\User\CentralId\CentralIdLookup; |
7 | use MediaWiki\User\UserIdentity; |
8 | use MediaWiki\Utils\MWTimestamp; |
9 | use Wikimedia\Rdbms\IDatabase; |
10 | |
11 | /** |
12 | * Manages what wikis a user has unread notifications on |
13 | */ |
14 | class UnreadWikis { |
15 | |
16 | private const DEFAULT_TS = '00000000000000'; |
17 | private const DEFAULT_TS_DB = '00010101010101'; |
18 | |
19 | /** |
20 | * @var int |
21 | */ |
22 | private $id; |
23 | |
24 | /** |
25 | * @var DbFactory |
26 | */ |
27 | private $dbFactory; |
28 | |
29 | /** |
30 | * @param int $id Central user id |
31 | */ |
32 | public function __construct( $id ) { |
33 | $this->id = $id; |
34 | $this->dbFactory = DbFactory::newFromDefault(); |
35 | } |
36 | |
37 | /** |
38 | * Use the user id provided by the CentralIdLookup |
39 | * |
40 | * @param UserIdentity $user |
41 | * @return UnreadWikis|false |
42 | */ |
43 | public static function newFromUser( UserIdentity $user ) { |
44 | $id = MediaWikiServices::getInstance() |
45 | ->getCentralIdLookup() |
46 | ->centralIdFromLocalUser( $user, CentralIdLookup::AUDIENCE_RAW ); |
47 | if ( !$id ) { |
48 | return false; |
49 | } |
50 | |
51 | return new self( $id ); |
52 | } |
53 | |
54 | /** |
55 | * @param int $index DB_* constant |
56 | * |
57 | * @return bool|IDatabase |
58 | */ |
59 | private function getDB( $index ) { |
60 | return $this->dbFactory->getSharedDb( $index ); |
61 | } |
62 | |
63 | /** |
64 | * @return array[][] |
65 | */ |
66 | public function getUnreadCounts() { |
67 | $dbr = $this->getDB( DB_REPLICA ); |
68 | if ( $dbr === false ) { |
69 | return []; |
70 | } |
71 | |
72 | $rows = $dbr->newSelectQueryBuilder() |
73 | ->select( [ |
74 | 'euw_wiki', |
75 | 'euw_alerts', 'euw_alerts_ts', |
76 | 'euw_messages', 'euw_messages_ts', |
77 | ] ) |
78 | ->from( 'echo_unread_wikis' ) |
79 | ->where( [ 'euw_user' => $this->id ] ) |
80 | ->caller( __METHOD__ ) |
81 | ->fetchResultSet(); |
82 | |
83 | $wikis = []; |
84 | foreach ( $rows as $row ) { |
85 | if ( !$row->euw_alerts && !$row->euw_messages ) { |
86 | // This shouldn't happen, but lets be safe... |
87 | continue; |
88 | } |
89 | $wikis[$row->euw_wiki] = [ |
90 | AttributeManager::ALERT => [ |
91 | 'count' => $row->euw_alerts, |
92 | 'ts' => wfTimestamp( TS_MW, $row->euw_alerts_ts ) === static::DEFAULT_TS_DB ? |
93 | static::DEFAULT_TS : wfTimestamp( TS_MW, $row->euw_alerts_ts ), |
94 | ], |
95 | AttributeManager::MESSAGE => [ |
96 | 'count' => $row->euw_messages, |
97 | 'ts' => wfTimestamp( TS_MW, $row->euw_messages_ts ) === static::DEFAULT_TS_DB ? |
98 | static::DEFAULT_TS : wfTimestamp( TS_MW, $row->euw_messages_ts ), |
99 | ], |
100 | ]; |
101 | } |
102 | |
103 | return $wikis; |
104 | } |
105 | |
106 | /** |
107 | * @param string $wiki Wiki code |
108 | * @param int $alertCount Number of alerts |
109 | * @param MWTimestamp|bool $alertTime Timestamp of most recent unread alert, or |
110 | * false meaning no timestamp because there are no unread alerts. |
111 | * @param int $msgCount Number of messages |
112 | * @param MWTimestamp|bool $msgTime Timestamp of most recent message, or |
113 | * false meaning no timestamp because there are no unread messages. |
114 | */ |
115 | public function updateCount( $wiki, $alertCount, $alertTime, $msgCount, $msgTime ) { |
116 | $dbw = $this->getDB( DB_PRIMARY ); |
117 | if ( $dbw === false || $dbw->isReadOnly() ) { |
118 | return; |
119 | } |
120 | |
121 | $conditions = [ |
122 | 'euw_user' => $this->id, |
123 | 'euw_wiki' => $wiki, |
124 | ]; |
125 | |
126 | if ( $alertCount || $msgCount ) { |
127 | $values = [ |
128 | 'euw_alerts' => $alertCount, |
129 | 'euw_alerts_ts' => $dbw->timestamp( |
130 | $alertTime |
131 | ? $alertTime->getTimestamp( TS_MW ) |
132 | : static::DEFAULT_TS_DB |
133 | ), |
134 | 'euw_messages' => $msgCount, |
135 | 'euw_messages_ts' => $dbw->timestamp( |
136 | $msgTime |
137 | ? $msgTime->getTimestamp( TS_MW ) |
138 | : static::DEFAULT_TS_DB |
139 | ), |
140 | ]; |
141 | |
142 | // when there is unread alert(s) and/or message(s), upsert the row |
143 | $dbw->newInsertQueryBuilder() |
144 | ->insertInto( 'echo_unread_wikis' ) |
145 | ->row( $conditions + $values ) |
146 | ->onDuplicateKeyUpdate() |
147 | ->uniqueIndexFields( [ 'euw_user', 'euw_wiki' ] ) |
148 | ->set( $values ) |
149 | ->caller( __METHOD__ ) |
150 | ->execute(); |
151 | } else { |
152 | // No unread notifications, delete the row |
153 | $dbw->newDeleteQueryBuilder() |
154 | ->deleteFrom( 'echo_unread_wikis' ) |
155 | ->where( $conditions ) |
156 | ->caller( __METHOD__ ) |
157 | ->execute(); |
158 | } |
159 | } |
160 | } |