PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/CollabWatchlist/includes/SpecialCollabWatchlist.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 605 lines | 421 code | 62 blank | 122 comment | 80 complexity | b138742ad6c2ad3518c6c759eb1d33df MD5 | raw file
  1. <?php
  2. /**
  3. * Implements Special:CollabWatchlist
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. * @file
  21. * @ingroup SpecialPage CollabWatchlist
  22. */
  23. class SpecialCollabWatchlist extends SpecialWatchlist {
  24. /**
  25. * Constructor
  26. */
  27. public function __construct() {
  28. //XXX That's nasty, SpecialWatchlist should have a corresponding constructor,
  29. // or expose the methods we need publicly
  30. SpecialPage::__construct( 'CollabWatchlist' );
  31. }
  32. /**
  33. * Main execution point
  34. *
  35. * @param $par Parameter passed to the page
  36. */
  37. function execute( $par ) {
  38. global $wgUser, $wgOut, $wgLang, $wgRequest;
  39. global $wgRCShowWatchingUsers;
  40. global $wgEnotifWatchlist;
  41. // Add feed links
  42. $wlToken = $wgUser->getOption( 'watchlisttoken' );
  43. if ( !$wlToken ) {
  44. $wlToken = sha1( mt_rand() . microtime( true ) );
  45. $wgUser->setOption( 'watchlisttoken', $wlToken );
  46. $wgUser->saveSettings();
  47. }
  48. global $wgFeedClasses;
  49. $apiParams = array( 'action' => 'feedwatchlist', 'allrev' => 'allrev',
  50. 'wlowner' => $wgUser->getName(), 'wltoken' => $wlToken );
  51. $feedTemplate = wfScript( 'api' ) . '?';
  52. foreach ( $wgFeedClasses as $format => $class ) {
  53. $theseParams = $apiParams + array( 'feedformat' => $format );
  54. $url = $feedTemplate . wfArrayToCGI( $theseParams );
  55. $wgOut->addFeedLink( $format, $url );
  56. }
  57. $skin = $wgUser->getSkin();
  58. $specialTitle = SpecialPage::getTitleFor( 'CollabWatchlist' );
  59. $wgOut->setRobotPolicy( 'noindex,nofollow' );
  60. # Anons don't get a watchlist
  61. if ( $wgUser->isAnon() ) {
  62. $wgOut->setPageTitle( wfMsg( 'watchnologin' ) );
  63. $llink = $skin->linkKnown(
  64. SpecialPage::getTitleFor( 'Userlogin' ),
  65. wfMsgHtml( 'loginreqlink' ),
  66. array(),
  67. array( 'returnto' => $specialTitle->getPrefixedText() )
  68. );
  69. $wgOut->addHTML( wfMsgWikiHtml( 'watchlistanontext', $llink ) );
  70. return;
  71. }
  72. $wgOut->setPageTitle( wfMsg( 'collabwatchlist' ) );
  73. $listIdsAndNames = CollabWatchlistChangesList::getCollabWatchlistIdAndName( $wgUser->getId() );
  74. $sub = wfMsgExt(
  75. 'watchlistfor2',
  76. array( 'parseinline', 'replaceafter' ),
  77. $wgUser->getName(),
  78. ''
  79. );
  80. $sub .= '<br />' . CollabWatchlistEditor::buildTools( $listIdsAndNames, $wgUser->getSkin() );
  81. $wgOut->setSubtitle( $sub );
  82. $uid = $wgUser->getId();
  83. // The filter form has one checkbox for each tag, build an array
  84. $postValues = $wgRequest->getValues();
  85. $tagFilter = array();
  86. foreach ( $postValues as $key => $value ) {
  87. if ( stripos( $key, 'collaborative-watchlist-filtertag-' ) === 0 ) {
  88. $tagFilter[] = $postValues[$key];
  89. }
  90. }
  91. // Alternative syntax for requests from links (show / hide ...)
  92. if ( empty( $tagFilter ) ) {
  93. $tagFilter = explode( '|', $wgRequest->getVal( 'filterTags' ) );
  94. }
  95. $defaults = array(
  96. /* float */ 'days' => floatval( $wgUser->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */
  97. /* bool */ 'hideMinor' => (int)$wgUser->getBoolOption( 'watchlisthideminor' ),
  98. /* bool */ 'hideBots' => (int)$wgUser->getBoolOption( 'watchlisthidebots' ),
  99. /* bool */ 'hideAnons' => (int)$wgUser->getBoolOption( 'watchlisthideanons' ),
  100. /* bool */ 'hideLiu' => (int)$wgUser->getBoolOption( 'watchlisthideliu' ),
  101. /* bool */ 'hideListUser' => (int)$wgUser->getBoolOption( 'collabwatchlisthidelistuser' ),
  102. /* bool */ 'hidePatrolled' => (int)$wgUser->getBoolOption( 'watchlisthidepatrolled' ),
  103. /* bool */ 'hideOwn' => (int)$wgUser->getBoolOption( 'watchlisthideown' ),
  104. /* int */ 'collabwatchlist' => 0,
  105. /* ? */ 'globalwatch' => 'all',
  106. /* ? */ 'invert' => false,
  107. /* ? */ 'invertTags' => false,
  108. /* ? */ 'filterTags' => '',
  109. );
  110. extract( $defaults );
  111. # Extract variables from the request, falling back to user preferences or
  112. # other default values if these don't exist
  113. $prefs['days'] = floatval( $wgUser->getOption( 'watchlistdays' ) );
  114. $prefs['hideminor'] = $wgUser->getBoolOption( 'watchlisthideminor' );
  115. $prefs['hidebots'] = $wgUser->getBoolOption( 'watchlisthidebots' );
  116. $prefs['hideanons'] = $wgUser->getBoolOption( 'watchlisthideanon' );
  117. $prefs['hideliu'] = $wgUser->getBoolOption( 'watchlisthideliu' );
  118. $prefs['hideown' ] = $wgUser->getBoolOption( 'watchlisthideown' );
  119. $prefs['hidelistuser'] = $wgUser->getBoolOption( 'collabwatchlisthidelistuser' );
  120. $prefs['hidepatrolled' ] = $wgUser->getBoolOption( 'watchlisthidepatrolled' );
  121. $prefs['invertTags' ] = $wgUser->getBoolOption( 'collabwatchlistinverttags' );
  122. $prefs['filterTags' ] = $wgUser->getOption( 'collabwatchlistfiltertags' );
  123. # Get query variables
  124. $days = $wgRequest->getVal( 'days' , $prefs['days'] );
  125. $hideMinor = $wgRequest->getBool( 'hideMinor', $prefs['hideminor'] );
  126. $hideBots = $wgRequest->getBool( 'hideBots' , $prefs['hidebots'] );
  127. $hideAnons = $wgRequest->getBool( 'hideAnons', $prefs['hideanons'] );
  128. $hideLiu = $wgRequest->getBool( 'hideLiu' , $prefs['hideliu'] );
  129. $hideOwn = $wgRequest->getBool( 'hideOwn' , $prefs['hideown'] );
  130. $hideListUser = $wgRequest->getBool( 'hideListUser', $prefs['hidelistuser'] );
  131. $hidePatrolled = $wgRequest->getBool( 'hidePatrolled' , $prefs['hidepatrolled'] );
  132. $filterTags = implode( '|', $tagFilter );
  133. $invertTags = $wgRequest->getBool( 'invertTags' , $prefs['invertTags'] );
  134. # Get collabwatchlist value, if supplied, and prepare a WHERE fragment
  135. $collabWatchlist = $wgRequest->getIntOrNull( 'collabwatchlist' );
  136. if ( !is_null( $collabWatchlist ) && $collabWatchlist !== 'all' ) {
  137. $collabWatchlist = intval( $collabWatchlist );
  138. }
  139. if ( array_key_exists( $collabWatchlist, $listIdsAndNames ) ) {
  140. $wgOut->addHTML( Xml::element( 'h2', null, $listIdsAndNames[$collabWatchlist] ) );
  141. }
  142. if ( ( $mode = CollabWatchlistEditor::getMode( $wgRequest, $par ) ) !== false ) {
  143. $editor = new CollabWatchlistEditor();
  144. $editor->execute( $collabWatchlist, $listIdsAndNames, $wgOut, $wgRequest, $mode );
  145. return;
  146. }
  147. if ( !$collabWatchlist )
  148. return;
  149. $dbr = wfGetDB( DB_SLAVE, 'watchlist' );
  150. $recentchanges = $dbr->tableName( 'recentchanges' );
  151. $nitems = $dbr->selectField( 'collabwatchlistcategory', 'COUNT(*)',
  152. $collabWatchlist == 0 ? array() : array( 'rl_id' => $collabWatchlist
  153. ), __METHOD__ );
  154. if ( $nitems == 0 ) {
  155. $wgOut->addWikiMsg( 'nowatchlist' );
  156. return;
  157. }
  158. // Dump everything here
  159. $nondefaults = array();
  160. wfAppendToArrayIfNotDefault( 'days' , $days , $defaults, $nondefaults );
  161. wfAppendToArrayIfNotDefault( 'hideMinor', (int)$hideMinor, $defaults, $nondefaults );
  162. wfAppendToArrayIfNotDefault( 'hideBots' , (int)$hideBots , $defaults, $nondefaults );
  163. wfAppendToArrayIfNotDefault( 'hideAnons', (int)$hideAnons, $defaults, $nondefaults );
  164. wfAppendToArrayIfNotDefault( 'hideLiu' , (int)$hideLiu , $defaults, $nondefaults );
  165. wfAppendToArrayIfNotDefault( 'hideOwn' , (int)$hideOwn , $defaults, $nondefaults );
  166. wfAppendToArrayIfNotDefault( 'hideListUser', (int)$hideListUser, $defaults, $nondefaults );
  167. wfAppendToArrayIfNotDefault( 'collabwatchlist', $collabWatchlist, $defaults, $nondefaults );
  168. wfAppendToArrayIfNotDefault( 'hidePatrolled', (int)$hidePatrolled, $defaults, $nondefaults );
  169. wfAppendToArrayIfNotDefault( 'filterTags', $filterTags , $defaults, $nondefaults );
  170. wfAppendToArrayIfNotDefault( 'invertTags', $invertTags , $defaults, $nondefaults );
  171. if ( $days <= 0 ) {
  172. $andcutoff = '';
  173. } else {
  174. $andcutoff = "rc_timestamp > '" . $dbr->timestamp( time() - intval( $days * 86400 ) ) . "'";
  175. }
  176. # If the watchlist is relatively short, it's simplest to zip
  177. # down its entirety and then sort the results.
  178. # If it's relatively long, it may be worth our while to zip
  179. # through the time-sorted page list checking for watched items.
  180. # Up estimate of watched items by 15% to compensate for talk pages...
  181. # Toggles
  182. $andHideOwn = $hideOwn ? "rc_user != $uid" : '';
  183. $andHideBots = $hideBots ? "rc_bot = 0" : '';
  184. $andHideMinor = $hideMinor ? "rc_minor = 0" : '';
  185. $andHideLiu = $hideLiu ? "rc_user = 0" : '';
  186. $andHideAnons = $hideAnons ? "rc_user != 0" : '';
  187. $andHideListUser = $hideListUser ? $this->wlGetFilterClauseListUser( $collabWatchlist ) : '';
  188. $andHidePatrolled = $wgUser->useRCPatrol() && $hidePatrolled ? "rc_patrolled != 1" : '';
  189. # Toggle watchlist content (all recent edits or just the latest)
  190. if ( $wgUser->getOption( 'extendwatchlist' ) ) {
  191. $andLatest = '';
  192. $limitWatchlist = intval( $wgUser->getOption( 'wllimit' ) );
  193. $usePage = false;
  194. } else {
  195. # Top log Ids for a page are not stored
  196. $andLatest = 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG;
  197. $limitWatchlist = 0;
  198. $usePage = true;
  199. }
  200. # Show a message about slave lag, if applicable
  201. $lag = wfGetLB()->safeGetLag( $dbr );
  202. if ( $lag > 0 )
  203. $wgOut->showLagWarning( $lag );
  204. # Create output form
  205. $form = Xml::fieldset( wfMsg( 'watchlist-options' ), false, array( 'id' => 'mw-watchlist-options' ) );
  206. # Show watchlist header
  207. $form .= wfMsgExt( 'collabwatchlist-details', array( 'parseinline' ), $wgLang->formatNum( $nitems ) );
  208. if ( $wgUser->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist ) {
  209. $form .= wfMsgExt( 'wlheader-enotif', 'parse' ) . "\n";
  210. }
  211. $form .= '<hr />';
  212. $tables = array( 'recentchanges', 'categorylinks' );
  213. $fields = array( "{$recentchanges}.*" );
  214. $categoryClause = $this->wlGetFilterClauseForCollabWatchlistIds( $collabWatchlist, 'cl_to', 'rc_cur_id' );
  215. // If this collaborative watchlist does not contain any categories, add a clause which gives
  216. // us an empty result
  217. $conds = isset( $categoryClause ) ? array( $categoryClause ) : array( 'false' );
  218. $join_conds = array(
  219. 'categorylinks' => array( 'LEFT OUTER JOIN', "rc_cur_id=cl_from" ),
  220. );
  221. if ( !empty( $tagFilter ) ) {
  222. // The tag filter causes a query runtime of O(MxN), where M is relative to the number
  223. // of recentchanges we select (from a table which is purged periodically, limited to 250)
  224. // and N is relative the number of change_tag entries for a recentchange. Doing it
  225. // the other way around (selecting from change_tag first, is probably slower, as the
  226. // change_tag table is never purged.
  227. // Using the tag_summary table for filtering is difficult, at least I have been unable to
  228. // find a common SQL compliant way for using regular expressions which works across Postgre / Mysql
  229. // Furthermore, ChangeTags does not seem to prevent tags containing ',' from being set,
  230. // which renders tag_summary quite unusable
  231. if ( $invertTags ) {
  232. $filter = 'EXISTS ';
  233. } else {
  234. $filter = 'NOT EXISTS ';
  235. }
  236. $filter .= '(SELECT cwlrt.ct_rc_id FROM collabwatchlistrevisiontag cwlrt
  237. WHERE cwlrt.ct_rc_id = recentchanges.rc_id AND cwlrt.ct_tag ';
  238. if ( count( $tagFilter ) > 1 )
  239. $filter .= 'IN (' . $dbr->makeList( $tagFilter ) . '))';
  240. else
  241. $filter .= ' = ' . $dbr->addQuotes( current( $tagFilter ) ) . ')';
  242. $conds[] = $filter;
  243. }
  244. $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
  245. if ( $limitWatchlist ) {
  246. $options['LIMIT'] = $limitWatchlist;
  247. }
  248. if ( $andcutoff ) $conds[] = $andcutoff;
  249. if ( $andLatest ) $conds[] = $andLatest;
  250. if ( $andHideOwn ) $conds[] = $andHideOwn;
  251. if ( $andHideBots ) $conds[] = $andHideBots;
  252. if ( $andHideMinor ) $conds[] = $andHideMinor;
  253. if ( $andHideLiu ) $conds[] = $andHideLiu;
  254. if ( $andHideAnons ) $conds[] = $andHideAnons;
  255. if ( $andHideListUser ) $conds[] = $andHideListUser;
  256. if ( $andHidePatrolled ) $conds[] = $andHidePatrolled;
  257. $rollbacker = $wgUser->isAllowed( 'rollback' );
  258. if ( $usePage || $rollbacker ) {
  259. $tables[] = 'page';
  260. $join_conds['page'] = array( 'LEFT JOIN', 'rc_cur_id=page.page_id' );
  261. if ( $rollbacker )
  262. $fields[] = 'page_latest';
  263. }
  264. ChangeTags::modifyDisplayQuery( $tables, $fields, $conds, $join_conds, $options, '' );
  265. wfRunHooks( 'SpecialCollabWatchlistQuery', array( &$conds, &$tables, &$join_conds, &$fields ) );
  266. $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options, $join_conds );
  267. $numRows = $dbr->numRows( $res );
  268. /* Start bottom header */
  269. $wlInfo = '';
  270. if ( $days >= 1 ) {
  271. $wlInfo = wfMsgExt( 'rcnote', 'parseinline',
  272. $wgLang->formatNum( $numRows ),
  273. $wgLang->formatNum( $days ),
  274. $wgLang->timeAndDate( wfTimestampNow(), true ),
  275. $wgLang->date( wfTimestampNow(), true ),
  276. $wgLang->time( wfTimestampNow(), true )
  277. ) . '<br />';
  278. } elseif ( $days > 0 ) {
  279. $wlInfo = wfMsgExt( 'wlnote', 'parseinline',
  280. $wgLang->formatNum( $numRows ),
  281. $wgLang->formatNum( round( $days * 24 ) )
  282. ) . '<br />';
  283. }
  284. $cutofflinks = "\n" . $this->cutoffLinks( $days, 'CollabWatchlist', $nondefaults ) . "<br />\n";
  285. $thisTitle = SpecialPage::getTitleFor( 'CollabWatchlist' );
  286. # Spit out some control panel links
  287. $links[] = $this->showHideLink( $nondefaults, 'rcshowhideminor', 'hideMinor', $hideMinor );
  288. $links[] = $this->showHideLink( $nondefaults, 'rcshowhidebots', 'hideBots', $hideBots );
  289. $links[] = $this->showHideLink( $nondefaults, 'rcshowhideanons', 'hideAnons', $hideAnons );
  290. $links[] = $this->showHideLink( $nondefaults, 'rcshowhideliu', 'hideLiu', $hideLiu );
  291. $links[] = $this->showHideLink( $nondefaults, 'rcshowhidemine', 'hideOwn', $hideOwn );
  292. $links[] = $this->showHideLink( $nondefaults, 'collabwatchlistshowhidelistusers', 'hideListUser', $hideListUser );
  293. if ( $wgUser->useRCPatrol() ) {
  294. $links[] = $this->showHideLink( $nondefaults, 'rcshowhidepatr', 'hidePatrolled', $hidePatrolled );
  295. }
  296. # Namespace filter and put the whole form together.
  297. $form .= $wlInfo;
  298. $form .= $cutofflinks;
  299. $form .= $wgLang->pipeList( $links );
  300. $form .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $thisTitle->getLocalUrl() ) );
  301. $form .= '<hr /><p>';
  302. $tagsAndInfo = CollabWatchlistChangesList::getValidTagsAndInfo( array_keys( $listIdsAndNames ) );
  303. if ( count( $tagsAndInfo ) > 0 ) {
  304. $form .= wfMsg( 'collabwatchlistfiltertags' ) . ':&nbsp;&nbsp;';
  305. }
  306. foreach ( $tagsAndInfo as $tag => $tagInfo ) {
  307. $tagAttr = array(
  308. 'name' => 'collaborative-watchlist-filtertag-' . $tag,
  309. 'type' => 'checkbox',
  310. 'value' => $tag );
  311. if ( in_array( $tag, $tagFilter ) ) {
  312. $tagAttr['checked'] = 'checked';
  313. }
  314. $form .= Xml::element( 'input', $tagAttr ) . '&nbsp;' . Xml::label( $tag, 'collaborative-watchlist-filtertag-' . $tag ) . '&nbsp;';
  315. }
  316. if ( count( $tagsAndInfo ) > 0 ) {
  317. $form .= '<br />';
  318. }
  319. $form .= Xml::checkLabel( wfMsg( 'collabwatchlistinverttags' ), 'invertTags', 'nsinvertTags', $invertTags ) . '<br />';
  320. $form .= CollabWatchlistChangesList::collabWatchlistSelector( $listIdsAndNames, $collabWatchlist, '', 'collabwatchlist', wfMsg( 'collabwatchlist' ) ) . '&nbsp;';
  321. $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . '</p>';
  322. $form .= Html::hidden( 'days', $days );
  323. if ( $hideMinor )
  324. $form .= Html::hidden( 'hideMinor', 1 );
  325. if ( $hideBots )
  326. $form .= Html::hidden( 'hideBots', 1 );
  327. if ( $hideAnons )
  328. $form .= Html::hidden( 'hideAnons', 1 );
  329. if ( $hideLiu )
  330. $form .= Html::hidden( 'hideLiu', 1 );
  331. if ( $hideOwn )
  332. $form .= Html::hidden( 'hideOwn', 1 );
  333. if ( $hideListUser )
  334. $form .= Html::hidden( 'hideListUser', 1 );
  335. if ( $wgUser->useRCPatrol() )
  336. if ( $hidePatrolled )
  337. $form .= Html::hidden( 'hidePatrolled', 1 );
  338. $form .= Xml::closeElement( 'form' );
  339. $form .= Xml::closeElement( 'fieldset' );
  340. $wgOut->addHTML( $form );
  341. # If there's nothing to show, stop here
  342. if ( $numRows == 0 ) {
  343. $wgOut->addWikiMsg( 'watchnochange' );
  344. return;
  345. }
  346. /* End bottom header */
  347. /* Do link batch query */
  348. $linkBatch = new LinkBatch;
  349. foreach ( $res as $row ) {
  350. $userNameUnderscored = str_replace( ' ', '_', $row->rc_user_text );
  351. if ( $row->rc_user != 0 ) {
  352. $linkBatch->add( NS_USER, $userNameUnderscored );
  353. }
  354. $linkBatch->add( NS_USER_TALK, $userNameUnderscored );
  355. $linkBatch->add( $row->rc_namespace, $row->rc_title );
  356. }
  357. $linkBatch->execute();
  358. $dbr->dataSeek( $res, 0 );
  359. $list = CollabWatchlistChangesList::newFromUser( $wgUser );
  360. $list->setWatchlistDivs();
  361. $s = $list->beginRecentChangesList();
  362. $counter = 1;
  363. foreach ( $res as $obj ) {
  364. # Make RC entry
  365. $rc = RecentChange::newFromRow( $obj );
  366. $rc->counter = $counter++;
  367. if ( $wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' ) ) {
  368. $rc->numberofWatchingusers = $dbr->selectField( 'watchlist',
  369. 'COUNT(*)',
  370. array(
  371. 'wl_namespace' => $obj->rc_namespace,
  372. 'wl_title' => $obj->rc_title,
  373. ),
  374. __METHOD__ );
  375. } else {
  376. $rc->numberofWatchingusers = 0;
  377. }
  378. $tags = $this->wlTagsForRevision( $obj->rc_this_oldid, array( $collabWatchlist ) );
  379. // if( isset($tags) ) {
  380. // // Filter recentchanges which contain unwanted tags
  381. // $tagNames = array();
  382. // foreach($tags as $tagInfo) {
  383. // $tagNames[] = $tagInfo['ct_tag'];
  384. // }
  385. // $unwantedTagsFound = array_intersect($tagFilter, $tagNames);
  386. // if( !empty($unwantedTagsFound) )
  387. // continue;
  388. // }
  389. $attrs = $rc->getAttributes();
  390. $attrs['collabwatchlist_tags'] = $tags;
  391. $rc->setAttribs( $attrs );
  392. $s .= $list->recentChangesLine( $rc, false, $counter );
  393. }
  394. $s .= $list->endRecentChangesList();
  395. $dbr->freeResult( $res );
  396. $wgOut->addHTML( $s );
  397. }
  398. /**
  399. * Returns html
  400. *
  401. * @return string
  402. */
  403. protected function cutoffLinks( $days, $page = 'Watchlist', $options = array() ) {
  404. return SpecialWatchlist::cutoffLinks( $days, $page, $options );
  405. }
  406. /** Returns an array of maps representing collab watchlist tags. The following fields are present
  407. * in each map:
  408. * - rl_id Id of the collaborative watchlist
  409. * - ct_tag Name of the tag
  410. * - collabwatchlistrevisiontag.user_id User which set the tag
  411. * - user_name Username of the user which set the tag
  412. * - rrt_comment Collabwatchlist tag comment
  413. * @param $rev_id
  414. * @param $rl_ids
  415. * @return unknown_type
  416. */
  417. function wlTagsForRevision( $rev_id, $rl_ids = array(), $filterTags = array() ) {
  418. // Some DB stuff
  419. $dbr = wfGetDB( DB_SLAVE );
  420. $cond = array();
  421. if ( isset( $rl_ids ) && !( count( $rl_ids ) == 1 && $rl_ids[0] == 0 ) ) {
  422. $cond = array( "rl_id" => $rl_ids );
  423. }
  424. if ( isset( $filterTags ) && count( $filterTags ) > 0 ) {
  425. $cond[] = "ct_tag not in (" . $dbr->makeList( $filterTags ) . ")";
  426. }
  427. // $table, $vars, $conds='', $fname = 'Database::select', $options = array(), $join_conds = array()
  428. $res = $dbr->select( array( 'change_tag', 'collabwatchlistrevisiontag', 'user' ), # Tables
  429. array( 'rl_id', 'collabwatchlistrevisiontag.ct_tag', 'collabwatchlistrevisiontag.user_id', 'user_name', 'rrt_comment' ), # Fields
  430. array( 'change_tag.ct_rev_id' => $rev_id ) + $cond, # Conditions
  431. __METHOD__, array(),
  432. # Join conditions
  433. array( 'collabwatchlistrevisiontag' => array( 'JOIN', 'change_tag.ct_rc_id = collabwatchlistrevisiontag.ct_rc_id AND change_tag.ct_tag = collabwatchlistrevisiontag.ct_tag' ),
  434. 'user' => array( 'JOIN', 'collabwatchlistrevisiontag.user_id = user.user_id' )
  435. )
  436. );
  437. $tags = array();
  438. foreach ( $res as $row ) {
  439. $tags[] = get_object_vars( $row );
  440. }
  441. return $tags;
  442. }
  443. /**
  444. * Constructs the filter SQL clause for the given collaborative watchlist ids.
  445. * It filters entries which are not relevant for the given watchlists. I.e.
  446. * entries which don't belong to a category and are not listed explicitly as a
  447. * page for one of the given watchlists.
  448. * @param $rl_ids Array: A list of collaborative watchlist ids
  449. * @param $catNameCol String: The name of the column containing category names
  450. * @param $pageIdCol String: The name of the column containing page ids
  451. * @return String: An SQL clause usable in the conditions parameter of $db->select()
  452. */
  453. function wlGetFilterClauseForCollabWatchlistIds( $rl_ids, $catNameCol, $pageIdCol ) {
  454. global $wgCollabWatchlistRecursiveCatScan;
  455. $excludedCatPageIds = array();
  456. $includedCatPageIds = array();
  457. $includedPageIds = array();
  458. $dbr = wfGetDB( DB_SLAVE );
  459. $res = $dbr->select( array( 'collabwatchlist', 'collabwatchlistcategory', 'page' ), # Tables
  460. array( 'cat_page_id', 'page_title', 'page_namespace', 'subtract' ), # Fields
  461. $rl_ids != 0 ? array( 'collabwatchlist.rl_id' => $rl_ids ) : array(), # Conditions
  462. __METHOD__, array(),
  463. # Join conditions
  464. array( 'collabwatchlistcategory' => array( 'JOIN', 'collabwatchlist.rl_id = collabwatchlistcategory.rl_id' ),
  465. 'page' => array( 'JOIN', 'page.page_id = collabwatchlistcategory.cat_page_id' ) )
  466. );
  467. foreach ( $res as $row ) {
  468. if ( $row->page_namespace == NS_CATEGORY ) {
  469. if ( $row->subtract ) {
  470. $excludedCatPageIds[$row->cat_page_id] = $row->page_title;
  471. } else {
  472. $includedCatPageIds[$row->cat_page_id] = $row->page_title;
  473. }
  474. } else {
  475. $includedPageIds[$row->cat_page_id] = $row->page_title;
  476. }
  477. }
  478. if ( $wgCollabWatchlistRecursiveCatScan && $includedCatPageIds ) {
  479. $catTree = new CategoryTreeManip();
  480. $catTree->setMaxDepth($wgCollabWatchlistRecursiveCatScan);
  481. $catTree->initialiseFromCategoryNames( array_values( $includedCatPageIds ) );
  482. $catTree->disableCategoryIds( array_keys( $excludedCatPageIds ) );
  483. $enabledCategoryNames = $catTree->getEnabledCategoryNames();
  484. if ( empty( $enabledCategoryNames ) )
  485. return;
  486. $collabWatchlistClause = '(' . $catNameCol . " IN (" . implode( ',', $this->addQuotes( $dbr, $enabledCategoryNames ) ) . ") ";
  487. if ( !empty( $includedPageIds ) ) {
  488. $collabWatchlistClause .= ' OR ' . $pageIdCol . ' IN (' . implode( ',', $this->addQuotes( $dbr, array_keys( $includedPageIds ) ) ) . ')';
  489. }
  490. $collabWatchlistClause .= ')';
  491. } else if ( !empty( $includedPageIds ) ) {
  492. $collabWatchlistClause = $pageIdCol . ' IN (' . implode( ',', $this->addQuotes( $dbr, array_keys( $includedPageIds ) ) ) . ')';
  493. }
  494. return $collabWatchlistClause;
  495. }
  496. /**
  497. * Constructs the user filter SQL clause for the given collaborative watchlist ids.
  498. * It filters entries from the users of the given watchlists.
  499. * @param $rl_ids Array: A list of collaborative watchlist ids
  500. * @return String: An SQL clause usable in the conditions parameter of $db->select()
  501. */
  502. function wlGetFilterClauseListUser( $rl_id ) {
  503. $excludedUserIds = array();
  504. $dbr = wfGetDB( DB_SLAVE );
  505. $res = $dbr->select( 'collabwatchlistuser', # Tables
  506. 'user_id', # Fields
  507. array( 'collabwatchlistuser.rl_id' => $rl_id ) # Conditions
  508. );
  509. $clause = '';
  510. foreach ( $res as $row ) {
  511. $excludedUserIds[] = $row->user_id;
  512. }
  513. if ( $res->numRows() > 0 ) {
  514. $clause = '( rc_user NOT IN (';
  515. $clause .= implode( ',', $this->addQuotes( $dbr, $excludedUserIds ) ) . ') )';
  516. }
  517. return $clause;
  518. }
  519. //XXX SpecialWatchlist should let us pass the page title
  520. public function showHideLink( $options, $message, $name, $value ) {
  521. global $wgUser;
  522. $showLinktext = wfMsgHtml( 'show' );
  523. $hideLinktext = wfMsgHtml( 'hide' );
  524. $title = SpecialPage::getTitleFor( 'CollabWatchlist' );
  525. $skin = $wgUser->getSkin();
  526. $label = $value ? $showLinktext : $hideLinktext;
  527. $options[$name] = 1 - (int) $value;
  528. return wfMsgHtml( $message, $skin->linkKnown( $title, $label, array(), $options ) );
  529. }
  530. /**
  531. * Runs $db->addQuotes() for each of the strings
  532. * @param $db Database: The db object to use
  533. * @param $strings Array: A list of strings to quote
  534. * @return Array: The $strings quoted by $db->addQuotes()
  535. */
  536. public static function addQuotes( $db, $strings ) {
  537. $result = array();
  538. foreach ( $strings as $string ) {
  539. $result[] = $db->addQuotes( $string );
  540. }
  541. return $result;
  542. }
  543. }