r35239 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r35238‎ | r35239 | r35240 >
Date:18:39, 23 May 2008
Author:aaron
Status:old
Tags:
Comment:
Split out special pages
Modified paths:
  • /trunk/extensions/ConfirmAccount/ConfirmAccount_body.php (modified) (history)
  • /trunk/extensions/ConfirmAccount/RequestAccount_body.php (added) (history)
  • /trunk/extensions/ConfirmAccount/SpecialConfirmAccount.php (modified) (history)
  • /trunk/extensions/ConfirmAccount/UserCredentials_body.php (added) (history)

Diff [purge]

Index: trunk/extensions/ConfirmAccount/UserCredentials_body.php
@@ -0,0 +1,218 @@
 2+<?php
 3+
 4+if ( !defined( 'MEDIAWIKI' ) ) {
 5+ echo "ConfirmAccount extension\n";
 6+ exit( 1 );
 7+}
 8+
 9+# Add messages
 10+wfLoadExtensionMessages( 'ConfirmAccount' );
 11+
 12+class UserCredentialsPage extends SpecialPage
 13+{
 14+
 15+ function __construct() {
 16+ SpecialPage::SpecialPage('UserCredentials','lookupcredentials');
 17+ }
 18+
 19+ function execute( $par ) {
 20+ global $wgRequest, $wgOut, $wgUser, $wgAccountRequestTypes;
 21+
 22+ if( !$wgUser->isAllowed( 'lookupcredentials' ) ) {
 23+ $wgOut->permissionRequired( 'lookupcredentials' );
 24+ return;
 25+ }
 26+
 27+ $this->setHeaders();
 28+
 29+ # A target user
 30+ $this->target = $wgRequest->getText( 'target' );
 31+ # Attachments
 32+ $this->file = $wgRequest->getVal( 'file' );
 33+
 34+ $this->skin = $wgUser->getSkin();
 35+
 36+ if( $this->file ) {
 37+ $this->showFile( $this->file );
 38+ } else if( $this->target ) {
 39+ $this->showForm();
 40+ $this->showCredentials();
 41+ } else {
 42+ $this->showForm();
 43+ }
 44+ }
 45+
 46+ function showForm() {
 47+ global $wgOut, $wgTitle, $wgScript;
 48+
 49+ $username = str_replace( '_', ' ', $this->target );
 50+ $form = Xml::openElement( 'form', array( 'name' => 'stablization', 'action' => $wgScript, 'method' => 'get' ) );
 51+ $form .= "<fieldset><legend>".wfMsg('usercredentials-leg')."</legend>";
 52+ $form .= "<table><tr>";
 53+ $form .= "<td>".Xml::hidden( 'title', $wgTitle->getPrefixedText() )."</td>";
 54+ $form .= "<td>".wfMsgHtml("usercredentials-user")."</td>";
 55+ $form .= "<td>".Xml::input('target', 35, $username, array( 'id' => 'wpUsername' ) )."</td>";
 56+ $form .= "<td>".Xml::submitButton( wfMsg( 'go' ) )."</td>";
 57+ $form .= "</tr></table>";
 58+ $form .= "</fieldset></form>\n";
 59+
 60+ $wgOut->addHTML( $form );
 61+ }
 62+
 63+ function showCredentials() {
 64+ global $wgOut, $wgUser, $wgLang, $wgAccountRequestTypes;
 65+
 66+ $titleObj = Title::makeTitle( NS_SPECIAL, "UserCredentials" );
 67+
 68+ $row = $this->getRequest();
 69+ if( !$row ) {
 70+ $wgOut->addHTML( wfMsgHtml('usercredentials-badid') );
 71+ return;
 72+ }
 73+
 74+ $wgOut->addWikiText( wfMsg( "usercredentials-text" ) );
 75+
 76+ $user = User::newFromName( $this->target );
 77+
 78+ $list = array();
 79+ foreach( $user->getGroups() as $group )
 80+ $list[] = self::buildGroupLink( $group );
 81+
 82+ $grouplist = '';
 83+ if( count( $list ) > 0 ) {
 84+ $grouplist = '<tr><td>'.wfMsgHtml( 'usercredentials-member' ).'</td><td>'.implode( ', ', $list ).'</td></tr>';
 85+ }
 86+
 87+ $form = "<fieldset>";
 88+ $form .= '<legend>' . wfMsgHtml('usercredentials-leg-user') . '</legend>';
 89+ $form .= '<table cellpadding=\'4\'>';
 90+ $form .= "<tr><td>".wfMsgHtml('username')."</td>";
 91+ $form .= "<td>".$this->skin->makeLinkObj( $user->getUserPage(), $user->getUserPage()->getText() )."</td></tr>\n";
 92+
 93+ $econf = $row->acd_email_authenticated ? ' <strong>'.wfMsgHtml('confirmaccount-econf').'</strong>' : '';
 94+ $form .= "<tr><td>".wfMsgHtml('usercredentials-email')."</td>";
 95+ $form .= "<td>".htmlspecialchars($row->acd_email).$econf."</td></tr>\n";
 96+
 97+ $form .= $grouplist;
 98+
 99+ $form .= '</table></fieldset>';
 100+
 101+ $areaSet = RequestAccountPage::expandAreas( $row->acd_areas );
 102+
 103+ if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
 104+ $form .= '<fieldset>';
 105+ $form .= '<legend>' . wfMsgHtml('confirmaccount-leg-areas') . '</legend>';
 106+
 107+ $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
 108+ $form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
 109+ $form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
 110+ $count = 0;
 111+
 112+ $att = array('disabled' => 'disabled');
 113+ foreach( $areas as $area ) {
 114+ $set = explode("|",$area,3);
 115+ if( $set[0] && isset($set[1]) ) {
 116+ $count++;
 117+ if( $count > 5 ) {
 118+ $form .= "</tr><tr valign='top'>";
 119+ $count = 1;
 120+ }
 121+ $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
 122+ if( isset($set[1]) ) {
 123+ $pg = $this->skin->makeKnownLink( $set[1], wfMsgHtml('requestaccount-info') );
 124+ } else {
 125+ $pg = '';
 126+ }
 127+ $form .= "<td>".wfCheckLabel( $set[0], $formName, $formName, in_array($formName,$areaSet), $att )." {$pg}</td>\n";
 128+ }
 129+ }
 130+ $form .= "</tr></table></div>";
 131+ $form .= '</fieldset>';
 132+ }
 133+
 134+ $form .= '<fieldset>';
 135+ $form .= '<legend>' . wfMsgHtml('usercredentials-leg-person') . '</legend>';
 136+ $form .= '<table cellpadding=\'4\'>';
 137+ $form .= "<tr><td>".wfMsgHtml('usercredentials-real')."</td>";
 138+ $form .= "<td>".htmlspecialchars($row->acd_real_name)."</td></tr>\n";
 139+ $form .= '</table>';
 140+ $form .= "<p>".wfMsgHtml('usercredentials-bio')."</p>";
 141+ $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpBio' id='wpNewBio' rows='10' cols='80' style='width:100%'>" .
 142+ htmlspecialchars($row->acd_bio) .
 143+ "</textarea></p>\n";
 144+ $form .= '</fieldset>';
 145+
 146+ $form .= '<fieldset>';
 147+ $form .= '<legend>' . wfMsgHtml('usercredentials-leg-other') . '</legend>';
 148+ $form .= '<p>'.wfMsgHtml('usercredentials-attach') . ' ';
 149+ if( $row->acd_filename ) {
 150+ $form .= $this->skin->makeKnownLinkObj( $titleObj, htmlspecialchars($row->acd_filename),
 151+ 'file=' . $row->acd_storage_key );
 152+ } else {
 153+ $form .= wfMsgHtml('confirmaccount-none-p');
 154+ }
 155+ $form .= "</p><p>".wfMsgHtml('usercredentials-notes')."</p>\n";
 156+ $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%'>" .
 157+ htmlspecialchars($row->acd_notes) .
 158+ "</textarea></p>\n";
 159+ $form .= "<p>".wfMsgHtml('usercredentials-urls')."</p>\n";
 160+ $form .= ConfirmAccountsPage::parseLinks($row->acd_urls);
 161+ if( $wgUser->isAllowed( 'requestips' ) ) {
 162+ $blokip = SpecialPage::getTitleFor( 'blockip' );
 163+ $form .= "<p>".wfMsgHtml('usercredentials-ip')." ".htmlspecialchars($row->acd_ip)."</p>\n";
 164+ }
 165+ $form .= '</fieldset>';
 166+
 167+ $wgOut->addHTML( $form );
 168+ }
 169+
 170+ /**
 171+ * Format a link to a group description page
 172+ *
 173+ * @param string $group
 174+ * @return string
 175+ */
 176+ private static function buildGroupLink( $group ) {
 177+ static $cache = array();
 178+ if( !isset( $cache[$group] ) )
 179+ $cache[$group] = User::makeGroupLinkHtml( $group, User::getGroupMember( $group ) );
 180+ return $cache[$group];
 181+ }
 182+
 183+ /**
 184+ * Show a private file requested by the visitor.
 185+ */
 186+ function showFile( $key ) {
 187+ global $wgOut, $wgRequest;
 188+ $wgOut->disable();
 189+
 190+ # We mustn't allow the output to be Squid cached, otherwise
 191+ # if an admin previews a private image, and it's cached, then
 192+ # a user without appropriate permissions can toddle off and
 193+ # nab the image, and Squid will serve it
 194+ $wgRequest->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
 195+ $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
 196+ $wgRequest->response()->header( 'Pragma: no-cache' );
 197+
 198+ $store = FileStore::get( 'accountcreds' );
 199+ if( !$store ) {
 200+ wfDebug( __METHOD__.": invalid storage group '{$store}'.\n" );
 201+ return false;
 202+ }
 203+ $store->stream( $key );
 204+ }
 205+
 206+ function getRequest() {
 207+ $uid = User::idFromName( $this->target );
 208+ if( !$uid )
 209+ return false;
 210+ # For now, just get the first revision...
 211+ $dbr = wfGetDB( DB_SLAVE );
 212+ $row = $dbr->selectRow( 'account_credentials', '*',
 213+ array( 'acd_user_id' => $uid ),
 214+ __METHOD__,
 215+ array( 'ORDER BY' => 'acd_user_id,acd_id ASC' ) );
 216+ return $row;
 217+ }
 218+
 219+}
Property changes on: trunk/extensions/ConfirmAccount/UserCredentials_body.php
___________________________________________________________________
Added: svn:eol-style
1220 + native
Index: trunk/extensions/ConfirmAccount/SpecialConfirmAccount.php
@@ -184,14 +184,14 @@
185185 $dir = dirname(__FILE__) . '/';
186186 # Request an account
187187 $wgSpecialPages['RequestAccount'] = 'RequestAccountPage';
188 -$wgAutoloadClasses['RequestAccountPage'] = $dir . 'ConfirmAccount_body.php';
 188+$wgAutoloadClasses['RequestAccountPage'] = $dir . 'RequestAccount_body.php';
189189 # Confirm accounts
190190 $wgSpecialPages['ConfirmAccounts'] = 'ConfirmAccountsPage';
191191 $wgAutoloadClasses['ConfirmAccountsPage'] = $dir . 'ConfirmAccount_body.php';
192192 $wgSpecialPageGroups['ConfirmAccounts'] = 'users';
193193 # Account credentials
194194 $wgSpecialPages['UserCredentials'] = 'UserCredentialsPage';
195 -$wgAutoloadClasses['UserCredentialsPage'] = $dir . 'ConfirmAccount_body.php';
 195+$wgAutoloadClasses['UserCredentialsPage'] = $dir . 'UserCredentials_body.php';
196196 $wgSpecialPageGroups['UserCredentials'] = 'users';
197197
198198 $wgExtensionFunctions[] = 'efLoadConfirmAccount';
Index: trunk/extensions/ConfirmAccount/RequestAccount_body.php
@@ -0,0 +1,685 @@
 2+<?php
 3+
 4+if ( !defined( 'MEDIAWIKI' ) ) {
 5+ echo "ConfirmAccount extension\n";
 6+ exit( 1 );
 7+}
 8+
 9+# Add messages
 10+wfLoadExtensionMessages( 'ConfirmAccount' );
 11+
 12+class RequestAccountPage extends SpecialPage {
 13+
 14+ function __construct() {
 15+ parent::__construct( 'RequestAccount' );
 16+ }
 17+
 18+ function execute( $par ) {
 19+ global $wgUser, $wgOut, $wgRequest, $action, $wgUseRealNamesOnly,
 20+ $wgAccountRequestToS, $wgAccountRequestExtraInfo, $wgAccountRequestTypes;
 21+ # If a user cannot make accounts, don't let them request them either
 22+ global $wgAccountRequestWhileBlocked;
 23+ if( !$wgAccountRequestWhileBlocked && $wgUser->isBlockedFromCreateAccount() ) {
 24+ $wgOut->blockedPage();
 25+ return;
 26+ }
 27+ if ( wfReadOnly() ) {
 28+ $wgOut->readOnlyPage();
 29+ return;
 30+ }
 31+
 32+ $this->setHeaders();
 33+
 34+ $this->mRealName = trim( $wgRequest->getText( 'wpRealName' ) );
 35+ # We may only want real names being used
 36+ if( $wgUseRealNamesOnly )
 37+ $this->mUsername = $this->mRealName;
 38+ else
 39+ $this->mUsername = trim( $wgRequest->getText( 'wpUsername' ) );
 40+ # Attachments...
 41+ $this->initializeUpload( $wgRequest );
 42+ $this->mPrevAttachment = $wgRequest->getText( 'attachment' );
 43+ $this->mForgotAttachment = $wgRequest->getBool( 'forgotAttachment' );
 44+ # Other fields...
 45+ $this->mEmail = trim( $wgRequest->getText( 'wpEmail' ) );
 46+ $this->mBio = $wgRequest->getText( 'wpBio', '' );
 47+ $this->mNotes = $wgAccountRequestExtraInfo ?
 48+ $wgRequest->getText( 'wpNotes', '' ) : '';
 49+ $this->mUrls = $wgAccountRequestExtraInfo ?
 50+ $wgRequest->getText( 'wpUrls', '' ) : '';
 51+ $this->mToS = $wgAccountRequestToS ?
 52+ $wgRequest->getBool('wpToS') : false;
 53+ $this->mType = $wgRequest->getInt( 'wpType' );
 54+ $this->mType = isset($wgAccountRequestTypes[$this->mType]) ? $this->mType : 0;
 55+ # Load areas user plans to be active in...
 56+ $this->mAreas = $this->mAreaSet = array();
 57+ if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
 58+ $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
 59+ foreach( $areas as $n => $area ) {
 60+ $set = explode("|",$area,2);
 61+ if( $set[0] && isset($set[1]) ) {
 62+ $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
 63+ $this->mAreas[$formName] = $wgRequest->getInt( $formName, -1 );
 64+ # Make a simple list of interests
 65+ if( $this->mAreas[$formName] > 0 )
 66+ $this->mAreaSet[] = str_replace( '_', ' ', $set[0] );
 67+ }
 68+ }
 69+ }
 70+ # We may be confirming an email address here
 71+ $emailCode = $wgRequest->getText( 'wpEmailToken' );
 72+
 73+ $this->skin = $wgUser->getSkin();
 74+
 75+ if ( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('wpEditToken') ) ) {
 76+ if( !$this->mPrevAttachment )
 77+ $this->mPrevAttachment = $this->mSrcName;
 78+ $this->doSubmit();
 79+ } else if( $action == 'confirmemail' ) {
 80+ $this->confirmEmailToken( $emailCode );
 81+ } else {
 82+ $this->showForm();
 83+ }
 84+ }
 85+
 86+ function showForm( $msg='', $forgotFile=0 ) {
 87+ global $wgOut, $wgUser, $wgUseRealNamesOnly, $wgAllowRealName, $wgAccountRequestToS,
 88+ $wgAccountRequestTypes, $wgAccountRequestExtraInfo, $wgAllowAccountRequestFiles;
 89+
 90+ $this->mForgotAttachment = $forgotFile;
 91+
 92+ $wgOut->setPagetitle( wfMsgHtml( "requestaccount" ) );
 93+ # Output failure message if any
 94+ if( $msg ) {
 95+ $wgOut->addHTML( '<div class="errorbox">'.$msg.'</div><div class="visualClear"></div>' );
 96+ }
 97+ # Give notice to users that are logged in
 98+ if( $wgUser->getID() ) {
 99+ $wgOut->addWikiText( wfMsgHtml( "requestaccount-dup" ) );
 100+ }
 101+
 102+ $wgOut->addWikiText( wfMsgHtml( "requestaccount-text" ) );
 103+
 104+ $titleObj = Title::makeTitle( NS_SPECIAL, 'RequestAccount' );
 105+
 106+ $form = wfOpenElement( 'form', array( 'method' => 'post', 'name' => 'accountrequest',
 107+ 'action' => $titleObj->getLocalUrl(), 'enctype' => 'multipart/form-data' ) );
 108+ $form .= '<fieldset><legend>' . wfMsgHtml('requestaccount-leg-user') . '</legend>';
 109+ $form .= wfMsgExt( 'requestaccount-acc-text', array('parse') )."\n";
 110+ $form .= '<table cellpadding=\'4\'>';
 111+ if( $wgUseRealNamesOnly ) {
 112+ $form .= "<tr><td>".wfMsgHtml('username')."</td>";
 113+ $form .= "<td>".wfMsgHtml('requestaccount-same')."</td></tr>\n";
 114+ } else {
 115+ $form .= "<tr><td>".Xml::label( wfMsgHtml('username'), 'wpUsername' )."</td>";
 116+ $form .= "<td>".Xml::input( 'wpUsername', 30, $this->mUsername, array('id' => 'wpUsername') )."</td></tr>\n";
 117+ }
 118+ $form .= "<tr><td>".Xml::label( wfMsgHtml('requestaccount-email'), 'wpEmail' )."</td>";
 119+ $form .= "<td>".Xml::input( 'wpEmail', 30, $this->mEmail, array('id' => 'wpEmail') )."</td></tr>\n";
 120+ if( count($wgAccountRequestTypes) > 1 ) {
 121+ $form .= "<tr><td>".wfMsgHtml('requestaccount-reqtype')."</td><td>";
 122+ foreach( $wgAccountRequestTypes as $i => $params ) {
 123+ $options[] = Xml::option( wfMsg( "requestaccount-level-$i" ), $i, ($i == $this->mType) );
 124+ }
 125+ $form .= Xml::openElement( 'select', array( 'name' => "wpType" ) );
 126+ $form .= implode( "\n", $options );
 127+ $form .= Xml::closeElement('select')."\n";
 128+ }
 129+ $form .= '</td></tr></table></fieldset>';
 130+
 131+ if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
 132+ $form .= '<fieldset>';
 133+ $form .= '<legend>' . wfMsgHtml('requestaccount-leg-areas') . '</legend>';
 134+ $form .= wfMsgExt( 'requestaccount-areas-text', array('parse') )."\n";
 135+
 136+ $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
 137+ $form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
 138+ $form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
 139+ $count = 0;
 140+ foreach( $areas as $area ) {
 141+ $set = explode("|",$area,3);
 142+ if( $set[0] && isset($set[1]) ) {
 143+ $count++;
 144+ if( $count > 5 ) {
 145+ $form .= "</tr><tr valign='top'>";
 146+ $count = 1;
 147+ }
 148+ $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
 149+ if( isset($set[1]) ) {
 150+ $pg = $this->skin->makeKnownLink( $set[1], wfMsgHtml('requestaccount-info') );
 151+ } else {
 152+ $pg = '';
 153+ }
 154+
 155+ $form .= "<td>".wfCheckLabel( $set[0], $formName, $formName, $this->mAreas[$formName] > 0 )." {$pg}</td>\n";
 156+ }
 157+ }
 158+ $form .= "</tr></table></div>";
 159+ $form .= '</fieldset>';
 160+ }
 161+
 162+ $form .= '<fieldset>';
 163+ $form .= '<legend>' . wfMsgHtml('requestaccount-leg-person') . '</legend>';
 164+ $form .= wfMsgExt( 'requestaccount-bio-text', array('parse') )."\n";
 165+ if( $wgUseRealNamesOnly || $wgAllowRealName ) {
 166+ $form .= '<table cellpadding=\'4\'>';
 167+ $form .= "<tr><td>".Xml::label( wfMsgHtml('requestaccount-real'), 'wpRealName' )."</td>";
 168+ $form .= "<td>".Xml::input( 'wpRealName', 35, $this->mRealName, array('id' => 'wpRealName') )."</td></tr>\n";
 169+ $form .= '</table>';
 170+ }
 171+ $form .= "<p>".wfMsgHtml('requestaccount-bio')."\n";
 172+ $form .= "<textarea tabindex='1' name='wpBio' id='wpBio' rows='12' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
 173+ htmlspecialchars($this->mBio) . "</textarea></p>\n";
 174+ $form .= '</fieldset>';
 175+ if( $wgAccountRequestExtraInfo ) {
 176+ $form .= '<fieldset>';
 177+ $form .= '<legend>' . wfMsgHtml('requestaccount-leg-other') . '</legend>';
 178+ $form .= wfMsgExt( 'requestaccount-ext-text', array('parse') )."\n";
 179+ if( $wgAllowAccountRequestFiles ) {
 180+ $form .= "<p>".wfMsgHtml('requestaccount-attach')." ";
 181+ $form .= Xml::input( 'wpUploadFile', 35, '',
 182+ array('id' => 'wpUploadFile', 'type' => 'file') )."</p>\n";
 183+ }
 184+ $form .= "<p>".wfMsgHtml('requestaccount-notes')."\n";
 185+ $form .= "<textarea tabindex='1' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%;background-color:#f9f9f9;'>" .
 186+ htmlspecialchars($this->mNotes) .
 187+ "</textarea></p>\n";
 188+ $form .= "<p>".wfMsgHtml('requestaccount-urls')."\n";
 189+ $form .= "<textarea tabindex='1' name='wpUrls' id='wpUrls' rows='2' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
 190+ htmlspecialchars($this->mUrls) .
 191+ "</textarea></p>\n";
 192+ $form .= '</fieldset>';
 193+ }
 194+ # Pseudo template for extensions
 195+ # FIXME: do this better...
 196+ global $wgConfirmAccountCaptchas, $wgCaptchaClass, $wgCaptchaTriggers;
 197+ if( $wgConfirmAccountCaptchas && isset($wgCaptchaClass) && $wgCaptchaTriggers['createaccount'] ) {
 198+ global $wgExtensionMessagesFiles;
 199+
 200+ $captcha = new $wgCaptchaClass;
 201+ # Hook point to add captchas
 202+ wfLoadExtensionMessages( 'ConfirmEdit' );
 203+ if( isset( $wgExtensionMessagesFiles[$wgCaptchaClass] ) ) {
 204+ wfLoadExtensionMessages( $wgCaptchaClass );
 205+ }
 206+ $form .= '<fieldset>';
 207+ $form .= wfMsgExt('captcha-createaccount','parse');
 208+ $form .= $captcha->getForm();
 209+ $form .= '</fieldset>';
 210+ }
 211+ if( $wgAccountRequestToS ) {
 212+ $form .= "<p>".Xml::check( 'wpToS', $this->mToS, array('id' => 'wpToS') ).
 213+ ' <label for="wpToS">'.wfMsgExt( 'requestaccount-tos', array('parseinline') )."</label></p>\n";
 214+ }
 215+ $form .= Xml::hidden( 'title', $titleObj->getPrefixedUrl() )."\n";
 216+ $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken() )."\n";
 217+ $form .= Xml::hidden( 'attachment', $this->mPrevAttachment )."\n";
 218+ $form .= Xml::hidden( 'forgotAttachment', $this->mForgotAttachment )."\n";
 219+ $form .= "<p>".Xml::submitButton( wfMsgHtml( 'requestaccount-submit') )."</p>";
 220+ $form .= wfCloseElement( 'form' );
 221+
 222+ $wgOut->addHTML( $form );
 223+
 224+ $wgOut->addWikiText( wfMsgHtml( "requestaccount-footer" ) );
 225+ }
 226+
 227+ function doSubmit() {
 228+ global $wgOut, $wgUser, $wgAuth, $wgAccountRequestThrottle;
 229+ # Now create a dummy user ($u) and check if it is valid
 230+ $name = trim( $this->mUsername );
 231+ $u = User::newFromName( $name, 'creatable' );
 232+ if( is_null($u) ) {
 233+ $this->showForm( wfMsgHtml('noname') );
 234+ return;
 235+ }
 236+ # FIXME: Hack! If we don't want them for requests, temporarily turn it off!
 237+ global $wgConfirmAccountCaptchas, $wgCaptchaTriggers;
 238+ if( !$wgConfirmAccountCaptchas && isset($wgCaptchaTriggers) ) {
 239+ $old = $wgCaptchaTriggers['createaccount'];
 240+ $wgCaptchaTriggers['createaccount'] = false;
 241+ }
 242+ $abortError = '';
 243+ if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
 244+ // Hook point to add extra creation throttles and blocks
 245+ wfDebug( "RequestAccount::doSubmit: a hook blocked creation\n" );
 246+ $this->showForm( $abortError );
 247+ return;
 248+ }
 249+ if( !$wgConfirmAccountCaptchas && isset($wgCaptchaTriggers) ) {
 250+ $wgCaptchaTriggers['createaccount'] = $old;
 251+ }
 252+ # No request spamming...
 253+ if( $wgAccountRequestThrottle && ( !method_exists($wgUser,'isPingLimitable') || $wgUser->isPingLimitable() ) ) {
 254+ global $wgMemc;
 255+
 256+ $key = wfMemcKey( 'acctrequest', 'ip', wfGetIP() );
 257+ $value = $wgMemc->get( $key );
 258+ if( $value > $wgAccountRequestThrottle ) {
 259+ $this->throttleHit( $wgAccountRequestThrottle );
 260+ return;
 261+ }
 262+ }
 263+ # Check if already in use
 264+ if( 0 != $u->idForName() || $wgAuth->userExists( $u->getName() ) ) {
 265+ $this->showForm( wfMsgHtml('userexists') );
 266+ return;
 267+ }
 268+ # Check pending accounts for name use
 269+ $dbw = wfGetDB( DB_MASTER );
 270+ $dup = $dbw->selectField( 'account_requests', '1',
 271+ array( 'acr_name' => $u->getName() ),
 272+ __METHOD__ );
 273+ if( $dup ) {
 274+ $this->showForm( wfMsgHtml('requestaccount-inuse') );
 275+ return;
 276+ }
 277+ # Make sure user agrees to policy here
 278+ global $wgAccountRequestToS;
 279+ if( $wgAccountRequestToS && !$this->mToS ) {
 280+ $this->showForm( wfMsgHtml('requestaccount-agree') );
 281+ return;
 282+ }
 283+ # Validate email address
 284+ if( !$u->isValidEmailAddr( $this->mEmail ) ) {
 285+ $this->showForm( wfMsgHtml('invalidemailaddress') );
 286+ return;
 287+ }
 288+ global $wgAccountRequestMinWords;
 289+ # Check if biography is long enough
 290+ if( str_word_count($this->mBio) < $wgAccountRequestMinWords ) {
 291+ $this->showForm( wfMsgHtml('requestaccount-tooshort',$wgAccountRequestMinWords) );
 292+ return;
 293+ }
 294+ # Set some additional data so the AbortNewAccount hook can be
 295+ # used for more than just username validation
 296+ $u->setEmail( $this->mEmail );
 297+ # Check if someone else has an account request with the same email
 298+ $dup = $dbw->selectField( 'account_requests', '1',
 299+ array( 'acr_email' => $u->getEmail() ),
 300+ __METHOD__ );
 301+ if( $dup ) {
 302+ $this->showForm( wfMsgHtml('requestaccount-emaildup') );
 303+ return;
 304+ }
 305+
 306+ $u->setRealName( $this->mRealName );
 307+ # Per security reasons, file dir cannot be pulled from client,
 308+ # so ask them to resubmit it then...
 309+ global $wgAllowAccountRequestFiles, $wgAccountRequestExtraInfo;
 310+ # If the extra fields are off, then uploads are off
 311+ $allowFiles = $wgAccountRequestExtraInfo && $wgAllowAccountRequestFiles;
 312+ if( $allowFiles && $this->mPrevAttachment && !$this->mSrcName ) {
 313+ # If the user is submitting forgotAttachment as true with no file,
 314+ # then they saw the notice and choose not to re-select the file.
 315+ # Assume that they don't want to send one anymore.
 316+ if( !$this->mForgotAttachment ) {
 317+ $this->mPrevAttachment = '';
 318+ $this->showForm( wfMsgHtml('requestaccount-resub'), 1 );
 319+ return false;
 320+ }
 321+ }
 322+ # Process upload...
 323+ if( $allowFiles && $this->mSrcName ) {
 324+ $ext = explode('.',$this->mSrcName);
 325+ $finalExt = $ext[count($ext)-1];
 326+ # File must have size.
 327+ if( trim( $this->mSrcName ) == '' || empty( $this->mFileSize ) ) {
 328+ $this->mPrevAttachment = '';
 329+ $this->showForm( wfMsgHtml( 'emptyfile' ) );
 330+ return false;
 331+ }
 332+ # Look at the contents of the file; if we can recognize the
 333+ # type but it's corrupt or data of the wrong type, we should
 334+ # probably not accept it.
 335+ global $wgAccountRequestExts;
 336+ if( !in_array($finalExt,$wgAccountRequestExts) ) {
 337+ $this->mPrevAttachment = '';
 338+ $this->showForm( wfMsgHtml( 'requestaccount-exts' ) );
 339+ return false;
 340+ }
 341+ $veri = $this->verify( $this->mTempPath, $finalExt );
 342+ if( $veri !== true ) {
 343+ $this->mPrevAttachment = '';
 344+ $this->showForm( wfMsgHtml( 'uploadcorrupt' ) );
 345+ return false;
 346+ }
 347+ # Start a transaction, move file from temp to account request directory.
 348+ $transaction = new FSTransaction();
 349+ if( !FileStore::lock() ) {
 350+ wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" );
 351+ return false;
 352+ }
 353+ $store = FileStore::get( 'accountreqs' );
 354+ if( !$store ) {
 355+ wfDebug( __METHOD__.": invalid storage group '{$store}'.\n" );
 356+ return false;
 357+ }
 358+
 359+ $key = FileStore::calculateKey( $this->mTempPath, $finalExt );
 360+
 361+ $transaction->add( $store->insert( $key, $this->mTempPath, FileStore::DELETE_ORIGINAL ) );
 362+ if( $transaction === false ) {
 363+ // Failed to move?
 364+ wfDebug( __METHOD__.": import to file store failed, aborting\n" );
 365+ throw new MWException( "Could not insert file {$this->mTempPath}" );
 366+ return false;
 367+ }
 368+ }
 369+ $expires = null; // passed by reference
 370+ $token = $this->getConfirmationToken( $u, $expires );
 371+ # Insert into pending requests...
 372+ $acr_id = $dbw->nextSequenceValue( 'account_requests_acr_id_seq' );
 373+ $dbw->begin();
 374+ $dbw->insert( 'account_requests',
 375+ array(
 376+ 'acr_id' => $acr_id,
 377+ 'acr_name' => $u->getName(),
 378+ 'acr_email' => $u->getEmail(),
 379+ 'acr_real_name' => $u->getRealName(),
 380+ 'acr_registration' => $dbw->timestamp(),
 381+ 'acr_bio' => $this->mBio,
 382+ 'acr_notes' => $this->mNotes,
 383+ 'acr_urls' => $this->mUrls,
 384+ 'acr_filename' => isset($this->mSrcName) ? $this->mSrcName : null,
 385+ 'acr_type' => $this->mType,
 386+ 'acr_areas' => self::flattenAreas( $this->mAreaSet ),
 387+ 'acr_storage_key' => isset($key) ? $key : null,
 388+ 'acr_comment' => '',
 389+ 'acr_email_token' => md5($token),
 390+ 'acr_email_token_expires' => $dbw->timestamp( $expires ),
 391+ 'acr_ip' => wfGetIP() // Possible use for spam blocking
 392+ ),
 393+ __METHOD__
 394+ );
 395+ # Clear cache for notice of how many account requests there are
 396+ global $wgMemc;
 397+ $key = wfMemcKey( 'confirmaccount', 'noticecount' );
 398+ $wgMemc->delete( $key );
 399+ # Send confirmation, required!
 400+ $result = $this->sendConfirmationMail( $u, $token, $expires );
 401+ if( WikiError::isError( $result ) ) {
 402+ $dbw->rollback(); // Nevermind
 403+ $error = wfMsg( 'mailerror', htmlspecialchars( $result->toString() ) );
 404+ $this->showForm( $error );
 405+ return false;
 406+ }
 407+ $dbw->commit();
 408+ if( isset($transaction) ) {
 409+ wfDebug( __METHOD__.": set db items, applying file transactions\n" );
 410+ $transaction->commit();
 411+ FileStore::unlock();
 412+ }
 413+ # No request spamming...
 414+ # BC: check if isPingLimitable() exists
 415+ if( $wgAccountRequestThrottle && ( !method_exists($wgUser,'isPingLimitable') || $wgUser->isPingLimitable() ) ) {
 416+ global $wgMemc;
 417+
 418+ $key = wfMemcKey( 'acctrequest', 'ip', wfGetIP() );
 419+ $value = $wgMemc->incr( $key );
 420+ if( !$value ) {
 421+ $wgMemc->set( $key, 1, 86400 );
 422+ }
 423+ }
 424+ # Done!
 425+ $this->showSuccess();
 426+ }
 427+
 428+ function showSuccess() {
 429+ global $wgOut;
 430+
 431+ $wgOut->setPagetitle( wfMsg( "requestaccount" ) );
 432+ $wgOut->addWikiText( wfMsg( "requestaccount-sent" ) );
 433+
 434+ $wgOut->returnToMain();
 435+ }
 436+
 437+ /**
 438+ * Flatten an areas of interest array
 439+ * @access private
 440+ */
 441+ static function flattenAreas( $areas ) {
 442+ $flatAreas = '';
 443+ foreach( $areas as $area ) {
 444+ $flatAreas .= $area."\n";
 445+ }
 446+ return $flatAreas;
 447+ }
 448+
 449+ static function expandAreas( $areas ) {
 450+ $list = explode("\n",$areas);
 451+ foreach( $list as $n => $item ) {
 452+ $list[$n] = trim("wpArea-".str_replace( ' ', '_', $item ));
 453+ }
 454+ unset( $list[count($list)-1] );
 455+ return $list;
 456+ }
 457+
 458+ /**
 459+ * Initialize the uploaded file from PHP data
 460+ * @access private
 461+ */
 462+ function initializeUpload( $request ) {
 463+ $this->mTempPath = $request->getFileTempName( 'wpUploadFile' );
 464+ $this->mFileSize = $request->getFileSize( 'wpUploadFile' );
 465+ $this->mSrcName = $request->getFileName( 'wpUploadFile' );
 466+ $this->mRemoveTempFile = false; // PHP will handle this
 467+ }
 468+
 469+ /**
 470+ * Verifies that it's ok to include the uploaded file
 471+ *
 472+ * @param string $tmpfile the full path of the temporary file to verify
 473+ * @param string $extension The filename extension that the file is to be served with
 474+ * @return mixed true of the file is verified, a WikiError object otherwise.
 475+ */
 476+ function verify( $tmpfile, $extension ) {
 477+ #magically determine mime type
 478+ $magic=& MimeMagic::singleton();
 479+ $mime = $magic->guessMimeType($tmpfile,false);
 480+
 481+ #check mime type, if desired
 482+ global $wgVerifyMimeType;
 483+ if ($wgVerifyMimeType) {
 484+
 485+ wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n");
 486+ #check mime type against file extension
 487+ if( !$this->verifyExtension( $mime, $extension ) ) {
 488+ return new WikiErrorMsg( 'uploadcorrupt' );
 489+ }
 490+
 491+ #check mime type blacklist
 492+ global $wgMimeTypeBlacklist;
 493+ if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist)
 494+ && $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
 495+ return new WikiErrorMsg( 'filetype-badmime', htmlspecialchars( $mime ) );
 496+ }
 497+ }
 498+
 499+ wfDebug( __METHOD__.": all clear; passing.\n" );
 500+ return true;
 501+ }
 502+
 503+ /**
 504+ * Checks if the mime type of the uploaded file matches the file extension.
 505+ *
 506+ * @param string $mime the mime type of the uploaded file
 507+ * @param string $extension The filename extension that the file is to be served with
 508+ * @return bool
 509+ */
 510+ function verifyExtension( $mime, $extension ) {
 511+ $magic =& MimeMagic::singleton();
 512+
 513+ if ( ! $mime || $mime == 'unknown' || $mime == 'unknown/unknown' )
 514+ if ( ! $magic->isRecognizableExtension( $extension ) ) {
 515+ wfDebug( __METHOD__.": passing file with unknown detected mime type; " .
 516+ "unrecognized extension '$extension', can't verify\n" );
 517+ return true;
 518+ } else {
 519+ wfDebug( __METHOD__.": rejecting file with unknown detected mime type; ".
 520+ "recognized extension '$extension', so probably invalid file\n" );
 521+ return false;
 522+ }
 523+
 524+ $match = $magic->isMatchingExtension($extension,$mime);
 525+
 526+ if ($match===NULL) {
 527+ wfDebug( __METHOD__.": no file extension known for mime type $mime, passing file\n" );
 528+ return true;
 529+ } elseif ($match===true) {
 530+ wfDebug( __METHOD__.": mime type $mime matches extension $extension, passing file\n" );
 531+
 532+ #TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
 533+ return true;
 534+
 535+ } else {
 536+ wfDebug( __METHOD__.": mime type $mime mismatches file extension $extension, rejecting file\n" );
 537+ return false;
 538+ }
 539+ }
 540+
 541+ /**
 542+ * Perform case-insensitive match against a list of file extensions.
 543+ * Returns true if the extension is in the list.
 544+ *
 545+ * @param string $ext
 546+ * @param array $list
 547+ * @return bool
 548+ */
 549+ function checkFileExtension( $ext, $list ) {
 550+ return in_array( strtolower( $ext ), $list );
 551+ }
 552+
 553+ /**
 554+ * @private
 555+ */
 556+ function throttleHit( $limit ) {
 557+ global $wgOut;
 558+
 559+ $wgOut->addWikiText( wfMsgHtml( 'acct_request_throttle_hit', $limit ) );
 560+ }
 561+
 562+ function confirmEmailToken( $code ) {
 563+ global $wgUser, $wgOut;
 564+ # Confirm if this token is in the pending requests
 565+ $name = $this->requestFromEmailToken( $code );
 566+ if( $name !== false ) {
 567+ # Send confirmation email to prospective user
 568+ $this->confirmEmail( $name );
 569+ # Send mail to admin after e-mail has been confirmed;
 570+ global $wgConfirmAccountContact;
 571+ if( $wgConfirmAccountContact ) {
 572+ $u = User::newFromName( $name, 'creatable' );
 573+ $u->setEmail( $wgConfirmAccountContact );
 574+ $title = Title::makeTitle( NS_SPECIAL, 'ConfirmAccounts' );
 575+ $url = $title->getFullUrl();
 576+ $u->sendMail( wfMsg('requestaccount-email-subj-admin'),
 577+ wfMsg( 'requestaccount-email-body-admin', $name, $url ) );
 578+ }
 579+ $wgOut->addWikiText( wfMsgHtml( 'request-account-econf' ) );
 580+ $wgOut->returnToMain();
 581+ return;
 582+ }
 583+ # Maybe the user confirmed after account was created...
 584+ $user = User::newFromConfirmationCode( $code );
 585+ if( is_object( $user ) ) {
 586+ if( $user->confirmEmail() ) {
 587+ $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
 588+ $wgOut->addWikiText( wfMsg( $message ) );
 589+ if( !$wgUser->isLoggedIn() ) {
 590+ $title = SpecialPage::getTitleFor( 'Userlogin' );
 591+ $wgOut->returnToMain( true, $title->getPrefixedUrl() );
 592+ }
 593+ } else {
 594+ $wgOut->addWikiText( wfMsg( 'confirmemail_error' ) );
 595+ }
 596+ } else {
 597+ $wgOut->addWikiText( wfMsg( 'confirmemail_invalid' ) );
 598+ }
 599+ }
 600+
 601+ /**
 602+ * Get a request name from an emailconfirm token
 603+ *
 604+ * @param sring $code
 605+ * @returns string $name
 606+ */
 607+ function requestFromEmailToken( $code ) {
 608+ $dbr = wfGetDB( DB_SLAVE );
 609+ $reqID = $dbr->selectField( 'account_requests', 'acr_name',
 610+ array( 'acr_email_token' => md5($code),
 611+ 'acr_email_token_expires > ' . $dbr->addQuotes( $dbr->timestamp() ),
 612+ )
 613+ );
 614+ return $reqID;
 615+ }
 616+
 617+ /**
 618+ * Flag a user's email as confirmed in the db
 619+ *
 620+ * @param sring $name
 621+ */
 622+ function confirmEmail( $name ) {
 623+ $dbw = wfGetDB( DB_MASTER );
 624+ $dbw->update( 'account_requests',
 625+ array( 'acr_email_authenticated' => $dbw->timestamp() ),
 626+ array( 'acr_name' => $name ),
 627+ __METHOD__ );
 628+ # Clear cache for notice of how many account requests there are
 629+ global $wgMemc;
 630+ $key = wfMemcKey( 'confirmaccount', 'noticecount' );
 631+ $wgMemc->delete( $key );
 632+ }
 633+
 634+ /**
 635+ * Generate a new e-mail confirmation token and send a confirmation
 636+ * mail to the user's given address.
 637+ *
 638+ * @param User $user
 639+ * @param string $token
 640+ * @param string $expiration
 641+ * @return mixed True on success, a WikiError object on failure.
 642+ */
 643+ function sendConfirmationMail( $user, $token, $expiration ) {
 644+ global $wgContLang;
 645+ $url = $this->confirmationTokenUrl( $token );
 646+ return $user->sendMail( wfMsg( 'requestaccount-email-subj' ),
 647+ wfMsg( 'requestaccount-email-body',
 648+ wfGetIP(),
 649+ $user->getName(),
 650+ $url,
 651+ $wgContLang->timeanddate( $expiration, false ) ) );
 652+ }
 653+
 654+ /**
 655+ * Generate and store a new e-mail confirmation token, and return
 656+ * the URL the user can use to confirm.
 657+ * @param string $token
 658+ * @return string
 659+ * @private
 660+ */
 661+ function confirmationTokenUrl( $token ) {
 662+ $title = Title::makeTitle( NS_SPECIAL, 'RequestAccount' );
 663+ return $title->getFullUrl( 'action=confirmemail&wpEmailToken='.$token );
 664+ }
 665+
 666+ /**
 667+ * Generate, store, and return a new e-mail confirmation code.
 668+ * A hash (unsalted since it's used as a key) is stored.
 669+ * @param User $user
 670+ * @param string $expiration
 671+ * @return string
 672+ * @private
 673+ */
 674+ function getConfirmationToken( $user, &$expiration ) {
 675+ global $wgConfirmAccountRejectAge;
 676+
 677+ $expires = time() + $wgConfirmAccountRejectAge;
 678+ $expiration = wfTimestamp( TS_MW, $expires );
 679+
 680+ $token = $user->generateToken( $user->getName() . $user->getEmail() . $expires );
 681+
 682+ return $token;
 683+ }
 684+
 685+}
 686+
Property changes on: trunk/extensions/ConfirmAccount/RequestAccount_body.php
___________________________________________________________________
Added: svn:eol-style
1687 + native
Index: trunk/extensions/ConfirmAccount/ConfirmAccount_body.php
@@ -8,681 +8,6 @@
99 # Add messages
1010 wfLoadExtensionMessages( 'ConfirmAccount' );
1111
12 -class RequestAccountPage extends SpecialPage {
13 -
14 - function __construct() {
15 - parent::__construct( 'RequestAccount' );
16 - }
17 -
18 - function execute( $par ) {
19 - global $wgUser, $wgOut, $wgRequest, $action, $wgUseRealNamesOnly,
20 - $wgAccountRequestToS, $wgAccountRequestExtraInfo, $wgAccountRequestTypes;
21 - # If a user cannot make accounts, don't let them request them either
22 - global $wgAccountRequestWhileBlocked;
23 - if( !$wgAccountRequestWhileBlocked && $wgUser->isBlockedFromCreateAccount() ) {
24 - $wgOut->blockedPage();
25 - return;
26 - }
27 - if ( wfReadOnly() ) {
28 - $wgOut->readOnlyPage();
29 - return;
30 - }
31 -
32 - $this->setHeaders();
33 -
34 - $this->mRealName = trim( $wgRequest->getText( 'wpRealName' ) );
35 - # We may only want real names being used
36 - if( $wgUseRealNamesOnly )
37 - $this->mUsername = $this->mRealName;
38 - else
39 - $this->mUsername = trim( $wgRequest->getText( 'wpUsername' ) );
40 - # Attachments...
41 - $this->initializeUpload( $wgRequest );
42 - $this->mPrevAttachment = $wgRequest->getText( 'attachment' );
43 - $this->mForgotAttachment = $wgRequest->getBool( 'forgotAttachment' );
44 - # Other fields...
45 - $this->mEmail = trim( $wgRequest->getText( 'wpEmail' ) );
46 - $this->mBio = $wgRequest->getText( 'wpBio', '' );
47 - $this->mNotes = $wgAccountRequestExtraInfo ?
48 - $wgRequest->getText( 'wpNotes', '' ) : '';
49 - $this->mUrls = $wgAccountRequestExtraInfo ?
50 - $wgRequest->getText( 'wpUrls', '' ) : '';
51 - $this->mToS = $wgAccountRequestToS ?
52 - $wgRequest->getBool('wpToS') : false;
53 - $this->mType = $wgRequest->getInt( 'wpType' );
54 - $this->mType = isset($wgAccountRequestTypes[$this->mType]) ? $this->mType : 0;
55 - # Load areas user plans to be active in...
56 - $this->mAreas = $this->mAreaSet = array();
57 - if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
58 - $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
59 - foreach( $areas as $n => $area ) {
60 - $set = explode("|",$area,2);
61 - if( $set[0] && isset($set[1]) ) {
62 - $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
63 - $this->mAreas[$formName] = $wgRequest->getInt( $formName, -1 );
64 - # Make a simple list of interests
65 - if( $this->mAreas[$formName] > 0 )
66 - $this->mAreaSet[] = str_replace( '_', ' ', $set[0] );
67 - }
68 - }
69 - }
70 - # We may be confirming an email address here
71 - $emailCode = $wgRequest->getText( 'wpEmailToken' );
72 -
73 - $this->skin = $wgUser->getSkin();
74 -
75 - if ( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('wpEditToken') ) ) {
76 - if( !$this->mPrevAttachment )
77 - $this->mPrevAttachment = $this->mSrcName;
78 - $this->doSubmit();
79 - } else if( $action == 'confirmemail' ) {
80 - $this->confirmEmailToken( $emailCode );
81 - } else {
82 - $this->showForm();
83 - }
84 - }
85 -
86 - function showForm( $msg='', $forgotFile=0 ) {
87 - global $wgOut, $wgUser, $wgUseRealNamesOnly, $wgAllowRealName, $wgAccountRequestToS,
88 - $wgAccountRequestTypes, $wgAccountRequestExtraInfo, $wgAllowAccountRequestFiles;
89 -
90 - $this->mForgotAttachment = $forgotFile;
91 -
92 - $wgOut->setPagetitle( wfMsgHtml( "requestaccount" ) );
93 - # Output failure message if any
94 - if( $msg ) {
95 - $wgOut->addHTML( '<div class="errorbox">'.$msg.'</div><div class="visualClear"></div>' );
96 - }
97 - # Give notice to users that are logged in
98 - if( $wgUser->getID() ) {
99 - $wgOut->addWikiText( wfMsgHtml( "requestaccount-dup" ) );
100 - }
101 -
102 - $wgOut->addWikiText( wfMsgHtml( "requestaccount-text" ) );
103 -
104 - $titleObj = Title::makeTitle( NS_SPECIAL, 'RequestAccount' );
105 -
106 - $form = wfOpenElement( 'form', array( 'method' => 'post', 'name' => 'accountrequest',
107 - 'action' => $titleObj->getLocalUrl(), 'enctype' => 'multipart/form-data' ) );
108 - $form .= '<fieldset><legend>' . wfMsgHtml('requestaccount-leg-user') . '</legend>';
109 - $form .= wfMsgExt( 'requestaccount-acc-text', array('parse') )."\n";
110 - $form .= '<table cellpadding=\'4\'>';
111 - if( $wgUseRealNamesOnly ) {
112 - $form .= "<tr><td>".wfMsgHtml('username')."</td>";
113 - $form .= "<td>".wfMsgHtml('requestaccount-same')."</td></tr>\n";
114 - } else {
115 - $form .= "<tr><td>".Xml::label( wfMsgHtml('username'), 'wpUsername' )."</td>";
116 - $form .= "<td>".Xml::input( 'wpUsername', 30, $this->mUsername, array('id' => 'wpUsername') )."</td></tr>\n";
117 - }
118 - $form .= "<tr><td>".Xml::label( wfMsgHtml('requestaccount-email'), 'wpEmail' )."</td>";
119 - $form .= "<td>".Xml::input( 'wpEmail', 30, $this->mEmail, array('id' => 'wpEmail') )."</td></tr>\n";
120 - if( count($wgAccountRequestTypes) > 1 ) {
121 - $form .= "<tr><td>".wfMsgHtml('requestaccount-reqtype')."</td><td>";
122 - foreach( $wgAccountRequestTypes as $i => $params ) {
123 - $options[] = Xml::option( wfMsg( "requestaccount-level-$i" ), $i, ($i == $this->mType) );
124 - }
125 - $form .= Xml::openElement( 'select', array( 'name' => "wpType" ) );
126 - $form .= implode( "\n", $options );
127 - $form .= Xml::closeElement('select')."\n";
128 - }
129 - $form .= '</td></tr></table></fieldset>';
130 -
131 - if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
132 - $form .= '<fieldset>';
133 - $form .= '<legend>' . wfMsgHtml('requestaccount-leg-areas') . '</legend>';
134 - $form .= wfMsgExt( 'requestaccount-areas-text', array('parse') )."\n";
135 -
136 - $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
137 - $form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
138 - $form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
139 - $count = 0;
140 - foreach( $areas as $area ) {
141 - $set = explode("|",$area,3);
142 - if( $set[0] && isset($set[1]) ) {
143 - $count++;
144 - if( $count > 5 ) {
145 - $form .= "</tr><tr valign='top'>";
146 - $count = 1;
147 - }
148 - $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
149 - if( isset($set[1]) ) {
150 - $pg = $this->skin->makeKnownLink( $set[1], wfMsgHtml('requestaccount-info') );
151 - } else {
152 - $pg = '';
153 - }
154 -
155 - $form .= "<td>".wfCheckLabel( $set[0], $formName, $formName, $this->mAreas[$formName] > 0 )." {$pg}</td>\n";
156 - }
157 - }
158 - $form .= "</tr></table></div>";
159 - $form .= '</fieldset>';
160 - }
161 -
162 - $form .= '<fieldset>';
163 - $form .= '<legend>' . wfMsgHtml('requestaccount-leg-person') . '</legend>';
164 - $form .= wfMsgExt( 'requestaccount-bio-text', array('parse') )."\n";
165 - if( $wgUseRealNamesOnly || $wgAllowRealName ) {
166 - $form .= '<table cellpadding=\'4\'>';
167 - $form .= "<tr><td>".Xml::label( wfMsgHtml('requestaccount-real'), 'wpRealName' )."</td>";
168 - $form .= "<td>".Xml::input( 'wpRealName', 35, $this->mRealName, array('id' => 'wpRealName') )."</td></tr>\n";
169 - $form .= '</table>';
170 - }
171 - $form .= "<p>".wfMsgHtml('requestaccount-bio')."\n";
172 - $form .= "<textarea tabindex='1' name='wpBio' id='wpBio' rows='12' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
173 - htmlspecialchars($this->mBio) . "</textarea></p>\n";
174 - $form .= '</fieldset>';
175 - if( $wgAccountRequestExtraInfo ) {
176 - $form .= '<fieldset>';
177 - $form .= '<legend>' . wfMsgHtml('requestaccount-leg-other') . '</legend>';
178 - $form .= wfMsgExt( 'requestaccount-ext-text', array('parse') )."\n";
179 - if( $wgAllowAccountRequestFiles ) {
180 - $form .= "<p>".wfMsgHtml('requestaccount-attach')." ";
181 - $form .= Xml::input( 'wpUploadFile', 35, '',
182 - array('id' => 'wpUploadFile', 'type' => 'file') )."</p>\n";
183 - }
184 - $form .= "<p>".wfMsgHtml('requestaccount-notes')."\n";
185 - $form .= "<textarea tabindex='1' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%;background-color:#f9f9f9;'>" .
186 - htmlspecialchars($this->mNotes) .
187 - "</textarea></p>\n";
188 - $form .= "<p>".wfMsgHtml('requestaccount-urls')."\n";
189 - $form .= "<textarea tabindex='1' name='wpUrls' id='wpUrls' rows='2' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
190 - htmlspecialchars($this->mUrls) .
191 - "</textarea></p>\n";
192 - $form .= '</fieldset>';
193 - }
194 - # Pseudo template for extensions
195 - # FIXME: do this better...
196 - global $wgConfirmAccountCaptchas, $wgCaptchaClass, $wgCaptchaTriggers;
197 - if( $wgConfirmAccountCaptchas && isset($wgCaptchaClass) && $wgCaptchaTriggers['createaccount'] ) {
198 - global $wgExtensionMessagesFiles;
199 -
200 - $captcha = new $wgCaptchaClass;
201 - # Hook point to add captchas
202 - wfLoadExtensionMessages( 'ConfirmEdit' );
203 - if( isset( $wgExtensionMessagesFiles[$wgCaptchaClass] ) ) {
204 - wfLoadExtensionMessages( $wgCaptchaClass );
205 - }
206 - $form .= '<fieldset>';
207 - $form .= wfMsgExt('captcha-createaccount','parse');
208 - $form .= $captcha->getForm();
209 - $form .= '</fieldset>';
210 - }
211 - if( $wgAccountRequestToS ) {
212 - $form .= "<p>".Xml::check( 'wpToS', $this->mToS, array('id' => 'wpToS') ).
213 - ' <label for="wpToS">'.wfMsgExt( 'requestaccount-tos', array('parseinline') )."</label></p>\n";
214 - }
215 - $form .= Xml::hidden( 'title', $titleObj->getPrefixedUrl() )."\n";
216 - $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken() )."\n";
217 - $form .= Xml::hidden( 'attachment', $this->mPrevAttachment )."\n";
218 - $form .= Xml::hidden( 'forgotAttachment', $this->mForgotAttachment )."\n";
219 - $form .= "<p>".Xml::submitButton( wfMsgHtml( 'requestaccount-submit') )."</p>";
220 - $form .= wfCloseElement( 'form' );
221 -
222 - $wgOut->addHTML( $form );
223 -
224 - $wgOut->addWikiText( wfMsgHtml( "requestaccount-footer" ) );
225 - }
226 -
227 - function doSubmit() {
228 - global $wgOut, $wgUser, $wgAuth, $wgAccountRequestThrottle;
229 - # Now create a dummy user ($u) and check if it is valid
230 - $name = trim( $this->mUsername );
231 - $u = User::newFromName( $name, 'creatable' );
232 - if( is_null($u) ) {
233 - $this->showForm( wfMsgHtml('noname') );
234 - return;
235 - }
236 - # FIXME: Hack! If we don't want them for requests, temporarily turn it off!
237 - global $wgConfirmAccountCaptchas, $wgCaptchaTriggers;
238 - if( !$wgConfirmAccountCaptchas && isset($wgCaptchaTriggers) ) {
239 - $old = $wgCaptchaTriggers['createaccount'];
240 - $wgCaptchaTriggers['createaccount'] = false;
241 - }
242 - $abortError = '';
243 - if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
244 - // Hook point to add extra creation throttles and blocks
245 - wfDebug( "RequestAccount::doSubmit: a hook blocked creation\n" );
246 - $this->showForm( $abortError );
247 - return;
248 - }
249 - if( !$wgConfirmAccountCaptchas && isset($wgCaptchaTriggers) ) {
250 - $wgCaptchaTriggers['createaccount'] = $old;
251 - }
252 - # No request spamming...
253 - if( $wgAccountRequestThrottle && ( !method_exists($wgUser,'isPingLimitable') || $wgUser->isPingLimitable() ) ) {
254 - global $wgMemc;
255 -
256 - $key = wfMemcKey( 'acctrequest', 'ip', wfGetIP() );
257 - $value = $wgMemc->get( $key );
258 - if( $value > $wgAccountRequestThrottle ) {
259 - $this->throttleHit( $wgAccountRequestThrottle );
260 - return;
261 - }
262 - }
263 - # Check if already in use
264 - if( 0 != $u->idForName() || $wgAuth->userExists( $u->getName() ) ) {
265 - $this->showForm( wfMsgHtml('userexists') );
266 - return;
267 - }
268 - # Check pending accounts for name use
269 - $dbw = wfGetDB( DB_MASTER );
270 - $dup = $dbw->selectField( 'account_requests', '1',
271 - array( 'acr_name' => $u->getName() ),
272 - __METHOD__ );
273 - if( $dup ) {
274 - $this->showForm( wfMsgHtml('requestaccount-inuse') );
275 - return;
276 - }
277 - # Make sure user agrees to policy here
278 - global $wgAccountRequestToS;
279 - if( $wgAccountRequestToS && !$this->mToS ) {
280 - $this->showForm( wfMsgHtml('requestaccount-agree') );
281 - return;
282 - }
283 - # Validate email address
284 - if( !$u->isValidEmailAddr( $this->mEmail ) ) {
285 - $this->showForm( wfMsgHtml('invalidemailaddress') );
286 - return;
287 - }
288 - global $wgAccountRequestMinWords;
289 - # Check if biography is long enough
290 - if( str_word_count($this->mBio) < $wgAccountRequestMinWords ) {
291 - $this->showForm( wfMsgHtml('requestaccount-tooshort',$wgAccountRequestMinWords) );
292 - return;
293 - }
294 - # Set some additional data so the AbortNewAccount hook can be
295 - # used for more than just username validation
296 - $u->setEmail( $this->mEmail );
297 - # Check if someone else has an account request with the same email
298 - $dup = $dbw->selectField( 'account_requests', '1',
299 - array( 'acr_email' => $u->getEmail() ),
300 - __METHOD__ );
301 - if( $dup ) {
302 - $this->showForm( wfMsgHtml('requestaccount-emaildup') );
303 - return;
304 - }
305 -
306 - $u->setRealName( $this->mRealName );
307 - # Per security reasons, file dir cannot be pulled from client,
308 - # so ask them to resubmit it then...
309 - global $wgAllowAccountRequestFiles, $wgAccountRequestExtraInfo;
310 - # If the extra fields are off, then uploads are off
311 - $allowFiles = $wgAccountRequestExtraInfo && $wgAllowAccountRequestFiles;
312 - if( $allowFiles && $this->mPrevAttachment && !$this->mSrcName ) {
313 - # If the user is submitting forgotAttachment as true with no file,
314 - # then they saw the notice and choose not to re-select the file.
315 - # Assume that they don't want to send one anymore.
316 - if( !$this->mForgotAttachment ) {
317 - $this->mPrevAttachment = '';
318 - $this->showForm( wfMsgHtml('requestaccount-resub'), 1 );
319 - return false;
320 - }
321 - }
322 - # Process upload...
323 - if( $allowFiles && $this->mSrcName ) {
324 - $ext = explode('.',$this->mSrcName);
325 - $finalExt = $ext[count($ext)-1];
326 - # File must have size.
327 - if( trim( $this->mSrcName ) == '' || empty( $this->mFileSize ) ) {
328 - $this->mPrevAttachment = '';
329 - $this->showForm( wfMsgHtml( 'emptyfile' ) );
330 - return false;
331 - }
332 - # Look at the contents of the file; if we can recognize the
333 - # type but it's corrupt or data of the wrong type, we should
334 - # probably not accept it.
335 - global $wgAccountRequestExts;
336 - if( !in_array($finalExt,$wgAccountRequestExts) ) {
337 - $this->mPrevAttachment = '';
338 - $this->showForm( wfMsgHtml( 'requestaccount-exts' ) );
339 - return false;
340 - }
341 - $veri = $this->verify( $this->mTempPath, $finalExt );
342 - if( $veri !== true ) {
343 - $this->mPrevAttachment = '';
344 - $this->showForm( wfMsgHtml( 'uploadcorrupt' ) );
345 - return false;
346 - }
347 - # Start a transaction, move file from temp to account request directory.
348 - $transaction = new FSTransaction();
349 - if( !FileStore::lock() ) {
350 - wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" );
351 - return false;
352 - }
353 - $store = FileStore::get( 'accountreqs' );
354 - if( !$store ) {
355 - wfDebug( __METHOD__.": invalid storage group '{$store}'.\n" );
356 - return false;
357 - }
358 -
359 - $key = FileStore::calculateKey( $this->mTempPath, $finalExt );
360 -
361 - $transaction->add( $store->insert( $key, $this->mTempPath, FileStore::DELETE_ORIGINAL ) );
362 - if( $transaction === false ) {
363 - // Failed to move?
364 - wfDebug( __METHOD__.": import to file store failed, aborting\n" );
365 - throw new MWException( "Could not insert file {$this->mTempPath}" );
366 - return false;
367 - }
368 - }
369 - $expires = null; // passed by reference
370 - $token = $this->getConfirmationToken( $u, $expires );
371 - # Insert into pending requests...
372 - $acr_id = $dbw->nextSequenceValue( 'account_requests_acr_id_seq' );
373 - $dbw->begin();
374 - $dbw->insert( 'account_requests',
375 - array(
376 - 'acr_id' => $acr_id,
377 - 'acr_name' => $u->getName(),
378 - 'acr_email' => $u->getEmail(),
379 - 'acr_real_name' => $u->getRealName(),
380 - 'acr_registration' => $dbw->timestamp(),
381 - 'acr_bio' => $this->mBio,
382 - 'acr_notes' => $this->mNotes,
383 - 'acr_urls' => $this->mUrls,
384 - 'acr_filename' => isset($this->mSrcName) ? $this->mSrcName : null,
385 - 'acr_type' => $this->mType,
386 - 'acr_areas' => self::flattenAreas( $this->mAreaSet ),
387 - 'acr_storage_key' => isset($key) ? $key : null,
388 - 'acr_comment' => '',
389 - 'acr_email_token' => md5($token),
390 - 'acr_email_token_expires' => $dbw->timestamp( $expires ),
391 - 'acr_ip' => wfGetIP() // Possible use for spam blocking
392 - ),
393 - __METHOD__
394 - );
395 - # Clear cache for notice of how many account requests there are
396 - global $wgMemc;
397 - $key = wfMemcKey( 'confirmaccount', 'noticecount' );
398 - $wgMemc->delete( $key );
399 - # Send confirmation, required!
400 - $result = $this->sendConfirmationMail( $u, $token, $expires );
401 - if( WikiError::isError( $result ) ) {
402 - $dbw->rollback(); // Nevermind
403 - $error = wfMsg( 'mailerror', htmlspecialchars( $result->toString() ) );
404 - $this->showForm( $error );
405 - return false;
406 - }
407 - $dbw->commit();
408 - if( isset($transaction) ) {
409 - wfDebug( __METHOD__.": set db items, applying file transactions\n" );
410 - $transaction->commit();
411 - FileStore::unlock();
412 - }
413 - # No request spamming...
414 - # BC: check if isPingLimitable() exists
415 - if( $wgAccountRequestThrottle && ( !method_exists($wgUser,'isPingLimitable') || $wgUser->isPingLimitable() ) ) {
416 - global $wgMemc;
417 -
418 - $key = wfMemcKey( 'acctrequest', 'ip', wfGetIP() );
419 - $value = $wgMemc->incr( $key );
420 - if( !$value ) {
421 - $wgMemc->set( $key, 1, 86400 );
422 - }
423 - }
424 - # Done!
425 - $this->showSuccess();
426 - }
427 -
428 - function showSuccess() {
429 - global $wgOut;
430 -
431 - $wgOut->setPagetitle( wfMsg( "requestaccount" ) );
432 - $wgOut->addWikiText( wfMsg( "requestaccount-sent" ) );
433 -
434 - $wgOut->returnToMain();
435 - }
436 -
437 - /**
438 - * Flatten an areas of interest array
439 - * @access private
440 - */
441 - static function flattenAreas( $areas ) {
442 - $flatAreas = '';
443 - foreach( $areas as $area ) {
444 - $flatAreas .= $area."\n";
445 - }
446 - return $flatAreas;
447 - }
448 -
449 - static function expandAreas( $areas ) {
450 - $list = explode("\n",$areas);
451 - foreach( $list as $n => $item ) {
452 - $list[$n] = trim("wpArea-".str_replace( ' ', '_', $item ));
453 - }
454 - unset( $list[count($list)-1] );
455 - return $list;
456 - }
457 -
458 - /**
459 - * Initialize the uploaded file from PHP data
460 - * @access private
461 - */
462 - function initializeUpload( $request ) {
463 - $this->mTempPath = $request->getFileTempName( 'wpUploadFile' );
464 - $this->mFileSize = $request->getFileSize( 'wpUploadFile' );
465 - $this->mSrcName = $request->getFileName( 'wpUploadFile' );
466 - $this->mRemoveTempFile = false; // PHP will handle this
467 - }
468 -
469 - /**
470 - * Verifies that it's ok to include the uploaded file
471 - *
472 - * @param string $tmpfile the full path of the temporary file to verify
473 - * @param string $extension The filename extension that the file is to be served with
474 - * @return mixed true of the file is verified, a WikiError object otherwise.
475 - */
476 - function verify( $tmpfile, $extension ) {
477 - #magically determine mime type
478 - $magic=& MimeMagic::singleton();
479 - $mime = $magic->guessMimeType($tmpfile,false);
480 -
481 - #check mime type, if desired
482 - global $wgVerifyMimeType;
483 - if ($wgVerifyMimeType) {
484 -
485 - wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n");
486 - #check mime type against file extension
487 - if( !$this->verifyExtension( $mime, $extension ) ) {
488 - return new WikiErrorMsg( 'uploadcorrupt' );
489 - }
490 -
491 - #check mime type blacklist
492 - global $wgMimeTypeBlacklist;
493 - if( isset($wgMimeTypeBlacklist) && !is_null($wgMimeTypeBlacklist)
494 - && $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
495 - return new WikiErrorMsg( 'filetype-badmime', htmlspecialchars( $mime ) );
496 - }
497 - }
498 -
499 - wfDebug( __METHOD__.": all clear; passing.\n" );
500 - return true;
501 - }
502 -
503 - /**
504 - * Checks if the mime type of the uploaded file matches the file extension.
505 - *
506 - * @param string $mime the mime type of the uploaded file
507 - * @param string $extension The filename extension that the file is to be served with
508 - * @return bool
509 - */
510 - function verifyExtension( $mime, $extension ) {
511 - $magic =& MimeMagic::singleton();
512 -
513 - if ( ! $mime || $mime == 'unknown' || $mime == 'unknown/unknown' )
514 - if ( ! $magic->isRecognizableExtension( $extension ) ) {
515 - wfDebug( __METHOD__.": passing file with unknown detected mime type; " .
516 - "unrecognized extension '$extension', can't verify\n" );
517 - return true;
518 - } else {
519 - wfDebug( __METHOD__.": rejecting file with unknown detected mime type; ".
520 - "recognized extension '$extension', so probably invalid file\n" );
521 - return false;
522 - }
523 -
524 - $match = $magic->isMatchingExtension($extension,$mime);
525 -
526 - if ($match===NULL) {
527 - wfDebug( __METHOD__.": no file extension known for mime type $mime, passing file\n" );
528 - return true;
529 - } elseif ($match===true) {
530 - wfDebug( __METHOD__.": mime type $mime matches extension $extension, passing file\n" );
531 -
532 - #TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
533 - return true;
534 -
535 - } else {
536 - wfDebug( __METHOD__.": mime type $mime mismatches file extension $extension, rejecting file\n" );
537 - return false;
538 - }
539 - }
540 -
541 - /**
542 - * Perform case-insensitive match against a list of file extensions.
543 - * Returns true if the extension is in the list.
544 - *
545 - * @param string $ext
546 - * @param array $list
547 - * @return bool
548 - */
549 - function checkFileExtension( $ext, $list ) {
550 - return in_array( strtolower( $ext ), $list );
551 - }
552 -
553 - /**
554 - * @private
555 - */
556 - function throttleHit( $limit ) {
557 - global $wgOut;
558 -
559 - $wgOut->addWikiText( wfMsgHtml( 'acct_request_throttle_hit', $limit ) );
560 - }
561 -
562 - function confirmEmailToken( $code ) {
563 - global $wgUser, $wgOut;
564 - # Confirm if this token is in the pending requests
565 - $name = $this->requestFromEmailToken( $code );
566 - if( $name !== false ) {
567 - # Send confirmation email to prospective user
568 - $this->confirmEmail( $name );
569 - # Send mail to admin after e-mail has been confirmed;
570 - global $wgConfirmAccountContact;
571 - if( $wgConfirmAccountContact ) {
572 - $u = User::newFromName( $name, 'creatable' );
573 - $u->setEmail( $wgConfirmAccountContact );
574 - $title = Title::makeTitle( NS_SPECIAL, 'ConfirmAccounts' );
575 - $url = $title->getFullUrl();
576 - $u->sendMail( wfMsg('requestaccount-email-subj-admin'),
577 - wfMsg( 'requestaccount-email-body-admin', $name, $url ) );
578 - }
579 - $wgOut->addWikiText( wfMsgHtml( 'request-account-econf' ) );
580 - $wgOut->returnToMain();
581 - return;
582 - }
583 - # Maybe the user confirmed after account was created...
584 - $user = User::newFromConfirmationCode( $code );
585 - if( is_object( $user ) ) {
586 - if( $user->confirmEmail() ) {
587 - $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
588 - $wgOut->addWikiText( wfMsg( $message ) );
589 - if( !$wgUser->isLoggedIn() ) {
590 - $title = SpecialPage::getTitleFor( 'Userlogin' );
591 - $wgOut->returnToMain( true, $title->getPrefixedUrl() );
592 - }
593 - } else {
594 - $wgOut->addWikiText( wfMsg( 'confirmemail_error' ) );
595 - }
596 - } else {
597 - $wgOut->addWikiText( wfMsg( 'confirmemail_invalid' ) );
598 - }
599 - }
600 -
601 - /**
602 - * Get a request name from an emailconfirm token
603 - *
604 - * @param sring $code
605 - * @returns string $name
606 - */
607 - function requestFromEmailToken( $code ) {
608 - $dbr = wfGetDB( DB_SLAVE );
609 - $reqID = $dbr->selectField( 'account_requests', 'acr_name',
610 - array( 'acr_email_token' => md5($code),
611 - 'acr_email_token_expires > ' . $dbr->addQuotes( $dbr->timestamp() ),
612 - )
613 - );
614 - return $reqID;
615 - }
616 -
617 - /**
618 - * Flag a user's email as confirmed in the db
619 - *
620 - * @param sring $name
621 - */
622 - function confirmEmail( $name ) {
623 - $dbw = wfGetDB( DB_MASTER );
624 - $dbw->update( 'account_requests',
625 - array( 'acr_email_authenticated' => $dbw->timestamp() ),
626 - array( 'acr_name' => $name ),
627 - __METHOD__ );
628 - # Clear cache for notice of how many account requests there are
629 - global $wgMemc;
630 - $key = wfMemcKey( 'confirmaccount', 'noticecount' );
631 - $wgMemc->delete( $key );
632 - }
633 -
634 - /**
635 - * Generate a new e-mail confirmation token and send a confirmation
636 - * mail to the user's given address.
637 - *
638 - * @param User $user
639 - * @param string $token
640 - * @param string $expiration
641 - * @return mixed True on success, a WikiError object on failure.
642 - */
643 - function sendConfirmationMail( $user, $token, $expiration ) {
644 - global $wgContLang;
645 - $url = $this->confirmationTokenUrl( $token );
646 - return $user->sendMail( wfMsg( 'requestaccount-email-subj' ),
647 - wfMsg( 'requestaccount-email-body',
648 - wfGetIP(),
649 - $user->getName(),
650 - $url,
651 - $wgContLang->timeanddate( $expiration, false ) ) );
652 - }
653 -
654 - /**
655 - * Generate and store a new e-mail confirmation token, and return
656 - * the URL the user can use to confirm.
657 - * @param string $token
658 - * @return string
659 - * @private
660 - */
661 - function confirmationTokenUrl( $token ) {
662 - $title = Title::makeTitle( NS_SPECIAL, 'RequestAccount' );
663 - return $title->getFullUrl( 'action=confirmemail&wpEmailToken='.$token );
664 - }
665 -
666 - /**
667 - * Generate, store, and return a new e-mail confirmation code.
668 - * A hash (unsalted since it's used as a key) is stored.
669 - * @param User $user
670 - * @param string $expiration
671 - * @return string
672 - * @private
673 - */
674 - function getConfirmationToken( $user, &$expiration ) {
675 - global $wgConfirmAccountRejectAge;
676 -
677 - $expires = time() + $wgConfirmAccountRejectAge;
678 - $expiration = wfTimestamp( TS_MW, $expires );
679 -
680 - $token = $user->generateToken( $user->getName() . $user->getEmail() . $expires );
681 -
682 - return $token;
683 - }
684 -
685 -}
686 -
68712 class ConfirmAccountsPage extends SpecialPage
68813 {
68914
@@ -1685,212 +1010,3 @@
16861011 return 'acr_registration';
16871012 }
16881013 }
1689 -
1690 -class UserCredentialsPage extends SpecialPage
1691 -{
1692 -
1693 - function __construct() {
1694 - SpecialPage::SpecialPage('UserCredentials','lookupcredentials');
1695 - }
1696 -
1697 - function execute( $par ) {
1698 - global $wgRequest, $wgOut, $wgUser, $wgAccountRequestTypes;
1699 -
1700 - if( !$wgUser->isAllowed( 'lookupcredentials' ) ) {
1701 - $wgOut->permissionRequired( 'lookupcredentials' );
1702 - return;
1703 - }
1704 -
1705 - $this->setHeaders();
1706 -
1707 - # A target user
1708 - $this->target = $wgRequest->getText( 'target' );
1709 - # Attachments
1710 - $this->file = $wgRequest->getVal( 'file' );
1711 -
1712 - $this->skin = $wgUser->getSkin();
1713 -
1714 - if( $this->file ) {
1715 - $this->showFile( $this->file );
1716 - } else if( $this->target ) {
1717 - $this->showForm();
1718 - $this->showCredentials();
1719 - } else {
1720 - $this->showForm();
1721 - }
1722 - }
1723 -
1724 - function showForm() {
1725 - global $wgOut, $wgTitle, $wgScript;
1726 -
1727 - $username = str_replace( '_', ' ', $this->target );
1728 - $form = Xml::openElement( 'form', array( 'name' => 'stablization', 'action' => $wgScript, 'method' => 'get' ) );
1729 - $form .= "<fieldset><legend>".wfMsg('usercredentials-leg')."</legend>";
1730 - $form .= "<table><tr>";
1731 - $form .= "<td>".Xml::hidden( 'title', $wgTitle->getPrefixedText() )."</td>";
1732 - $form .= "<td>".wfMsgHtml("usercredentials-user")."</td>";
1733 - $form .= "<td>".Xml::input('target', 35, $username, array( 'id' => 'wpUsername' ) )."</td>";
1734 - $form .= "<td>".Xml::submitButton( wfMsg( 'go' ) )."</td>";
1735 - $form .= "</tr></table>";
1736 - $form .= "</fieldset></form>\n";
1737 -
1738 - $wgOut->addHTML( $form );
1739 - }
1740 -
1741 - function showCredentials() {
1742 - global $wgOut, $wgUser, $wgLang, $wgAccountRequestTypes;
1743 -
1744 - $titleObj = Title::makeTitle( NS_SPECIAL, "UserCredentials" );
1745 -
1746 - $row = $this->getRequest();
1747 - if( !$row ) {
1748 - $wgOut->addHTML( wfMsgHtml('usercredentials-badid') );
1749 - return;
1750 - }
1751 -
1752 - $wgOut->addWikiText( wfMsg( "usercredentials-text" ) );
1753 -
1754 - $user = User::newFromName( $this->target );
1755 -
1756 - $list = array();
1757 - foreach( $user->getGroups() as $group )
1758 - $list[] = self::buildGroupLink( $group );
1759 -
1760 - $grouplist = '';
1761 - if( count( $list ) > 0 ) {
1762 - $grouplist = '<tr><td>'.wfMsgHtml( 'usercredentials-member' ).'</td><td>'.implode( ', ', $list ).'</td></tr>';
1763 - }
1764 -
1765 - $form = "<fieldset>";
1766 - $form .= '<legend>' . wfMsgHtml('usercredentials-leg-user') . '</legend>';
1767 - $form .= '<table cellpadding=\'4\'>';
1768 - $form .= "<tr><td>".wfMsgHtml('username')."</td>";
1769 - $form .= "<td>".$this->skin->makeLinkObj( $user->getUserPage(), $user->getUserPage()->getText() )."</td></tr>\n";
1770 -
1771 - $econf = $row->acd_email_authenticated ? ' <strong>'.wfMsgHtml('confirmaccount-econf').'</strong>' : '';
1772 - $form .= "<tr><td>".wfMsgHtml('usercredentials-email')."</td>";
1773 - $form .= "<td>".htmlspecialchars($row->acd_email).$econf."</td></tr>\n";
1774 -
1775 - $form .= $grouplist;
1776 -
1777 - $form .= '</table></fieldset>';
1778 -
1779 - $areaSet = RequestAccountPage::expandAreas( $row->acd_areas );
1780 -
1781 - if( !wfEmptyMsg( 'requestaccount-areas', wfMsg('requestaccount-areas') ) ) {
1782 - $form .= '<fieldset>';
1783 - $form .= '<legend>' . wfMsgHtml('confirmaccount-leg-areas') . '</legend>';
1784 -
1785 - $areas = explode("\n*","\n".wfMsg('requestaccount-areas'));
1786 - $form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
1787 - $form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
1788 - $count = 0;
1789 -
1790 - $att = array('disabled' => 'disabled');
1791 - foreach( $areas as $area ) {
1792 - $set = explode("|",$area,3);
1793 - if( $set[0] && isset($set[1]) ) {
1794 - $count++;
1795 - if( $count > 5 ) {
1796 - $form .= "</tr><tr valign='top'>";
1797 - $count = 1;
1798 - }
1799 - $formName = "wpArea-" . htmlspecialchars(str_replace(' ','_',$set[0]));
1800 - if( isset($set[1]) ) {
1801 - $pg = $this->skin->makeKnownLink( $set[1], wfMsgHtml('requestaccount-info') );
1802 - } else {
1803 - $pg = '';
1804 - }
1805 - $form .= "<td>".wfCheckLabel( $set[0], $formName, $formName, in_array($formName,$areaSet), $att )." {$pg}</td>\n";
1806 - }
1807 - }
1808 - $form .= "</tr></table></div>";
1809 - $form .= '</fieldset>';
1810 - }
1811 -
1812 - $form .= '<fieldset>';
1813 - $form .= '<legend>' . wfMsgHtml('usercredentials-leg-person') . '</legend>';
1814 - $form .= '<table cellpadding=\'4\'>';
1815 - $form .= "<tr><td>".wfMsgHtml('usercredentials-real')."</td>";
1816 - $form .= "<td>".htmlspecialchars($row->acd_real_name)."</td></tr>\n";
1817 - $form .= '</table>';
1818 - $form .= "<p>".wfMsgHtml('usercredentials-bio')."</p>";
1819 - $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpBio' id='wpNewBio' rows='10' cols='80' style='width:100%'>" .
1820 - htmlspecialchars($row->acd_bio) .
1821 - "</textarea></p>\n";
1822 - $form .= '</fieldset>';
1823 -
1824 - $form .= '<fieldset>';
1825 - $form .= '<legend>' . wfMsgHtml('usercredentials-leg-other') . '</legend>';
1826 - $form .= '<p>'.wfMsgHtml('usercredentials-attach') . ' ';
1827 - if( $row->acd_filename ) {
1828 - $form .= $this->skin->makeKnownLinkObj( $titleObj, htmlspecialchars($row->acd_filename),
1829 - 'file=' . $row->acd_storage_key );
1830 - } else {
1831 - $form .= wfMsgHtml('confirmaccount-none-p');
1832 - }
1833 - $form .= "</p><p>".wfMsgHtml('usercredentials-notes')."</p>\n";
1834 - $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%'>" .
1835 - htmlspecialchars($row->acd_notes) .
1836 - "</textarea></p>\n";
1837 - $form .= "<p>".wfMsgHtml('usercredentials-urls')."</p>\n";
1838 - $form .= ConfirmAccountsPage::parseLinks($row->acd_urls);
1839 - if( $wgUser->isAllowed( 'requestips' ) ) {
1840 - $blokip = SpecialPage::getTitleFor( 'blockip' );
1841 - $form .= "<p>".wfMsgHtml('usercredentials-ip')." ".htmlspecialchars($row->acd_ip)."</p>\n";
1842 - }
1843 - $form .= '</fieldset>';
1844 -
1845 - $wgOut->addHTML( $form );
1846 - }
1847 -
1848 - /**
1849 - * Format a link to a group description page
1850 - *
1851 - * @param string $group
1852 - * @return string
1853 - */
1854 - private static function buildGroupLink( $group ) {
1855 - static $cache = array();
1856 - if( !isset( $cache[$group] ) )
1857 - $cache[$group] = User::makeGroupLinkHtml( $group, User::getGroupMember( $group ) );
1858 - return $cache[$group];
1859 - }
1860 -
1861 - /**
1862 - * Show a private file requested by the visitor.
1863 - */
1864 - function showFile( $key ) {
1865 - global $wgOut, $wgRequest;
1866 - $wgOut->disable();
1867 -
1868 - # We mustn't allow the output to be Squid cached, otherwise
1869 - # if an admin previews a private image, and it's cached, then
1870 - # a user without appropriate permissions can toddle off and
1871 - # nab the image, and Squid will serve it
1872 - $wgRequest->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
1873 - $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
1874 - $wgRequest->response()->header( 'Pragma: no-cache' );
1875 -
1876 - $store = FileStore::get( 'accountcreds' );
1877 - if( !$store ) {
1878 - wfDebug( __METHOD__.": invalid storage group '{$store}'.\n" );
1879 - return false;
1880 - }
1881 - $store->stream( $key );
1882 - }
1883 -
1884 - function getRequest() {
1885 - $uid = User::idFromName( $this->target );
1886 - if( !$uid )
1887 - return false;
1888 - # For now, just get the first revision...
1889 - $dbr = wfGetDB( DB_SLAVE );
1890 - $row = $dbr->selectRow( 'account_credentials', '*',
1891 - array( 'acd_user_id' => $uid ),
1892 - __METHOD__,
1893 - array( 'ORDER BY' => 'acd_user_id,acd_id ASC' ) );
1894 - return $row;
1895 - }
1896 -
1897 -}

Status & tagging log