Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 114 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
FileDeleteAction | |
0.00% |
0 / 114 |
|
0.00% |
0 / 10 |
812 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
getPageTitle | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
tempDelete | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
tempExecute | |
0.00% |
0 / 51 |
|
0.00% |
0 / 1 |
156 | |||
showFormWarnings | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
showConfirm | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
prepareMessage | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
6 | |||
getFormAction | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
checkCanExecute | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getFormMessages | |
0.00% |
0 / 11 |
|
0.00% |
0 / 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 |
14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
16 | * |
17 | * @file |
18 | * @ingroup Actions |
19 | */ |
20 | |
21 | namespace MediaWiki\Actions; |
22 | |
23 | use Article; |
24 | use DeleteAction; |
25 | use ErrorPageError; |
26 | use File; |
27 | use LocalFile; |
28 | use MediaWiki\Context\IContextSource; |
29 | use MediaWiki\MainConfigNames; |
30 | use MediaWiki\MediaWikiServices; |
31 | use MediaWiki\Page\File\FileDeleteForm; |
32 | use MediaWiki\Permissions\PermissionStatus; |
33 | use MediaWiki\Title\Title; |
34 | use MediaWiki\User\User; |
35 | use OldLocalFile; |
36 | use PermissionsError; |
37 | |
38 | /** |
39 | * Handle file deletion |
40 | * |
41 | * @ingroup Actions |
42 | */ |
43 | class FileDeleteAction extends DeleteAction { |
44 | /** @var File */ |
45 | private $file; |
46 | /** @var string Descriptor for the old version of the image, if applicable */ |
47 | private $oldImage; |
48 | /** @var OldLocalFile|null Corresponding to oldImage, if applicable */ |
49 | private $oldFile; |
50 | |
51 | /** |
52 | * @inheritDoc |
53 | */ |
54 | public function __construct( Article $article, IContextSource $context ) { |
55 | parent::__construct( $article, $context ); |
56 | $services = MediaWikiServices::getInstance(); |
57 | $this->file = $this->getArticle()->getFile(); |
58 | $this->oldImage = $this->getRequest()->getText( 'oldimage', '' ); |
59 | if ( $this->oldImage !== '' ) { |
60 | $this->oldFile = $services->getRepoGroup()->getLocalRepo()->newFromArchiveName( |
61 | $this->getTitle(), |
62 | $this->oldImage |
63 | ); |
64 | } |
65 | } |
66 | |
67 | protected function getPageTitle() { |
68 | $title = $this->getTitle(); |
69 | return $this->msg( 'filedelete' )->plaintextParams( $title->getText() ); |
70 | } |
71 | |
72 | protected function tempDelete() { |
73 | $file = $this->file; |
74 | /** @var LocalFile $file */'@phan-var LocalFile $file'; |
75 | $this->tempExecute( $file ); |
76 | } |
77 | |
78 | private function tempExecute( LocalFile $file ): void { |
79 | $context = $this->getContext(); |
80 | $title = $this->getTitle(); |
81 | $article = $this->getArticle(); |
82 | $outputPage = $context->getOutput(); |
83 | $request = $context->getRequest(); |
84 | |
85 | $checkFile = $this->oldFile ?: $file; |
86 | if ( !$checkFile->exists() || !$checkFile->isLocal() ) { |
87 | $outputPage->addHTML( $this->prepareMessage( 'filedelete-nofile' ) ); |
88 | $outputPage->addReturnTo( $title ); |
89 | return; |
90 | } |
91 | |
92 | // Perform the deletion if appropriate |
93 | $token = $request->getVal( 'wpEditToken' ); |
94 | if ( |
95 | !$request->wasPosted() || |
96 | !$context->getUser()->matchEditToken( $token, [ 'delete', $title->getPrefixedText() ] ) |
97 | ) { |
98 | $this->showConfirm(); |
99 | return; |
100 | } |
101 | |
102 | // Check to make sure the page has not been edited while the deletion was being confirmed |
103 | if ( $article->getRevIdFetched() !== $request->getIntOrNull( 'wpConfirmationRevId' ) ) { |
104 | $this->showEditedWarning(); |
105 | $this->showConfirm(); |
106 | return; |
107 | } |
108 | |
109 | $permissionStatus = PermissionStatus::newEmpty(); |
110 | if ( !$context->getAuthority()->authorizeWrite( |
111 | 'delete', $title, $permissionStatus |
112 | ) ) { |
113 | throw new PermissionsError( 'delete', $permissionStatus ); |
114 | } |
115 | |
116 | $reason = $this->getDeleteReason(); |
117 | |
118 | # Flag to hide all contents of the archived revisions |
119 | $suppress = $request->getCheck( 'wpSuppress' ) && |
120 | $context->getAuthority()->isAllowed( 'suppressrevision' ); |
121 | |
122 | $status = FileDeleteForm::doDelete( |
123 | $title, |
124 | $file, |
125 | $this->oldImage, |
126 | $reason, |
127 | $suppress, |
128 | $context->getUser(), |
129 | [], |
130 | $request->getCheck( 'wpDeleteTalk' ) |
131 | ); |
132 | |
133 | if ( !$status->isGood() ) { |
134 | $outputPage->wrapWikiTextAsInterface( |
135 | 'error', |
136 | $status->getWikiText( 'filedeleteerror-short', 'filedeleteerror-long' ) |
137 | ); |
138 | } |
139 | if ( $status->isOK() ) { |
140 | $outputPage->setPageTitleMsg( $context->msg( 'actioncomplete' ) ); |
141 | $outputPage->addHTML( $this->prepareMessage( 'filedelete-success' ) ); |
142 | // Return to the main page if we just deleted all versions of the |
143 | // file, otherwise go back to the description page |
144 | $outputPage->addReturnTo( $this->oldImage ? $title : Title::newMainPage() ); |
145 | |
146 | $this->watchlistManager->setWatch( |
147 | $request->getCheck( 'wpWatch' ), |
148 | $context->getAuthority(), |
149 | $title |
150 | ); |
151 | } |
152 | } |
153 | |
154 | protected function showFormWarnings(): void { |
155 | $this->getOutput()->addHTML( $this->prepareMessage( 'filedelete-intro' ) ); |
156 | $this->showSubpagesWarnings(); |
157 | } |
158 | |
159 | /** |
160 | * Show the confirmation form |
161 | */ |
162 | private function showConfirm() { |
163 | $this->prepareOutputForForm(); |
164 | $context = $this->getContext(); |
165 | $article = $this->getArticle(); |
166 | |
167 | // oldid is set to the revision id of the page when the page was displayed. |
168 | // Check to make sure the page has not been edited between loading the page |
169 | // and clicking the delete link |
170 | $oldid = $context->getRequest()->getIntOrNull( 'oldid' ); |
171 | if ( $oldid !== null && $oldid !== $article->getRevIdFetched() ) { |
172 | $this->showEditedWarning(); |
173 | } |
174 | |
175 | $this->showFormWarnings(); |
176 | $form = $this->getForm(); |
177 | if ( $form->show() ) { |
178 | $this->onSuccess(); |
179 | } |
180 | $this->showEditReasonsLinks(); |
181 | $this->showLogEntries(); |
182 | } |
183 | |
184 | /** |
185 | * Prepare a message referring to the file being deleted, |
186 | * showing an appropriate message depending upon whether |
187 | * it's a current file or an old version |
188 | * |
189 | * @param string $message Message base |
190 | * @return string |
191 | */ |
192 | private function prepareMessage( string $message ) { |
193 | if ( $this->oldFile ) { |
194 | $lang = $this->getContext()->getLanguage(); |
195 | # Message keys used: |
196 | # 'filedelete-intro-old', 'filedelete-nofile-old', 'filedelete-success-old' |
197 | return $this->getContext()->msg( |
198 | "{$message}-old", |
199 | wfEscapeWikiText( $this->getTitle()->getText() ), |
200 | $lang->date( $this->oldFile->getTimestamp(), true ), |
201 | $lang->time( $this->oldFile->getTimestamp(), true ), |
202 | (string)MediaWikiServices::getInstance()->getUrlUtils()->expand( |
203 | $this->file->getArchiveUrl( $this->oldImage ), |
204 | PROTO_CURRENT |
205 | ) |
206 | )->parseAsBlock(); |
207 | } else { |
208 | return $this->getContext()->msg( |
209 | $message, |
210 | wfEscapeWikiText( $this->getTitle()->getText() ) |
211 | )->parseAsBlock(); |
212 | } |
213 | } |
214 | |
215 | /** |
216 | * @return string |
217 | */ |
218 | protected function getFormAction(): string { |
219 | $q = []; |
220 | $q['action'] = 'delete'; |
221 | |
222 | if ( $this->oldImage ) { |
223 | $q['oldimage'] = $this->oldImage; |
224 | } |
225 | |
226 | return $this->getTitle()->getLocalURL( $q ); |
227 | } |
228 | |
229 | protected function checkCanExecute( User $user ) { |
230 | parent::checkCanExecute( $user ); |
231 | |
232 | if ( $this->getContext()->getConfig()->get( MainConfigNames::UploadMaintenance ) ) { |
233 | throw new ErrorPageError( 'filedelete-maintenance-title', 'filedelete-maintenance' ); |
234 | } |
235 | } |
236 | |
237 | /** |
238 | * TODO Do we need all these messages to be different? |
239 | * @return string[] |
240 | */ |
241 | protected function getFormMessages(): array { |
242 | return [ |
243 | self::MSG_REASON_DROPDOWN => 'filedelete-reason-dropdown', |
244 | self::MSG_REASON_DROPDOWN_SUPPRESS => 'filedelete-reason-dropdown-suppress', |
245 | self::MSG_REASON_DROPDOWN_OTHER => 'filedelete-reason-otherlist', |
246 | self::MSG_COMMENT => 'filedelete-comment', |
247 | self::MSG_REASON_OTHER => 'filedelete-otherreason', |
248 | self::MSG_SUBMIT => 'filedelete-submit', |
249 | self::MSG_LEGEND => 'filedelete-legend', |
250 | self::MSG_EDIT_REASONS => 'filedelete-edit-reasonlist', |
251 | self::MSG_EDIT_REASONS_SUPPRESS => 'filedelete-edit-reasonlist-suppress', |
252 | ]; |
253 | } |
254 | } |