Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 125 |
|
0.00% |
0 / 20 |
CRAP | |
0.00% |
0 / 1 |
| RevDelFileItem | |
0.00% |
0 / 124 |
|
0.00% |
0 / 20 |
1122 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| initFile | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| getIdField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getTimestampField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getAuthorIdField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getAuthorNameField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getAuthorActorField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getId | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| canView | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| canViewContent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getBits | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setBits | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
20 | |||
| isDeleted | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getLink | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
| getUserTools | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
| getComment | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
| getHTML | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
| getApiData | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
30 | |||
| lock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| unlock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * @license GPL-2.0-or-later |
| 4 | * @file |
| 5 | * @ingroup RevisionDelete |
| 6 | */ |
| 7 | |
| 8 | namespace MediaWiki\RevisionDelete; |
| 9 | |
| 10 | use MediaWiki\Api\ApiResult; |
| 11 | use MediaWiki\FileRepo\File\File; |
| 12 | use MediaWiki\FileRepo\File\OldLocalFile; |
| 13 | use MediaWiki\Html\Html; |
| 14 | use MediaWiki\Linker\Linker; |
| 15 | use MediaWiki\MediaWikiServices; |
| 16 | use MediaWiki\RevisionList\RevisionListBase; |
| 17 | use MediaWiki\SpecialPage\SpecialPage; |
| 18 | use Wikimedia\Rdbms\IConnectionProvider; |
| 19 | use Wikimedia\Timestamp\TimestampFormat as TS; |
| 20 | |
| 21 | /** |
| 22 | * Item class for an oldimage table row |
| 23 | */ |
| 24 | class RevDelFileItem extends RevDelItem { |
| 25 | /** @var RevDelFileList */ |
| 26 | protected $list; |
| 27 | /** @var OldLocalFile */ |
| 28 | protected $file; |
| 29 | protected IConnectionProvider $dbProvider; |
| 30 | |
| 31 | /** @inheritDoc */ |
| 32 | public function __construct( RevisionListBase $list, $row ) { |
| 33 | parent::__construct( $list, $row ); |
| 34 | $this->file = static::initFile( $list, $row ); |
| 35 | $this->dbProvider = MediaWikiServices::getInstance()->getConnectionProvider(); |
| 36 | } |
| 37 | |
| 38 | /** |
| 39 | * Create file object from $row sourced from $list |
| 40 | * |
| 41 | * @param RevisionListBase $list |
| 42 | * @param mixed $row |
| 43 | * @return mixed |
| 44 | */ |
| 45 | protected static function initFile( $list, $row ) { |
| 46 | return MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo() |
| 47 | ->newFileFromRow( $row ); |
| 48 | } |
| 49 | |
| 50 | /** @inheritDoc */ |
| 51 | public function getIdField() { |
| 52 | return 'oi_archive_name'; |
| 53 | } |
| 54 | |
| 55 | /** @inheritDoc */ |
| 56 | public function getTimestampField() { |
| 57 | return 'oi_timestamp'; |
| 58 | } |
| 59 | |
| 60 | /** @inheritDoc */ |
| 61 | public function getAuthorIdField() { |
| 62 | return 'oi_user'; |
| 63 | } |
| 64 | |
| 65 | /** @inheritDoc */ |
| 66 | public function getAuthorNameField() { |
| 67 | return 'oi_user_text'; |
| 68 | } |
| 69 | |
| 70 | /** @inheritDoc */ |
| 71 | public function getAuthorActorField() { |
| 72 | return 'oi_actor'; |
| 73 | } |
| 74 | |
| 75 | /** @inheritDoc */ |
| 76 | public function getId() { |
| 77 | $parts = explode( '!', $this->row->oi_archive_name ); |
| 78 | |
| 79 | return $parts[0]; |
| 80 | } |
| 81 | |
| 82 | /** @inheritDoc */ |
| 83 | public function canView() { |
| 84 | return $this->file->userCan( File::DELETED_RESTRICTED, $this->list->getAuthority() ); |
| 85 | } |
| 86 | |
| 87 | /** @inheritDoc */ |
| 88 | public function canViewContent() { |
| 89 | return $this->file->userCan( File::DELETED_FILE, $this->list->getAuthority() ); |
| 90 | } |
| 91 | |
| 92 | /** @inheritDoc */ |
| 93 | public function getBits() { |
| 94 | return $this->file->getVisibility(); |
| 95 | } |
| 96 | |
| 97 | /** @inheritDoc */ |
| 98 | public function setBits( $bits ) { |
| 99 | # Queue the file op |
| 100 | # @todo FIXME: Move to LocalFile.php |
| 101 | if ( $this->isDeleted() ) { |
| 102 | if ( $bits & File::DELETED_FILE ) { |
| 103 | # Still deleted |
| 104 | } else { |
| 105 | # Newly undeleted |
| 106 | $key = $this->file->getStorageKey(); |
| 107 | $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key; |
| 108 | $this->list->storeBatch[] = [ |
| 109 | $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel, |
| 110 | 'public', |
| 111 | $this->file->getRel() |
| 112 | ]; |
| 113 | $this->list->cleanupBatch[] = $key; |
| 114 | } |
| 115 | } elseif ( $bits & File::DELETED_FILE ) { |
| 116 | # Newly deleted |
| 117 | $key = $this->file->getStorageKey(); |
| 118 | $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key; |
| 119 | $this->list->deleteBatch[] = [ $this->file->getRel(), $dstRel ]; |
| 120 | } |
| 121 | |
| 122 | # Do the database operations |
| 123 | $dbw = $this->dbProvider->getPrimaryDatabase(); |
| 124 | $dbw->newUpdateQueryBuilder() |
| 125 | ->update( 'oldimage' ) |
| 126 | ->set( [ 'oi_deleted' => $bits ] ) |
| 127 | ->where( [ |
| 128 | 'oi_name' => $this->row->oi_name, |
| 129 | 'oi_timestamp' => $this->row->oi_timestamp, |
| 130 | 'oi_deleted' => $this->getBits() |
| 131 | ] ) |
| 132 | ->caller( __METHOD__ )->execute(); |
| 133 | |
| 134 | return (bool)$dbw->affectedRows(); |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * @return bool |
| 139 | */ |
| 140 | public function isDeleted() { |
| 141 | return $this->file->isDeleted( File::DELETED_FILE ); |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * Get the link to the file. |
| 146 | * Overridden by RevDelArchivedFileItem. |
| 147 | * @return string |
| 148 | */ |
| 149 | protected function getLink() { |
| 150 | $date = $this->list->getLanguage()->userTimeAndDate( |
| 151 | $this->file->getTimestamp(), $this->list->getUser() ); |
| 152 | |
| 153 | if ( !$this->isDeleted() ) { |
| 154 | # Regular files... |
| 155 | return Html::element( 'a', [ 'href' => $this->file->getUrl() ], $date ); |
| 156 | } |
| 157 | |
| 158 | # Hidden files... |
| 159 | if ( !$this->canViewContent() ) { |
| 160 | $link = htmlspecialchars( $date ); |
| 161 | } else { |
| 162 | $link = $this->getLinkRenderer()->makeLink( |
| 163 | SpecialPage::getTitleFor( 'Revisiondelete' ), |
| 164 | $date, |
| 165 | [], |
| 166 | [ |
| 167 | 'target' => $this->list->getPageName(), |
| 168 | 'file' => $this->file->getArchiveName(), |
| 169 | 'token' => $this->list->getUser()->getEditToken( |
| 170 | $this->file->getArchiveName() ) |
| 171 | ] |
| 172 | ); |
| 173 | } |
| 174 | |
| 175 | return '<span class="history-deleted">' . $link . '</span>'; |
| 176 | } |
| 177 | |
| 178 | /** |
| 179 | * Generate a user tool link cluster if the current user is allowed to view it |
| 180 | * @return string HTML |
| 181 | */ |
| 182 | protected function getUserTools() { |
| 183 | $uploader = $this->file->getUploader( File::FOR_THIS_USER, $this->list->getAuthority() ); |
| 184 | if ( $uploader ) { |
| 185 | $link = Linker::userLink( $uploader->getId(), $uploader->getName() ) . |
| 186 | Linker::userToolLinks( $uploader->getId(), $uploader->getName() ); |
| 187 | return $link; |
| 188 | } else { |
| 189 | $link = $this->list->msg( 'rev-deleted-user' )->escaped(); |
| 190 | } |
| 191 | if ( $this->file->isDeleted( File::DELETED_USER ) ) { |
| 192 | return '<span class="history-deleted">' . $link . '</span>'; |
| 193 | } |
| 194 | return $link; |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Wrap and format the file's comment block, if the current |
| 199 | * user is allowed to view it. |
| 200 | * |
| 201 | * @return string HTML |
| 202 | */ |
| 203 | protected function getComment() { |
| 204 | if ( $this->file->userCan( File::DELETED_COMMENT, $this->list->getAuthority() ) ) { |
| 205 | $block = MediaWikiServices::getInstance()->getCommentFormatter() |
| 206 | ->formatBlock( $this->file->getDescription() ); |
| 207 | } else { |
| 208 | $block = ' ' . $this->list->msg( 'rev-deleted-comment' )->escaped(); |
| 209 | } |
| 210 | if ( $this->file->isDeleted( File::DELETED_COMMENT ) ) { |
| 211 | return "<span class=\"history-deleted\">$block</span>"; |
| 212 | } |
| 213 | |
| 214 | return $block; |
| 215 | } |
| 216 | |
| 217 | /** @inheritDoc */ |
| 218 | public function getHTML() { |
| 219 | $data = |
| 220 | $this->list->msg( 'widthheight' )->numParams( |
| 221 | $this->file->getWidth(), |
| 222 | $this->file->getHeight() )->escaped() . |
| 223 | ' (' . $this->list->msg( 'nbytes' )->numParams( |
| 224 | $this->file->getSize() )->escaped() . ')'; |
| 225 | |
| 226 | return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' . |
| 227 | $data . ' ' . $this->getComment() . '</li>'; |
| 228 | } |
| 229 | |
| 230 | /** @inheritDoc */ |
| 231 | public function getApiData( ApiResult $result ) { |
| 232 | $file = $this->file; |
| 233 | $user = $this->list->getUser(); |
| 234 | $ret = [ |
| 235 | 'title' => $this->list->getPageName(), |
| 236 | 'archivename' => $file->getArchiveName(), |
| 237 | 'timestamp' => wfTimestamp( TS::ISO_8601, $file->getTimestamp() ), |
| 238 | 'width' => $file->getWidth(), |
| 239 | 'height' => $file->getHeight(), |
| 240 | 'size' => $file->getSize(), |
| 241 | 'userhidden' => (bool)$file->isDeleted( File::DELETED_USER ), |
| 242 | 'commenthidden' => (bool)$file->isDeleted( File::DELETED_COMMENT ), |
| 243 | 'contenthidden' => (bool)$this->isDeleted(), |
| 244 | ]; |
| 245 | if ( !$this->isDeleted() ) { |
| 246 | $ret += [ |
| 247 | 'url' => $file->getUrl(), |
| 248 | ]; |
| 249 | } elseif ( $this->canViewContent() ) { |
| 250 | $ret += [ |
| 251 | 'url' => SpecialPage::getTitleFor( 'Revisiondelete' )->getLinkURL( |
| 252 | [ |
| 253 | 'target' => $this->list->getPageName(), |
| 254 | 'file' => $file->getArchiveName(), |
| 255 | 'token' => $user->getEditToken( $file->getArchiveName() ) |
| 256 | ] |
| 257 | ), |
| 258 | ]; |
| 259 | } |
| 260 | $uploader = $file->getUploader( File::FOR_THIS_USER, $user ); |
| 261 | if ( $uploader ) { |
| 262 | $ret += [ |
| 263 | 'userid' => $uploader->getId(), |
| 264 | 'user' => $uploader->getName(), |
| 265 | ]; |
| 266 | } |
| 267 | $comment = $file->getDescription( File::FOR_THIS_USER, $user ); |
| 268 | if ( ( $comment ?? '' ) !== '' ) { |
| 269 | $ret += [ |
| 270 | 'comment' => $comment, |
| 271 | ]; |
| 272 | } |
| 273 | |
| 274 | return $ret; |
| 275 | } |
| 276 | |
| 277 | /** @inheritDoc */ |
| 278 | public function lock() { |
| 279 | return $this->file->acquireFileLock(); |
| 280 | } |
| 281 | |
| 282 | /** @inheritDoc */ |
| 283 | public function unlock() { |
| 284 | return $this->file->releaseFileLock(); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | /** @deprecated class alias since 1.46 */ |
| 289 | class_alias( RevDelFileItem::class, 'RevDelFileItem' ); |