Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
94.74% |
36 / 38 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
WatchedItemQueryServiceExtension | |
94.74% |
36 / 38 |
|
50.00% |
1 / 2 |
20.06 | |
0.00% |
0 / 1 |
modifyWatchedItemsWithRCInfoQuery | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
9 | |||
modifyWatchedItemsWithRCInfo | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
11.29 |
1 | <?php |
2 | /** |
3 | * Copyright (C) 2016 Brad Jorsch <bjorsch@wikimedia.org> |
4 | * |
5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation, either version 3 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | namespace ORES\Hooks\Api; |
20 | |
21 | use MediaWiki\User\UserIdentity; |
22 | use ORES\Hooks\Helpers; |
23 | use ORES\Services\ORESServices; |
24 | use Wikimedia\Rdbms\IReadableDatabase; |
25 | use Wikimedia\Rdbms\IResultWrapper; |
26 | |
27 | class WatchedItemQueryServiceExtension implements \WatchedItemQueryServiceExtension { |
28 | |
29 | /** |
30 | * Modify the query |
31 | * |
32 | * This adds the joins and conditions necessary to implement the |
33 | * 'oresreview' and '!oresreview' filters, and ensures that query includes |
34 | * the fields necessary to handle the 'oresscores' value in 'includeFields'. |
35 | * |
36 | * @warning Any joins added *must* join on a unique key of the target table |
37 | * unless you really know what you're doing. |
38 | * @param UserIdentity $user |
39 | * @param array $options Options from |
40 | * WatchedItemQueryService::getWatchedItemsWithRecentChangeInfo() |
41 | * @param IReadableDatabase $db Database connection being used for the query |
42 | * @param string[] &$tables Tables for Database::select() |
43 | * @param string[] &$fields Fields for Database::select() |
44 | * @param array &$conds Conditions for Database::select() |
45 | * @param array &$dbOptions Options for Database::select() |
46 | * @param array &$joinConds Join conditions for Database::select() |
47 | */ |
48 | public function modifyWatchedItemsWithRCInfoQuery( UserIdentity $user, array $options, |
49 | IReadableDatabase $db, array &$tables, array &$fields, array &$conds, array &$dbOptions, |
50 | array &$joinConds |
51 | ) { |
52 | if ( !$options['usedInGenerator'] && in_array( 'oresscores', $options['includeFields'], true ) ) { |
53 | if ( !in_array( 'rc_this_oldid', $fields, true ) ) { |
54 | $fields[] = 'rc_this_oldid'; |
55 | } |
56 | if ( !in_array( 'rc_type', $fields, true ) ) { |
57 | $fields[] = 'rc_type'; |
58 | } |
59 | } |
60 | |
61 | $show = Helpers::isModelEnabled( 'damaging' ) |
62 | ? array_flip( $options['filters'] ?? [] ) |
63 | : []; |
64 | if ( isset( $show['oresreview'] ) || isset( $show['!oresreview'] ) ) { |
65 | $threshold = Helpers::getThreshold( 'damaging', $user ); |
66 | $tables[] = 'ores_classification'; |
67 | |
68 | if ( isset( $show['oresreview'] ) ) { |
69 | $join = 'INNER JOIN'; |
70 | |
71 | // Filter out non-damaging and unscored edits. |
72 | $conds[] = $db->expr( 'oresc_probability', '>', $threshold ); |
73 | } else { |
74 | $join = 'LEFT JOIN'; |
75 | |
76 | // Filter out damaging edits. |
77 | $conds[] = $db->expr( 'oresc_probability', '<=', $threshold ) |
78 | ->or( 'oresc_probability', '=', null ); |
79 | } |
80 | |
81 | $modelId = ORESServices::getModelLookup()->getModelId( 'damaging' ); |
82 | $joinConds['ores_classification'] = [ $join, [ |
83 | 'rc_this_oldid=oresc_rev', |
84 | 'oresc_model' => $modelId, |
85 | 'oresc_class' => 1 |
86 | ] ]; |
87 | } |
88 | } |
89 | |
90 | /** |
91 | * Modify the result |
92 | * |
93 | * This handles the 'oresscores' value in 'includeFields': it collects the |
94 | * applicable revision IDs, loads scores for them (using |
95 | * ApiHooksHandler::loadScoresForRevisions()), and adds the scoring data to the |
96 | * $recentChangeInfo portion of $items. If all scores were not available |
97 | * and the API is able to fetch them later, it truncates $items and adjusts |
98 | * $startFrom accordingly. |
99 | * |
100 | * @param UserIdentity $user |
101 | * @param array $options Options from |
102 | * WatchedItemQueryService::getWatchedItemsWithRecentChangeInfo() |
103 | * @param IReadableDatabase $db Database connection being used for the query |
104 | * @param array[] &$items Array of pairs ( WatchedItem $watchedItem, string[] $recentChangeInfo ) |
105 | * @param IResultWrapper|bool $res Database query result |
106 | * @param array|null &$startFrom Continuation value |
107 | */ |
108 | public function modifyWatchedItemsWithRCInfo( UserIdentity $user, array $options, |
109 | IReadableDatabase $db, array &$items, $res, &$startFrom |
110 | ) { |
111 | if ( $options['usedInGenerator'] || !in_array( 'oresscores', $options['includeFields'], true ) ) { |
112 | return; |
113 | } |
114 | |
115 | $revids = []; |
116 | foreach ( $items as [ $watchedItem, $rcInfo ] ) { |
117 | if ( (int)$rcInfo['rc_type'] === RC_EDIT || (int)$rcInfo['rc_type'] === RC_NEW ) { |
118 | $revids[] = $rcInfo['rc_this_oldid']; |
119 | } |
120 | } |
121 | |
122 | if ( $revids ) { |
123 | $scores = ApiHooksHandler::loadScoresForRevisions( $revids ); |
124 | foreach ( $items as &$item ) { |
125 | $rcInfo = &$item[1]; |
126 | if ( (int)$rcInfo['rc_type'] !== RC_EDIT && (int)$rcInfo['rc_type'] !== RC_NEW ) { |
127 | continue; |
128 | } |
129 | |
130 | $revid = $rcInfo['rc_this_oldid']; |
131 | if ( isset( $scores[$revid] ) ) { |
132 | $rcInfo['oresScores'] = $scores[$revid]; |
133 | } |
134 | } |
135 | } |
136 | } |
137 | |
138 | } |