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
21 * @author Rob Church <robchur@gmail.com>
25 namespace MediaWiki\Page\File
;
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
;
37 * File deletion user interface
41 class FileDeleteForm
{
43 * Really delete the file
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
56 public static function doDelete(
64 bool $deleteTalk = false
66 $services = MediaWikiServices
::getInstance();
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;
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 );
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;
121 $deletedID = $deletePage->getSuccessfulDeletionsIDs()[DeletePage
::PAGE_BASE
];
122 if ( $deletedID !== null ) {
123 $status->value
= $deletedID;
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 );
139 $status->value
= $logid;
142 $dbw->endAtomic( __METHOD__
);
144 // Page deleted but file still there? rollback page delete
145 $dbw->cancelAtomic( __METHOD__
);
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 );
163 * Is the provided `oldimage` value valid?
165 * @param string $oldimage
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' );