Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
WikiRevisionFactory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 7
132
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
 newWikiRevision
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 setInterWikiPrefix
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 newFromFileRevision
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 newFromTextRevision
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
2
 createCentralAuthUser
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 prefixCommentLinks
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace FileImporter\Services;
4
5use FileImporter\Data\FileRevision;
6use FileImporter\Data\TextRevision;
7use MediaWiki\Content\IContentHandlerFactory;
8use MediaWiki\Revision\SlotRecord;
9use MediaWiki\Title\Title;
10use MediaWiki\User\ExternalUserNames;
11use WikiRevision;
12
13/**
14 * @license GPL-2.0-or-later
15 * @author Addshore
16 */
17class WikiRevisionFactory {
18
19    private IContentHandlerFactory $contentHandlerFactory;
20    /** @var string */
21    private $interwikiPrefix;
22    private ExternalUserNames $externalUserNames;
23
24    // TODO: should be changed back to lowercase when T221235 is fixed.
25    public const DEFAULT_USERNAME_PREFIX = 'Imported';
26
27    public function __construct( IContentHandlerFactory $contentHandlerFactory ) {
28        $this->contentHandlerFactory = $contentHandlerFactory;
29        $this->externalUserNames = new ExternalUserNames( self::DEFAULT_USERNAME_PREFIX, true );
30    }
31
32    private function newWikiRevision(
33        string $title,
34        string $timestamp,
35        ?string $sha1
36    ): WikiRevision {
37        $titleParts = explode( ':', $title );
38        $filename = end( $titleParts );
39
40        // The 3 fields rev_page, rev_timestamp, and rev_sha1 make a revision unique, see
41        // ImportableOldRevisionImporter::import()
42        $revision = new WikiRevision();
43        $revision->setTitle( Title::makeTitleSafe( NS_FILE, $filename ) );
44        $revision->setTimestamp( $timestamp );
45        // File revisions older than 2012 might not have a hash yet. Import as is.
46        if ( $sha1 ) {
47            $revision->setSha1Base36( $sha1 );
48        }
49
50        return $revision;
51    }
52
53    public function setInterWikiPrefix( string $prefix ): void {
54        $this->interwikiPrefix = $prefix;
55        $this->externalUserNames = new ExternalUserNames(
56            $prefix ?: self::DEFAULT_USERNAME_PREFIX,
57            true
58        );
59    }
60
61    public function newFromFileRevision( FileRevision $fileRevision, string $src ): WikiRevision {
62        $revision = $this->newWikiRevision(
63            $fileRevision->getField( 'name' ),
64            $fileRevision->getField( 'timestamp' ),
65            $fileRevision->getField( 'sha1' )
66        );
67        $revision->setFileSrc( $src, true );
68        $revision->setComment( $fileRevision->getField( 'description' ) );
69
70        $importedUser = $this->createCentralAuthUser( $fileRevision->getField( 'user' ) );
71        $revision->setUsername( $importedUser );
72
73        // Mark old file revisions as such
74        $archiveName = $fileRevision->getField( 'archivename' );
75        if ( $archiveName ) {
76            $revision->setArchiveName( $archiveName );
77        }
78
79        return $revision;
80    }
81
82    /**
83     * @return WikiRevision
84     */
85    public function newFromTextRevision( TextRevision $textRevision ) {
86        $content = $this->contentHandlerFactory
87            ->getContentHandler( $textRevision->getContentModel() )
88            ->unserializeContent(
89                $textRevision->getContent(),
90                $textRevision->getContentFormat()
91            );
92
93        $revision = $this->newWikiRevision(
94            $textRevision->getField( 'title' ),
95            $textRevision->getField( 'timestamp' ),
96            $textRevision->getField( 'sha1' )
97        );
98        $revision->setUsername( $this->createCentralAuthUser( $textRevision->getField( 'user' ) ) );
99        $revision->setComment( $this->prefixCommentLinks( $textRevision->getField( 'comment' ) ) );
100        $revision->setMinor( $textRevision->getField( 'minor' ) );
101        $revision->setContent( SlotRecord::MAIN, $content );
102        $revision->setTags(
103            array_merge( $textRevision->getField( 'tags' ), [ 'fileimporter-imported' ] )
104        );
105
106        return $revision;
107    }
108
109    /**
110     * @return string Either the unchanged username if it's a known local or valid CentralAuth/SUL
111     *  user, otherwise the name with the DEFAULT_USERNAME_PREFIX prefix prepended.
112     */
113    private function createCentralAuthUser( string $username ): string {
114        // This uses the prefix only as fallback
115        return $this->externalUserNames->applyPrefix( $username );
116    }
117
118    /**
119     * TODO: We can almost certainly replace this with WikiLinkCleaners.
120     */
121    private function prefixCommentLinks( string $summaryText ): string {
122        if ( !$this->interwikiPrefix ) {
123            return $summaryText;
124        }
125
126        /** Mostly taken from @see \MediaWiki\CommentFormatter\CommentParser::doWikiLinks */
127        return preg_replace(
128            '/
129                \[\[
130                \s*+ # ignore leading whitespace, the *+ quantifier disallows backtracking
131                :?
132                (?=
133                    [^\[\]|]+
134                    (?:\|
135                        # The "possessive" *+ quantifier disallows backtracking
136                        (?:]?[^\]])*+
137                    )?
138                    \]\]
139                )
140            /x',
141            '[[' . $this->interwikiPrefix . ':',
142            $summaryText
143        );
144    }
145
146}