Thanks link and other links should be styled consistently with other links
[mediawiki.git] / includes / page / File / FileDeleteForm.php
blob9f94891b419ffcea1dbf3a9b51446e855d57b8df
1 <?php
2 /**
3 * File deletion utilities.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
20 * @file
21 * @author Rob Church <robchur@gmail.com>
22 * @ingroup Media
25 namespace MediaWiki\Page\File;
27 use LocalFile;
28 use ManualLogEntry;
29 use MediaWiki\HookContainer\HookRunner;
30 use MediaWiki\MediaWikiServices;
31 use MediaWiki\Page\DeletePage;
32 use MediaWiki\Status\Status;
33 use MediaWiki\Title\Title;
34 use MediaWiki\User\UserIdentity;
36 /**
37 * File deletion user interface
39 * @ingroup Media
41 class FileDeleteForm {
42 /**
43 * Really delete the file
45 * @param Title $title
46 * @param LocalFile $file
47 * @param string|null $oldimage Archive name
48 * @param string $reason Reason of the deletion
49 * @param bool $suppress Whether to mark all deleted versions as restricted
50 * @param UserIdentity $user
51 * @param string[] $tags Tags to apply to the deletion action
52 * @param bool $deleteTalk
53 * @return Status The value can be an integer with the log ID of the deletion, or false in case of
54 * scheduled deletion.
56 public static function doDelete(
57 Title $title,
58 LocalFile $file,
59 ?string $oldimage,
60 $reason,
61 $suppress,
62 UserIdentity $user,
63 $tags = [],
64 bool $deleteTalk = false
65 ): Status {
66 $services = MediaWikiServices::getInstance();
67 if ( $oldimage ) {
68 $page = null;
69 $status = $file->deleteOldFile( $oldimage, $reason, $user, $suppress );
70 if ( $status->isOK() ) {
71 // Need to do a log item
72 $logComment = wfMessage( 'deletedrevision', $oldimage )->inContentLanguage()->text();
73 if ( trim( $reason ) !== '' ) {
74 $logComment .= wfMessage( 'colon-separator' )
75 ->inContentLanguage()->text() . $reason;
78 $logtype = $suppress ? 'suppress' : 'delete';
80 $logEntry = new ManualLogEntry( $logtype, 'delete' );
81 $logEntry->setPerformer( $user );
82 $logEntry->setTarget( $title );
83 $logEntry->setComment( $logComment );
84 $logEntry->addTags( $tags );
85 $logid = $logEntry->insert();
86 $logEntry->publish( $logid );
88 $status->value = $logid;
90 } else {
91 $status = Status::newFatal( 'cannotdelete',
92 wfEscapeWikiText( $title->getPrefixedText() )
94 $page = $services->getWikiPageFactory()->newFromTitle( $title );
95 '@phan-var \WikiFilePage $page';
96 $deleter = $services->getUserFactory()->newFromUserIdentity( $user );
97 $deletePage = $services->getDeletePageFactory()->newDeletePage( $page, $deleter );
98 if ( $deleteTalk ) {
99 $checkStatus = $deletePage->canProbablyDeleteAssociatedTalk();
100 if ( !$checkStatus->isGood() ) {
101 return Status::wrap( $checkStatus );
103 $deletePage->setDeleteAssociatedTalk( true );
105 $dbw = $services->getConnectionProvider()->getPrimaryDatabase();
106 $dbw->startAtomic( __METHOD__, $dbw::ATOMIC_CANCELABLE );
107 // delete the associated article first
108 $deleteStatus = $deletePage
109 ->setSuppress( $suppress )
110 ->setTags( $tags ?: [] )
111 ->deleteIfAllowed( $reason );
113 // DeletePage returns a non-fatal error status if the page
114 // or revision is missing, so check for isOK() rather than isGood().
115 if ( $deleteStatus->isOK() ) {
116 $status = $file->deleteFile( $reason, $user, $suppress );
117 if ( $status->isOK() ) {
118 if ( $deletePage->deletionsWereScheduled()[DeletePage::PAGE_BASE] ) {
119 $status->value = false;
120 } else {
121 $deletedID = $deletePage->getSuccessfulDeletionsIDs()[DeletePage::PAGE_BASE];
122 if ( $deletedID !== null ) {
123 $status->value = $deletedID;
124 } else {
125 // Means that the page/revision didn't exist, so create a log entry here.
126 $logtype = $suppress ? 'suppress' : 'delete';
127 $logEntry = new ManualLogEntry( $logtype, 'delete' );
128 $logEntry->setPerformer( $user );
129 $logEntry->setTarget( $title );
130 $logEntry->setComment( $reason );
131 $logEntry->addTags( $tags );
132 $logid = $logEntry->insert();
133 $dbw->onTransactionPreCommitOrIdle(
134 static function () use ( $logEntry, $logid ) {
135 $logEntry->publish( $logid );
137 __METHOD__
139 $status->value = $logid;
142 $dbw->endAtomic( __METHOD__ );
143 } else {
144 // Page deleted but file still there? rollback page delete
145 $dbw->cancelAtomic( __METHOD__ );
147 } else {
148 $dbw->endAtomic( __METHOD__ );
152 if ( $status->isOK() ) {
153 $legacyUser = $services->getUserFactory()
154 ->newFromUserIdentity( $user );
155 ( new HookRunner( $services->getHookContainer() ) )
156 ->onFileDeleteComplete( $file, $oldimage, $page, $legacyUser, $reason );
159 return $status;
163 * Is the provided `oldimage` value valid?
165 * @param string $oldimage
166 * @return bool
168 public static function isValidOldSpec( $oldimage ) {
169 return strlen( $oldimage ) >= 16
170 && strpos( $oldimage, '/' ) === false
171 && strpos( $oldimage, '\\' ) === false;
175 /** @deprecated class alias since 1.40 */
176 class_alias( FileDeleteForm::class, 'FileDeleteForm' );