PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/extensions/MultilingualLiquidThreads/LiquidThreads/classes/Hooks.php

https://github.com/brion/mediawiki-svn
PHP | 485 lines | 352 code | 104 blank | 29 comment | 59 complexity | 8a24ea4c4d25e35a804ec950afe3b4ba MD5 | raw file
  1. <?php
  2. class LqtHooks {
  3. // Used to inform hooks about edits that are taking place.
  4. public static $editType = null;
  5. public static $editThread = null;
  6. public static $editAppliesTo = null;
  7. public static $editArticle = null;
  8. public static $editTalkpage = null;
  9. static function customizeOldChangesList( &$changeslist, &$s, $rc ) {
  10. if ( $rc->getTitle()->getNamespace() != NS_LQT_THREAD )
  11. return true;
  12. $thread = Threads::withRoot( new Article( $rc->getTitle() ) );
  13. if ( !$thread ) return true;
  14. LqtView::addJSandCSS();
  15. wfLoadExtensionMessages( 'LiquidThreads' );
  16. global $wgUser, $wgLang;
  17. $sk = $wgUser->getSkin();
  18. // Custom display for new posts.
  19. if ( $rc->mAttribs['rc_new'] ) {
  20. global $wgOut;
  21. // Article link, timestamp, user
  22. $s = '';
  23. $s .= $sk->link( $thread->article()->getTitle() );
  24. $changeslist->insertTimestamp( $s, $rc );
  25. $changeslist->insertUserRelatedLinks( $s, $rc );
  26. // Action text
  27. $msg = $thread->isTopmostThread()
  28. ? 'lqt_rc_new_discussion' : 'lqt_rc_new_reply';
  29. $link = LqtView::linkInContext( $thread );
  30. $s .= ' ' . wfMsgExt( $msg, array( 'parseinline', 'replaceafter' ), $link );
  31. // add the truncated post content
  32. $quote = $thread->root()->getContent();
  33. $quote = $wgLang->truncate( $quote, 200 );
  34. $s .= ' ' . $sk->commentBlock( $quote );
  35. $classes = array();
  36. $changeslist->insertTags( $s, $rc, $classes );
  37. $changeslist->insertExtra( $s, $rc, $classes );
  38. }
  39. return true;
  40. }
  41. static function setNewtalkHTML( $skintemplate, $tpl ) {
  42. global $wgUser, $wgTitle, $wgOut;
  43. if ( ! LqtDispatch::isLqtPage( $wgUser->getTalkPage() ) ) {
  44. return true;
  45. }
  46. wfLoadExtensionMessages( 'LiquidThreads' );
  47. $newmsg_t = SpecialPage::getTitleFor( 'NewMessages' );
  48. $watchlist_t = SpecialPage::getTitleFor( 'Watchlist' );
  49. $usertalk_t = $wgUser->getTalkPage();
  50. if ( $wgUser->getNewtalk()
  51. && ! $newmsg_t->equals( $wgTitle )
  52. && ! $watchlist_t->equals( $wgTitle )
  53. && ! $usertalk_t->equals( $wgTitle )
  54. ) {
  55. $s = wfMsgExt( 'lqt_youhavenewmessages', array( 'parseinline' ),
  56. $newmsg_t->getFullURL() );
  57. $tpl->set( "newtalk", $s );
  58. $wgOut->setSquidMaxage( 0 );
  59. } else {
  60. $tpl->set( "newtalk", '' );
  61. }
  62. return true;
  63. }
  64. static function beforeWatchlist( &$conds, &$tables, &$join_conds, &$fields ) {
  65. global $wgOut, $wgUser;
  66. $db = wfGetDB( DB_SLAVE );
  67. if ( !in_array( 'page', $tables ) ) {
  68. $tables[] = 'page';
  69. // Yes, this is the correct field to join to. Weird naming.
  70. $join_conds['page'] = array( 'LEFT JOIN', 'rc_cur_id=page_id' );
  71. }
  72. $conds[] = "page_namespace != " . $db->addQuotes( NS_LQT_THREAD );
  73. $talkpage_messages = NewMessages::newUserMessages( $wgUser );
  74. $tn = count( $talkpage_messages );
  75. $watch_messages = NewMessages::watchedThreadsForUser( $wgUser );
  76. $wn = count( $watch_messages );
  77. if ( $tn == 0 && $wn == 0 )
  78. return true;
  79. LqtView::addJSandCSS();
  80. wfLoadExtensionMessages( 'LiquidThreads' );
  81. $messages_title = SpecialPage::getTitleFor( 'NewMessages' );
  82. $new_messages = wfMsgExt( 'lqt-new-messages', 'parseinline' );
  83. $sk = $wgUser->getSkin();
  84. $link = $sk->link( $messages_title, $new_messages,
  85. array( 'class' => 'lqt_watchlist_messages_notice' ) );
  86. $wgOut->addHTML( $link );
  87. return true;
  88. }
  89. static function getPreferences( $user, &$preferences ) {
  90. global $wgEnableEmail;
  91. wfLoadExtensionMessages( 'LiquidThreads' );
  92. if ( $wgEnableEmail ) {
  93. $preferences['lqtnotifytalk'] =
  94. array(
  95. 'type' => 'toggle',
  96. 'label-message' => 'lqt-preference-notify-talk',
  97. 'section' => 'personal/email'
  98. );
  99. }
  100. $preferences['lqt-watch-threads'] = array(
  101. 'type' => 'toggle',
  102. 'label-message' => 'lqt-preference-watch-threads',
  103. 'section' => 'watchlist/advancedwatchlist',
  104. );
  105. // Display depth and count
  106. $preferences['lqtdisplaydepth'] = array(
  107. 'type' => 'int',
  108. 'label-message' => 'lqt-preference-display-depth',
  109. 'section' => 'lqt',
  110. );
  111. $preferences['lqtdisplaycount'] = array(
  112. 'type' => 'int',
  113. 'label-message' => 'lqt-preference-display-count',
  114. 'section' => 'lqt',
  115. );
  116. return true;
  117. }
  118. static function updateNewtalkOnEdit( $article ) {
  119. $title = $article->getTitle();
  120. if ( LqtDispatch::isLqtPage( $title ) ) {
  121. // They're only editing the header, don't update newtalk.
  122. return false;
  123. }
  124. return true;
  125. }
  126. static function dumpThreadData( $writer, &$out, $row, $title ) {
  127. $editedStati = array(
  128. Threads::EDITED_NEVER => 'never',
  129. Threads::EDITED_HAS_REPLY => 'has-reply',
  130. Threads::EDITED_BY_AUTHOR => 'by-author',
  131. Threads::EDITED_BY_OTHERS => 'by-others'
  132. );
  133. $threadTypes = array(
  134. Threads::TYPE_NORMAL => 'normal',
  135. Threads::TYPE_MOVED => 'moved',
  136. Threads::TYPE_DELETED => 'deleted'
  137. );
  138. // Is it a thread
  139. if ( !empty( $row->thread_id ) ) {
  140. $thread = Thread::newFromRow( $row );
  141. $threadInfo = "\n";
  142. $attribs = array();
  143. $attribs['ThreadSubject'] = $thread->subject();
  144. if ( $thread->hasSuperThread() ) {
  145. $attribs['ThreadParent'] = $thread->superThread()->id();
  146. }
  147. $attribs['ThreadAncestor'] = $thread->topmostThread()->id();
  148. $attribs['ThreadPage'] = $thread->article()->getTitle()->getPrefixedText();
  149. $attribs['ThreadID'] = $thread->id();
  150. if ( $thread->hasSummary() && $thread->summary() ) {
  151. $attribs['ThreadSummaryPage'] = $thread->summary()->getId();
  152. }
  153. $attribs['ThreadAuthor'] = $thread->author()->getName();
  154. $attribs['ThreadEditStatus'] = $editedStati[$thread->editedness()];
  155. $attribs['ThreadType'] = $threadTypes[$thread->type()];
  156. foreach ( $attribs as $key => $value ) {
  157. $threadInfo .= "\t" . Xml::element( $key, null, $value ) . "\n";
  158. }
  159. $out .= Xml::tags( 'DiscussionThreading', null, $threadInfo ) . "\n";
  160. }
  161. return true;
  162. }
  163. static function modifyExportQuery( $db, &$tables, &$cond, &$opts, &$join ) {
  164. $tables[] = 'thread';
  165. $join['thread'] = array( 'left join', array( 'thread_root=page_id' ) );
  166. return true;
  167. }
  168. static function modifyOAIQuery( &$tables, &$fields, &$conds,
  169. &$options, &$join_conds ) {
  170. $tables[] = 'thread';
  171. $join_conds['thread'] = array( 'left join', array( 'thread_root=page_id' ) );
  172. $db = wfGetDB( DB_SLAVE );
  173. $fields[] = $db->tableName( 'thread' ) . '.*';
  174. return true;
  175. }
  176. static function customiseSearchResultTitle( &$title, &$text, $result, $terms, $page ) {
  177. if ( $title->getNamespace() != NS_LQT_THREAD ) {
  178. return true;
  179. }
  180. $thread = Threads::withRoot( new Article( $title ) );
  181. $text = $thread->subject();
  182. $title = clone $thread->topmostThread()->title();
  183. $title->setFragment( '#' . $thread->getAnchorName() );
  184. return true;
  185. }
  186. static function onUserRename( $renameUserSQL ) {
  187. // Always use the job queue, talk page edits will take forever
  188. $renameUserSQL->tablesJob['thread'] =
  189. array( 'thread_author_name', 'thread_author_id', 'thread_modified' );
  190. $renameUserSQL->tablesJob['thread_history'] =
  191. array( 'th_user_text', 'th_user', 'th_timestamp' );
  192. return true;
  193. }
  194. static function editCheckboxes( $editPage, &$checkboxes, &$tabIndex ) {
  195. global $wgRequest;
  196. $article = $editPage->getArticle();
  197. $title = $article->getTitle();
  198. if ( !$article->exists() && $title->getNamespace() == NS_LQT_THREAD ) {
  199. unset( $checkboxes['minor'] );
  200. unset( $checkboxes['watch'] );
  201. }
  202. if ( $title->getNamespace() == NS_LQT_THREAD && self::$editType != 'new' ) {
  203. wfLoadExtensionMessages( 'LiquidThreads' );
  204. $label = wfMsgExt( 'lqt-edit-bump', 'parseinline' );
  205. $tooltip = wfMsgExt( 'lqt-edit-bump-tooltip', 'parsemag' );
  206. $checked = ! $wgRequest->wasPosted() ||
  207. $wgRequest->getBool( 'wpBumpThread' );
  208. $html =
  209. Xml::check( 'wpBumpThread', $checked, array(
  210. 'title' => $tooltip, 'id' => 'wpBumpThread'
  211. ) );
  212. $html .= Xml::tags( 'label', array( 'for' => 'wpBumpThread',
  213. 'title' => $tooltip ), $label );
  214. $checkboxes['bump'] = $html;
  215. }
  216. return true;
  217. }
  218. static function customiseSearchProfiles( &$profiles ) {
  219. wfLoadExtensionMessages( 'LiquidThreads' );
  220. $namespaces = array( NS_LQT_THREAD, NS_LQT_SUMMARY );
  221. // Add odd namespaces
  222. foreach ( SearchEngine::searchableNamespaces() as $ns => $nsName ) {
  223. if ( $ns % 2 == 1 ) {
  224. $namespaces[] = $ns;
  225. }
  226. }
  227. $insert = array(
  228. 'threads' => array(
  229. 'message' => 'searchprofile-threads',
  230. 'tooltip' => 'searchprofile-threads-tooltip',
  231. 'namespaces' => $namespaces,
  232. 'namespace-messages' => SearchEngine::namespacesAsText( $namespaces ),
  233. ),
  234. );
  235. $profiles = wfArrayInsertAfter( $profiles, $insert, 'help' );
  236. return true;
  237. }
  238. public static function onLoadExtensionSchemaUpdates() {
  239. global $wgExtNewTables, $wgExtNewFields, $wgExtPGNewFields,
  240. $wgExtPGAlteredFields, $wgExtNewIndexes;
  241. $dir = realpath( dirname( __FILE__ ) . '/..' );
  242. // DB updates
  243. $wgExtNewTables[] = array( 'thread', "$dir/lqt.sql" );
  244. $wgExtNewTables[] = array( 'user_message_state', "$dir/lqt.sql" );
  245. $wgExtNewTables[] = array( 'thread_history', "$dir/schema-changes/thread_history_table.sql" );
  246. $wgExtNewFields[] = array( "thread", "thread_article_namespace", "$dir/schema-changes/split-thread_article.sql" );
  247. $wgExtNewFields[] = array( "thread", "thread_article_title", "$dir/schema-changes/split-thread_article.sql" );
  248. $wgExtNewFields[] = array( "thread", "thread_ancestor", "$dir/schema-changes/normalise-ancestry.sql" );
  249. $wgExtNewFields[] = array( "thread", "thread_parent", "$dir/schema-changes/normalise-ancestry.sql" );
  250. $wgExtNewFields[] = array( "thread", "thread_modified", "$dir/schema-changes/split-timestamps.sql" );
  251. $wgExtNewFields[] = array( "thread", "thread_created", "$dir/schema-changes/split-timestamps.sql" );
  252. $wgExtNewFields[] = array( "thread", "thread_editedness", "$dir/schema-changes/store-editedness.sql" );
  253. $wgExtNewFields[] = array( "thread", "thread_subject", "$dir/schema-changes/store_subject-author.sql" );
  254. $wgExtNewFields[] = array( "thread", "thread_author_id", "$dir/schema-changes/store_subject-author.sql" );
  255. $wgExtNewFields[] = array( "thread", "thread_author_name", "$dir/schema-changes/store_subject-author.sql" );
  256. $wgExtNewFields[] = array( "thread", "thread_sortkey", "$dir/schema-changes/new-sortkey.sql" );
  257. $wgExtNewFields[] = array( 'thread', 'thread_replies', "$dir/schema-changes/store_reply_count.sql" );
  258. $wgExtNewFields[] = array( 'thread', 'thread_article_id', "$dir/schema-changes/store_article_id.sql" );
  259. $wgExtNewFields[] = array( 'thread', 'thread_signature', "$dir/schema-changes/thread_signature.sql" );
  260. $wgExtNewIndexes[] = array( 'thread', 'thread_summary_page', '(thread_summary_page)' );
  261. return true;
  262. }
  263. static function onArticleMoveComplete( &$form, &$ot, &$nt ) {
  264. // Check if it's a talk page.
  265. if ( !LqtDispatch::isLqtPage( $ot ) && !LqtDispatch::isLqtPage( $nt ) ) {
  266. return true;
  267. }
  268. // Synchronise the first 500 threads, in reverse order by thread id. If
  269. // there are more threads to synchronise, the job queue will take over.
  270. Threads::synchroniseArticleData( new Article( $nt ), 500, 'cascade' );
  271. return true;
  272. }
  273. static function onArticleMove( $ot, $nt, $user, &$err, $reason ) {
  274. // Synchronise article data so that moving the article doesn't break any
  275. // article association.
  276. Threads::synchroniseArticleData( new Article( $ot ) );
  277. return true;
  278. }
  279. static function userIsBlockedFrom( $user, $title, &$isBlocked, &$allowUserTalk ) {
  280. // Limit applicability
  281. if ( !( $isBlocked && $allowUserTalk && $title->getNamespace() == NS_LQT_THREAD ) ) {
  282. return true;
  283. }
  284. // Now we're dealing with blocked users with user talk editing allowed editing pages
  285. // in the thread namespace.
  286. if ( $title->exists() ) {
  287. // If the page actually exists, allow the user to edit posts on their own talk page.
  288. $thread = Threads::withRoot( new Article( $title ) );
  289. if ( !$thread )
  290. return true;
  291. $articleTitle = $thread->article()->getTitle();
  292. if ( $articleTitle->getNamespace() == NS_USER_TALK &&
  293. $user->getName() == $title->getText() ) {
  294. $isBlocked = false;
  295. return true;
  296. }
  297. } else {
  298. // Otherwise, it's a bit trickier. Allow creation of thread titles prefixed by the
  299. // user's talk page.
  300. // Figure out if it's on the talk page
  301. $talkPage = $user->getTalkPage();
  302. $isOnTalkPage = ( self::$editThread &&
  303. self::$editThread->article()->getTitle()->equals( $talkPage ) );
  304. $isOnTalkPage = $isOnTalkPage || ( self::$editAppliesTo &&
  305. self::$editAppliesTo->article()->getTitle()->equals( $talkPage ) );
  306. $isOnTalkPage = $isOnTalkPage ||
  307. ( self::$editArticle->getTitle()->equals( $talkPage ) );
  308. if ( self::$editArticle->getTitle()->equals( $title ) && $isOnTalkPage ) {
  309. $isBlocked = false;
  310. return true;
  311. }
  312. }
  313. return true;
  314. }
  315. static function onPersonalUrls( &$personal_urls, &$title ) {
  316. global $wgUser, $wgLang;
  317. if ( $wgUser->isAnon() ) return true;
  318. wfLoadExtensionMessages( 'LiquidThreads' );
  319. $dbr = wfGetDB( DB_SLAVE );
  320. $newMessagesCount = NewMessages::newMessageCount( $wgUser );
  321. // Add new messages link.
  322. $url = SpecialPage::getTitleFor( 'NewMessages' )->getLocalURL();
  323. $msg = $newMessagesCount ? 'lqt-newmessages-n' : 'lqt_newmessages';
  324. $newMessagesLink = array(
  325. 'href' => $url,
  326. 'text' => wfMsg( $msg, $wgLang->formatNum( $newMessagesCount ) ),
  327. 'active' => $newMessagesCount > 0,
  328. );
  329. $insertUrls = array( 'newmessages' => $newMessagesLink );
  330. $personal_urls = wfArrayInsertAfter( $personal_urls, $insertUrls, 'watchlist' );
  331. return true;
  332. }
  333. static function onArticleSaveComplete( &$article, &$user, $text, $summary,
  334. $minoredit, $watchthis, $sectionanchor, &$flags, $revision,
  335. &$status, $baseRevId ) {
  336. if ( !$status->isGood() ) {
  337. // Failed
  338. return true;
  339. }
  340. $title = $article->getTitle();
  341. if ( $title->getNamespace() != NS_LQT_THREAD ) {
  342. // Not a thread
  343. return true;
  344. }
  345. if ( !$baseRevId ) {
  346. // New page
  347. return true;
  348. }
  349. $thread = Threads::withRoot( $article );
  350. if ( !$thread ) {
  351. // No matching thread.
  352. return true;
  353. }
  354. LqtView::postEditUpdates(
  355. 'editExisting',
  356. null,
  357. $article,
  358. $thread->article(),
  359. $thread->article(),
  360. $summary,
  361. $thread,
  362. $text
  363. );
  364. return true;
  365. }
  366. static function getProtectionTypes( $title, &$types ) {
  367. $isLqtPage = LqtDispatch::isLqtPage( $title );
  368. $isThread = $title->getNamespace() == NS_LQT_THREAD;
  369. if ( !$isLqtPage && !$isThread ) {
  370. return true;
  371. }
  372. if ( $isLqtPage ) {
  373. $types[] = 'newthread';
  374. $types[] = 'reply';
  375. }
  376. if ( $isThread ) {
  377. $types[] = 'reply';
  378. }
  379. return true;
  380. }
  381. }