Difference between revisions of "Extension:AWCmod"

From Organic Design wiki
(current state)
 
m (few more client mandated mods...should be a wrap...)
 
(21 intermediate revisions by 2 users not shown)
Line 10: Line 10:
 
if (!defined('MEDIAWIKI')) die('Not an entry point.');
 
if (!defined('MEDIAWIKI')) die('Not an entry point.');
  
define('AWCMOD_VERSION', '0.0.0, 2008-09-13');
+
define('AWCMOD_VERSION', '0.2.7, 2008-11-06');
 +
 
 +
$wgAutoConfirmCount = 10^10;
 +
 
 +
$awcDefaultImage = '';
 +
$awcMaxImageSize = 100000;
  
 
$wgExtensionFunctions[] = 'wfSetupAWCmod';
 
$wgExtensionFunctions[] = 'wfSetupAWCmod';
$wgExtensionCredits['other'][] = array(
+
$wgExtensionCredits['other'][] = $wgExtensionCredits['specialpage'][] = array(
 
'name'        => 'AWCmod',
 
'name'        => 'AWCmod',
 
'author'      => '[http://www.organicdesign.co.nz/User:Nad User:Nad]',
 
'author'      => '[http://www.organicdesign.co.nz/User:Nad User:Nad]',
Line 19: Line 24:
 
'url'        => 'http://www.organicdesign.co.nz/Extension:AWCmod',
 
'url'        => 'http://www.organicdesign.co.nz/Extension:AWCmod',
 
'version'    => AWCMOD_VERSION
 
'version'    => AWCMOD_VERSION
);
+
);
 +
 
 +
require_once "$IP/includes/SpecialPage.php";
 +
 
 +
# Check if any awcpref parameters passed in request
 +
$awcSearchByPref = array();
 +
foreach ($_REQUEST as $k => $v) if (ereg('^awcsbp_(.+)$', $k, $m)) $awcSearchByPref[$m[1]] = $v;
 +
 
 +
# Process posted contact details
 +
if (isset($_POST['wpFirstName'])) $_POST['wpRealName'] = $_POST['wpFirstName'].' '.$_POST['wpLastName'];
  
AWCmod::fixSearchType();
+
# Don't apply the db hook unless awcsearchprefs have been posted
 +
if ($awcDBHook = count($awcSearchByPref) > 0) $_POST['fID'] = array('all');
 +
 +
# First stage of db patch
 +
if ($awcDBHook) {
  
$awcDBHook = true;
+
# SearchEngine is based on $wgDBtype so must be set before it gets changed to DatabaseAWC
if (class_exists('Database')) wfAWCmodDBHook();
+
# - 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 {
 
class AWCmod {
  
 +
var $JS = '';
 +
var $searchPrefs = array();
 +
var $skillsOptions = '';
 +
var $stateOptions  = '';
 +
var $countyOptions = '';
 +
 
function __construct() {
 
function __construct() {
global $wgHooks, $wgMessageCache, $wgParser;
+
global $wgUser, $wgHooks, $wgMessageCache, $wgParser, $awcSearchByPref, $wgGroupPermissions, $wgWhitelistRead, $wgRequest;
$wgHooks['RenderPreferencesForm'][] = $this;
 
$wgHooks['UserCreateForm'][] = $this;
 
  
# Override the existing AWC tag
+
# Deny access until email address confirmed
$this->oldtag = $wgParser->mTagHooks['forum_info'];
+
#$wgGroupPermissions['*']['read'] = false;
$wgParser->mTagHooks['forum_info'] = array($this, 'forum_info');
+
#$wgWhitelistRead = array("Special:Preferences", "Special:Userlogin", "-");
 +
#if (!$wgUser->isEmailConfirmed()) $wgGroupPermissions['user']['read'] = false;
 
 
 +
$this->searchPrefs = $awcSearchByPref;
 +
 +
#$wgHooks['AbortNewAccount'][]            = $this;  # Save the extra prefs after posting account-create
 +
#$wgHooks['UserCreateForm'][]            = $this;  # Modify the create-account form to add new prefs
 +
$wgHooks['RenderPreferencesForm'][]      = $this;  # Add the new pref tab
 +
$wgHooks['SavePreferences'][]            = $this;  # Save the extra posted data to the user object's options
 +
$wgHooks['SpecialPageExecuteAfterPage'][] = $this;  # Modify preferences forms enctype and onsubmit
 +
$wgHooks['OutputPageBeforeHTML'][]        = $this;  # Add profile info to user pages
 +
 
# 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, 'forumTag'));
 +
$wgParser->setHook('profile_search', array($this, 'profileTag'));
 +
 
 +
# Process an uploaded profile image if one was posted
 +
if (array_key_exists('wpProfileImage', $_FILES) && $_FILES['wpProfileImage']['size'] > 0)
 +
$this->processUploadedImage($_FILES['wpProfileImage']);
 +
 
 +
}
 +
 +
 
 +
/**
 +
* Prepare the dropdown list content if using a special page containing one of our forms
 +
*/
 +
function buildOptionLists(&$user = false) {
 +
include(dirname(__FILE__)."/states.php");
 +
$this->JS = $awcJS;
 +
 +
# Build skills option list
 +
$skills = $this->getOption($user, 'skills');
 +
$this->skillsOptions = '<option/>';
 +
foreach (array(
 +
'Concerned Citizen',
 +
'Accountant',
 +
'Lawyer',
 +
'Tax Advisor',
 +
'Tax Agent',
 +
'Assessor',
 +
'Realtor'
 +
) as $s) {
 +
$selected = $skills == $s ? ' selected' : '';
 +
$this->skillsOptions .= "<option$selected>$s</option>\n";
 +
}
 +
 
 +
# Build state options list
 +
$state = $this->getOption($user, 'state');
 +
$this->stateOptions = '<option value="">Enter state...</option>';
 +
foreach (array_keys($awcStates) as $s) {
 +
$selected = $state == $s ? ' selected' : '';
 +
$this->stateOptions .= "<option$selected>$s</option>\n";
 +
}
  
 +
# Build county options list
 +
$county = $this->getOption($user, 'county');
 +
$this->countyOptions = '<option value="">Enter county...</option>';
 +
if ($state) {
 +
foreach (split(',', $awcStates[$state]) as $c) {
 +
$c = substr($c, 1, -1);
 +
$selected = $county == $c ? ' selected' : '';
 +
$this->countyOptions .= "<option$selected>$c</option>\n";
 +
}
 +
}
 +
}
 +
 +
/**
 +
* Get an option from the passed user or array (or it can be false)
 +
*/
 +
function getOption(&$obj, $opt, $default = '') {
 +
if (is_object($obj)) return $obj->getOption($opt);
 +
if (is_array($obj) && array_key_exists($opt, $obj)) return $obj[$opt];
 +
return $default;
 +
}
 +
 +
/**
 +
* Hack to add onSubmit for validation and enctype for image upload to form tag
 +
*/
 +
function onSpecialPageExecuteAfterPage(&$special, $par, $func) {
 +
global $wgOut;
 +
if ($special->mName == 'Preferences') {
 +
$wgOut->mBodytext = str_replace(
 +
'<form',
 +
'<form onsubmit="return awcValidate(this)" enctype="multipart/form-data"',
 +
$wgOut->mBodytext
 +
);
 +
}
 +
return true;
 
}
 
}
 
 
Line 47: Line 160:
 
*/
 
*/
 
function onRenderPreferencesForm(&$form, &$out) {
 
function onRenderPreferencesForm(&$form, &$out) {
$out->addHTML('<fieldset><legend>Contact details</legend>'.$this->renderAWCprefs().'</fieldset>');
+
$out->addHTML('<fieldset><legend>'.wfMsg('awc-preftab').'</legend>'.wfMsg('awc-prefmsg').$this->renderAWCprefs().'</fieldset>');
 
return true;
 
return true;
 
}
 
}
+
 
 
/**
 
/**
 
* Add the new prefs to the "create new account" form
 
* Add the new prefs to the "create new account" form
Line 57: Line 170:
 
$template->data['header'] = $this->renderAWCprefs();
 
$template->data['header'] = $this->renderAWCprefs();
 
return true;
 
return true;
 +
}
 +
 +
/**
 +
* Update the user object when the prefs from the form are saved
 +
*/
 +
function onSavePreferences(&$form, &$user) {
 +
$this->setOptions($user);
 +
return true;
 +
}
 +
 +
/**
 +
* Update the user object with extra prefs in the account-creation form
 +
*/
 +
function onAbortNewAccount(&$user, &$error) {
 +
$this->setOptions($user);
 +
return true;
 +
}
 +
 +
/**
 +
* Set user options from posted form
 +
*/
 +
function setOptions(&$user) {
 +
global $wgRequest;
 +
$user->setOption('firstname', $wgRequest->getVal('wpFirstName'));
 +
$user->setOption('lastname',  $wgRequest->getVal('wpLastName'));
 +
$user->setOption('phone',    $wgRequest->getVal('wpPhone'));
 +
$user->setOption('mobile',    $wgRequest->getVal('wpMobile'));
 +
$user->setOption('business',  $wgRequest->getVal('wpBusiness'));
 +
$user->setOption('skills',    $wgRequest->getVal('wpSkills'));
 +
$user->setOption('website',  $wgRequest->getVal('wpWebsite'));
 +
$user->setOption('fax',      $wgRequest->getVal('wpFax'));
 +
$user->setOption('address',  $wgRequest->getVal('wpAddress'));
 +
$user->setOption('address2',  $wgRequest->getVal('wpAddress2'));
 +
$user->setOption('city',      $wgRequest->getVal('wpCity'));
 +
$user->setOption('state',    $wgRequest->getVal('wpState'));
 +
$user->setOption('county',    $wgRequest->getVal('wpCounty'));
 +
$user->setOption('zipcode',  $wgRequest->getVal('wpZipCode'));
 +
$user->setOption('logo',      $wgRequest->getVal('wpProfileImage'));
 +
$user->setOption('notes',    $wgRequest->getVal('wpNotes'));
 
}
 
}
 
 
Line 63: Line 215:
 
*/
 
*/
 
function renderAWCprefs() {
 
function renderAWCprefs() {
$html = '<div class=awc-loginprefs><table>' .
+
global $wgUser, $wgOut, $wgHooks;
 +
$this->buildOptionLists($wgUser);
 +
$wgOut->addScript("<script type='text/javascript'>{$this->JS}</script>");
 +
 
 +
$html = "<div class=awc-loginprefs><table>" .
 
$this->addRow(
 
$this->addRow(
wfLabel('Phone', 'wpPhone'),
+
wfLabel('First Name', 'wpFirstName'),
wfInput('wpPhone', 20, '', array('id' => 'wpPhone')),
+
wfInput('wpFirstName', 20, $wgUser->getOption('firstname'), array('id' => 'wpFirstName'))
'Required'
+
) .
 +
$this->addRow(
 +
wfLabel('Last Name', 'wpLastName'),
 +
wfInput('wpLastName', 20, $wgUser->getOption('lastname'), array('id' => 'wpLastName'))
 +
) .
 +
$this->addRow(
 +
wfLabel('Voice Phone', 'wpPhone'),
 +
wfInput('wpPhone', 10, $wgUser->getOption('phone'), array('id' => 'wpPhone'))
 +
) .
 +
$this->addRow(
 +
wfLabel('Mobile Phone', 'wpMobile'),
 +
wfInput('wpMobile', 10, $wgUser->getOption('mobile'), array('id' => 'wpMobile'))
 +
) .
 +
$this->addRow(
 +
wfLabel('Fax', 'wpFax'),
 +
wfInput('wpFax', 10, $wgUser->getOption('fax'), array('id' => 'wpFax'))
 
) .
 
) .
 
$this->addRow(
 
$this->addRow(
wfLabel('Mobile', 'wpMobile'),
+
wfLabel('Expertise', 'wpSkills'),
wfInput('wpMobile', 20, '', array('id' => 'wpMobile'))
+
'<select name="wpSkills" id="wpSkills">'.$this->skillsOptions.'</select>'
 
) .
 
) .
 
$this->addRow(
 
$this->addRow(
wfLabel('Business', 'wpBusiness'),
+
wfLabel('Business Name', 'wpBusiness'),
wfInput('wpBusiness', 20, '', array('id' => 'wpBusiness')),
+
wfInput('wpBusiness', 20, $wgUser->getOption('business'), array('id' => 'wpBusiness'))
'Can be "none"'
 
 
) .
 
) .
 
$this->addRow(
 
$this->addRow(
 
wfLabel('Website', 'wpWebsite'),
 
wfLabel('Website', 'wpWebsite'),
wfInput('wpWebsite', 20, '', array('id' => 'wpWebsite'))
+
wfInput('wpWebsite', 20, $wgUser->getOption('website'), array('id' => 'wpWebsite'))
 +
) .
 +
$this->addRow(
 +
wfLabel('Address', 'wpAddress'),
 +
wfInput('wpAddress', 20, $wgUser->getOption('address'), array('id' => 'wpAddress'))
 +
) .
 +
$this->addRow(
 +
wfLabel('Address 2', 'wpAddress2'),
 +
wfInput('wpAddress2', 20, $wgUser->getOption('address2'), array('id' => 'wpAddress2'))
 +
) .
 +
$this->addRow(
 +
wfLabel('City', 'wpCity'),
 +
wfInput('wpCity', 20, $wgUser->getOption('city'), array('id' => 'wpCity'))
 +
) .
 +
$this->addRow(
 +
wfLabel('State', 'wpState'),
 +
'<select name="wpState" id="wpState" onchange="awcUpdateCounty(this.value)">'.$this->stateOptions.'</select>',
 +
'Required'
 +
) .
 +
$this->addRow(
 +
wfLabel('County', 'wpCounty'),
 +
'<select name="wpCounty" id="wpCounty">'.$this->countyOptions.'</select>',
 +
'Required'
 
) .
 
) .
 
$this->addRow(
 
$this->addRow(
 
wfLabel('Zip Code', 'wpZipCode'),
 
wfLabel('Zip Code', 'wpZipCode'),
wfInput('wpZipCode', 10, '', array('id' => 'wpZipCode')),
+
wfInput('wpZipCode', 10, $wgUser->getOption('zipcode'), array('id' => 'wpZipCode'))
'Required'
+
) .
) . '</table></div>';
+
$this->addRow(
 +
wfLabel('Logo', 'wpProfileImage'),
 +
wfInput('wpProfileImage', 10, $wgUser->getOption('logo'), array('id' => 'wpProfileImage', 'type' => 'file'))
 +
) .
 +
$this->addRow(wfLabel('Additional Information (1000 Characters Max)', 'wpNotes'), '')
 +
. '<tr><td colspan="3"><textarea cols=30 rows="7" id="wpNotes" name="wpNotes">'.$wgUser->getOption('notes').'</textarea></td></tr>'
 +
. '</table></div>';
 +
 
 +
 +
 +
$html .= '<script type="text/javascript">awcAddValidation()</script>';
 
return $html;
 
return $html;
 
}
 
}
 
 
 +
/**
 +
* Add a table row to the form
 +
*/
 
function addRow($td1, $td2, $td3 = '') {
 
function addRow($td1, $td2, $td3 = '') {
 
return "<tr>
 
return "<tr>
Line 97: Line 302:
 
</tr>";
 
</tr>";
 
}
 
}
+
 
 +
/**
 +
* Add the user profile info if it's a user page
 +
*/
 +
function onOutputPageBeforeHTML(&$out, &$text) {
 +
global $wgTitle, $wgDBname, $wgUploadDirectory, $wgUploadPath, $awcDefaultImage;
 +
if (is_object($wgTitle) && $wgTitle->getNamespace() == NS_USER) {
 +
$user = User::newFromName($wgTitle->getText());
 +
$id  = $user->getId();
 +
$m    = glob("$wgUploadDirectory/user-$wgDBname-$id.*");
 +
$src  = count($m) > 0 ? $m[0] : $awcDefaultImage;
 +
$src  = preg_replace("%^.+(?=/user-)%", $wgUploadPath, $src);
 +
$profile  = "<table class='userprofile'><tr align='left'>\n";
 +
$profile .= "<td rowspan='12' valign='top'><img height='228' src=\"$src\" /></td>\n";
 +
$tr = '';
 +
foreach(array(
 +
'Name'      => $user->getRealName(),
 +
'Business'  => $user->getOption('business'),
 +
'Website'  => $user->getOption('website'),
 +
'Expertise' => $user->getOption('skills'),
 +
'City'      => $user->getOption('city'),
 +
'County'    => $user->getOption('county'),
 +
'State'    => $user->getOption('state'),
 +
'Zip'    => $user->getOption('zipcode'),
 +
'Voice'    => $user->getOption('phone'),
 +
'Mobile'    => $user->getOption('mobile'),
 +
'Fax'    => $user->getOption('fax'),
 +
'Info'    => $user->getOption('notes')
 +
) as $k => $v) {
 +
$profile .= "$tr<th valign='top' align='left'>$k:</th><td valign='top' align='left'>$v</td></tr>\n";
 +
$tr = "<tr>";
 +
}
 +
$profile .= "</table>\n";
 +
$text = $profile.$text;
 +
}
 +
return true;
 +
}
 +
 
 +
/**
 +
* Process uploaded image file
 +
*/
 +
function processUploadedImage($file) {
 +
global $wgUser, $wgDBname, $wgSiteNotice, $wgUploadDirectory, $awcMaxImageSize;
 +
$error = false;
 +
if (!ereg('^image/(jpeg|png|gif)$', $file['type'])) $error = 'Uploaded file was not of a valid type!';
 +
if ($file['size'] > $awcMaxImageSize)              $error = 'Profile images are restricted to a maximum of 100KBytes';
 +
if ($file['error'] > 0)                            $error = 'Uploaded error number '.$file['error'].' occurred';
 +
if ($error) $wgSiteNotice = "<div class='errorbox'>$error</div>";
 +
else {
 +
$name = preg_replace('%.+(\..+?)$%', "user-{$wgDBname}-{$wgUser->getId()}$1", $file['name']);
 +
move_uploaded_file($file['tmp_name'], "$wgUploadDirectory/$name");
 +
}
 +
}
 +
 
 +
/**
 +
* Render a link to Special:AWCForum
 +
*/
 +
function forumTag($text, $argv, &$parser) {
 +
 +
# Default args for a search link
 +
$defaults = array(
 +
'action'    => 'search/s_form',
 +
'full'      => 'full',
 +
'Sis_like'  => 'like',
 +
'kw'        => 'default',
 +
's_memposts' => 'on',
 +
'is_like'    => 'is',
 +
'memname'    => '',
 +
'fID'        => array('all')
 +
);
 +
 
 +
# Build query string from defaults and tag args
 +
$qs = array();
 +
foreach ($argv as $k => $v) {
 +
if (!in_array($k, array_keys($defaults))) $qs[] = "awcsbp_$k=$v";
 +
}
 +
if (count($qs)) $argv['memname'] = 'dummy';
 +
foreach ($defaults as $k => $v) {
 +
if (in_array($k, array_keys($argv))) $v = $argv[$k];
 +
if (is_array($v)) foreach ($v as $i) $qs[] = "{$k}[]=$i"; else $qs[] = "$k=$v";
 +
}
 +
$qs = join('&', $qs);
 +
 
 +
# Build link
 +
$title = Title::newFromText('AWCForum', NS_SPECIAL);
 +
$url = $title->getLocalURL($qs);
 +
if (empty($text)) $text = $title->getPrefixedText($title);
 +
$link = "<a href='$url'>$text</a>";
 +
 +
return $link;
 +
}
 +
 
 
/**
 
/**
* AWC forum_info tag is overridden with this one to catch the tag parameters
+
* Render a link to Special:AWCProfile
 
*/
 
*/
function forum_info($input, $argv) {
+
function profileTag($text, $argv, &$parser) {
$this->tagargs = $input;
+
 
return call_user_func($this->oldtag, $input, $argv);
+
# Build query string from defaults and tag args
 +
$qs = array();
 +
foreach ($argv as $k => $v) {
 +
$k = ucfirst($k);
 +
if ($k == 'Expertise' || $k == 'State' || $k == 'County' || $k == 'City') $qs[] = "wp$k=$v";
 +
}
 +
$qs = join('&', $qs);
 +
 
 +
# Build link
 +
$title = Title::newFromText('ProfileSearch', NS_SPECIAL);
 +
$url = $title->getLocalURL($qs);
 +
if (empty($text)) $text = $title->getPrefixedText($title);
 +
$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) {
print_r($this->tagargs);
+
 
 +
# Convert the prefs to an SQL condition statement for selecting users
 +
$cond = array();
 +
foreach ($this->searchPrefs as $k => $v) $cond[] = "(user_options REGEXP('$k=$v'))";
 +
if (count($cond)) {
 +
 
 +
# Convert the resulting users to an SQL condition statement for the AWC query
 +
$dbr = wfGetDB(DB_SLAVE);
 +
$tbl = $dbr->tableName('user');
 +
$res = $dbr->select($tbl, 'user_name', join(' AND ', $cond));
 +
$cond = array();
 +
while ($row = $dbr->fetchRow($res)) $cond[] = "p.p_user='$row[0]'";
 +
$dbr->freeResult($res);
 +
 
 +
# Replace the default user condition in the SQL with the new one
 +
if (count($cond)) {
 +
$sql = preg_replace("|p.p_user\\s=\\s*'dummy'|", '('.join(' OR ', $cond).')', $sql);
 +
$sql = preg_replace("|'%default%'|", "'%%'", $sql);
 +
}
 +
}
 +
 
 
}
 
}
 
 
Line 118: Line 448:
 
static function updateLB(&$lb) {
 
static function updateLB(&$lb) {
 
$lb->closeAll();
 
$lb->closeAll();
foreach ($lb->mServers as $i => $server) $lb->mServers[$i]['type'] = 'SimpleSecurity';
+
foreach ($lb->mServers as $i => $server) $lb->mServers[$i]['type'] = 'AWC';
 
}
 
}
  
Line 141: Line 471:
 
function wfAWCmodDBHook() {
 
function wfAWCmodDBHook() {
 
global $wgDBtype, $awcDBHook, $wgOldDBtype;
 
global $wgDBtype, $awcDBHook, $wgOldDBtype;
$wgOldDBtype = $wgDBtype;
 
 
$oldClass = ucfirst($wgDBtype);
 
$oldClass = ucfirst($wgDBtype);
 
$wgDBtype = 'AWC';
 
$wgDBtype = 'AWC';
 
eval("class Database{$wgDBtype} extends Database{$oldClass}".' {
 
eval("class Database{$wgDBtype} extends Database{$oldClass}".' {
 
public function query($sql, $fname = "", $tempIgnore = false) {
 
public function query($sql, $fname = "", $tempIgnore = false) {
 +
#print $sql;
 
global $wgAWCmod;
 
global $wgAWCmod;
if (ereg("^SELECT",$sql)
+
if (is_object($wgAWCmod) && (preg_match("|^SELECT.+?FROM.+?WHERE.+?p.p_user\\s*=\\s*\'dummy\'|s",$sql)))
&& ereg("awc_f_threads", $sql)
 
&& ereg("awc_f_forums",$sql)
 
&& ereg("awc_f_cats",$sql)
 
&& ereg("awc_f_posts",$sql)
 
) {
 
 
$wgAWCmod->patchSQL($sql);
 
$wgAWCmod->patchSQL($sql);
}
 
 
return parent::query($sql, $fname, $tempIgnore);
 
return parent::query($sql, $fname, $tempIgnore);
 
}
 
}
 
}');
 
}');
 
$awcDBHook = false;
 
$awcDBHook = false;
 +
}
 +
 +
/**
 +
* Define a new class based on the SpecialPage class
 +
*/
 +
class SpecialProfileSearch extends SpecialPage {
 +
 +
var $posted  = array();
 +
var $results = array();
 +
 +
function __construct() {
 +
 +
SpecialPage::SpecialPage(
 +
'ProfileSearch', # name as seen in links etc
 +
false,          # user rights required
 +
true,            # listed in special:specialpages
 +
false,          # function called by execute() - defaults to wfSpecial{$name}
 +
false,          # file included by execute() - defaults to Special{$name}.php, only used if no function
 +
false            # includable
 +
);
 +
}
 +
 +
/**
 +
* Override SpecialPage::execute()
 +
*/
 +
function execute($param) {
 +
global $wgAWCmod, $wgOut, $wgRequest;
 +
$this->setHeaders();
 +
$title = Title::makeTitle(NS_SPECIAL, 'ProfileSearch');
 +
 +
# Get any posted/getted values and add to object->posted array
 +
$this->posted = array(
 +
'skills' => $wgRequest->getText('wpExpertise'),
 +
'city'  => $wgRequest->getText('wpCity'),
 +
'state'  => $wgRequest->getText('wpState'),
 +
'county' => $wgRequest->getText('wpCounty')
 +
);
 +
 +
# Render form including any posted vals
 +
$wgAWCmod->buildOptionLists($this->posted);
 +
$wgOut->addScript("<script type='text/javascript'>{$wgAWCmod->JS}</script>");
 +
$wgOut->addWikiText(wfMsg('awc-searchmsg'));
 +
$wgOut->addHTML('<br><table>'
 +
.wfElement('form', array('class' => 'profilesearch', 'action' => $title->getLocalURL('action=submit'), 'method' => 'post'), null)
 +
."<tr><td>Expertise:</td><td><select name=\"wpExpertise\" id=\"wpExpertise\">{$wgAWCmod->skillsOptions}</select></td></tr>\n"
 +
."<tr><td>City:</td><td>".wfInput('wpCity', 20, $this->posted['city'], array('id' => 'wpCity'))."</td></tr>\n"
 +
."<tr><td>State:</td><td><select name=\"wpState\" id=\"wpState\" onchange=\"awcUpdateCounty(this.value)\">{$wgAWCmod->stateOptions}</select></td></tr>\n"
 +
."<tr><td>County:</td><td><select name=\"wpCounty\" id=\"wpCounty\">{$wgAWCmod->countyOptions}</select></td></tr>\n"
 +
."<tr><td></td><td>".wfElement('input', array('type' => 'submit', 'name' => 'wpFind', 'value' => "Search"))."</td></tr>\n"
 +
."</form></table><br>"
 +
);
 +
 +
# Perform query and render results if any posted vals
 +
if (count($this->posted)) {
 +
 +
# Convert the prefs to an SQL condition statement for selecting users
 +
$cond = array();
 +
foreach ($this->posted as $k => $v) if ($v) $cond[] = "(user_options REGEXP('$k=$v'))";
 +
 +
# Extract the fields for each user from the database
 +
$dbr = wfGetDB(DB_SLAVE);
 +
$tbl = $dbr->tableName('user');
 +
$res = $dbr->select($tbl, 'user_id', join(' AND ', $cond));
 +
while ($row = $dbr->fetchRow($res)) {
 +
$user = User::newFromId($row[0]);
 +
$name = $user->getName();
 +
$page = Title::newFromText($name, NS_USER)->getLocalURL();
 +
$this->results[] = array(
 +
'User ID'    => "<a href='$page'>$name</a>",
 +
'First Name' => $user->getOption('firstname'),
 +
'Last Name'  => $user->getOption('lastname'),
 +
'Expertise'  => $user->getOption('skills'),
 +
'Business'  => $user->getOption('business'),
 +
'City'      => $user->getOption('city'),
 +
'State'      => $user->getOption('state'),
 +
'County'    => $user->getOption('county')
 +
);
 +
}
 +
$dbr->freeResult($res);
 +
 +
# Render results if any
 +
if (count($this->results)) {
 +
$title = Title::makeTitle(NS_SPECIAL, 'ProfileSearch');
 +
$head = join('</th><th>', array_keys($this->results[0]));
 +
$wgOut->addHTML("<table class='sortable' id='searchResults'><tr><th>$head</th></tr>\n");
 +
foreach ($this->results as $row) $wgOut->addHTML("<tr><td>".join("</td><td>", $row)."</td></tr>\n");
 +
$wgOut->addHTML("</table>\n");
 +
} else $wgOut->addHTML('<i>No results to display</i>');
 +
}
 +
}
 
}
 
}
  
Line 164: Line 578:
 
global $wgAWCmod, $awcDBHook, $wgLanguageCode, $wgMessageCache, $wgLoadBalancer, $wgDBtype, $wgOldDBtype;
 
global $wgAWCmod, $awcDBHook, $wgLanguageCode, $wgMessageCache, $wgLoadBalancer, $wgDBtype, $wgOldDBtype;
  
 +
# Add the messages used by the specialpage
 +
if ($wgLanguageCode == 'en') {
 +
$wgMessageCache->addMessages(array(
 +
'profilesearch' => "Search by profile",
 +
'awc-preftab'  => "Extended Profile",
 +
'awc-prefmsg'  => "<br><b>Let others find you by filling in this information!</b><br>",
 +
'awc-searchmsg' => "\n\n<b>Search for other Property Tax pros here! If you want to be added, edit your Extended Profile in User Preferences</b>\n\n"
 +
));
 +
}
 +
 +
# Add the specialpage to the environment
 +
SpecialPage::addPage(new SpecialProfileSearch());
 +
 
# Instantiate the AWC singleton now that the environment is prepared
 
# Instantiate the AWC singleton now that the environment is prepared
 
$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
 
if ($wgLanguageCode == 'en') {
 
$wgMessageCache->addMessages(array(
 
'awc-prefhead' => "AWC"
 
));
 
}
 
 
}
 
}

Latest revision as of 03:32, 6 November 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.2.7, 2008-11-06');

$wgAutoConfirmCount = 10^10;

$awcDefaultImage = ; $awcMaxImageSize = 100000;

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

require_once "$IP/includes/SpecialPage.php";

  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. Process posted contact details

if (isset($_POST['wpFirstName'])) $_POST['wpRealName'] = $_POST['wpFirstName'].' '.$_POST['wpLastName'];

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

if ($awcDBHook = count($awcSearchByPref) > 0) $_POST['fID'] = array('all');

  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 $JS = ; var $searchPrefs = array(); var $skillsOptions = ; var $stateOptions = ; var $countyOptions = ;

function __construct() { global $wgUser, $wgHooks, $wgMessageCache, $wgParser, $awcSearchByPref, $wgGroupPermissions, $wgWhitelistRead, $wgRequest;

# Deny access until email address confirmed #$wgGroupPermissions['*']['read'] = false; #$wgWhitelistRead = array("Special:Preferences", "Special:Userlogin", "-");

		#if (!$wgUser->isEmailConfirmed()) $wgGroupPermissions['user']['read'] = false;

$this->searchPrefs = $awcSearchByPref;

#$wgHooks['AbortNewAccount'][] = $this; # Save the extra prefs after posting account-create #$wgHooks['UserCreateForm'][] = $this; # Modify the create-account form to add new prefs $wgHooks['RenderPreferencesForm'][] = $this; # Add the new pref tab $wgHooks['SavePreferences'][] = $this; # Save the extra posted data to the user object's options $wgHooks['SpecialPageExecuteAfterPage'][] = $this; # Modify preferences forms enctype and onsubmit $wgHooks['OutputPageBeforeHTML'][] = $this; # Add profile info to user pages

# Modify login form messages to say email and name compulsory

  1. $wgMessageCache->addMessages(array('prefs-help-email' => '
    Required
    '));
  2. $wgMessageCache->addMessages(array('prefs-help-realname' => '
    Required
    '));

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

# Process an uploaded profile image if one was posted if (array_key_exists('wpProfileImage', $_FILES) && $_FILES['wpProfileImage']['size'] > 0) $this->processUploadedImage($_FILES['wpProfileImage']);

}


/** * Prepare the dropdown list content if using a special page containing one of our forms */ function buildOptionLists(&$user = false) { include(dirname(__FILE__)."/states.php"); $this->JS = $awcJS;

# Build skills option list $skills = $this->getOption($user, 'skills'); $this->skillsOptions = '<option/>'; foreach (array( 'Concerned Citizen', 'Accountant', 'Lawyer', 'Tax Advisor', 'Tax Agent', 'Assessor', 'Realtor' ) as $s) { $selected = $skills == $s ? ' selected' : ; $this->skillsOptions .= "<option$selected>$s</option>\n"; }

# Build state options list $state = $this->getOption($user, 'state'); $this->stateOptions = '<option value="">Enter state...</option>'; foreach (array_keys($awcStates) as $s) { $selected = $state == $s ? ' selected' : ; $this->stateOptions .= "<option$selected>$s</option>\n"; }

# Build county options list $county = $this->getOption($user, 'county'); $this->countyOptions = '<option value="">Enter county...</option>'; if ($state) { foreach (split(',', $awcStates[$state]) as $c) { $c = substr($c, 1, -1); $selected = $county == $c ? ' selected' : ; $this->countyOptions .= "<option$selected>$c</option>\n"; } } }

/** * Get an option from the passed user or array (or it can be false) */ function getOption(&$obj, $opt, $default = ) { if (is_object($obj)) return $obj->getOption($opt); if (is_array($obj) && array_key_exists($opt, $obj)) return $obj[$opt]; return $default; }

/** * Hack to add onSubmit for validation and enctype for image upload to form tag */ function onSpecialPageExecuteAfterPage(&$special, $par, $func) { global $wgOut; if ($special->mName == 'Preferences') { $wgOut->mBodytext = str_replace( '<form', '<form onsubmit="return awcValidate(this)" enctype="multipart/form-data"', $wgOut->mBodytext ); } return true; }

/** * Add the new prefs to a new tab in the preferences form */ function onRenderPreferencesForm(&$form, &$out) { $out->addHTML('<fieldset><legend>'.wfMsg('awc-preftab').'</legend>'.wfMsg('awc-prefmsg').$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) { $this->setOptions($user); return true; }

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

/** * Set user options from posted form */ function setOptions(&$user) { global $wgRequest; $user->setOption('firstname', $wgRequest->getVal('wpFirstName')); $user->setOption('lastname', $wgRequest->getVal('wpLastName')); $user->setOption('phone', $wgRequest->getVal('wpPhone')); $user->setOption('mobile', $wgRequest->getVal('wpMobile')); $user->setOption('business', $wgRequest->getVal('wpBusiness')); $user->setOption('skills', $wgRequest->getVal('wpSkills')); $user->setOption('website', $wgRequest->getVal('wpWebsite')); $user->setOption('fax', $wgRequest->getVal('wpFax')); $user->setOption('address', $wgRequest->getVal('wpAddress')); $user->setOption('address2', $wgRequest->getVal('wpAddress2')); $user->setOption('city', $wgRequest->getVal('wpCity')); $user->setOption('state', $wgRequest->getVal('wpState')); $user->setOption('county', $wgRequest->getVal('wpCounty')); $user->setOption('zipcode', $wgRequest->getVal('wpZipCode')); $user->setOption('logo', $wgRequest->getVal('wpProfileImage')); $user->setOption('notes', $wgRequest->getVal('wpNotes')); }

/** * Return the HTML for the AWC preference inputs */ function renderAWCprefs() { global $wgUser, $wgOut, $wgHooks; $this->buildOptionLists($wgUser); $wgOut->addScript("<script type='text/javascript'>{$this->JS}</script>");

$html = "

" .

$this->addRow( wfLabel('First Name', 'wpFirstName'), wfInput('wpFirstName', 20, $wgUser->getOption('firstname'), array('id' => 'wpFirstName')) ) . $this->addRow( wfLabel('Last Name', 'wpLastName'), wfInput('wpLastName', 20, $wgUser->getOption('lastname'), array('id' => 'wpLastName')) ) . $this->addRow( wfLabel('Voice Phone', 'wpPhone'), wfInput('wpPhone', 10, $wgUser->getOption('phone'), array('id' => 'wpPhone')) ) . $this->addRow( wfLabel('Mobile Phone', 'wpMobile'), wfInput('wpMobile', 10, $wgUser->getOption('mobile'), array('id' => 'wpMobile')) ) . $this->addRow( wfLabel('Fax', 'wpFax'), wfInput('wpFax', 10, $wgUser->getOption('fax'), array('id' => 'wpFax')) ) . $this->addRow( wfLabel('Expertise', 'wpSkills'), '<select name="wpSkills" id="wpSkills">'.$this->skillsOptions.'</select>' ) . $this->addRow( wfLabel('Business Name', 'wpBusiness'), wfInput('wpBusiness', 20, $wgUser->getOption('business'), array('id' => 'wpBusiness')) ) . $this->addRow( wfLabel('Website', 'wpWebsite'), wfInput('wpWebsite', 20, $wgUser->getOption('website'), array('id' => 'wpWebsite')) ) . $this->addRow( wfLabel('Address', 'wpAddress'), wfInput('wpAddress', 20, $wgUser->getOption('address'), array('id' => 'wpAddress')) ) . $this->addRow( wfLabel('Address 2', 'wpAddress2'), wfInput('wpAddress2', 20, $wgUser->getOption('address2'), array('id' => 'wpAddress2')) ) . $this->addRow( wfLabel('City', 'wpCity'), wfInput('wpCity', 20, $wgUser->getOption('city'), array('id' => 'wpCity')) ) . $this->addRow( wfLabel('State', 'wpState'), '<select name="wpState" id="wpState" onchange="awcUpdateCounty(this.value)">'.$this->stateOptions.'</select>', 'Required' ) . $this->addRow( wfLabel('County', 'wpCounty'), '<select name="wpCounty" id="wpCounty">'.$this->countyOptions.'</select>', 'Required' ) . $this->addRow( wfLabel('Zip Code', 'wpZipCode'), wfInput('wpZipCode', 10, $wgUser->getOption('zipcode'), array('id' => 'wpZipCode')) ) . $this->addRow( wfLabel('Logo', 'wpProfileImage'), wfInput('wpProfileImage', 10, $wgUser->getOption('logo'), array('id' => 'wpProfileImage', 'type' => 'file')) ) . $this->addRow(wfLabel('Additional Information (1000 Characters Max)', 'wpNotes'), )

. '' . '
<textarea cols=30 rows="7" id="wpNotes" name="wpNotes">'.$wgUser->getOption('notes').'</textarea>

';


$html .= '<script type="text/javascript">awcAddValidation()</script>'; return $html; }

/** * Add a table row to the form */ function addRow($td1, $td2, $td3 = ) {

return " $td1: $td2

$td3

"; } /** * Add the user profile info if it's a user page */ function onOutputPageBeforeHTML(&$out, &$text) { global $wgTitle, $wgDBname, $wgUploadDirectory, $wgUploadPath, $awcDefaultImage; if (is_object($wgTitle) && $wgTitle->getNamespace() == NS_USER) { $user = User::newFromName($wgTitle->getText()); $id = $user->getId(); $m = glob("$wgUploadDirectory/user-$wgDBname-$id.*"); $src = count($m) > 0 ? $m[0] : $awcDefaultImage; $src = preg_replace("%^.+(?=/user-)%", $wgUploadPath, $src); $profile = "

\n"; $profile .= "\n";

$tr = ; foreach(array( 'Name' => $user->getRealName(), 'Business' => $user->getOption('business'), 'Website' => $user->getOption('website'), 'Expertise' => $user->getOption('skills'), 'City' => $user->getOption('city'), 'County' => $user->getOption('county'), 'State' => $user->getOption('state'), 'Zip' => $user->getOption('zipcode'), 'Voice' => $user->getOption('phone'), 'Mobile' => $user->getOption('mobile'), 'Fax' => $user->getOption('fax'), 'Info' => $user->getOption('notes') ) as $k => $v) {

$profile .= "$tr\n"; $tr = ""; } $profile .= "
<img height='228' src=\"$src\" />$k:$v

\n";

$text = $profile.$text; } return true; }

/** * Process uploaded image file */ function processUploadedImage($file) { global $wgUser, $wgDBname, $wgSiteNotice, $wgUploadDirectory, $awcMaxImageSize; $error = false; if (!ereg('^image/(jpeg|png|gif)$', $file['type'])) $error = 'Uploaded file was not of a valid type!'; if ($file['size'] > $awcMaxImageSize) $error = 'Profile images are restricted to a maximum of 100KBytes'; if ($file['error'] > 0) $error = 'Uploaded error number '.$file['error'].' occurred';

if ($error) $wgSiteNotice = "

$error

";

else { $name = preg_replace('%.+(\..+?)$%', "user-{$wgDBname}-{$wgUser->getId()}$1", $file['name']); move_uploaded_file($file['tmp_name'], "$wgUploadDirectory/$name"); } }

/** * Render a link to Special:AWCForum */ function forumTag($text, $argv, &$parser) {

# Default args for a search link $defaults = array( 'action' => 'search/s_form', 'full' => 'full', 'Sis_like' => 'like', 'kw' => 'default', 's_memposts' => 'on', 'is_like' => 'is', 'memname' => , 'fID' => array('all') );

# Build query string from defaults and tag args $qs = array(); foreach ($argv as $k => $v) { if (!in_array($k, array_keys($defaults))) $qs[] = "awcsbp_$k=$v"; } if (count($qs)) $argv['memname'] = 'dummy'; foreach ($defaults as $k => $v) { if (in_array($k, array_keys($argv))) $v = $argv[$k]; if (is_array($v)) foreach ($v as $i) $qs[] = "{$k}[]=$i"; else $qs[] = "$k=$v"; } $qs = join('&', $qs);

# Build link $title = Title::newFromText('AWCForum', NS_SPECIAL); $url = $title->getLocalURL($qs); if (empty($text)) $text = $title->getPrefixedText($title); $link = "<a href='$url'>$text</a>";

return $link; }

/** * Render a link to Special:AWCProfile */ function profileTag($text, $argv, &$parser) {

# Build query string from defaults and tag args $qs = array(); foreach ($argv as $k => $v) { $k = ucfirst($k); if ($k == 'Expertise' || $k == 'State' || $k == 'County' || $k == 'City') $qs[] = "wp$k=$v"; } $qs = join('&', $qs);

# Build link $title = Title::newFromText('ProfileSearch', NS_SPECIAL); $url = $title->getLocalURL($qs); if (empty($text)) $text = $title->getPrefixedText($title); $link = "<a href='$url'>$text</a>";

return $link; }

/** * Patch the SQL used by the search to filter by user properties */ function patchSQL(&$sql) {

# Convert the prefs to an SQL condition statement for selecting users $cond = array(); foreach ($this->searchPrefs as $k => $v) $cond[] = "(user_options REGEXP('$k=$v'))"; if (count($cond)) {

# Convert the resulting users to an SQL condition statement for the AWC query $dbr = wfGetDB(DB_SLAVE); $tbl = $dbr->tableName('user'); $res = $dbr->select($tbl, 'user_name', join(' AND ', $cond)); $cond = array(); while ($row = $dbr->fetchRow($res)) $cond[] = "p.p_user='$row[0]'"; $dbr->freeResult($res);

# Replace the default user condition in the SQL with the new one if (count($cond)) { $sql = preg_replace("|p.p_user\\s=\\s*'dummy'|", '('.join(' OR ', $cond).')', $sql); $sql = preg_replace("|'%default%'|", "'%%'", $sql); } }

}

/** * 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) { #print $sql; global $wgAWCmod; if (is_object($wgAWCmod) && (preg_match("|^SELECT.+?FROM.+?WHERE.+?p.p_user\\s*=\\s*\'dummy\'|s",$sql))) $wgAWCmod->patchSQL($sql); return parent::query($sql, $fname, $tempIgnore); } }'); $awcDBHook = false; }

/**

* Define a new class based on the SpecialPage class
*/

class SpecialProfileSearch extends SpecialPage {

var $posted = array(); var $results = array();

function __construct() {

SpecialPage::SpecialPage( 'ProfileSearch', # name as seen in links etc false, # user rights required true, # listed in special:specialpages false, # function called by execute() - defaults to wfSpecial{$name} false, # file included by execute() - defaults to Special{$name}.php, only used if no function false # includable ); }

/** * Override SpecialPage::execute() */ function execute($param) { global $wgAWCmod, $wgOut, $wgRequest; $this->setHeaders(); $title = Title::makeTitle(NS_SPECIAL, 'ProfileSearch');

# Get any posted/getted values and add to object->posted array $this->posted = array( 'skills' => $wgRequest->getText('wpExpertise'), 'city' => $wgRequest->getText('wpCity'), 'state' => $wgRequest->getText('wpState'), 'county' => $wgRequest->getText('wpCounty') );

# Render form including any posted vals $wgAWCmod->buildOptionLists($this->posted); $wgOut->addScript("<script type='text/javascript'>{$wgAWCmod->JS}</script>"); $wgOut->addWikiText(wfMsg('awc-searchmsg'));

$wgOut->addHTML('

' .wfElement('form', array('class' => 'profilesearch', 'action' => $title->getLocalURL('action=submit'), 'method' => 'post'), null) ."\n" ."\n" ."\n" ."\n" ."\n" ."</form>
Expertise:<select name=\"wpExpertise\" id=\"wpExpertise\">{$wgAWCmod->skillsOptions}</select>
City:".wfInput('wpCity', 20, $this->posted['city'], array('id' => 'wpCity'))."
State:<select name=\"wpState\" id=\"wpState\" onchange=\"awcUpdateCounty(this.value)\">{$wgAWCmod->stateOptions}</select>
County:<select name=\"wpCounty\" id=\"wpCounty\">{$wgAWCmod->countyOptions}</select>
".wfElement('input', array('type' => 'submit', 'name' => 'wpFind', 'value' => "Search"))."


"

);

# Perform query and render results if any posted vals if (count($this->posted)) {

# Convert the prefs to an SQL condition statement for selecting users $cond = array(); foreach ($this->posted as $k => $v) if ($v) $cond[] = "(user_options REGEXP('$k=$v'))";

# Extract the fields for each user from the database $dbr = wfGetDB(DB_SLAVE); $tbl = $dbr->tableName('user'); $res = $dbr->select($tbl, 'user_id', join(' AND ', $cond)); while ($row = $dbr->fetchRow($res)) { $user = User::newFromId($row[0]); $name = $user->getName(); $page = Title::newFromText($name, NS_USER)->getLocalURL(); $this->results[] = array( 'User ID' => "<a href='$page'>$name</a>", 'First Name' => $user->getOption('firstname'), 'Last Name' => $user->getOption('lastname'), 'Expertise' => $user->getOption('skills'), 'Business' => $user->getOption('business'), 'City' => $user->getOption('city'), 'State' => $user->getOption('state'), 'County' => $user->getOption('county') ); } $dbr->freeResult($res);

# Render results if any if (count($this->results)) { $title = Title::makeTitle(NS_SPECIAL, 'ProfileSearch');

$head = join('', array_keys($this->results[0])); $wgOut->addHTML("

\n"); foreach ($this->results as $row) $wgOut->addHTML("\n"); $wgOut->addHTML("
$head
".join("", $row)."

\n");

} else $wgOut->addHTML('No results to display'); } } }

function wfSetupAWCmod() { global $wgAWCmod, $awcDBHook, $wgLanguageCode, $wgMessageCache, $wgLoadBalancer, $wgDBtype, $wgOldDBtype;

# Add the messages used by the specialpage if ($wgLanguageCode == 'en') { $wgMessageCache->addMessages(array( 'profilesearch' => "Search by profile", 'awc-preftab' => "Extended Profile", 'awc-prefmsg' => "
Let others find you by filling in this information!
", 'awc-searchmsg' => "\n\nSearch for other Property Tax pros here! If you want to be added, edit your Extended Profile in User Preferences\n\n" )); }

# Add the specialpage to the environment SpecialPage::addPage(new SpecialProfileSearch());

# 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; }

}