Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
36.00% |
18 / 50 |
|
50.00% |
7 / 14 |
CRAP | |
0.00% |
0 / 1 |
| ConversionStrategy | |
36.00% |
18 / 50 |
|
50.00% |
7 / 14 |
73.98 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
| getSourceStore | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getMoveComment | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getCleanupComment | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isConversionFinished | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| createImportSource | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| decideArchiveTitle | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| createArchiveCleanupRevisionContent | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
| getPostprocessor | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| shouldConvert | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| removePrefixText | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| getPrefixText | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| removeLqtMagicWord | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
| getDisableLqtMagicWord | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace Flow\Import\LiquidThreadsApi; |
| 4 | |
| 5 | use Flow\Import\ArchiveNameHelper; |
| 6 | use Flow\Import\IConversionStrategy; |
| 7 | use Flow\Import\Postprocessor\LqtNotifications; |
| 8 | use Flow\Import\Postprocessor\LqtRedirector; |
| 9 | use Flow\Import\Postprocessor\ProcessorGroup; |
| 10 | use Flow\Import\SourceStore\SourceStoreInterface; |
| 11 | use Flow\Notifications\Controller; |
| 12 | use Flow\UrlGenerator; |
| 13 | use LqtDispatch; |
| 14 | use MediaWiki\Content\WikitextContent; |
| 15 | use MediaWiki\MediaWikiServices; |
| 16 | use MediaWiki\Title\Title; |
| 17 | use MediaWiki\User\User; |
| 18 | use MediaWiki\Utils\MWTimestamp; |
| 19 | use Wikimedia\Rdbms\IReadableDatabase; |
| 20 | |
| 21 | /** |
| 22 | * Converts LiquidThreads pages on a wiki to Flow. This converter is idempotent |
| 23 | * when used with an appropriate SourceStoreInterface, and may be run many times |
| 24 | * without worry for duplicate imports. |
| 25 | * |
| 26 | * Pages with the LQT magic word will be moved to a subpage of their original location |
| 27 | * named 'LQT Archive N' with N increasing starting at 1 looking for the first empty page. |
| 28 | * On successful import of an entire page the LQT magic word will be stripped from the |
| 29 | * archive version of the page. |
| 30 | */ |
| 31 | class ConversionStrategy implements IConversionStrategy { |
| 32 | |
| 33 | protected IReadableDatabase $dbr; |
| 34 | /** |
| 35 | * @var SourceStoreInterface |
| 36 | */ |
| 37 | protected $sourceStore; |
| 38 | |
| 39 | /** |
| 40 | * @var ApiBackend |
| 41 | */ |
| 42 | public $api; |
| 43 | |
| 44 | /** |
| 45 | * @var UrlGenerator |
| 46 | */ |
| 47 | protected $urlGenerator; |
| 48 | |
| 49 | /** |
| 50 | * @var User |
| 51 | */ |
| 52 | protected $talkpageUser; |
| 53 | |
| 54 | /** |
| 55 | * @var Controller |
| 56 | */ |
| 57 | protected $notificationController; |
| 58 | |
| 59 | public function __construct( |
| 60 | IReadableDatabase $dbr, |
| 61 | SourceStoreInterface $sourceStore, |
| 62 | ApiBackend $api, |
| 63 | UrlGenerator $urlGenerator, |
| 64 | User $talkpageUser, |
| 65 | Controller $notificationController |
| 66 | ) { |
| 67 | $this->dbr = $dbr; |
| 68 | $this->sourceStore = $sourceStore; |
| 69 | $this->api = $api; |
| 70 | $this->urlGenerator = $urlGenerator; |
| 71 | $this->talkpageUser = $talkpageUser; |
| 72 | $this->notificationController = $notificationController; |
| 73 | } |
| 74 | |
| 75 | public function getSourceStore() { |
| 76 | return $this->sourceStore; |
| 77 | } |
| 78 | |
| 79 | public function getMoveComment( Title $from, Title $to ) { |
| 80 | return "Conversion of LQT to Flow from: {$from->getPrefixedText()}"; |
| 81 | } |
| 82 | |
| 83 | public function getCleanupComment( Title $from, Title $to ) { |
| 84 | return "LQT to Flow conversion"; |
| 85 | } |
| 86 | |
| 87 | public function isConversionFinished( Title $title, ?Title $movedFrom = null ) { |
| 88 | if ( LqtDispatch::isLqtPage( $title ) ) { |
| 89 | return false; |
| 90 | } else { |
| 91 | return true; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | public function createImportSource( Title $title ) { |
| 96 | return new ImportSource( $this->api, $title->getPrefixedText(), $this->talkpageUser ); |
| 97 | } |
| 98 | |
| 99 | /** |
| 100 | * Flow does not support viewing the history of the wikitext pages it takes |
| 101 | * over, so those need to be moved out the way. This method decides that |
| 102 | * destination. The archived revisions include the headers displayed with |
| 103 | * lqt and potentially any pre-lqt wikitext talk page content. |
| 104 | * |
| 105 | * @param Title $source |
| 106 | * @return Title |
| 107 | */ |
| 108 | public function decideArchiveTitle( Title $source ) { |
| 109 | $archiveNameHelper = new ArchiveNameHelper(); |
| 110 | return $archiveNameHelper->decideArchiveTitle( $source, [ |
| 111 | '%s/LQT Archive %d', |
| 112 | ] ); |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Creates a new revision that ensures the LQT magic word is there and turning LQT off. |
| 117 | * It also adds a template about the move. |
| 118 | * effectively no longer be LQT pages. |
| 119 | * |
| 120 | * @param WikitextContent $content |
| 121 | * @param Title $title |
| 122 | * @return WikitextContent |
| 123 | */ |
| 124 | public function createArchiveCleanupRevisionContent( WikitextContent $content, Title $title ) { |
| 125 | // cleanup existing text |
| 126 | $existing = $content->getText(); |
| 127 | $existing = self::removeLqtMagicWord( $existing ); |
| 128 | $existing = $this->removePrefixText( $existing ); |
| 129 | |
| 130 | // prefix the existing text with some additional info related to the conversion |
| 131 | $text = $this->getPrefixText( $content, $title ) . "\n\n"; |
| 132 | $text .= self::getDisableLqtMagicWord() . "\n\n"; |
| 133 | $text .= $existing; |
| 134 | |
| 135 | return new WikitextContent( $text ); |
| 136 | } |
| 137 | |
| 138 | public function getPostprocessor() { |
| 139 | $group = new ProcessorGroup; |
| 140 | $group->add( new LqtRedirector( $this->urlGenerator, $this->talkpageUser ) ); |
| 141 | $group->add( new LqtNotifications( $this->notificationController, $this->dbr ) ); |
| 142 | |
| 143 | return $group; |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * @inheritDoc |
| 148 | */ |
| 149 | public function shouldConvert( Title $sourceTitle ) { |
| 150 | // The expensive part of this (user-override checking) is cached by LQT. |
| 151 | return LqtDispatch::isLqtPage( $sourceTitle ); |
| 152 | } |
| 153 | |
| 154 | /** |
| 155 | * Gets rid of any "This page is an archived page..." prefix that may have |
| 156 | * been added in an earlier conversion run. |
| 157 | * |
| 158 | * @param string $content |
| 159 | * @return string |
| 160 | */ |
| 161 | protected function removePrefixText( $content ) { |
| 162 | $template = wfMessage( 'flow-importer-lqt-converted-archive-template' )->inContentLanguage()->plain(); |
| 163 | $templateSearch = preg_quote( $template, '/' ); |
| 164 | return preg_replace( '/{{' . $templateSearch . '}\\|[^\\}]+}/', '', $content ); |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * Generates a "This page is an archived page..." text to add to the |
| 169 | * existing content. |
| 170 | * |
| 171 | * @param WikitextContent $content |
| 172 | * @param Title $title |
| 173 | * @return string |
| 174 | */ |
| 175 | protected function getPrefixText( WikitextContent $content, Title $title ) { |
| 176 | $arguments = implode( '|', [ |
| 177 | 'from=' . $title->getPrefixedText(), |
| 178 | 'date=' . MWTimestamp::getInstance()->timestamp->format( 'Y-m-d' ), |
| 179 | ] ); |
| 180 | |
| 181 | $template = wfMessage( 'flow-importer-lqt-converted-archive-template' )->inContentLanguage()->plain(); |
| 182 | |
| 183 | return "{{{$template}|$arguments}}\n\n" . self::getDisableLqtMagicWord() . "\n\n"; |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Remove the LQT magic word or its localized version |
| 188 | * @param string $content |
| 189 | * @return string |
| 190 | */ |
| 191 | public static function removeLqtMagicWord( $content ) { |
| 192 | $magicWord = MediaWikiServices::getInstance()->getMagicWordFactory()-> |
| 193 | get( 'useliquidthreads' ); |
| 194 | $patterns = array_map( |
| 195 | // delete any status: enabled or disabled doesn't matter (we're |
| 196 | // adding disabled magic word anyway and having it twice is messy) |
| 197 | static function ( $word ) { |
| 198 | return '/{{\\s*#' . preg_quote( $word ) . ':\\s*[01]*\\s*}}/i'; |
| 199 | }, |
| 200 | [ 'useliquidthreads' ] + $magicWord->getSynonyms() ); |
| 201 | |
| 202 | return preg_replace( $patterns, '', $content ); |
| 203 | } |
| 204 | |
| 205 | /** |
| 206 | * @return string The localized magic word to disable LQT on a page |
| 207 | */ |
| 208 | public static function getDisableLqtMagicWord() { |
| 209 | $wordObj = MediaWikiServices::getInstance()->getMagicWordFactory()-> |
| 210 | get( 'useliquidthreads' ); |
| 211 | $magicWord = strtolower( $wordObj->getSynonym( 0 ) ); |
| 212 | return "{{#$magicWord:0}}"; |
| 213 | } |
| 214 | } |