Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
LqtDispatch
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 8
3422
0.00% covered (danger)
0.00%
0 / 1
 talkpageMain
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
210
 threadPermalinkMain
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
182
 threadSummaryMain
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 isLqtPage
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
132
 getUserLqtOverride
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
56
 tryPage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 onSkinTemplateNavigation
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 onPageContentLanguage
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2
3use MediaWiki\Context\RequestContext;
4use MediaWiki\MediaWikiServices;
5use MediaWiki\Output\OutputPage;
6use MediaWiki\Request\WebRequest;
7use MediaWiki\Title\Title;
8use MediaWiki\User\User;
9
10class LqtDispatch {
11    /** @var (int|null)[] static cache of per-page LiquidThreads activation setting */
12    public static $userLqtOverride = [];
13    /** @var LqtView|null */
14    public static $primaryView = null;
15
16    /**
17     * @param OutputPage &$output
18     * @param Article &$article
19     * @param Title &$title
20     * @param User &$user
21     * @param WebRequest &$request
22     * @return bool
23     */
24    public static function talkpageMain( &$output, &$article, &$title, &$user, &$request ) {
25        // We are given a talkpage article and title. Fire up a TalkpageView
26
27        if ( $title->getNamespace() == NS_LQT_THREAD + 1 /* talk page */ ) {
28            // Threads don't have talk pages; redirect to the thread page.
29            $output->redirect( $title->getSubjectPage()->getLocalURL() );
30            return false;
31        }
32
33        // If we came here from a red-link, redirect to the thread page.
34        $redlink = $request->getCheck( 'redlink' ) &&
35            $request->getText( 'action' ) == 'edit';
36        if ( $redlink ) {
37            $output->redirect( $title->getLocalURL() );
38            return false;
39        }
40
41        $action = $request->getVal( 'action', 'view' );
42
43        // Actions handled by LQT.
44        $lqt_actions = [ 'view', 'protect', 'unprotect' ];
45
46        $lqt_action = $request->getVal( 'lqt_method' );
47        if ( $action == 'edit' && $request->getVal( 'section' ) == 'new' ) {
48            // Hijack section=new for "new thread".
49            $request->setVal( 'lqt_method', 'talkpage_new_thread' );
50            $request->setVal( 'section', '' );
51
52            $viewname = TalkpageView::class;
53        } elseif ( !$lqt_action && (
54            ( !in_array( $action, $lqt_actions ) && $action ) ||
55            $request->getVal( 'diff', null ) !== null ||
56            $request->getVal( 'oldid', null ) !== null )
57        ) {
58            // Pass through wrapper
59            $viewname = TalkpageHeaderView::class;
60        } elseif ( $action == 'protect' || $action == 'unprotect' ) {
61            // Pass through wrapper
62            $viewname = ThreadProtectionFormView::class;
63        } elseif ( $lqt_action == 'talkpage_history' ) {
64            $viewname = TalkpageHistoryView::class;
65        } else {
66            $viewname = TalkpageView::class;
67        }
68
69        Thread::$titleCacheById[$article->getPage()->getId()] = $title;
70
71        /** @var LqtView $view */
72        $view = new $viewname( $output, $article, $title, $user, $request );
73        self::$primaryView = $view;
74        return $view->show();
75    }
76
77    /**
78     * @param OutputPage &$output
79     * @param Article &$article
80     * @param Title &$title
81     * @param User &$user
82     * @param WebRequest &$request
83     * @return bool
84     */
85    public static function threadPermalinkMain( &$output, &$article, &$title, &$user, &$request ) {
86        $action = $request->getVal( 'action' );
87        $lqt_method = $request->getVal( 'lqt_method' );
88
89        if ( $lqt_method == 'thread_history' ) {
90            $viewname = ThreadHistoryListingView::class;
91        } elseif ( $lqt_method == 'diff' ) {
92            // this clause and the next must be in this order.
93            $viewname = ThreadDiffView::class;
94        } elseif ( $action == 'history'
95            || $request->getVal( 'diff', null ) !== null ) {
96            $viewname = IndividualThreadHistoryView::class;
97        } elseif ( $action == 'protect' || $action == 'unprotect' ) {
98            $viewname = ThreadProtectionFormView::class;
99        } elseif ( $request->getVal( 'lqt_oldid', null ) !== null ) {
100            $viewname = ThreadHistoricalRevisionView::class;
101        } elseif ( $action == 'watch' || $action == 'unwatch' ) {
102            $viewname = ThreadWatchView::class;
103        } elseif ( $action == 'delete' || $action == 'rollback' || $action == 'markpatrolled' ) {
104            return true;
105        } else {
106            $viewname = ThreadPermalinkView::class;
107        }
108
109        /** @var LqtView $view */
110        $view = new $viewname( $output, $article, $title, $user, $request );
111        self::$primaryView = $view;
112        return $view->show();
113    }
114
115    public static function threadSummaryMain( &$output, &$article, &$title, &$user, &$request ) {
116        $view = new SummaryPageView( $output, $article, $title, $user, $request );
117        self::$primaryView = $view;
118        return $view->show();
119    }
120
121    /**
122     * @param Title|null $title
123     * @return bool|null
124     */
125    public static function isLqtPage( $title ) {
126        if ( !$title ) {
127            return false;
128        }
129        // Ignore it if it's a thread or a summary, makes no sense to have LiquidThreads there.
130        if ( $title->getNamespace() == NS_LQT_THREAD || $title->getNamespace() == NS_LQT_SUMMARY ) {
131            return false;
132        }
133
134        global $wgLqtPages, $wgLqtTalkPages, $wgLqtNamespaces;
135        $isTalkPage = ( $title->isTalkPage() && $wgLqtTalkPages ) ||
136            in_array( $title->getPrefixedText(), $wgLqtPages );
137
138        if ( in_array( $title->getNamespace(), $wgLqtNamespaces ) ) {
139            $isTalkPage = true;
140        }
141
142        if ( $title->exists() ) {
143            $override = self::getUserLqtOverride( $title );
144        } else {
145            $override = null;
146        }
147
148        global $wgLiquidThreadsAllowUserControl;
149        if ( $override !== null && $wgLiquidThreadsAllowUserControl ) {
150            $isTalkPage = $override;
151        }
152
153        $isTalkPage = $isTalkPage && !$title->isRedirect();
154
155        MediaWikiServices::getInstance()->getHookContainer()
156            ->run( 'LiquidThreadsIsLqtPage', [ $title, &$isTalkPage ] );
157
158        return $isTalkPage;
159    }
160
161    /**
162     * @param Title $title
163     * @return null|int
164     */
165    public static function getUserLqtOverride( $title ) {
166        if ( !is_object( $title ) ) {
167            return null;
168        }
169
170        global $wgLiquidThreadsAllowUserControl;
171
172        if ( !$wgLiquidThreadsAllowUserControl ) {
173            return null;
174        }
175
176        global $wgLiquidThreadsAllowUserControlNamespaces;
177
178        $namespaces = $wgLiquidThreadsAllowUserControlNamespaces;
179
180        if ( $namespaces !== null && !in_array( $title->getNamespace(), $namespaces ) ) {
181            return null;
182        }
183
184        $articleid = $title->getArticleID();
185
186        // Check instance cache.
187        if ( array_key_exists( $articleid, self::$userLqtOverride ) ) {
188            return self::$userLqtOverride[$articleid];
189        }
190
191        // Load from the database.
192        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
193
194        $row = $dbr->newSelectQueryBuilder()
195            ->select( 'pp_value' )
196            ->from( 'page_props' )
197            ->where( [
198                'pp_propname' => 'use-liquid-threads',
199                'pp_page' => $articleid
200            ] )
201            ->caller( __METHOD__ )
202            ->fetchRow();
203
204        if ( $row ) {
205            $dbVal = $row->pp_value;
206
207            self::$userLqtOverride[$articleid] = $dbVal;
208            return $dbVal;
209        } else {
210            // Negative caching.
211            self::$userLqtOverride[$articleid] = null;
212            return null;
213        }
214    }
215
216    /**
217     * If the page we receive is a LiquidThreads page of any kind, process it
218     * as needed and return True. If it's a normal, non-liquid page, return false.
219     * @param OutputPage $output
220     * @param Article $article
221     * @param Title $title
222     * @param User $user
223     * @param WebRequest $request
224     * @return bool
225     */
226    public static function tryPage( $output, $article, $title, $user, $request ) {
227        if ( self::isLqtPage( $title ) ) {
228            // LiquidThreads pages, Talk:X etc
229            return self::talkpageMain( $output, $article, $title, $user, $request );
230        } elseif ( $title->getNamespace() == NS_LQT_THREAD ) {
231            // Thread permalink pages, Thread:X
232            return self::threadPermalinkMain( $output, $article, $title, $user, $request );
233        } elseif ( $title->getNamespace() == NS_LQT_SUMMARY ) {
234            // Summary pages, Summary:X
235            return self::threadSummaryMain( $output, $article, $title, $user, $request );
236        }
237        return true;
238    }
239
240    public static function onSkinTemplateNavigation( $skinTemplate, &$links ) {
241        if ( !self::$primaryView ) {
242            return true;
243        }
244
245        self::$primaryView->customizeNavigation( $skinTemplate, $links );
246
247        return true;
248    }
249
250    /**
251     * Most stuff is in the user language.
252     * @param Title $title
253     * @param Language &$pageLang
254     */
255    public static function onPageContentLanguage( $title, &$pageLang ) {
256        global $wgRequest;
257        $method = $wgRequest->getVal( 'lqt_method' );
258        $oldid = $wgRequest->getVal( 'lqt_oldid' );
259        if ( $title->inNamespace( NS_LQT_THREAD ) ) {
260            $pageLang = RequestContext::getMain()->getLanguage();
261        } elseif ( $method == 'diff' ) {
262            # the diff contains the wikitext, which is in the content language
263            return;
264        } elseif ( $method == 'talkpage_history' || $method == 'thread_history' || $oldid != '' ) {
265            $pageLang = RequestContext::getMain()->getLanguage();
266        }
267    }
268}