92 $repo = $this->file->getRepo();
93 if ( !$this->all && !$this->ids ) {
95 return $repo->newGood();
98 $lockOwnsTrx = $this->file->lock();
100 $dbw = $this->file->repo->getMasterDB();
102 $commentStore = MediaWikiServices::getInstance()->getCommentStore();
103 $actorMigration = ActorMigration::newMigration();
105 $status = $this->file->repo->newGood();
107 $exists = (bool)$dbw->selectField(
'image',
'1',
108 [
'img_name' => $this->file->getName() ],
113 $lockOwnsTrx ? [] : [
'LOCK IN SHARE MODE' ]
118 $conditions = [
'fa_name' => $this->file->getName() ];
125 $result = $dbw->select(
126 $arFileQuery[
'tables'],
127 $arFileQuery[
'fields'],
130 [
'ORDER BY' =>
'fa_timestamp DESC' ],
131 $arFileQuery[
'joins']
137 $insertCurrent =
false;
142 foreach ( $result as $row ) {
143 $idsPresent[] = $row->fa_id;
145 if ( $row->fa_name != $this->file->getName() ) {
146 $status->error(
'undelete-filename-mismatch',
$wgLang->timeanddate( $row->fa_timestamp ) );
147 $status->failCount++;
151 if ( $row->fa_storage_key ==
'' ) {
153 $status->error(
'undelete-bad-store-key',
$wgLang->timeanddate( $row->fa_timestamp ) );
154 $status->failCount++;
158 $deletedRel = $repo->getDeletedHashPath( $row->fa_storage_key ) .
159 $row->fa_storage_key;
160 $deletedUrl = $repo->getVirtualUrl() .
'/deleted/' . $deletedRel;
162 if ( isset( $row->fa_sha1 ) ) {
163 $sha1 = $row->fa_sha1;
170 if ( strlen( $sha1 ) == 32 && $sha1[0] ==
'0' ) {
171 $sha1 = substr( $sha1, 1 );
174 if ( is_null( $row->fa_major_mime ) || $row->fa_major_mime ==
'unknown'
175 || is_null( $row->fa_minor_mime ) || $row->fa_minor_mime ==
'unknown'
176 || is_null( $row->fa_media_type ) || $row->fa_media_type ==
'UNKNOWN'
177 || is_null( $row->fa_metadata )
181 $props = RepoGroup::singleton()->getFileProps( $deletedUrl );
184 'minor_mime' => $row->fa_minor_mime,
185 'major_mime' => $row->fa_major_mime,
186 'media_type' => $row->fa_media_type,
187 'metadata' => $row->fa_metadata
191 $comment = $commentStore->getComment(
'fa_description', $row );
192 $user = User::newFromAnyId( $row->fa_user, $row->fa_user_text, $row->fa_actor );
193 if ( $first && !$exists ) {
195 $destRel = $this->file->getRel();
196 $commentFields = $commentStore->insert( $dbw,
'img_description', $comment );
197 $actorFields = $actorMigration->getInsertValues( $dbw,
'img_user', $user );
199 'img_name' => $row->fa_name,
200 'img_size' => $row->fa_size,
201 'img_width' => $row->fa_width,
202 'img_height' => $row->fa_height,
203 'img_metadata' => $props[
'metadata'],
204 'img_bits' => $row->fa_bits,
205 'img_media_type' => $props[
'media_type'],
206 'img_major_mime' => $props[
'major_mime'],
207 'img_minor_mime' => $props[
'minor_mime'],
208 'img_timestamp' => $row->fa_timestamp,
210 ] + $commentFields + $actorFields;
213 if ( !$this->unsuppress && $row->fa_deleted ) {
214 $status->fatal(
'undeleterevdel' );
215 $this->file->unlock();
219 $archiveName = $row->fa_archive_name;
221 if ( $archiveName ==
'' ) {
225 $timestamp =
wfTimestamp( TS_UNIX, $row->fa_deleted_timestamp );
228 $archiveName =
wfTimestamp( TS_MW, $timestamp ) .
'!' . $row->fa_name;
230 }
while ( isset( $archiveNames[$archiveName] ) );
233 $archiveNames[$archiveName] =
true;
234 $destRel = $this->file->getArchiveRel( $archiveName );
236 'oi_name' => $row->fa_name,
237 'oi_archive_name' => $archiveName,
238 'oi_size' => $row->fa_size,
239 'oi_width' => $row->fa_width,
240 'oi_height' => $row->fa_height,
241 'oi_bits' => $row->fa_bits,
242 'oi_timestamp' => $row->fa_timestamp,
243 'oi_metadata' => $props[
'metadata'],
244 'oi_media_type' => $props[
'media_type'],
245 'oi_major_mime' => $props[
'major_mime'],
246 'oi_minor_mime' => $props[
'minor_mime'],
247 'oi_deleted' => $this->unsuppress ? 0 : $row->fa_deleted,
249 ] + $commentStore->insert( $dbw,
'oi_description', $comment )
250 + $actorMigration->getInsertValues( $dbw,
'oi_user', $user );
253 $deleteIds[] = $row->fa_id;
255 if ( !$this->unsuppress && $row->fa_deleted & File::DELETED_FILE ) {
257 $status->successCount++;
259 $storeBatch[] = [ $deletedUrl,
'public', $destRel ];
260 $this->cleanupBatch[] = $row->fa_storage_key;
269 $missingIds = array_diff( $this->ids, $idsPresent );
271 foreach ( $missingIds as $id ) {
272 $status->error(
'undelete-missing-filearchive', $id );
275 if ( !$repo->hasSha1Storage() ) {
278 if ( !$checkStatus->isGood() ) {
279 $status->merge( $checkStatus );
282 $storeBatch = $checkStatus->value;
287 $status->merge( $storeStatus );
289 if ( !$status->isGood() ) {
293 $status->setOK(
false );
294 $this->file->unlock();
306 if ( $insertCurrent ) {
307 $dbw->insert(
'image', $insertCurrent, __METHOD__ );
310 if ( $insertBatch ) {
311 $dbw->insert(
'oldimage', $insertBatch, __METHOD__ );
315 $dbw->delete(
'filearchive',
316 [
'fa_id' => $deleteIds ],
321 if ( $status->successCount > 0 || !$storeBatch || $repo->hasSha1Storage() ) {
323 wfDebug( __METHOD__ .
" restored {$status->successCount} items, creating a new current\n" );
325 DeferredUpdates::addUpdate( SiteStatsUpdate::factory( [
'images' => 1 ] ) );
327 $this->file->purgeEverything();
329 wfDebug( __METHOD__ .
" restored {$status->successCount} as archived versions\n" );
330 $this->file->purgeDescription();
334 $this->file->unlock();