Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 113
0.00% covered (danger)
0.00%
0 / 52
CRAP
0.00% covered (danger)
0.00%
0 / 1
WikiRevision
0.00% covered (danger)
0.00%
0 / 112
0.00% covered (danger)
0.00%
0 / 52
4032
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setID
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setTimestamp
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setUsername
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setUserObj
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
 setUserIP
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setModel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setText
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 setContent
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 setComment
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setMinor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setSrc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setFileSrc
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setSha1Base36
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 setTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setFilename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setArchiveName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setSize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setAction
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setNoUpdates
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getID
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTimestamp
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUser
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUserObj
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContentHandler
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getContent
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSlot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSlotRoles
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getModel
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getFormat
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getComment
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMinor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSrc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSha1
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getSha1Base36
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTags
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFileSrc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isTempSrc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFilename
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getArchiveName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAction
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 importOldRevision
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 importLogItem
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * MediaWiki page data importer.
4 *
5 * Copyright © 2003,2005 Brooke Vibber <bvibber@wikimedia.org>
6 * https://www.mediawiki.org/
7 *
8 * @license GPL-2.0-or-later
9 * @file
10 * @ingroup SpecialPage
11 */
12
13namespace MediaWiki\Import;
14
15use MediaWiki\Content\Content;
16use MediaWiki\Content\ContentHandler;
17use MediaWiki\Exception\MWUnknownContentModelException;
18use MediaWiki\MediaWikiServices;
19use MediaWiki\Revision\MutableRevisionSlots;
20use MediaWiki\Revision\SlotRecord;
21use MediaWiki\Title\Title;
22use MediaWiki\User\ExternalUserNames;
23use MediaWiki\User\User;
24use MediaWiki\User\UserIdentityValue;
25use Wikimedia\Timestamp\TimestampFormat as TS;
26
27/**
28 * Represents a revision, log entry or upload during the import process.
29 * This class sticks closely to the structure of the XML dump.
30 *
31 * @since 1.2
32 *
33 * @ingroup SpecialPage
34 */
35class WikiRevision implements ImportableUploadRevision, ImportableOldRevision {
36
37    /**
38     * @since 1.2
39     * @var Title
40     */
41    public $title = null;
42
43    /**
44     * @since 1.6.4
45     * @var int
46     */
47    public $id = 0;
48
49    /**
50     * @since 1.2
51     * @var string TS::MW timestamp, a string with 14 digits
52     */
53    public $timestamp = "20010115000000";
54
55    /**
56     * @since 1.2
57     * @var string
58     */
59    public $user_text = "";
60
61    /**
62     * @deprecated since 1.39, use {@see $user_text} instead
63     * @since 1.27
64     * @var User|null
65     */
66    public $userObj = null;
67
68    /**
69     * @since 1.21
70     * @deprecated since 1.35, use getContent
71     * @var string
72     */
73    public $model = null;
74
75    /**
76     * @since 1.21
77     * @deprecated since 1.35, use getContent
78     * @var string
79     */
80    public $format = null;
81
82    /**
83     * @since 1.2
84     * @deprecated since 1.35, use getContent
85     * @var string
86     */
87    public $text = "";
88
89    /**
90     * @since 1.12.2
91     * @var int
92     */
93    protected $size;
94
95    /**
96     * @since 1.21
97     * @deprecated since 1.35, use getContent
98     * @var Content
99     */
100    public $content = null;
101
102    /**
103     * @since 1.24
104     * @var ContentHandler
105     */
106    protected $contentHandler = null;
107
108    /**
109     * @since 1.2.6
110     * @var string
111     */
112    public $comment = "";
113
114    private MutableRevisionSlots $slots;
115
116    /**
117     * @since 1.5.7
118     * @var bool
119     */
120    public $minor = false;
121
122    /**
123     * @since 1.12.2
124     * @var string
125     */
126    public $type = "";
127
128    /**
129     * @since 1.12.2
130     * @var string
131     */
132    public $action = "";
133
134    /**
135     * @since 1.12.2
136     * @var string
137     */
138    public $params = "";
139
140    /**
141     * @since 1.17
142     * @var string
143     */
144    public $fileSrc = '';
145
146    /**
147     * @var string|null
148     */
149    private $sha1base36;
150
151    /**
152     * @since 1.34
153     * @var string[]
154     */
155    protected $tags = [];
156
157    /**
158     * @since 1.17
159     * @var string
160     */
161    public $archiveName = '';
162
163    /**
164     * @since 1.12.2
165     * @var string|null
166     */
167    protected $filename;
168
169    /**
170     * @since 1.12.2
171     * @var string|null
172     */
173    protected $src = null;
174
175    /**
176     * @since 1.18
177     * @var bool
178     * @todo Unused?
179     */
180    public $isTemp = false;
181
182    /** @var bool */
183    private $mNoUpdates = false;
184
185    public function __construct() {
186        $this->slots = new MutableRevisionSlots();
187    }
188
189    public function setTitle( Title $title ) {
190        $this->title = $title;
191    }
192
193    /**
194     * @since 1.6.4
195     * @param int $id
196     */
197    public function setID( $id ) {
198        $this->id = $id;
199    }
200
201    /**
202     * @since 1.2
203     * @param string $ts
204     */
205    public function setTimestamp( $ts ) {
206        # 2003-08-05T18:30:02Z
207        $this->timestamp = wfTimestamp( TS::MW, $ts );
208    }
209
210    /**
211     * @since 1.2
212     * @param string $user
213     */
214    public function setUsername( $user ) {
215        $this->user_text = $user;
216    }
217
218    /**
219     * @deprecated since 1.39, use {@see setUsername} instead
220     * @since 1.27
221     * @param User $user
222     */
223    public function setUserObj( $user ) {
224        // Not officially supported, but some callers pass false from e.g. User::newFromName()
225        $this->userObj = $user ?: null;
226        if ( $this->user_text === '' && $user ) {
227            $this->user_text = $user->getName();
228        }
229    }
230
231    /**
232     * @deprecated since 1.39, use {@see setUsername} instead, it does the same anyway
233     * @since 1.2
234     * @param string $ip
235     */
236    public function setUserIP( $ip ) {
237        $this->user_text = $ip;
238    }
239
240    /**
241     * @since 1.21
242     * @deprecated since 1.35, use setContent instead.
243     * @param string $model
244     */
245    public function setModel( $model ) {
246        $this->model = $model;
247    }
248
249    /**
250     * @since 1.21
251     * @deprecated since 1.35, use setContent instead.
252     * @param string $format
253     */
254    public function setFormat( $format ) {
255        $this->format = $format;
256    }
257
258    /**
259     * @since 1.2
260     * @deprecated since 1.35, use setContent instead.
261     * @param string $text
262     */
263    public function setText( $text ) {
264        $handler = $this->getContentHandler();
265        $content = $handler->unserializeContent( $text );
266        $this->setContent( SlotRecord::MAIN, $content );
267    }
268
269    /**
270     * @since 1.35
271     * @param string $role
272     * @param Content $content
273     */
274    public function setContent( $role, $content ) {
275        $this->slots->setContent( $role, $content );
276
277        // backwards compat
278        if ( $role === SlotRecord::MAIN ) {
279            $this->content = $content;
280            $this->model = $content->getModel();
281            $this->format = $content->getDefaultFormat();
282            $this->text = $content->serialize();
283        }
284    }
285
286    /**
287     * @since 1.2.6
288     * @param string $text
289     */
290    public function setComment( string $text ) {
291        $this->comment = $text;
292    }
293
294    /**
295     * @since 1.5.7
296     * @param bool $minor
297     */
298    public function setMinor( $minor ) {
299        $this->minor = (bool)$minor;
300    }
301
302    /**
303     * @since 1.12.2
304     * @param string|null $src
305     */
306    public function setSrc( $src ) {
307        $this->src = $src;
308    }
309
310    /**
311     * @since 1.17
312     * @param string $src
313     * @param bool $isTemp
314     */
315    public function setFileSrc( $src, $isTemp ) {
316        $this->fileSrc = $src;
317        $this->isTemp = $isTemp;
318    }
319
320    /**
321     * @since 1.17
322     * @param string $sha1base36
323     */
324    public function setSha1Base36( $sha1base36 ) {
325        $this->sha1base36 = $sha1base36 ?: null;
326    }
327
328    /**
329     * @since 1.34
330     * @param string[] $tags
331     */
332    public function setTags( array $tags ) {
333        $this->tags = $tags;
334    }
335
336    /**
337     * @since 1.12.2
338     * @param string $filename
339     */
340    public function setFilename( $filename ) {
341        $this->filename = $filename;
342    }
343
344    /**
345     * @since 1.17
346     * @param string $archiveName
347     */
348    public function setArchiveName( $archiveName ) {
349        $this->archiveName = $archiveName;
350    }
351
352    /**
353     * @since 1.12.2
354     * @param int $size
355     */
356    public function setSize( $size ) {
357        $this->size = intval( $size );
358    }
359
360    /**
361     * @since 1.12.2
362     * @param string $type
363     */
364    public function setType( $type ) {
365        $this->type = $type;
366    }
367
368    /**
369     * @since 1.12.2
370     * @param string $action
371     */
372    public function setAction( $action ) {
373        $this->action = $action;
374    }
375
376    /**
377     * @since 1.12.2
378     * @param string $params
379     */
380    public function setParams( $params ) {
381        $this->params = $params;
382    }
383
384    /**
385     * @since 1.18
386     * @param bool $noupdates
387     */
388    public function setNoUpdates( $noupdates ) {
389        $this->mNoUpdates = $noupdates;
390    }
391
392    /**
393     * @since 1.2
394     * @return Title
395     */
396    public function getTitle() {
397        return $this->title;
398    }
399
400    /**
401     * @since 1.6.4
402     * @return int
403     */
404    public function getID() {
405        return $this->id;
406    }
407
408    /**
409     * @since 1.2
410     * @return string TS::MW timestamp, a string with 14 digits
411     */
412    public function getTimestamp() {
413        return $this->timestamp;
414    }
415
416    /**
417     * @since 1.2
418     * @return string
419     */
420    public function getUser() {
421        return $this->user_text;
422    }
423
424    /**
425     * @deprecated since 1.39, use {@see getUser} instead; this is almost always null anyway
426     * @since 1.27
427     * @return User|null Typically null, use {@see getUser} instead
428     */
429    public function getUserObj() {
430        return $this->userObj;
431    }
432
433    /**
434     * @since 1.2
435     * @return string
436     */
437    public function getText() {
438        return $this->text;
439    }
440
441    /**
442     * @since 1.24
443     * @deprecated since 1.35, use getContent
444     * @return ContentHandler
445     * @throws MWUnknownContentModelException
446     */
447    public function getContentHandler() {
448        $this->contentHandler ??= MediaWikiServices::getInstance()
449            ->getContentHandlerFactory()
450            ->getContentHandler( $this->getModel() );
451
452        return $this->contentHandler;
453    }
454
455    /**
456     * @since 1.21
457     * @param string $role added in 1.35
458     * @return Content
459     */
460    public function getContent( $role = SlotRecord::MAIN ) {
461        return $this->slots->getContent( $role );
462    }
463
464    /**
465     * @since 1.35
466     * @param string $role
467     * @return SlotRecord
468     */
469    public function getSlot( $role ) {
470        return $this->slots->getSlot( $role );
471    }
472
473    /**
474     * @since 1.35
475     * @return string[]
476     */
477    public function getSlotRoles() {
478        return $this->slots->getSlotRoles();
479    }
480
481    /**
482     * @since 1.21
483     * @deprecated since 1.35, use getContent
484     * @return string
485     */
486    public function getModel() {
487        $this->model ??= $this->getTitle()->getContentModel();
488
489        return $this->model;
490    }
491
492    /**
493     * @since 1.21
494     * @deprecated since 1.35, use getContent
495     * @return string
496     */
497    public function getFormat() {
498        $this->format ??= $this->getContentHandler()->getDefaultFormat();
499
500        return $this->format;
501    }
502
503    /**
504     * @since 1.2.6
505     * @return string
506     */
507    public function getComment(): string {
508        return $this->comment;
509    }
510
511    /**
512     * @since 1.5.7
513     * @return bool
514     */
515    public function getMinor() {
516        return $this->minor;
517    }
518
519    /**
520     * @since 1.12.2
521     * @return string|null
522     */
523    public function getSrc() {
524        return $this->src;
525    }
526
527    /**
528     * @since 1.17
529     * @return string|false
530     */
531    public function getSha1() {
532        if ( $this->sha1base36 ) {
533            return \Wikimedia\base_convert( $this->sha1base36, 36, 16 );
534        }
535        return false;
536    }
537
538    /**
539     * @since 1.31
540     * @return string|false
541     */
542    public function getSha1Base36() {
543        return $this->sha1base36 ?? false;
544    }
545
546    /**
547     * @since 1.34
548     * @return string[]
549     */
550    public function getTags() {
551        return $this->tags;
552    }
553
554    /**
555     * @since 1.17
556     * @return string
557     */
558    public function getFileSrc() {
559        return $this->fileSrc;
560    }
561
562    /**
563     * @since 1.17
564     * @return bool
565     */
566    public function isTempSrc() {
567        return $this->isTemp;
568    }
569
570    /**
571     * @since 1.12.2
572     * @return mixed
573     */
574    public function getFilename() {
575        return $this->filename;
576    }
577
578    /**
579     * @since 1.17
580     * @return string
581     */
582    public function getArchiveName() {
583        return $this->archiveName;
584    }
585
586    /**
587     * @since 1.12.2
588     * @return mixed
589     */
590    public function getSize() {
591        return $this->size;
592    }
593
594    /**
595     * @since 1.12.2
596     * @return string
597     */
598    public function getType() {
599        return $this->type;
600    }
601
602    /**
603     * @since 1.12.2
604     * @return string
605     */
606    public function getAction() {
607        return $this->action;
608    }
609
610    /**
611     * @since 1.12.2
612     * @return string
613     */
614    public function getParams() {
615        return $this->params;
616    }
617
618    /**
619     * @since 1.4.1
620     * @deprecated since 1.31. Use OldRevisionImporter::import
621     * @return bool
622     */
623    public function importOldRevision() {
624        if ( $this->mNoUpdates ) {
625            $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporterNoUpdates();
626        } else {
627            $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporter();
628        }
629        return $importer->import( $this );
630    }
631
632    /**
633     * @since 1.12.2
634     * @return bool
635     */
636    public function importLogItem() {
637        $services = MediaWikiServices::getInstance();
638        $dbw = $services->getConnectionProvider()->getPrimaryDatabase();
639
640        $userName = $this->getUser();
641        if ( ExternalUserNames::isExternal( $userName ) ) {
642            // Use newAnonymous() since the user name is already prefixed.
643            $user = UserIdentityValue::newAnonymous( $userName );
644        } else {
645            $user = $this->getUserObj() ?: User::newFromName( $userName, false );
646        }
647
648        # @todo FIXME: This will not record autoblocks
649        if ( !$this->getTitle() ) {
650            wfDebug( __METHOD__ . ": skipping invalid {$this->type}/{$this->action} log time, timestamp " .
651                $this->timestamp );
652            return false;
653        }
654        # Check if it exists already
655        // @todo FIXME: Use original log ID (better for backups)
656        $prior = (bool)$dbw->newSelectQueryBuilder()
657            ->select( '1' )
658            ->from( 'logging' )
659            ->where( [
660                'log_type' => $this->getType(),
661                'log_action' => $this->getAction(),
662                'log_timestamp' => $dbw->timestamp( $this->timestamp ),
663                'log_namespace' => $this->getTitle()->getNamespace(),
664                'log_title' => $this->getTitle()->getDBkey(),
665                'log_params' => $this->params
666            ] )
667            ->caller( __METHOD__ )->fetchField();
668        // @todo FIXME: This could fail slightly for multiple matches :P
669        if ( $prior ) {
670            wfDebug( __METHOD__
671                . ": skipping existing item for Log:{$this->type}/{$this->action}, timestamp "
672                . $this->timestamp );
673            return false;
674        }
675        $actorId = $services->getActorNormalization()->acquireActorId( $user, $dbw );
676        $dbw->newInsertQueryBuilder()
677            ->insertInto( 'logging' )
678            ->row( [
679                'log_type' => $this->type,
680                'log_action' => $this->action,
681                'log_timestamp' => $dbw->timestamp( $this->timestamp ),
682                'log_actor' => $actorId,
683                'log_namespace' => $this->getTitle()->getNamespace(),
684                'log_title' => $this->getTitle()->getDBkey(),
685                'log_params' => $this->params
686                ] + $services->getCommentStore()->insert( $dbw, 'log_comment', $this->getComment() ) )
687            ->caller( __METHOD__ )->execute();
688        return true;
689    }
690
691}
692
693/** @deprecated class alias since 1.46 */
694class_alias( WikiRevision::class, 'WikiRevision' );