Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
86.12% |
912 / 1059 |
|
62.26% |
33 / 53 |
CRAP | |
0.00% |
0 / 1 |
ChangesListSpecialPage | |
86.20% |
912 / 1058 |
|
62.26% |
33 / 53 |
269.05 | |
0.00% |
0 / 1 |
__construct | |
96.40% |
428 / 444 |
|
0.00% |
0 / 1 |
7 | |||
removeRegistrationFilterDefinitions | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
areFiltersInConflict | |
62.50% |
10 / 16 |
|
0.00% |
0 / 1 |
13.27 | |||
execute | |
52.94% |
27 / 51 |
|
0.00% |
0 / 1 |
42.68 | |||
setTempUserConfig | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
considerActionsForDefaultSavedQuery | |
39.39% |
13 / 33 |
|
0.00% |
0 / 1 |
27.03 | |||
getLinkDays | |
45.45% |
5 / 11 |
|
0.00% |
0 / 1 |
6.60 | |||
includeRcFiltersApp | |
95.24% |
40 / 42 |
|
0.00% |
0 / 1 |
5 | |||
getRcFiltersConfigSummary | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
getRcFiltersConfigVars | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
outputNoResults | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
outputTimeout | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getRows | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
getOptions | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
registerFilters | |
100.00% |
57 / 57 |
|
100.00% |
1 / 1 |
7 | |||
transformFilterDefinition | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
registerFiltersFromDefinitions | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
4 | |||
getLegacyShowHideFilters | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
5 | |||
setup | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
getDefaultOptions | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
2 | |||
registerFilterGroup | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getFilterGroups | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFilterGroup | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getStructuredFilterJsData | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
fetchOptionsFromRequest | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
parseParameters | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
10 | |||
validateOptions | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
3 | |||
fixContradictoryOptions | |
94.44% |
17 / 18 |
|
0.00% |
0 / 1 |
7.01 | |||
fixBackwardsCompatibilityOptions | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
replaceOldOptions | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
7 | |||
convertParamsForLink | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
buildQuery | |
96.43% |
27 / 28 |
|
0.00% |
0 / 1 |
8 | |||
doMainQuery | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
6 | |||
runMainQueryHook | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getDB | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
webOutputHeader | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
webOutput | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
outputFeedLinks | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
outputChangesList | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
doHeader | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
setTopText | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setBottomText | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExtraOptions | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
makeLegend | |
67.80% |
40 / 59 |
|
0.00% |
0 / 1 |
10.14 | |||
addModules | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRegisteredExpr | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
getExperienceExpr | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
3 | |||
filterOnUserExperienceLevel | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
11 | |||
isStructuredFilterUiEnabled | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
checkStructuredFilterUiEnabled | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getDefaultLimit | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getDefaultDays | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getLimitPreferenceName | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getSavedQueriesPreferenceName | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getDefaultDaysPreferenceName | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getCollapsedPreferenceName | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
expandSymbolicNamespaceFilters | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
3 |
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 | */ |
20 | |
21 | namespace MediaWiki\SpecialPage; |
22 | |
23 | use ChangesListBooleanFilter; |
24 | use ChangesListBooleanFilterGroup; |
25 | use ChangesListFilterGroup; |
26 | use ChangesListStringOptionsFilterGroup; |
27 | use ChangeTags; |
28 | use MediaWiki\Context\IContextSource; |
29 | use MediaWiki\Html\FormOptions; |
30 | use MediaWiki\Html\Html; |
31 | use MediaWiki\Json\FormatJson; |
32 | use MediaWiki\MainConfigNames; |
33 | use MediaWiki\MediaWikiServices; |
34 | use MediaWiki\Parser\Sanitizer; |
35 | use MediaWiki\ResourceLoader as RL; |
36 | use MediaWiki\User\TempUser\TempUserConfig; |
37 | use MediaWiki\User\UserArray; |
38 | use MediaWiki\User\UserIdentity; |
39 | use MediaWiki\User\UserIdentityUtils; |
40 | use MWExceptionHandler; |
41 | use OOUI\IconWidget; |
42 | use RecentChange; |
43 | use Wikimedia\Rdbms\DBQueryTimeoutError; |
44 | use Wikimedia\Rdbms\FakeResultWrapper; |
45 | use Wikimedia\Rdbms\IExpression; |
46 | use Wikimedia\Rdbms\IReadableDatabase; |
47 | use Wikimedia\Rdbms\IResultWrapper; |
48 | use Wikimedia\Rdbms\RawSQLValue; |
49 | use Wikimedia\Timestamp\ConvertibleTimestamp; |
50 | |
51 | /** |
52 | * Special page which uses a ChangesList to show query results. |
53 | * |
54 | * @todo Most of the functions here should be protected instead of public. |
55 | * |
56 | * @ingroup RecentChanges |
57 | * @ingroup SpecialPage |
58 | */ |
59 | abstract class ChangesListSpecialPage extends SpecialPage { |
60 | |
61 | /** @var string */ |
62 | protected $rcSubpage; |
63 | |
64 | /** @var FormOptions */ |
65 | protected $rcOptions; |
66 | |
67 | protected UserIdentityUtils $userIdentityUtils; |
68 | protected TempUserConfig $tempUserConfig; |
69 | |
70 | // Order of both groups and filters is significant; first is top-most priority, |
71 | // descending from there. |
72 | // 'showHideSuffix' is a shortcut to and avoid spelling out |
73 | // details specific to subclasses here. |
74 | /** |
75 | * Definition information for the filters and their groups |
76 | * |
77 | * The value is $groupDefinition, a parameter to the ChangesListFilterGroup constructor. |
78 | * However, priority is dynamically added for the core groups, to ease maintenance. |
79 | * |
80 | * Groups are displayed to the user in the structured UI. However, if necessary, |
81 | * all of the filters in a group can be configured to only display on the |
82 | * unstuctured UI, in which case you don't need a group title. |
83 | * |
84 | * @var array |
85 | */ |
86 | private $filterGroupDefinitions; |
87 | |
88 | /** |
89 | * @var array Same format as filterGroupDefinitions, but for a single group (reviewStatus) |
90 | * that is registered conditionally. |
91 | */ |
92 | private $legacyReviewStatusFilterGroupDefinition; |
93 | |
94 | /** @var array Single filter group registered conditionally */ |
95 | private $reviewStatusFilterGroupDefinition; |
96 | |
97 | /** @var array Single filter group registered conditionally */ |
98 | private $hideCategorizationFilterDefinition; |
99 | |
100 | /** |
101 | * Filter groups, and their contained filters |
102 | * This is an associative array (with group name as key) of ChangesListFilterGroup objects. |
103 | * |
104 | * @var ChangesListFilterGroup[] |
105 | */ |
106 | protected $filterGroups = []; |
107 | |
108 | /** |
109 | * @param string $name |
110 | * @param string $restriction |
111 | * @param UserIdentityUtils $userIdentityUtils |
112 | * @param TempUserConfig $tempUserConfig |
113 | */ |
114 | public function __construct( |
115 | $name, |
116 | $restriction, |
117 | UserIdentityUtils $userIdentityUtils, |
118 | TempUserConfig $tempUserConfig |
119 | ) { |
120 | parent::__construct( $name, $restriction ); |
121 | |
122 | $this->userIdentityUtils = $userIdentityUtils; |
123 | $this->tempUserConfig = $tempUserConfig; |
124 | |
125 | $nonRevisionTypes = [ RC_LOG ]; |
126 | $this->getHookRunner()->onSpecialWatchlistGetNonRevisionTypes( $nonRevisionTypes ); |
127 | |
128 | $this->filterGroupDefinitions = [ |
129 | [ |
130 | 'name' => 'registration', |
131 | 'title' => 'rcfilters-filtergroup-registration', |
132 | 'class' => ChangesListBooleanFilterGroup::class, |
133 | 'filters' => [ |
134 | [ |
135 | 'name' => 'hideliu', |
136 | // rcshowhideliu-show, rcshowhideliu-hide, |
137 | // wlshowhideliu |
138 | 'showHideSuffix' => 'showhideliu', |
139 | 'default' => false, |
140 | 'queryCallable' => function ( string $specialClassName, IContextSource $ctx, |
141 | IReadableDatabase $dbr, &$tables, &$fields, &$conds, &$query_options, &$join_conds |
142 | ) { |
143 | $conds[] = $this->getRegisteredExpr( false, $dbr ); |
144 | $join_conds['recentchanges_actor'] = [ 'JOIN', 'actor_id=rc_actor' ]; |
145 | }, |
146 | 'isReplacedInStructuredUi' => true, |
147 | |
148 | ], |
149 | [ |
150 | 'name' => 'hideanons', |
151 | // rcshowhideanons-show, rcshowhideanons-hide, |
152 | // wlshowhideanons |
153 | 'showHideSuffix' => 'showhideanons', |
154 | 'default' => false, |
155 | 'queryCallable' => function ( string $specialClassName, IContextSource $ctx, |
156 | IReadableDatabase $dbr, &$tables, &$fields, &$conds, &$query_options, &$join_conds |
157 | ) { |
158 | $conds[] = $this->getRegisteredExpr( true, $dbr ); |
159 | $join_conds['recentchanges_actor'] = [ 'JOIN', 'actor_id=rc_actor' ]; |
160 | }, |
161 | 'isReplacedInStructuredUi' => true, |
162 | ] |
163 | ], |
164 | ], |
165 | |
166 | [ |
167 | 'name' => 'userExpLevel', |
168 | 'title' => 'rcfilters-filtergroup-user-experience-level', |
169 | 'class' => ChangesListStringOptionsFilterGroup::class, |
170 | 'isFullCoverage' => true, |
171 | 'filters' => [ |
172 | [ |
173 | 'name' => 'unregistered', |
174 | 'label' => 'rcfilters-filter-user-experience-level-unregistered-label', |
175 | 'description' => $this->tempUserConfig->isKnown() ? |
176 | 'rcfilters-filter-user-experience-level-unregistered-description-temp' : |
177 | 'rcfilters-filter-user-experience-level-unregistered-description', |
178 | 'cssClassSuffix' => 'user-unregistered', |
179 | 'isRowApplicableCallable' => function ( IContextSource $ctx, RecentChange $rc ) { |
180 | return !$this->userIdentityUtils->isNamed( $rc->getPerformerIdentity() ); |
181 | } |
182 | ], |
183 | [ |
184 | 'name' => 'registered', |
185 | 'label' => 'rcfilters-filter-user-experience-level-registered-label', |
186 | 'description' => 'rcfilters-filter-user-experience-level-registered-description', |
187 | 'cssClassSuffix' => 'user-registered', |
188 | 'isRowApplicableCallable' => function ( IContextSource $ctx, RecentChange $rc ) { |
189 | return $this->userIdentityUtils->isNamed( $rc->getPerformerIdentity() ); |
190 | } |
191 | ], |
192 | [ |
193 | 'name' => 'newcomer', |
194 | 'label' => 'rcfilters-filter-user-experience-level-newcomer-label', |
195 | 'description' => 'rcfilters-filter-user-experience-level-newcomer-description', |