Extension:WhoIsWatchingTabbed

From MediaWiki.org

Jump to: navigation, search


Manual on MediaWiki Extensions
List of MediaWiki Extensions
WhoIsWatchingTabbed

Release status: beta

Implementation User activity, Page action
Description Creates a tab to see who is watching a particular page. Or what pages a user is watching.
Author(s) Jack Bredberg and Danila Ulyanov
Version 1.1
MediaWiki 1.11.1
Download no link
Hooks used

UnknownAction
SkinTemplateTabs

Contents

[edit] What can this extension do?

When installed this extension will create a tab in the tab bar that has the text "Who's watching this? (X)" where X is the number of users watching the page. When the tab is viewed it will display a grid of users who are watching the page. Each result will display the username, user real name, and page name. Usernames are linked to the same watching page, but will display all pages that the user is watching. Page names are linked to the same page, but will display all users watching that page. This installation will provide access only to group, sysop. An item will be added to the special page list for accessing this extension. Viewing the special page will display top ten watching users and top ten watched pages.

[edit] Download instructions

Please cut and paste the code found below and place it in the correct file in the $IP/extensions/WhoIsWatchingTabbed/ directory. Note: $IP stands for the root directory of your MediaWiki installation, the same directory that holds LocalSettings.php.

[edit] Installation

To install this extension, add the following to LocalSettings.php:

$wgGroupPermissions['sysop']['whoiswatchingtabbed']       = true;
require_once("$IP/extensions/WhoIsWatchingTabbed/WhoIsWatchingTabbed.php" );

[edit] User rights

If you want to modify the groups that can access/view the tab you should add them to the $wgGroupPermissionsArray where the second index is 'whoiswatchingtabbed'.

[edit] Code

To use this extension you will need to create a new directory in the extensions directory called, WhoIsWatchingTabbed. Inside of that directory you will need to create two files: WhoIsWatchingTabbed.php and WhoIsWatchingTabbed.i18n.php. You will find the contents for each file below, just copy and paste. Ensure that you have added the two lines above to LocalSettings.php.

WhoIsWatchingTabbed.php

<?php 
#
# WhoIsWatchingTabbed Mediawiki extension
# 
# Original by Jack Bredberg and Danila Ulyanov 05.05.2008
# 
# http://www.mediawiki.org/
#
# This file should be placed in the $IP/extensions/WhoIsWatchingTabbed/ directory.
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or 
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
 
/**
* ChangeLog
*
* 05.08.2008 1.1
* - Fixed namespace bugs
* - Added special page for most X Ys
*
* 05.05.2008 1.0.0
*  - First version release
*/
 
require_once "$IP/includes/SpecialPage.php";
 
/* Global variables */
$wgAllowAnonUsers = false; # set to false to deny access to anonymous users
 
/* Extension variables */
$wgExtensionFunctions[] = "wfSetupWhoIsWatchingTabbed";
 
$wgExtensionCredits['specialpage'][] = array(
  'name' => 'WhoIsWatchingTabbed',
  'description' => 'Adds Who Is Watching tab and special page to see who is watching any page, as well as, what pages a user is watching.',
  'url' => 'http://www.mediawiki.org/wiki/Extension:WhoIsWatchingTabbed',
  'author' => 'Jack Bredberg and Danila Ulyanov',
  'version'=>'1.1.0');
 
/* Define titles of each namespace */
$namespace_title = array(
  NS_MEDIA=>"Media",
  NS_SPECIAL=>"Special",
  NS_MAIN=>"Main",
  NS_USER=>"User",
  NS_IMAGE=>"Image",
  NS_MEDIAWIKI=>"MediaWiki",
  NS_TEMPLATE=>"Template",
  NS_HELP=>"Help",
  NS_CATEGORY=>"Category",
  NS_PROJECT=>$wgSitename
);
 
class WhoIsWatchingTabbed extends SpecialPage {
  // Constructor
  function WhoIsWatchingTabbed() {
    global $wgHooks, $wgSpecialPages, $wgWatchingMessages;
    // Add all of our needed hooks
    $wgHooks["UnknownAction"][] = $this;
    $wgHooks["SkinTemplateTabs"][] = $this;
    SpecialPage::SpecialPage('WhoIsWatchingTabbed', 'block');
  }
 
  //Provides MediaWiki with a description/title of the extension
  function getDescription() {
    global $wgMessageCache, $wgWatchingMessages;
    require_once("WhoIsWatchingTabbed.i18n.php");
    foreach($wgWatchingMessages as $language_code => $message) {
      $wgMessageCache->addMessages($message, $language_code);
    }
    return wfMsg('special_page_link');
  }
 
  function execute() {
    global $wgOut, $wgSitename, $wgCachePages, $wgUser, $wgTitle, $wgDenyAccessMessage, $wgAllowAnonUsers, $wgRequest, $wgMessageCache, $wgWatchingMessages, $wgDBtype, $namespace_title;
    require_once("WhoIsWatchingTabbed.i18n.php");
    foreach($wgWatchingMessages as $language_code => $message) {
      $wgMessageCache->addMessages($message, $language_code);
    }
    $wgOut->setPagetitle(wfMsg("special_page_link"));
 
    //Use different limiting command/style depending on database
    $db_top = array("mssql");
    $db_limit = array("mysql","postgres");
    $db   = &wfGetDB(DB_SLAVE);
 
    //Get the pages that are being watdched by the most users.
    $query =  "SELECT ".(in_array(strtolower($wgDBtype),$db_top) ? 'TOP 10' : '')." w.wl_title, w.wl_namespace, COUNT(1) AS theCount ".
              "FROM ".$db->tableName("watchlist") ." AS w ".
              "WHERE w.wl_namespace IN (".NS_MEDIA.",".NS_SPECIAL.",".NS_MAIN.",".NS_USER.",".NS_IMAGE.",".NS_MEDIAWIKI.",".NS_TEMPLATE.",".NS_HELP.",".NS_CATEGORY.",".NS_PROJECT." ) ".
              "GROUP BY LOWER(w.wl_title), w.wl_namespace ".
              "ORDER BY theCount DESC ".(in_array(strtolower($wgDBtype),$db_limit) ? 'LIMIT 10' : '');
    $output = "";
 
    if (false == $result = $db->doQuery($query)) {
      $output .= '<p>Error accessing watchlist.</p>';
    } else if($db->numRows($result) == 0) {
      $output .= '<p>Nobody is watching any page.</p>';
    } else {
      $output .= '<table><tr><th colspan="3">'.$db->numRows($result).' Most Watched Pages</th></tr><tr><td>Namespace</td><td>Page</td><td>Watchers</td></tr>';
      while ($row = $db->fetchRow($result)) {
        $output .= '<tr><td>'.$namespace_title[$row[1]].'</td>';
        $output .= '<td><a href="'.$_SERVER["PHP_SELF"].'?title='.($row[1]!=0 ? $namespace_title[$row[1]].':' : '').$row[0].'&action=watching">'.$row[0].'</a></td>';
        $output .= '<td>'.$row[2] .'</td></tr>';
      }
    $output .= '</table>';
    }
 
    //Get the users who are watching the most pages
    $query =  "SELECT ".(in_array(strtolower($wgDBtype),$db_top) ? 'TOP 10' : '')." COUNT(1) AS theCount, u.user_name, u.user_real_name ".
              "FROM ".$db->tableName("watchlist") ." AS w JOIN ".$db->tableName("user")." AS u ON u.user_id=w.wl_user ".
              "WHERE w.wl_namespace IN (".NS_MEDIA.",".NS_SPECIAL.",".NS_MAIN.",".NS_USER.",".NS_IMAGE.",".NS_MEDIAWIKI.",".NS_TEMPLATE.",".NS_HELP.",".NS_CATEGORY.",".NS_PROJECT." ) ".
              "GROUP BY w.wl_user ".
              "ORDER BY theCount DESC ".(in_array(strtolower($wgDBtype),$db_limit) ? 'LIMIT 10' : '');
 
    if (false == $result = $db->doQuery($query)) {
      $output .= '<p>Error accessing watchlist.</p>';
    } else if($db->numRows($result) == 0) {
      $output .= '<p>Nobody is watching any page.</p>';
    } else {
      $output .= '<table><tr><th colspan="3">'.$db->numRows($result).' Users Watching the Most Pages</th></tr><tr><td>Namespace</td><td>Page</td><td>Pages</td></tr>';
      while ($row = $db->fetchRow($result)) {
        $output .= '<tr><td>'.$row[2].'</td><td><a href="'.$_SERVER["PHP_SELF"].'?title=&user_name='.$row[1].'&action=watching">'.$row[1].'</a></td><td>'.$row[0] .'</td></tr>';
      }
      $output .= '</table>';
    }
 
    $wgOut->addHTML($output);
    return false;
  }
 
  function onUnknownAction($action, $article) {
    global $wgOut, $wgSitename, $wgCachePages, $wgUser, $wgTitle, $wgDenyAccessMessage, $wgAllowAnonUsers, $wgRequest,$wgMessageCache, $wgWatchingMessages, $namespace_title, $wgSitename;
    require_once("WhoIsWatchingTabbed.i18n.php");
 
    $wgCachePages = false;
 
    // Gather all the messages from the language file.
    foreach($wgWatchingMessages as $language_code => $message) {
      $wgMessageCache->addMessages($message, $language_code);
    }
 
    //Determine which results are going to be shown and the appropriate columns
    if(isset($_REQUEST["user_name"])) {
      $wgOut->setPagetitle(wfMsg("pages_watched_by_user"));
      $columns = array("page_namespace","page_title");
    } else {
      $columns = array("user_name","user_real_name");
      $wgOut->setPagetitle(wfMsg("users_watching_page"));
    }
 
    //Verify that the action coming in is 'watching' (not to be confused with the system action 'watch/unwatch'
    if($action == "watching") {
      if (!$wgUser->isAllowed("whoiswatchingtabbed")) {
        $wgOut->permissionRequired("whoiswatchingtabbed");
        return true;
      }
      $db   = &wfGetDB(DB_SLAVE);
 
      $order_col = "user_name";
      if(isset($_REQUEST["order_col"]) && in_array($_REQUEST["order_col"], $columns)) {
        $order_col = $_REQUEST["order_col"];
      }
 
      //Change the way the results are ordered
      if(isset($_REQUEST["order_type"]) && $_REQUEST["order_type"] == "DESC") {
        $ordertype  = "DESC";
        $ordertypeR = "ASC";
      } else {
        $ordertype  = "ASC";
        $ordertypeR = "DESC";
      }
 
      //Determine the namespace and the title of the current page.
      $pt = explode(":",$_REQUEST['title']);
      if(sizeof($pt)==1) {
        $page_namespace = 0;
        $page_title = $pt[0];
      } else {
        //Check for namespace that is the NS_PROJECT name
        if(strtoupper($pt[0])==strtoupper($wgSitename)) {
          $page_namespace = constant("NS_PROJECT");
        } else {
          $page_namespace = constant("NS_".strtoupper($pt[0]));
        }
        $page_title = $pt[1];
      }
 
      //Which query to run? If user_name is set then do the 'User X is watching these pages', else X users are watching this page.
      if(isset($_REQUEST["user_name"])) {
        $query = "SELECT  w.wl_namespace AS page_namespace, w.wl_title AS page_title "
                ."FROM " . $db->tableName("user") . " AS u "
                ."JOIN " . $db->tableName("watchlist") . " AS w "
                ."ON u.user_id = w.wl_user " 
                ."WHERE LOWER(u.user_name) = " . $db->addQuotes(strtolower($_REQUEST["user_name"])) ." "
                ."AND w.wl_namespace IN (".NS_MEDIA.",".NS_SPECIAL.",".NS_MAIN.",".NS_USER.",".NS_IMAGE.",".NS_MEDIAWIKI.",".NS_TEMPLATE.",".NS_HELP.",".NS_CATEGORY.",".NS_PROJECT." ) "
                ."ORDER BY " . $order_col . " " . $ordertype;
      } else {
        $query = "SELECT u.user_name, u.user_real_name "
                ."FROM " . $db->tableName("user") . " AS u "
                ."JOIN " . $db->tableName("watchlist") . " AS w "
                ."ON u.user_id = w.wl_user " 
                ."WHERE LOWER(w.wl_title) = " . $db->addQuotes(strtolower($page_title)) ." "
                ."AND w.wl_namespace = ".$db->addQuotes(strtolower($page_namespace))." "
                ."ORDER BY " . $order_col . " " . $ordertype;
      } 
      $output = "";
      if (false == $result = $db->doQuery($query)) {
        $output .= '<p>Error accessing watchlist.</p>';
      } else if($db->numRows($result) == 0) {
        $output .= '<p>Nobody is watching this page.</p>';
      } else {
        $output .= '<table cellspacing="0" cellpadding="5"><tr>';
 
        //Generate sortable column headings
        foreach($columns as $column){
          $output .= '<th>
          <a href="'.$_SERVER["PHP_SELF"].'?title='.$_REQUEST["title"].'&order_col='.$column.'&action=watching&order_type='.$ordertypeR.
          (isset($_REQUEST["user_name"]) ? '&user_name='.$_REQUEST["user_name"] : '').
          (isset($_REQUEST["user_real_name"]) ? '&user_real_name='.$_REQUEST["user_real_name"] : '').
          '">
          '.wfMsg($column).'</a></th>';
        }
        $output .= '</tr>';
 
        //Display the data--display some data differently than others.
        while ($row = $db->fetchRow($result)) {
          $output .= '<tr>';
          foreach($columns as $column){
            if ($column == "user_name") {
              $output .= '<td><a href="'.$_SERVER["PHP_SELF"].'?title='.$_REQUEST["title"].'&action=watching&user_name='.$row[$column].'">'.$row[$column].'</td>';            
            } elseif ($column == "user_real_name") {
              $output .= '<td>'.$row[$column].'</td>';   
            } elseif ($column == "page_title") {
              $output .= '<td>';
              $output .= '<a href="'.$_SERVER["PHP_SELF"].'?title='.($row['page_namespace']!=0 ? $namespace_title[$row['page_namespace']].':' : '').$row[$column].'&action=watching">'.$row[$column];
              $output .= '</a></td>';   
            } elseif ($column == "page_namespace") {
              $output .= '<td>'.$namespace_title[$row[$column]].'</td>';
            } else {
              $output .= '<td>'.htmlspecialchars($row[$column]).'&nbsp;</td>';
            }
          }
          $output .= '</tr>';
        }
        $output .= '</table>';
      }
      $wgOut->addHTML($output);
      return false;
    } else {
      return true;
    }
  }
 
  function onSkinTemplateTabs(&$skin, &$content_actions) {
    global $wgRequest, $wgUser, $wgSitename;
    $action = $wgRequest->getText('action');
    $db = &wfGetDB(DB_SLAVE);
 
    $page_title = $_REQUEST['title'];
    $page_namespace = 0;
    $pt = explode(":",$_REQUEST['title']);
    if(sizeof($pt)>1) {
      if(strtoupper($pt[0])==strtoupper($wgSitename)) {
        $page_namespace = constant("NS_PROJECT");
      } else {
        $page_namespace = constant("NS_".strtoupper($pt[0]));
      }
      $page_title = $pt[1];
    }
 
    //Get count for display in tab
    $query = "SELECT COUNT(1) AS users_watching "
            ."FROM " . $db->tableName("watchlist") . " AS w "
            ."WHERE LOWER(w.wl_title) = ". $db->addQuotes(strtolower($page_title))." AND w.wl_namespace=".$page_namespace." ";
    $watcherCount = 0;
 
    if ($result = $db->doQuery($query)) {
      $row = $db->fetchRow($result);
      $watcherCount = $row["users_watching"];
    }
    //tab links
    $content_actions["watching"] = array(
      'class' => ($action == 'watching') ? 'selected' : false,
      'text' => "who is watching this? (".$watcherCount.")",
      'href' => $skin->mTitle->getLocalURL('action=watching')
     );
    return false;
  }
} //end class
 
/* Global function */
# Called from $wgExtensionFunctions array when initialising extensions
function wfSetupWhoIsWatchingTabbed() {
  global $wgUser;
  SpecialPage::addPage( new WhoIsWatchingTabbed );
  if ($wgUser->isAllowed('whoiswatchingtabbed')) {
    global $wgWhoIsWatchingTabbed;
    $wgWhoIsWatchingTabbed = new WhoIsWatchingTabbed();
  }
}

WhoIsWatchingTabbed.i18n.php

<?php
$user_name = "Unknown User";
if(isset($_REQUEST["user_name"])) {
    $user_name = $_REQUEST["user_name"];
}
$page_title = "Unknown Page";
if(isset($_REQUEST["title"])) {
    $page_title = $_REQUEST["title"];
}
 
$wgWatchingMessages['en'] = array(
    'pages_watched_by_user'  => "Pages watched by ".$user_name,
    'users_watching_page'    => "Users watching ".$page_title,
    'special_page_link'    => "Who is Watching Statistics",
    'user_name'              => 'Username',
    'user_real_name'         => 'Real name',
    'page_title'             => 'Page Title',
    'page_namespace'             => 'Page Namespace'
);

[edit] Known Issues

  • In MediaWiki 1.10.0 it has been found that this extension will break the Special:Version page for sysops. This issue is not present in 1.11.1.
  • The language file isn't entirely useful. There is some logic and text initializations occurring outside of the rest of the array/messsage initializations.

[edit] Revisions

  • 2008.05.08 - Fixed namespace issues and added the link to the special page list.
  • 2008.05.05 - Initial version released.

[edit] See also

Extensions that are similar in goal or style:

Personal tools