Difference between revisions of "Extension:AWCmod"

From Organic Design wiki
(get the new prefs into the db from prefs or create-account forms)
(update - searchTag done)
Line 20: Line 20:
 
'version'    => AWCMOD_VERSION
 
'version'    => AWCMOD_VERSION
 
);
 
);
 +
print_r($_REQUEST);
 +
# Check if any awcpref parameters passed in request
 +
$awcSearchByPref = array();
 +
foreach ($_REQUEST as $k => $v) if (ereg('^awcsbp_(.+)$', $k, $m)) $awcSearchByPref[$m[1]] = $v;
 +
 +
# Don't apply the db hook unless awcsearchprefs have been posted
 +
$awcDBHook = count($awcSearchByPref) > 0;
 +
 +
# First stage of db patch
 +
if ($awcDBHook) {
  
# SearchEngine is based on $wgDBtype so must be set before it gets changed to DatabaseAWC
+
# SearchEngine is based on $wgDBtype so must be set before it gets changed to DatabaseAWC
# - this may be paranoid now since $wgDBtype is changed back after LoadBalancer has initialised
+
# - this may be paranoid now since $wgDBtype is changed back after LoadBalancer has initialised
AWCmod::fixSearchType();
+
AWCmod::fixSearchType();
  
$awcDBHook = true;
+
$wgOldDBtype = $wgDBtype;
$wgOldDBtype = $wgDBtype;
+
if (class_exists('Database')) wfAWCmodDBHook();
if (class_exists('Database')) wfAWCmodDBHook();
+
}
  
 
class AWCmod {
 
class AWCmod {
  
var $patch = false;
+
var $searchPrefs = array();
var $oldtag = '';
 
  
 
function __construct() {
 
function __construct() {
global $wgHooks, $wgMessageCache, $wgParser, $wgTitle;
+
global $wgHooks, $wgMessageCache, $wgParser, $wgTitle, $awcSearchByPref;
 +
 +
$this->searchPrefs = $awcSearchByPref;
 +
 
$wgHooks['RenderPreferencesForm'][] = $this;
 
$wgHooks['RenderPreferencesForm'][] = $this;
 
$wgHooks['UserCreateForm'][]        = $this;
 
$wgHooks['UserCreateForm'][]        = $this;
Line 41: Line 53:
 
$wgHooks['AbortNewAccount'][]      = $this;
 
$wgHooks['AbortNewAccount'][]      = $this;
  
# Override the existing AWC tag
 
$this->oldtag = $wgParser->mTagHooks['forum_info'];
 
$wgParser->mTagHooks['forum_info'] = array($this, 'forum_info');
 
 
 
# Modify login form messages to say email and name compulsory
 
# Modify login form messages to say email and name compulsory
 
$wgMessageCache->addMessages(array('prefs-help-email' => '<div class="error">Required</div>'));
 
$wgMessageCache->addMessages(array('prefs-help-email' => '<div class="error">Required</div>'));
 
$wgMessageCache->addMessages(array('prefs-help-realname' => '<div class="error">Required</div>'));
 
$wgMessageCache->addMessages(array('prefs-help-realname' => '<div class="error">Required</div>'));
 +
 +
# Add a tag for creating search links
 +
$wgParser->setHook('forum_search', array($this, 'searchTag'));
 
}
 
}
 
 
Line 120: Line 131:
 
</tr>";
 
</tr>";
 
}
 
}
+
 
 
/**
 
/**
* AWC forum_info tag is overridden with this one to catch the tag parameters
+
* Render a link to Special:AWCForum
 
*/
 
*/
function forum_info($input, $argv) {
+
function searchTag($text, $argv, &$parser) {
$this->tagargs = $input;
+
$this->patch = true;
+
# Default args for a search link
return call_user_func($this->oldtag, $input, $argv);
+
$defaults = array(
 +
'full' => 'full',
 +
'Sis_like' => 'like',
 +
'kw'      => 'Enter search term',
 +
's_memposts' => 'on',
 +
'is_like'    => 'is',
 +
'memname'    => '',
 +
'fID'        => array('all')
 +
);
 +
 
 +
# Build query string from defaults and tag args
 +
$qs = array();
 +
foreach ($defaults as $k => $v) {
 +
if (in_array($k, $argv)) $v = $argv[$k];
 +
if (is_array($v)) foreach ($v as $i) $qs[] = "{$k}[]=$i"; else $qs[] = "$k=$v";
 +
}
 +
foreach ($argv as $k => $v) {
 +
if (!in_array($k, $defaults)) $qs[] = "awcsbp_$k=$v";
 +
}
 +
$qs = join('&', $qs);
 +
 
 +
# Build link
 +
$url = Title::newFromText('AWCForum', NS_SPECIAL)->getLocalURL($qs);
 +
$link = "<a href='$url'>$text</a>";
 +
 +
return $link;
 
}
 
}
  
 
/**
 
/**
* Patch the SQL used by the forum_info tag to filter by user properties
+
* Patch the SQL used by the search to filter by user properties
 
*/
 
*/
 
function patchSQL(&$sql) {
 
function patchSQL(&$sql) {
$this->patch = false;
+
 
 +
# Convert prefs to a list of matching users
 +
$users = array('Nad');
 +
foreach ($this->searchPref as $k => $v) {
 +
}
 
 
# Perform the original query first - a bit of a lame way but not enought time to do better :-/
+
# Convert the users list to an SQL condition statement
$dbr =& wfGetDB(DB_SLAVE);
+
$cond = array();
$res = $dbr->query($sql);
+
foreach ($users as $user) $cond[] = "p.p_user == '$user'";
 +
$cond = count($cond) > 0 ? ' AND ('.join(' OR ', $cond).')' : '';
  
# Scan the results and create a list of exclusions based on user properties
+
# Replace the default user condition in the SQL with the new one
$exc = '';
+
$like = empty($this->searchPref) ? '' : '$1';
while ($row = $dbr->fetchObject($res)) {
+
$sql = preg_replace("|(p.p_user LIKE '%.+?%')|", "$like$cond", $sql);
$user = User::newFromName($row->t_lastuser == '' ? $row->p_user : $row->t_lastuser);
+
print "$sql\n\n";
}
 
$dbr->freeResult($res);
 
 
}
 
}
 
 
Line 181: Line 220:
 
public function query($sql, $fname = "", $tempIgnore = false) {
 
public function query($sql, $fname = "", $tempIgnore = false) {
 
global $wgAWCmod;
 
global $wgAWCmod;
if (is_object($wgAWCmod) && $wgAWCmod->patch
+
if (is_object($wgAWCmod) && (1||ereg("^SELECT.+FROM.+`awc_f_cats`.+`awc_f_forums`",$sql))) $wgAWCmod->patchSQL($sql);
&& ereg("^SELECT",$sql)
 
&& ereg("awc_f_threads", $sql)
 
&& ereg("awc_f_forums",$sql)
 
&& ereg("awc_f_cats",$sql)
 
&& ereg("awc_f_posts",$sql)
 
) $wgAWCmod->patchSQL($sql);
 
 
return parent::query($sql, $fname, $tempIgnore);
 
return parent::query($sql, $fname, $tempIgnore);
 
}
 
}
Line 200: Line 233:
 
$wgAWCmod = new AWCmod();
 
$wgAWCmod = new AWCmod();
  
# If the DB hook couldn't be set up early, do it now
 
# - but now the LoadBalancer exists and must have its DB types changed
 
 
if ($awcDBHook) {
 
if ($awcDBHook) {
 +
 +
# If the DB hook couldn't be set up early, do it now
 +
# - but now the LoadBalancer exists and must have its DB types changed
 
wfAWCmodDBHook();
 
wfAWCmodDBHook();
 
if (function_exists('wfGetLBFactory')) wfGetLBFactory()->forEachLB(array('AWCmod', 'updateLB'));
 
if (function_exists('wfGetLBFactory')) wfGetLBFactory()->forEachLB(array('AWCmod', 'updateLB'));
 
elseif (is_object($wgLoadBalancer)) AWCmod::updateLB($wgLoadBalancer);
 
elseif (is_object($wgLoadBalancer)) AWCmod::updateLB($wgLoadBalancer);
 
else die("Can't hook in to Database class!");
 
else die("Can't hook in to Database class!");
 +
 +
# Request a DB connection to ensure the LoadBalancer is initialised,
 +
# then change back to old DBtype since it won't be used for making connections again but can affect other operations
 +
# such as $wgContLang->stripForSearch which is called by SearchMySQL::parseQuery
 +
wfGetDB();
 +
$wgDBtype = $wgOldDBtype;
 
}
 
}
  
# Request a DB connection to ensure the LoadBalancer is initialised,
 
# then change back to old DBtype since it won't be used for making connections again but can affect other operations
 
# such as $wgContLang->stripForSearch which is called by SearchMySQL::parseQuery
 
wfGetDB();
 
$wgDBtype = $wgOldDBtype;
 
 
 
 
# Add messages
 
# Add messages

Revision as of 01:31, 4 October 2008

<?php /**

* AWC extension
*Template:Php
Info.svg These are the MediaWiki extensions we're using and/or developing. Please refer to the information on the mediawiki.org wiki for installation and usage details. Extensions here which have no corresponding mediawiki article are either not ready for use or have been superseded. You can also browse our extension code in our local Subversion repository or our GitHub mirror.
* @package MediaWiki
* @subpackage Extensions
* @author Aran Dunkley User:Nad
* @licence GNU General Public Licence 2.0 or later
*/

if (!defined('MEDIAWIKI')) die('Not an entry point.');

define('AWCMOD_VERSION', '0.0.0, 2008-09-13');

$wgExtensionFunctions[] = 'wfSetupAWCmod'; $wgExtensionCredits['other'][] = array( 'name' => 'AWCmod', 'author' => 'User:Nad', 'description' => 'Custom extension for Adeft', 'url' => 'http://www.organicdesign.co.nz/Extension:AWCmod', 'version' => AWCMOD_VERSION ); print_r($_REQUEST);

  1. Check if any awcpref parameters passed in request

$awcSearchByPref = array(); foreach ($_REQUEST as $k => $v) if (ereg('^awcsbp_(.+)$', $k, $m)) $awcSearchByPref[$m[1]] = $v;

  1. Don't apply the db hook unless awcsearchprefs have been posted

$awcDBHook = count($awcSearchByPref) > 0;

  1. First stage of db patch

if ($awcDBHook) {

# SearchEngine is based on $wgDBtype so must be set before it gets changed to DatabaseAWC # - this may be paranoid now since $wgDBtype is changed back after LoadBalancer has initialised AWCmod::fixSearchType();

$wgOldDBtype = $wgDBtype; if (class_exists('Database')) wfAWCmodDBHook(); }

class AWCmod {

var $searchPrefs = array();

function __construct() { global $wgHooks, $wgMessageCache, $wgParser, $wgTitle, $awcSearchByPref;

$this->searchPrefs = $awcSearchByPref;

$wgHooks['RenderPreferencesForm'][] = $this; $wgHooks['UserCreateForm'][] = $this; $wgHooks['SavePreferences'][] = $this; $wgHooks['AbortNewAccount'][] = $this;

# Modify login form messages to say email and name compulsory

$wgMessageCache->addMessages(array('prefs-help-email' => '

Required

')); $wgMessageCache->addMessages(array('prefs-help-realname' => '

Required

'));

# Add a tag for creating search links $wgParser->setHook('forum_search', array($this, 'searchTag')); }

/** * Add the new prefs to a new tab in the preferences form */ function onRenderPreferencesForm(&$form, &$out) { $out->addHTML('<fieldset><legend>Contact details</legend>'.$this->renderAWCprefs().'</fieldset>'); return true; }

/** * Add the new prefs to the "create new account" form */ function onUserCreateForm(&$template) { $template->data['header'] = $this->renderAWCprefs(); return true; }

/** * Update the user object when the prefs from the form are saved */ function onSavePreferences(&$form, &$user, &$error, &$options) { $user->setOption('foo', 'onSavePreferences'); return true; }

/** * Update the user object with extra prefs in the account-creation form */ function onAbortNewAccount(&$user, &$error) { $user->setOption('foo', 'onAbortNewAccount'); return true; }

/** * Return the HTML for the AWC preference inputs */ function renderAWCprefs() {

$html = '

' .

$this->addRow( wfLabel('Phone', 'wpPhone'), wfInput('wpPhone', 20, , array('id' => 'wpPhone')), 'Required' ) . $this->addRow( wfLabel('Mobile', 'wpMobile'), wfInput('wpMobile', 20, , array('id' => 'wpMobile')) ) . $this->addRow( wfLabel('Business', 'wpBusiness'), wfInput('wpBusiness', 20, , array('id' => 'wpBusiness')), 'Can be "none"' ) . $this->addRow( wfLabel('Website', 'wpWebsite'), wfInput('wpWebsite', 20, , array('id' => 'wpWebsite')) ) . $this->addRow( wfLabel('Zip Code', 'wpZipCode'), wfInput('wpZipCode', 10, , array('id' => 'wpZipCode')), 'Required'

) . '

';

return $html; }

function addRow($td1, $td2, $td3 = ) {

return " $td1: $td2

$td3

"; } /** * Render a link to Special:AWCForum */ function searchTag($text, $argv, &$parser) { # Default args for a search link $defaults = array( 'full' => 'full', 'Sis_like' => 'like', 'kw' => 'Enter search term', 's_memposts' => 'on', 'is_like' => 'is', 'memname' => , 'fID' => array('all') ); # Build query string from defaults and tag args $qs = array(); foreach ($defaults as $k => $v) { if (in_array($k, $argv)) $v = $argv[$k]; if (is_array($v)) foreach ($v as $i) $qs[] = "{$k}[]=$i"; else $qs[] = "$k=$v"; } foreach ($argv as $k => $v) { if (!in_array($k, $defaults)) $qs[] = "awcsbp_$k=$v"; } $qs = join('&', $qs); # Build link $url = Title::newFromText('AWCForum', NS_SPECIAL)->getLocalURL($qs); $link = "<a href='$url'>$text</a>"; return $link; } /** * Patch the SQL used by the search to filter by user properties */ function patchSQL(&$sql) { # Convert prefs to a list of matching users $users = array('Nad'); foreach ($this->searchPref as $k => $v) { } # Convert the users list to an SQL condition statement $cond = array(); foreach ($users as $user) $cond[] = "p.p_user == '$user'"; $cond = count($cond) > 0 ? ' AND ('.join(' OR ', $cond).')' : ; # Replace the default user condition in the SQL with the new one $like = empty($this->searchPref) ?  : '$1'; $sql = preg_replace("|(p.p_user LIKE '%.+?%')|", "$like$cond", $sql); print "$sql\n\n"; } /** * Updates passed LoadBalancer's DB servers to secure class */ static function updateLB(&$lb) { $lb->closeAll(); foreach ($lb->mServers as $i => $server) $lb->mServers[$i]['type'] = 'AWC'; } /** * Hack to ensure proper search class is used * - $wgDBtype determines search class unless already defined in $wgSearchType * - just copied method from SearchEngine::create() */ static function fixSearchType() { global $wgDBtype, $wgSearchType; if ($wgSearchType) return; elseif ($wgDBtype == 'mysql') $wgSearchType = 'SearchMySQL4'; elseif ($wgDBtype == 'postgres') $wgSearchType = 'SearchPostgres'; elseif ($wgDBtype == 'oracle') $wgSearchType = 'SearchOracle'; else $wgSearchType = 'SearchEngineDummy'; } } /** * Hook in to DB class to allow overriding the AWC query (based on SimpleSecurity method) */ function wfAWCmodDBHook() { global $wgDBtype, $awcDBHook, $wgOldDBtype; $oldClass = ucfirst($wgDBtype); $wgDBtype = 'AWC'; eval("class Database{$wgDBtype} extends Database{$oldClass}".' { public function query($sql, $fname = "", $tempIgnore = false) { global $wgAWCmod; if (is_object($wgAWCmod) && (1||ereg("^SELECT.+FROM.+`awc_f_cats`.+`awc_f_forums`",$sql))) $wgAWCmod->patchSQL($sql); return parent::query($sql, $fname, $tempIgnore); } }'); $awcDBHook = false; } function wfSetupAWCmod() { global $wgAWCmod, $awcDBHook, $wgLanguageCode, $wgMessageCache, $wgLoadBalancer, $wgDBtype, $wgOldDBtype; # Instantiate the AWC singleton now that the environment is prepared $wgAWCmod = new AWCmod(); if ($awcDBHook) { # If the DB hook couldn't be set up early, do it now # - but now the LoadBalancer exists and must have its DB types changed wfAWCmodDBHook(); if (function_exists('wfGetLBFactory')) wfGetLBFactory()->forEachLB(array('AWCmod', 'updateLB')); elseif (is_object($wgLoadBalancer)) AWCmod::updateLB($wgLoadBalancer); else die("Can't hook in to Database class!"); # Request a DB connection to ensure the LoadBalancer is initialised, # then change back to old DBtype since it won't be used for making connections again but can affect other operations # such as $wgContLang->stripForSearch which is called by SearchMySQL::parseQuery wfGetDB(); $wgDBtype = $wgOldDBtype; } # Add messages if ($wgLanguageCode == 'en') { $wgMessageCache->addMessages(array( 'awc-prefhead' => "AWC" )); } }