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