Difference between revisions of "Extension:AWCmod"

From Organic Design wiki
(process uploaded profile images)
m (few more client mandated mods...should be a wrap...)
 
(5 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.2.2, 2008-10-31');
+
define('AWCMOD_VERSION', '0.2.7, 2008-11-06');
  
 
$wgAutoConfirmCount = 10^10;
 
$wgAutoConfirmCount = 10^10;
 +
 +
$awcDefaultImage = '';
 +
$awcMaxImageSize = 100000;
  
 
$wgExtensionFunctions[] = 'wfSetupAWCmod';
 
$wgExtensionFunctions[] = 'wfSetupAWCmod';
Line 30: Line 33:
  
 
# Process posted contact details
 
# Process posted contact details
if (isset($_POST['wpFirstName'])) {
+
if (isset($_POST['wpFirstName'])) $_POST['wpRealName'] = $_POST['wpFirstName'].' '.$_POST['wpLastName'];
$_POST['wpRealName'] = $_POST['wpFirstName'].' '.$_POST['wpLastName'];
 
}
 
  
 
# Don't apply the db hook unless awcsearchprefs have been posted
 
# Don't apply the db hook unless awcsearchprefs have been posted
Line 58: Line 59:
 
function __construct() {
 
function __construct() {
 
global $wgUser, $wgHooks, $wgMessageCache, $wgParser, $awcSearchByPref, $wgGroupPermissions, $wgWhitelistRead, $wgRequest;
 
global $wgUser, $wgHooks, $wgMessageCache, $wgParser, $awcSearchByPref, $wgGroupPermissions, $wgWhitelistRead, $wgRequest;
+
 
 
# Deny access until email address confirmed
 
# Deny access until email address confirmed
 
#$wgGroupPermissions['*']['read'] = false;
 
#$wgGroupPermissions['*']['read'] = false;
Line 66: Line 67:
 
$this->searchPrefs = $awcSearchByPref;
 
$this->searchPrefs = $awcSearchByPref;
 
 
$wgHooks['RenderPreferencesForm'][]       = $this;
+
#$wgHooks['AbortNewAccount'][]           = $this;   # Save the extra prefs after posting account-create
#$wgHooks['UserCreateForm'][]            = $this;
+
#$wgHooks['UserCreateForm'][]            = $this;   # Modify the create-account form to add new prefs
$wgHooks['SavePreferences'][]            = $this;
+
$wgHooks['RenderPreferencesForm'][]      = $this;  # Add the new pref tab
#$wgHooks['AbortNewAccount'][]           = $this;
+
$wgHooks['SavePreferences'][]            = $this;   # Save the extra posted data to the user object's options
$wgHooks['SpecialPageExecuteAfterPage'][] = $this;
+
$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
Line 81: Line 83:
  
 
# Process an uploaded profile image if one was posted
 
# Process an uploaded profile image if one was posted
if (array_key_exists('wpProfileImage', $_FILES)) $this->processUploadedImage($_FILES['wpProfileImage']);
+
if (array_key_exists('wpProfileImage', $_FILES) && $_FILES['wpProfileImage']['size'] > 0)
 +
$this->processUploadedImage($_FILES['wpProfileImage']);
  
 
}
 
}
Line 242: Line 245:
 
) .
 
) .
 
$this->addRow(
 
$this->addRow(
wfLabel('Business', 'wpBusiness'),
+
wfLabel('Business Name', 'wpBusiness'),
 
wfInput('wpBusiness', 20, $wgUser->getOption('business'), array('id' => 'wpBusiness'))
 
wfInput('wpBusiness', 20, $wgUser->getOption('business'), array('id' => 'wpBusiness'))
 
) .
 
) .
Line 279: Line 282:
 
wfInput('wpProfileImage', 10, $wgUser->getOption('logo'), array('id' => 'wpProfileImage', 'type' => 'file'))
 
wfInput('wpProfileImage', 10, $wgUser->getOption('logo'), array('id' => 'wpProfileImage', 'type' => 'file'))
 
) .
 
) .
$this->addRow(wfLabel('Additional information', 'wpNotes'), '')
+
$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>'
 
. '<tr><td colspan="3"><textarea cols=30 rows="7" id="wpNotes" name="wpNotes">'.$wgUser->getOption('notes').'</textarea></td></tr>'
 
. '</table></div>';
 
. '</table></div>';
 +
 +
 +
 
$html .= '<script type="text/javascript">awcAddValidation()</script>';
 
$html .= '<script type="text/javascript">awcAddValidation()</script>';
 
return $html;
 
return $html;
Line 295: Line 301:
 
<td><div class='prefsectiontip'><div class='error'>$td3</div></div></td>
 
<td><div class='prefsectiontip'><div class='error'>$td3</div></div></td>
 
</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;
 
}
 
}
  
Line 301: Line 344:
 
*/
 
*/
 
function processUploadedImage($file) {
 
function processUploadedImage($file) {
global $wgUser, $wgSiteNotice;
+
global $wgUser, $wgDBname, $wgSiteNotice, $wgUploadDirectory, $awcMaxImageSize;
 
$error = false;
 
$error = false;
 
if (!ereg('^image/(jpeg|png|gif)$', $file['type'])) $error = 'Uploaded file was not of a valid type!';
 
if (!ereg('^image/(jpeg|png|gif)$', $file['type'])) $error = 'Uploaded file was not of a valid type!';
if ($file['size'] > 100000)                         $error = 'Profile images are restricted to a maximum of 100KBytes';
+
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 ($file['error'] > 0)                            $error = 'Uploaded error number '.$file['error'].' occurred';
 
if ($error) $wgSiteNotice = "<div class='errorbox'>$error</div>";
 
if ($error) $wgSiteNotice = "<div class='errorbox'>$error</div>";
 
else {
 
else {
$name = preg_replace('%.+(\..+?)$%', $wgUser->getId().'$1', $file['name']);
+
$name = preg_replace('%.+(\..+?)$%', "user-{$wgDBname}-{$wgUser->getId()}$1", $file['name']);
move_uploaded_file($file['tmp_name'], dirname(__FILE__)."/images/$name");
+
move_uploaded_file($file['tmp_name'], "$wgUploadDirectory/$name");
 
}
 
}
 
}
 
}
Line 343: Line 386:
  
 
# Build link
 
# Build link
$url = Title::newFromText('AWCForum', NS_SPECIAL)->getLocalURL($qs);
+
$title = Title::newFromText('AWCForum', NS_SPECIAL);
 +
$url = $title->getLocalURL($qs);
 +
if (empty($text)) $text = $title->getPrefixedText($title);
 
$link = "<a href='$url'>$text</a>";
 
$link = "<a href='$url'>$text</a>";
 
 
Line 353: Line 398:
 
*/
 
*/
 
function profileTag($text, $argv, &$parser) {
 
function profileTag($text, $argv, &$parser) {
 +
 +
# Build query string from defaults and tag args
 
$qs = array();
 
$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);
 
$qs = join('&', $qs);
$url = Title::newFromText('ProfileSearch', NS_SPECIAL)->getLocalURL($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;
 
return $link;
 
}
 
}
Line 458: Line 515:
 
# Get any posted/getted values and add to object->posted array
 
# Get any posted/getted values and add to object->posted array
 
$this->posted = array(
 
$this->posted = array(
'skills' => $wgRequest->getText('wpSkills'),
+
'skills' => $wgRequest->getText('wpExpertise'),
 
'city'  => $wgRequest->getText('wpCity'),
 
'city'  => $wgRequest->getText('wpCity'),
 
'state'  => $wgRequest->getText('wpState'),
 
'state'  => $wgRequest->getText('wpState'),
Line 468: Line 525:
 
$wgOut->addScript("<script type='text/javascript'>{$wgAWCmod->JS}</script>");
 
$wgOut->addScript("<script type='text/javascript'>{$wgAWCmod->JS}</script>");
 
$wgOut->addWikiText(wfMsg('awc-searchmsg'));
 
$wgOut->addWikiText(wfMsg('awc-searchmsg'));
$wgOut->addHTML('<br>'
+
$wgOut->addHTML('<br><table>'
 
.wfElement('form', array('class' => 'profilesearch', 'action' => $title->getLocalURL('action=submit'), 'method' => 'post'), null)
 
.wfElement('form', array('class' => 'profilesearch', 'action' => $title->getLocalURL('action=submit'), 'method' => 'post'), null)
.'City: '.wfInput('wpCity', 20, $this->posted['city'], array('id' => 'wpCity')).' &nbsp; '
+
."<tr><td>Expertise:</td><td><select name=\"wpExpertise\" id=\"wpExpertise\">{$wgAWCmod->skillsOptions}</select></td></tr>\n"
.'State: <select name="wpState" id="wpState" onchange="awcUpdateCounty(this.value)">'.$wgAWCmod->stateOptions.'</select> &nbsp; '
+
."<tr><td>City:</td><td>".wfInput('wpCity', 20, $this->posted['city'], array('id' => 'wpCity'))."</td></tr>\n"
.'County: <select name="wpCounty" id="wpCounty">'.$wgAWCmod->countyOptions.'</select> &nbsp; '
+
."<tr><td>State:</td><td><select name=\"wpState\" id=\"wpState\" onchange=\"awcUpdateCounty(this.value)\">{$wgAWCmod->stateOptions}</select></td></tr>\n"
.wfElement('input', array('type' => 'submit', 'name' => 'wpFind', 'value' => "Search"))
+
."<tr><td>County:</td><td><select name=\"wpCounty\" id=\"wpCounty\">{$wgAWCmod->countyOptions}</select></td></tr>\n"
.'</form><br>'
+
."<tr><td></td><td>".wfElement('input', array('type' => 'submit', 'name' => 'wpFind', 'value' => "Search"))."</td></tr>\n"
 +
."</form></table><br>"
 
);
 
);
 
 
Line 490: Line 548:
 
while ($row = $dbr->fetchRow($res)) {
 
while ($row = $dbr->fetchRow($res)) {
 
$user = User::newFromId($row[0]);
 
$user = User::newFromId($row[0]);
 +
$name = $user->getName();
 +
$page = Title::newFromText($name, NS_USER)->getLocalURL();
 
$this->results[] = array(
 
$this->results[] = array(
 +
'User ID'    => "<a href='$page'>$name</a>",
 
'First Name' => $user->getOption('firstname'),
 
'First Name' => $user->getOption('firstname'),
 
'Last Name'  => $user->getOption('lastname'),
 
'Last Name'  => $user->getOption('lastname'),
Line 522: Line 583:
 
'profilesearch' => "Search by profile",
 
'profilesearch' => "Search by profile",
 
'awc-preftab'  => "Extended Profile",
 
'awc-preftab'  => "Extended Profile",
'awc-prefmsg'  => "<br><b>Client supplied explanation of this tab goes here.</b><br>
+
'awc-prefmsg'  => "<br><b>Let others find you by filling in this information!</b><br>",
                    Change at end of the <i>AWCmod.php</i> script, remember to update the source
+
'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"
                    <a href='http://www.organicdesign.co.nz/Extensions:AWCmod'>here</a>.<br><br>",
 
'awc-searchmsg' => "\n\n<b>Client supplied explanation of this page goes here.</b>\n
 
                    Change at end of the <i>AWCmod.php</i> script, remember to update the source
 
                    [http://www.organicdesign.co.nz/Extensions:AWCmod here].\n\n"
 
 
));
 
));
 
}
 
}

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

}