Extension:AWCmod

From Organic Design wiki

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

}