Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 55 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
| WikiRevisionFactory | |
0.00% |
0 / 55 |
|
0.00% |
0 / 7 |
132 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| newWikiRevision | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| setInterWikiPrefix | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
| newFromFileRevision | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
6 | |||
| newFromTextRevision | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
2 | |||
| createCentralAuthUser | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| prefixCommentLinks | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace FileImporter\Services; |
| 4 | |
| 5 | use FileImporter\Data\FileRevision; |
| 6 | use FileImporter\Data\TextRevision; |
| 7 | use MediaWiki\Content\IContentHandlerFactory; |
| 8 | use MediaWiki\Revision\SlotRecord; |
| 9 | use MediaWiki\Title\Title; |
| 10 | use MediaWiki\User\ExternalUserNames; |
| 11 | use WikiRevision; |
| 12 | |
| 13 | /** |
| 14 | * @license GPL-2.0-or-later |
| 15 | * @author Addshore |
| 16 | */ |
| 17 | class WikiRevisionFactory { |
| 18 | |
| 19 | /** @var string */ |
| 20 | private $interwikiPrefix; |
| 21 | private ExternalUserNames $externalUserNames; |
| 22 | |
| 23 | // TODO: should be changed back to lowercase when T221235 is fixed. |
| 24 | public const DEFAULT_USERNAME_PREFIX = 'Imported'; |
| 25 | |
| 26 | public function __construct( |
| 27 | private readonly IContentHandlerFactory $contentHandlerFactory, |
| 28 | ) { |
| 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 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 | } |