Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
7.94% |
5 / 63 |
|
25.00% |
1 / 4 |
CRAP | |
0.00% |
0 / 1 |
EditBoxBuilder | |
7.94% |
5 / 63 |
|
25.00% |
1 / 4 |
72.20 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
buildEditBox | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
30 | |||
getSuggestionsDropdown | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
6 | |||
getEditorControls | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getEditBox | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\AbuseFilter\EditBox; |
4 | |
5 | use MediaWiki\Extension\AbuseFilter\AbuseFilterPermissionManager; |
6 | use MediaWiki\Extension\AbuseFilter\KeywordsManager; |
7 | use MediaWiki\Html\Html; |
8 | use MediaWiki\Output\OutputPage; |
9 | use MediaWiki\Permissions\Authority; |
10 | use MessageLocalizer; |
11 | use OOUI\ButtonWidget; |
12 | use OOUI\DropdownInputWidget; |
13 | use OOUI\FieldLayout; |
14 | use OOUI\FieldsetLayout; |
15 | use OOUI\Widget; |
16 | |
17 | /** |
18 | * Base class for classes responsible for building filter edit boxes |
19 | */ |
20 | abstract class EditBoxBuilder { |
21 | /** @var AbuseFilterPermissionManager */ |
22 | protected $afPermManager; |
23 | |
24 | /** @var KeywordsManager */ |
25 | protected $keywordsManager; |
26 | |
27 | /** @var MessageLocalizer */ |
28 | protected $localizer; |
29 | |
30 | /** @var Authority */ |
31 | protected $authority; |
32 | |
33 | /** @var OutputPage */ |
34 | protected $output; |
35 | |
36 | /** |
37 | * @param AbuseFilterPermissionManager $afPermManager |
38 | * @param KeywordsManager $keywordsManager |
39 | * @param MessageLocalizer $messageLocalizer |
40 | * @param Authority $authority |
41 | * @param OutputPage $output |
42 | */ |
43 | public function __construct( |
44 | AbuseFilterPermissionManager $afPermManager, |
45 | KeywordsManager $keywordsManager, |
46 | MessageLocalizer $messageLocalizer, |
47 | Authority $authority, |
48 | OutputPage $output |
49 | ) { |
50 | $this->afPermManager = $afPermManager; |
51 | $this->keywordsManager = $keywordsManager; |
52 | $this->localizer = $messageLocalizer; |
53 | $this->authority = $authority; |
54 | $this->output = $output; |
55 | } |
56 | |
57 | /** |
58 | * @param string $rules |
59 | * @param bool $addResultDiv |
60 | * @param bool $externalForm |
61 | * @param bool $needsModifyRights |
62 | * @param-taint $rules none |
63 | * @return string |
64 | */ |
65 | public function buildEditBox( |
66 | string $rules, |
67 | bool $addResultDiv = true, |
68 | bool $externalForm = false, |
69 | bool $needsModifyRights = true |
70 | ): string { |
71 | $this->output->addModules( 'ext.abuseFilter.edit' ); |
72 | $this->output->enableOOUI(); |
73 | |
74 | $isUserAllowed = $needsModifyRights ? |
75 | $this->afPermManager->canEdit( $this->authority ) : |
76 | $this->afPermManager->canUseTestTools( $this->authority ); |
77 | if ( !$isUserAllowed ) { |
78 | $addResultDiv = false; |
79 | } |
80 | |
81 | $output = $this->getEditBox( $rules, $isUserAllowed, $externalForm ); |
82 | |
83 | if ( $isUserAllowed ) { |
84 | $dropdown = $this->getSuggestionsDropdown(); |
85 | |
86 | $formElements = [ |
87 | new FieldLayout( $dropdown ), |
88 | new FieldLayout( $this->getEditorControls() ) |
89 | ]; |
90 | |
91 | $fieldSet = new FieldsetLayout( [ |
92 | 'items' => $formElements, |
93 | 'classes' => [ 'mw-abusefilter-edit-buttons', 'mw-abusefilter-javascript-tools' ] |
94 | ] ); |
95 | |
96 | $output .= $fieldSet; |
97 | } |
98 | |
99 | if ( $addResultDiv ) { |
100 | $output .= Html::element( |
101 | 'div', |
102 | [ 'id' => 'mw-abusefilter-syntaxresult', 'style' => 'display: none;' ] |
103 | ); |
104 | } |
105 | |
106 | return $output; |
107 | } |
108 | |
109 | private function getSuggestionsDropdown(): DropdownInputWidget { |
110 | $rawDropdown = $this->keywordsManager->getBuilderValues(); |
111 | |
112 | // The array needs to be rearranged to be understood by OOUI. It comes with the format |
113 | // [ group-msg-key => [ text-to-add => text-msg-key ] ] and we need it as |
114 | // [ group-msg => [ text-msg => text-to-add ] ] |
115 | // Also, the 'other' element must be the first one. |
116 | $dropdownOptions = [ $this->localizer->msg( 'abusefilter-edit-builder-select' )->text() => 'other' ]; |
117 | foreach ( $rawDropdown as $group => $values ) { |
118 | // Give grep a chance to find the usages: |
119 | // abusefilter-edit-builder-group-op-arithmetic |
120 | // abusefilter-edit-builder-group-op-comparison |
121 | // abusefilter-edit-builder-group-op-bool |
122 | // abusefilter-edit-builder-group-misc |
123 | // abusefilter-edit-builder-group-funcs |
124 | // abusefilter-edit-builder-group-vars |
125 | $localisedGroup = $this->localizer->msg( "abusefilter-edit-builder-group-$group" )->text(); |
126 | $dropdownOptions[ $localisedGroup ] = array_flip( $values ); |
127 | $newKeys = array_map( |
128 | function ( $key ) use ( $group, $dropdownOptions, $localisedGroup ) { |
129 | // Force all operators and functions to be always shown as left to right text |
130 | // with the help of control characters: |
131 | // * 202A is LEFT-TO-RIGHT EMBEDDING (LRE) |
132 | // * 202C is POP DIRECTIONAL FORMATTING (PDF) |
133 | // This has to be done with control characters because |
134 | // markup cannot be used within <option> elements. |
135 | $operatorExample = "\u{202A}" . |
136 | $dropdownOptions[ $localisedGroup ][ $key ] . |
137 | "\u{202C}"; |
138 | return $this->localizer->msg( |
139 | "abusefilter-edit-builder-$group-$key", |
140 | $operatorExample |
141 | )->text(); |
142 | }, |
143 | array_keys( $dropdownOptions[ $localisedGroup ] ) |
144 | ); |
145 | $dropdownOptions[ $localisedGroup ] = array_combine( |
146 | $newKeys, |
147 | $dropdownOptions[ $localisedGroup ] |
148 | ); |
149 | } |
150 | |
151 | $dropdownList = Html::listDropdownOptionsOoui( $dropdownOptions ); |
152 | return new DropdownInputWidget( [ |
153 | 'name' => 'wpFilterBuilder', |
154 | 'inputId' => 'wpFilterBuilder', |
155 | 'options' => $dropdownList |
156 | ] ); |
157 | } |
158 | |
159 | /** |
160 | * Get an additional widget that "controls" the editor, and is placed next to it |
161 | * Precondition: the user has full rights. |
162 | */ |
163 | protected function getEditorControls(): Widget { |
164 | return new ButtonWidget( |
165 | [ |
166 | 'label' => $this->localizer->msg( 'abusefilter-edit-check' )->text(), |
167 | 'id' => 'mw-abusefilter-syntaxcheck' |
168 | ] |
169 | ); |
170 | } |
171 | |
172 | /** |
173 | * Generate the HTML for the actual edit box |
174 | * |
175 | * @param string $rules |
176 | * @param bool $isUserAllowed |
177 | * @param bool $externalForm |
178 | * @return string |
179 | */ |
180 | abstract protected function getEditBox( string $rules, bool $isUserAllowed, bool $externalForm ): string; |
181 | |
182 | } |