Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 117
0.00% covered (danger)
0.00%
0 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
RevDelRevisionItem
0.00% covered (danger)
0.00%
0 / 116
0.00% covered (danger)
0.00%
0 / 19
1056
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 initRevisionRecord
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getRevisionRecord
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIdField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTimestampField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAuthorIdField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAuthorNameField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAuthorActorField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 canView
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 canViewContent
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getBits
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setBits
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
6
 isDeleted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isHideCurrentOp
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getRevisionLink
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
 getDiffLink
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 getHTML
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
 getTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getApiData
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 * @ingroup RevisionDelete
6 */
7
8namespace MediaWiki\RevisionDelete;
9
10use MediaWiki\Api\ApiResult;
11use MediaWiki\ChangeTags\ChangeTagsFormatter;
12use MediaWiki\Html\Html;
13use MediaWiki\Linker\Linker;
14use MediaWiki\MediaWikiServices;
15use MediaWiki\RecentChanges\RecentChange;
16use MediaWiki\Revision\RevisionRecord;
17use MediaWiki\RevisionList\RevisionListBase;
18use Wikimedia\Timestamp\TimestampFormat as TS;
19
20/**
21 * Item class for a live revision table row
22 *
23 * @property RevDelRevisionList $list
24 */
25class RevDelRevisionItem extends RevDelItem {
26    /** @var RevisionRecord */
27    public $revisionRecord;
28
29    /** @inheritDoc */
30    public function __construct(
31        RevisionListBase $list,
32        $row,
33        private readonly ChangeTagsFormatter $changeTagsFormatter,
34    ) {
35        parent::__construct( $list, $row );
36        $this->revisionRecord = static::initRevisionRecord( $list, $row );
37    }
38
39    /**
40     * Create RevisionRecord object from $row sourced from $list
41     *
42     * @param RevisionListBase $list
43     * @param mixed $row
44     * @return RevisionRecord
45     */
46    protected static function initRevisionRecord( $list, $row ) {
47        return MediaWikiServices::getInstance()
48            ->getRevisionFactory()
49            ->newRevisionFromRow( $row );
50    }
51
52    /**
53     * Get the RevisionRecord for the item
54     */
55    protected function getRevisionRecord(): RevisionRecord {
56        return $this->revisionRecord;
57    }
58
59    /** @inheritDoc */
60    public function getIdField() {
61        return 'rev_id';
62    }
63
64    /** @inheritDoc */
65    public function getTimestampField() {
66        return 'rev_timestamp';
67    }
68
69    /** @inheritDoc */
70    public function getAuthorIdField() {
71        return 'rev_user';
72    }
73
74    /** @inheritDoc */
75    public function getAuthorNameField() {
76        return 'rev_user_text';
77    }
78
79    /** @inheritDoc */
80    public function getAuthorActorField() {
81        return 'rev_actor';
82    }
83
84    /** @inheritDoc */
85    public function canView() {
86        return $this->getRevisionRecord()->userCan(
87            RevisionRecord::DELETED_RESTRICTED,
88            $this->list->getAuthority()
89        );
90    }
91
92    /** @inheritDoc */
93    public function canViewContent() {
94        return $this->getRevisionRecord()->userCan(
95            RevisionRecord::DELETED_TEXT,
96            $this->list->getAuthority()
97        );
98    }
99
100    /** @inheritDoc */
101    public function getBits() {
102        return $this->getRevisionRecord()->getVisibility();
103    }
104
105    /** @inheritDoc */
106    public function setBits( $bits ) {
107        $revRecord = $this->getRevisionRecord();
108
109        $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
110        // Update revision table
111        $dbw->newUpdateQueryBuilder()
112            ->update( 'revision' )
113            ->set( [ 'rev_deleted' => $bits ] )
114            ->where( [
115                'rev_id' => $revRecord->getId(),
116                'rev_page' => $revRecord->getPageId(),
117                'rev_deleted' => $this->getBits() // cas
118            ] )
119            ->caller( __METHOD__ )->execute();
120
121        if ( !$dbw->affectedRows() ) {
122            // Concurrent fail!
123            return false;
124        }
125        // Update recentchanges table
126        $dbw->newUpdateQueryBuilder()
127            ->update( 'recentchanges' )
128            ->set( [
129                'rc_deleted' => $bits,
130                'rc_patrolled' => RecentChange::PRC_AUTOPATROLLED
131            ] )
132            ->where( [ 'rc_this_oldid' => $revRecord->getId() ] )
133            ->caller( __METHOD__ )->execute();
134
135        return true;
136    }
137
138    /**
139     * @return bool
140     */
141    public function isDeleted() {
142        return $this->getRevisionRecord()->isDeleted( RevisionRecord::DELETED_TEXT );
143    }
144
145    /** @inheritDoc */
146    public function isHideCurrentOp( $newBits ) {
147        return ( $newBits & RevisionRecord::DELETED_TEXT )
148            && $this->list->getCurrent() == $this->getId();
149    }
150
151    /**
152     * Get the HTML link to the revision text.
153     * Overridden by RevDelArchiveItem.
154     * @return string
155     */
156    protected function getRevisionLink() {
157        $date = $this->list->getLanguage()->userTimeAndDate(
158            $this->getRevisionRecord()->getTimestamp(),
159            $this->list->getUser()
160        );
161
162        if ( $this->isDeleted() && !$this->canViewContent() ) {
163            return htmlspecialchars( $date );
164        }
165
166        return $this->getLinkRenderer()->makeKnownLink(
167            $this->list->getPage(),
168            $date,
169            [],
170            [
171                'oldid' => $this->getRevisionRecord()->getId(),
172                'unhide' => 1
173            ]
174        );
175    }
176
177    /**
178     * Get the HTML link to the diff.
179     * Overridden by RevDelArchiveItem
180     * @return string
181     */
182    protected function getDiffLink() {
183        if ( $this->isDeleted() && !$this->canViewContent() ) {
184            return $this->list->msg( 'diff' )->escaped();
185        } else {
186            return $this->getLinkRenderer()->makeKnownLink(
187                $this->list->getPage(),
188                $this->list->msg( 'diff' )->text(),
189                [],
190                [
191                    'diff' => $this->getRevisionRecord()->getId(),
192                    'oldid' => 'prev',
193                    'unhide' => 1
194                ]
195            );
196        }
197    }
198
199    /**
200     * @return string A HTML <li> element representing this revision, showing
201     * change tags and everything
202     */
203    public function getHTML() {
204        $revRecord = $this->getRevisionRecord();
205
206        $difflink = $this->list->msg( 'parentheses' )
207            ->rawParams( $this->getDiffLink() )->escaped();
208        $revlink = $this->getRevisionLink();
209        $userlink = Linker::revUserLink( $revRecord );
210        $comment = MediaWikiServices::getInstance()->getCommentFormatter()
211            ->formatRevision( $revRecord, $this->list->getAuthority() );
212        if ( $this->isDeleted() ) {
213            $class = Linker::getRevisionDeletedClass( $revRecord );
214            $revlink = "<span class=\"$class\">$revlink</span>";
215        }
216        $content = "$difflink $revlink $userlink $comment";
217        $attribs = [];
218        $tags = $this->getTags();
219        if ( $tags ) {
220            [ $tagSummary, $classes ] = $this->changeTagsFormatter->formatTagsAsSummaryList(
221                $tags,
222                $this->list->getContext(),
223                $this->list->getAuthority()
224            );
225            $content .= " $tagSummary";
226            $attribs['class'] = $classes;
227        }
228        return Html::rawElement( 'li', $attribs, $content );
229    }
230
231    /**
232     * @return string Comma-separated list of tags
233     */
234    public function getTags() {
235        return $this->row->ts_tags;
236    }
237
238    /** @inheritDoc */
239    public function getApiData( ApiResult $result ) {
240        $revRecord = $this->getRevisionRecord();
241        $authority = $this->list->getAuthority();
242        $ret = [
243            'id' => $revRecord->getId(),
244            'timestamp' => wfTimestamp( TS::ISO_8601, $revRecord->getTimestamp() ),
245            'userhidden' => (bool)$revRecord->isDeleted( RevisionRecord::DELETED_USER ),
246            'commenthidden' => (bool)$revRecord->isDeleted( RevisionRecord::DELETED_COMMENT ),
247            'texthidden' => (bool)$revRecord->isDeleted( RevisionRecord::DELETED_TEXT ),
248        ];
249        if ( $revRecord->userCan( RevisionRecord::DELETED_USER, $authority ) ) {
250            $revUser = $revRecord->getUser( RevisionRecord::FOR_THIS_USER, $authority );
251            $ret += [
252                'userid' => $revUser ? $revUser->getId() : 0,
253                'user' => $revUser ? $revUser->getName() : '',
254            ];
255        }
256        if ( $revRecord->userCan( RevisionRecord::DELETED_COMMENT, $authority ) ) {
257            $revComment = $revRecord->getComment( RevisionRecord::FOR_THIS_USER, $authority );
258            $ret += [
259                'comment' => $revComment ? $revComment->text : ''
260            ];
261        }
262
263        return $ret;
264    }
265}
266
267/** @deprecated class alias since 1.46 */
268class_alias( RevDelRevisionItem::class, 'RevDelRevisionItem' );