Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
39 / 39 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
EditFilterMergedContentHookConstraint | |
100.00% |
39 / 39 |
|
100.00% |
5 / 5 |
12 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
checkConstraint | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
7 | |||
getLegacyStatus | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHookError | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
formatStatusErrors | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 |
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\EditPage\Constraint; |
22 | |
23 | use MediaWiki\Content\Content; |
24 | use MediaWiki\Context\IContextSource; |
25 | use MediaWiki\HookContainer\HookContainer; |
26 | use MediaWiki\HookContainer\HookRunner; |
27 | use MediaWiki\Html\Html; |
28 | use MediaWiki\Language\Language; |
29 | use MediaWiki\Message\Message; |
30 | use MediaWiki\Status\Status; |
31 | use MediaWiki\User\User; |
32 | use StatusValue; |
33 | |
34 | /** |
35 | * Verify `EditFilterMergedContent` hook |
36 | * |
37 | * @since 1.36 |
38 | * @author DannyS712 |
39 | * @internal |
40 | */ |
41 | class EditFilterMergedContentHookConstraint implements IEditConstraint { |
42 | |
43 | private HookRunner $hookRunner; |
44 | private Content $content; |
45 | private IContextSource $hookContext; |
46 | private string $summary; |
47 | private bool $minorEdit; |
48 | private Language $language; |
49 | private User $hookUser; |
50 | private Status $status; |
51 | private string $hookError = ''; |
52 | |
53 | /** |
54 | * @param HookContainer $hookContainer |
55 | * @param Content $content |
56 | * @param IContextSource $hookContext NOTE: This should only be passed to the hook. |
57 | * @param string $summary |
58 | * @param bool $minorEdit |
59 | * @param Language $language |
60 | * @param User $hookUser NOTE: This should only be passed to the hook. |
61 | */ |
62 | public function __construct( |
63 | HookContainer $hookContainer, |
64 | Content $content, |
65 | IContextSource $hookContext, |
66 | string $summary, |
67 | bool $minorEdit, |
68 | Language $language, |
69 | User $hookUser |
70 | ) { |
71 | $this->hookRunner = new HookRunner( $hookContainer ); |
72 | $this->content = $content; |
73 | $this->hookContext = $hookContext; |
74 | $this->summary = $summary; |
75 | $this->minorEdit = $minorEdit; |
76 | $this->language = $language; |
77 | $this->hookUser = $hookUser; |
78 | $this->status = Status::newGood(); |
79 | } |
80 | |
81 | public function checkConstraint(): string { |
82 | $hookResult = $this->hookRunner->onEditFilterMergedContent( |
83 | $this->hookContext, |
84 | $this->content, |
85 | $this->status, |
86 | $this->summary, |
87 | $this->hookUser, |
88 | $this->minorEdit |
89 | ); |
90 | if ( !$hookResult ) { |
91 | // Error messages etc. could be handled within the hook... |
92 | if ( $this->status->isGood() ) { |
93 | $this->status->fatal( 'hookaborted' ); |
94 | // Not setting $this->hookError here is a hack to allow the hook |
95 | // to cause a return to the edit page without $this->hookError |
96 | // being set. This is used by ConfirmEdit to display a captcha |
97 | // without any error message cruft. |
98 | } else { |
99 | if ( !$this->status->getMessages() ) { |
100 | // Provide a fallback error message if none was set |
101 | $this->status->fatal( 'hookaborted' ); |
102 | } |
103 | $this->hookError = $this->formatStatusErrors( $this->status ); |
104 | } |
105 | // Use the existing $status->value if the hook set it |
106 | if ( !$this->status->value ) { |
107 | // T273354: Should be AS_HOOK_ERROR_EXPECTED to display error message |
108 | $this->status->value = self::AS_HOOK_ERROR_EXPECTED; |
109 | } |
110 | return self::CONSTRAINT_FAILED; |
111 | } |
112 | |
113 | if ( !$this->status->isOK() ) { |
114 | // ...or the hook could be expecting us to produce an error |
115 | // FIXME this sucks, we should just use the Status object throughout |
116 | if ( !$this->status->getMessages() ) { |
117 | // Provide a fallback error message if none was set |
118 | $this->status->fatal( 'hookaborted' ); |
119 | } |
120 | $this->hookError = $this->formatStatusErrors( $this->status ); |
121 | $this->status->value = self::AS_HOOK_ERROR_EXPECTED; |
122 | return self::CONSTRAINT_FAILED; |
123 | } |
124 | |
125 | return self::CONSTRAINT_PASSED; |
126 | } |
127 | |
128 | public function getLegacyStatus(): StatusValue { |
129 | // This returns a Status instead of a StatusValue since a Status object is |
130 | // used in the hook |
131 | return $this->status; |
132 | } |
133 | |
134 | /** |
135 | * TODO this is really ugly. The constraint shouldn't know that the status |
136 | * will be used as wikitext, which is what the hookError represents, rather |
137 | * than just the error code. This needs a big refactor to remove the hook |
138 | * error string and just rely on the status object entirely. |
139 | * |
140 | * @internal |
141 | * @return string |
142 | */ |
143 | public function getHookError(): string { |
144 | return $this->hookError; |
145 | } |
146 | |
147 | /** |
148 | * Wrap status errors in error boxes for increased visibility. |
149 | * @param Status $status |
150 | * @return string |
151 | */ |
152 | private function formatStatusErrors( Status $status ): string { |
153 | $ret = ''; |
154 | foreach ( $status->getMessages() as $msg ) { |
155 | $msg = Message::newFromSpecifier( $msg ); |
156 | $ret .= Html::errorBox( "\n" . $msg->inLanguage( $this->language )->plain() . "\n" ); |
157 | } |
158 | return $ret; |
159 | } |
160 | |
161 | } |