added files

This commit is contained in:
jvvg 2013-06-06 15:09:12 -04:00
commit 4d9306b06c
32 changed files with 20436 additions and 0 deletions

4
ConfirmAccount/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.svn
*~
*.kate-swp
.*.swp

View file

@ -0,0 +1,6 @@
[gerrit]
host=gerrit.wikimedia.org
port=29418
project=mediawiki/extensions/ConfirmAccount
defaultbranch=master
defaultrebase=0

View file

@ -0,0 +1,118 @@
<?php
# ######## Configuration variables ########
# IMPORTANT: DO NOT EDIT THIS FILE
# When configuring globals, set them at LocalSettings.php instead
# Set the person's bio as their userpage?
$wgMakeUserPageFromBio = true;
# Text to add to bio pages if the above option is on
$wgAutoUserBioText = '';
# Create a user talk page with a welcome message for accepted users.
# The message can be customized by editing MediaWiki:confirmaccount-welc.
$wgAutoWelcomeNewUsers = true;
# How long to store rejected requests
$wgRejectedAccountMaxAge = 7 * 24 * 3600; // 1 week
# How long after accounts have been requested/held before they count as 'rejected'
$wgConfirmAccountRejectAge = 30 * 24 * 3600; // 1 month
# How many requests can an IP make at once?
$wgAccountRequestThrottle = 1;
# Can blocked users with "prevent account creation" request accounts?
$wgAccountRequestWhileBlocked = false;
# Which form elements to show at Special:RequestAccount
$wgConfirmAccountRequestFormItems = array(
# Let users make names other than their "real name"
'UserName' => array( 'enabled' => true ),
# Real name of user
'RealName' => array( 'enabled' => false ),
# Biographical info
'Biography' => array( 'enabled' => false, 'minWords' => 0 ),
# Interest checkboxes (defined in MediaWiki:requestaccount-areas)
'AreasOfInterest' => array( 'enabled' => true ),
# CV/resume attachment option
'CV' => array( 'enabled' => false ),
# Additional non-public info for reviewer
'Notes' => array( 'enabled' => true ),
# Option to place web URLs that establish the user
'Links' => array( 'enabled' => false ),
# Terms of Service checkbox
'TermsOfService' => array( 'enabled' => true ),
);
# If files can be attached, what types can be used? (MIME data is checked)
$wgAccountRequestExts = array( 'txt', 'pdf', 'doc', 'latex', 'rtf', 'text', 'wp', 'wpd', 'sxw' );
# Prospective account request types.
# Format is an array of (integer => (subpage param,user group,autotext)) pairs.
# The integer keys enumerate the request types. The key for a type should not change.
# Each type has its own request queue at Special:ConfirmAccount/<subpage param>.
# When a request of a certain type is approved, the new user:
# (a) is placed in the <user group> group (if not User or *)
# (b) has <autotext> appended to his or her user page
$wgAccountRequestTypes = array(
0 => array( 'authors', 'user', null )
);
# If set, will add {{DEFAULTSORT:sortkey}} to userpages for auto-categories.
# The sortkey will be made by doing a regex search and replace on the title.
# Set this variable to false to avoid sortkey use.
$wgConfirmAccountSortkey = false;
// For example, the below will do {{DEFAULTSORT:firstname, lastname}}
# $wgConfirmAccountSortkey = array( '/^(.+) ([^ ]+)$/', '$2, $1' );
# IMPORTANT: do we store the user's notes and credentials
# for sucessful account request? This will be stored indefinetely
# and will be accessible to users with crediential lookup permissions
$wgConfirmAccountSaveInfo = true;
# Send an email to this address when account requestors confirm their email.
# Set to false to skip this
$wgConfirmAccountContact = false;
# If ConfirmEdit is installed and set to trigger for createaccount,
# inject catpchas for requests too?
$wgConfirmAccountCaptchas = true;
# Storage repos. Has B/C for when this used FileStore.
$wgConfirmAccountFSRepos = array(
'accountreqs' => array( # Location of attached files for pending requests
'name' => 'accountreqs',
'directory' => isset( $wgFileStore['accountreqs'] ) ?
$wgFileStore['accountreqs']['directory'] : "{$IP}/images/accountreqs",
'url' => isset( $wgFileStore['accountreqs'] ) ?
$wgFileStore['accountreqs']['url'] : null,
'hashLevels' => isset( $wgFileStore['accountreqs'] ) ?
$wgFileStore['accountreqs']['hash'] : 3
),
'accountcreds' => array( # Location of credential files
'name' => 'accountcreds',
'directory' => isset( $wgFileStore['accountcreds'] ) ?
$wgFileStore['accountcreds']['directory'] : "{$IP}/images/accountcreds",
'url' => isset( $wgFileStore['accountcreds'] ) ?
$wgFileStore['accountcreds']['url'] : null,
'hashLevels' => isset( $wgFileStore['accountcreds'] ) ?
$wgFileStore['accountcreds']['hash'] : 3
)
);
# Restrict account creation
$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['user']['createaccount'] = false;
# Grant account queue rights
$wgGroupPermissions['bureaucrat']['confirmaccount'] = true;
# This right has the request IP show when confirming accounts
$wgGroupPermissions['bureaucrat']['requestips'] = true;
# If credentials are stored, this right lets users look them up
$wgGroupPermissions['bureaucrat']['lookupcredentials'] = true;
# Show notice for open requests to admins?
# This is cached, but still can be expensive on sites with thousands of requests.
$wgConfirmAccountNotice = true;
# End of configuration variables.
# ########

View file

@ -0,0 +1,81 @@
<?php
/*
(c) Aaron Schulz 2007, GPL
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
http://www.gnu.org/copyleft/gpl.html
*/
if ( !defined( 'MEDIAWIKI' ) ) {
echo "ConfirmAccount extension\n";
exit( 1 ) ;
}
$wgExtensionCredits['specialpage'][] = array(
'path' => __FILE__,
'name' => 'Confirm User Accounts',
'descriptionmsg' => 'confirmedit-desc',
'author' => 'Aaron Schulz',
'url' => 'https://www.mediawiki.org/wiki/Extension:ConfirmAccount',
);
# Load default config variables
require( dirname( __FILE__ ) . '/ConfirmAccount.config.php' );
# Define were PHP files and i18n files are located
require( dirname( __FILE__ ) . '/ConfirmAccount.setup.php' );
ConfirmAccountSetup::defineSourcePaths( $wgAutoloadClasses, $wgExtensionMessagesFiles );
# Define JS/CSS modules and file locations
ConfirmAccountUISetup::defineResourceModules( $wgResourceModules );
# Let some users confirm account requests and view credentials for created accounts
$wgAvailableRights[] = 'confirmaccount'; // user can confirm account requests
$wgAvailableRights[] = 'requestips'; // user can see IPs in request queue
$wgAvailableRights[] = 'lookupcredentials'; // user can lookup info on confirmed users
# Actually register special pages
ConfirmAccountUISetup::defineSpecialPages( $wgSpecialPages, $wgSpecialPageGroups );
# ####### HOOK CALLBACK FUNCTIONS #########
# UI-related hook handlers
ConfirmAccountUISetup::defineHookHandlers( $wgHooks );
# Check for account name collisions
$wgHooks['AbortNewAccount'][] = 'ConfirmAccountUIHooks::checkIfAccountNameIsPending';
# Schema changes
$wgHooks['LoadExtensionSchemaUpdates'][] = 'ConfirmAccountUpdaterHooks::addSchemaUpdates';
# ####### END HOOK CALLBACK FUNCTIONS #########
# Load the extension after setup is finished
$wgExtensionFunctions[] = 'efLoadConfirmAccount';
/**
* This function is for setup that has to happen in Setup.php
* when the functions in $wgExtensionFunctions get executed.
* @return void
*/
function efLoadConfirmAccount() {
global $wgEnableEmail;
# This extension needs email enabled!
# Otherwise users can't get their passwords...
if ( !$wgEnableEmail ) {
echo "ConfirmAccount extension requires \$wgEnableEmail set to true.\n";
exit( 1 ) ;
}
}

View file

@ -0,0 +1,56 @@
<?php
/**
* Class containing basic setup functions.
*/
class ConfirmAccountSetup {
/**
* Register source code paths.
* This function must NOT depend on any config vars.
*
* @param $classes Array $classes
* @param $messagesFiles Array $messagesFiles
* @return void
*/
public static function defineSourcePaths( array &$classes, array &$messagesFiles ) {
$dir = dirname( __FILE__ );
# Basic directory layout
$backendDir = "$dir/backend";
$schemaDir = "$dir/backend/schema";
$businessDir = "$dir/business";
$frontendDir = "$dir/frontend";
$langDir = "$dir/frontend/language/";
$spActionDir = "$dir/frontend/specialpages/actions";
# Main i18n file and special page alias file
$messagesFiles['ConfirmAccount'] = "$langDir/ConfirmAccount.i18n.php";
$messagesFiles['ConfirmAccountAliases'] = "$langDir/ConfirmAccount.alias.php";
# UI setup class
$classes['ConfirmAccountUISetup'] = "$frontendDir/ConfirmAccountUI.setup.php";
# UI event handler classes
$classes['ConfirmAccountUIHooks'] = "$frontendDir/ConfirmAccountUI.hooks.php";
# UI to request an account
$classes['RequestAccountPage'] = "$spActionDir/RequestAccount_body.php";
$messagesFiles['RequestAccountPage'] = "$langDir/RequestAccountPage.i18n.php";
# UI to confirm accounts
$classes['ConfirmAccountsPage'] = "$spActionDir/ConfirmAccount_body.php";
$messagesFiles['ConfirmAccountPage'] = "$langDir/ConfirmAccountPage.i18n.php";
# UI to see account credentials
$classes['UserCredentialsPage'] = "$spActionDir/UserCredentials_body.php";
$messagesFiles['UserCredentialsPage'] = "$langDir/UserCredentialsPage.i18n.php";
# Utility functions
$classes['ConfirmAccount'] = "$backendDir/ConfirmAccount.class.php";
# Data access objects
$classes['UserAccountRequest'] = "$backendDir/UserAccountRequest.php";
# Business logic
$classes['AccountRequestSubmission'] = "$businessDir/AccountRequestSubmission.php";
$classes['AccountConfirmSubmission'] = "$businessDir/AccountConfirmSubmission.php";
# Schema changes
$classes['ConfirmAccountUpdaterHooks'] = "$schemaDir/ConfirmAccountUpdater.hooks.php";
}
}

11
ConfirmAccount/README.txt Normal file
View file

@ -0,0 +1,11 @@
Complete online documenation:
http://www.mediawiki.org/wiki/Extension:ConfirmAccount
== Breaking changes ==
=== MediaWiki 1.20 ===
$wgAccountRequestMinWords, $wgAccountRequestToS, $wgAccountRequestExtraInfo,
and $wgAllowAccountRequestFiles were all folded into a new variable called
$wgConfirmAccountRequestFormItems.
== Licensing ==
© GPL, Aaron Schulz

View file

@ -0,0 +1,307 @@
<?php
class ConfirmAccount {
/**
* Move old stale requests to rejected list. Delete old rejected requests.
*/
public static function runAutoMaintenance() {
global $wgRejectedAccountMaxAge, $wgConfirmAccountRejectAge, $wgConfirmAccountFSRepos;
$dbw = wfGetDB( DB_MASTER );
$repo = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
# Select all items older than time $encCutoff
$encCutoff = $dbw->addQuotes( $dbw->timestamp( time() - $wgRejectedAccountMaxAge ) );
$res = $dbw->select( 'account_requests',
array( 'acr_id', 'acr_storage_key' ),
array( "acr_rejected < {$encCutoff}" ),
__METHOD__
);
# Clear out any associated attachments and delete those rows
foreach ( $res as $row ) {
$key = $row->acr_storage_key;
if ( $key ) {
$path = $repo->getZonePath( 'public' ) . '/' .
UserAccountRequest::relPathFromKey( $key );
if ( $path && file_exists( $path ) ) {
unlink( $path );
}
}
$dbw->delete( 'account_requests', array( 'acr_id' => $row->acr_id ), __METHOD__ );
}
# Select all items older than time $encCutoff
$encCutoff = $dbw->addQuotes( $dbw->timestamp( time() - $wgConfirmAccountRejectAge ) );
# Old stale accounts will count as rejected. If the request was held, give it more time.
$dbw->update( 'account_requests',
array( 'acr_rejected' => $dbw->timestamp(),
'acr_user' => 0, // dummy
'acr_comment' => wfMessage( 'confirmaccount-autorej' )->inContentLanguage()->text(),
'acr_deleted' => 1 ),
array( "acr_rejected IS NULL",
"acr_registration < {$encCutoff}",
"acr_held < {$encCutoff} OR acr_held IS NULL" ),
__METHOD__
);
# Clear cache for notice of how many account requests there are
self::clearAccountRequestCountCache();
}
/**
* Flag a user's email as confirmed in the db
*
* @param sring $name
*/
public static function confirmEmail( $name ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'account_requests',
array( 'acr_email_authenticated' => $dbw->timestamp() ),
array( 'acr_name' => $name ),
__METHOD__ );
# Clear cache for notice of how many account requests there are
self::clearAccountRequestCountCache();
}
/**
* Generate and store a new e-mail confirmation token, and return
* the URL the user can use to confirm.
* @param string $token
* @return string
*/
public static function confirmationTokenUrl( $token ) {
$title = SpecialPage::getTitleFor( 'RequestAccount' );
return $title->getFullUrl( array(
'action' => 'confirmemail',
'wpEmailToken' => $token
) );
}
/**
* Generate, store, and return a new e-mail confirmation code.
* A hash (unsalted since it's used as a key) is stored.
* @param User $user
* @param string $expiration
* @return string
*/
public static function getConfirmationToken( $user, &$expiration ) {
global $wgConfirmAccountRejectAge;
$expires = time() + $wgConfirmAccountRejectAge;
$expiration = wfTimestamp( TS_MW, $expires );
$token = $user->generateToken( $user->getName() . $user->getEmail() . $expires );
return $token;
}
/**
* Generate a new e-mail confirmation token and send a confirmation
* mail to the user's given address.
*
* @param User $user
* @param string $ip User IP address
* @param string $token
* @param string $expiration
* @return true|Status True on success, a Status object on failure.
*/
public static function sendConfirmationMail( User $user, $ip, $token, $expiration ) {
global $wgContLang;
$url = self::confirmationTokenUrl( $token );
$lang = $user->getOption( 'language' );
return $user->sendMail(
wfMessage( 'requestaccount-email-subj' )->inLanguage( $lang )->text(),
wfMessage( 'requestaccount-email-body',
$ip,
$user->getName(),
$url,
$wgContLang->timeanddate( $expiration, false ) ,
$wgContLang->date( $expiration, false ) ,
$wgContLang->time( $expiration, false )
)->inLanguage( $lang )->text()
);
}
/**
* Get a request name from an email confirmation token
*
* @param $code string
* @return string|false
*/
public static function requestNameFromEmailToken( $code ) {
$dbr = wfGetDB( DB_SLAVE );
return $dbr->selectField( 'account_requests',
'acr_name',
array(
'acr_email_token' => md5( $code ),
'acr_email_token_expires > ' . $dbr->addQuotes( $dbr->timestamp() ),
)
);
}
/**
* Get the number of account requests for a request type
* @param $type int
* @return Array Assosiative array with 'open', 'held', 'type' keys mapping to integers
*/
public static function getOpenRequestCount( $type ) {
$dbr = wfGetDB( DB_SLAVE );
$open = (int)$dbr->selectField( 'account_requests', 'COUNT(*)',
array( 'acr_type' => $type, 'acr_deleted' => 0, 'acr_held IS NULL' ),
__METHOD__
);
$held = (int)$dbr->selectField( 'account_requests', 'COUNT(*)',
array( 'acr_type' => $type, 'acr_deleted' => 0, 'acr_held IS NOT NULL' ),
__METHOD__
);
$rej = (int)$dbr->selectField( 'account_requests', 'COUNT(*)',
array( 'acr_type' => $type, 'acr_deleted' => 1, 'acr_user != 0' ),
__METHOD__
);
return array( 'open' => $open, 'held' => $held, 'rejected' => $rej );
}
/**
* Get the number of open email-confirmed account requests for a request type
* @param $type int|string A request type or '*' for all
* @return int
*/
public static function getOpenEmailConfirmedCount( $type = '*' ) {
global $wgMemc;
# Check cached results
$key = wfMemcKey( 'confirmaccount', 'econfopencount', $type );
$count = $wgMemc->get( $key );
# Only show message if there are any such requests
if ( $count === false ) {
$conds = array(
'acr_deleted' => 0, // not rejected
'acr_held IS NULL', // nor held
'acr_email_authenticated IS NOT NULL' ); // email confirmed
if ( $type !== '*' ) {
$conds['acr_type'] = (int)$type;
}
$dbw = wfGetDB( DB_MASTER );
$count = (int)$dbw->selectField( 'account_requests', 'COUNT(*)', $conds, __METHOD__ );
# Cache results (invalidated on change )
$wgMemc->set( $key, $count, 3600 * 24 * 7 );
}
return $count;
}
/**
* Clear account request cache
* @return void
*/
public static function clearAccountRequestCountCache() {
global $wgAccountRequestTypes, $wgMemc;
$types = array_keys( $wgAccountRequestTypes );
$types[] = '*'; // "all" types count
foreach ( $types as $type ) {
$key = wfMemcKey( 'confirmaccount', 'econfopencount', $type );
$wgMemc->delete( $key );
}
}
/**
* Verifies that it's ok to include the uploaded file
*
* @param string $tmpfile the full path of the temporary file to verify
* @param string $extension The filename extension that the file is to be served with
* @return Status object
*/
public static function verifyAttachment( $tmpfile, $extension ) {
global $wgVerifyMimeType, $wgMimeTypeBlacklist;
$magic =& MimeMagic::singleton(); // magically determine mime type
$mime = $magic->guessMimeType( $tmpfile, false );
# check mime type, if desired
if ( $wgVerifyMimeType ) {
wfDebug ( "\n\nmime: <$mime> extension: <$extension>\n\n" );
# Check mime type against file extension
if ( !UploadBase::verifyExtension( $mime, $extension ) ) {
return Status::newFatal( 'uploadcorrupt' );
}
# Check mime type blacklist
if ( isset( $wgMimeTypeBlacklist ) && !is_null( $wgMimeTypeBlacklist )
&& self::checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
return Status::newFatal( 'filetype-badmime', $mime );
}
}
wfDebug( __METHOD__ . ": all clear; passing.\n" );
return Status::newGood();
}
/**
* Perform case-insensitive match against a list of file extensions.
* Returns true if the extension is in the list.
*
* @param string $ext
* @param array $list
* @return bool
*/
protected static function checkFileExtension( $ext, $list ) {
return in_array( strtolower( $ext ), $list );
}
/**
* Get the text to add to this users page for describing editing topics
* for each "area" a user can be in, as defined in MediaWiki:requestaccount-areas.
*
* @return Array Associative mapping of the format:
* (name => ('project' => x, 'userText' => y, 'grpUserText' => (request type => z)))
* Any of the ultimate values can be the empty string
*/
public static function getUserAreaConfig() {
static $res; // process cache
if ( $res !== null ) {
return $res;
}
$res = array();
// Message describing the areas a user can be interested in, the corresponding wiki page,
// and any text that is automatically appended to the userpage on account acceptance.
// Format is <name> | <wikipage> [| <text for all>] [| <text group0>] [| <text group1>] ...
$msg = wfMessage( 'requestaccount-areas' )->inContentLanguage();
if ( $msg->exists() ) {
$areas = explode( "\n*", "\n" . $msg->text() );
foreach ( $areas as $n => $area ) {
$set = explode( "|", $area );
if ( count( $set ) >= 2 ) {
$name = trim( str_replace( '_', ' ', $set[0] ) );
$res[$name] = array();
$res[$name]['project'] = trim( $set[1] ); // name => WikiProject mapping
if ( isset( $set[2] ) ) {
$res[$name]['userText'] = trim( $set[2] ); // userpage text for all
} else {
$res[$name]['userText'] = '';
}
$res[$name]['grpUserText'] = array(); // userpage text for certain request types
$categories = array_slice( $set, 3 ); // keys start from 0 now in $categories
foreach ( $categories as $i => $cat ) {
$res[$name]['grpUserText'][$i] = trim( $cat ); // category for group $i
}
}
}
}
return $res;
}
/**
* Get a block for this user if they are blocked from requesting accounts
* @param User $user
* @return Block|null
*/
public static function getAccountRequestBlock( User $user ) {
global $wgAccountRequestWhileBlocked;
$block = false;
# If a user cannot make accounts, don't let them request them either
if ( !$wgAccountRequestWhileBlocked ) {
$block = $user->isBlockedFromCreateAccount();
}
return $block;
}
}

View file

@ -0,0 +1,487 @@
<?php
class UserAccountRequest {
/* Initially supplied fields */
protected $id;
protected $name;
protected $realName;
protected $email;
protected $registration;
protected $bio;
protected $notes;
protected $urls;
protected $type;
protected $areas;
protected $fileName;
protected $fileStorageKey;
protected $ip;
protected $xff;
protected $agent;
protected $emailToken;
protected $emailTokenExpires;
/* Fields set if user later confirms email */
protected $emailAuthTimestamp;
/* Fields used by the admins */
protected $deleted;
protected $rejectedTimestamp;
protected $heldTimestamp;
protected $user;
protected $comment;
private function __construct() {}
/**
* @param $row
* @return UserAccountRequest
*/
public static function newFromRow( $row ) {
$req = new self();
$req->id = (int)$row->acr_id;
$req->name = $row->acr_name;
$req->realName = $row->acr_real_name;
$req->email = $row->acr_email;
$req->registration = wfTimestampOrNull( TS_MW, $row->acr_registration );
$req->bio = $row->acr_bio;
$req->notes = $row->acr_notes;
$req->urls = $row->acr_urls;
$req->type = (int)$row->acr_type;
$req->areas = self::expandAreas( $row->acr_areas );
$req->fileName = strlen( $row->acr_filename )
? $row->acr_filename
: null;
$req->fileStorageKey = $row->acr_storage_key;
$req->ip = $row->acr_ip;
$req->xff = $row->acr_xff;
$req->agent = $row->acr_agent;
$req->emailToken = $row->acr_email_token; // MD5 of token
$req->emailTokenExpires = wfTimestampOrNull( TS_MW, $row->acr_email_token_expires );
$req->emailAuthTimestamp = wfTimestampOrNull( TS_MW, $row->acr_email_authenticated );
$req->deleted = (bool)$row->acr_deleted;
$req->rejectedTimestamp = wfTimestampOrNull( TS_MW, $row->acr_rejected );
$req->heldTimestamp = wfTimestampOrNull( TS_MW, $row->acr_held );
$req->user = (int)$row->acr_user;
$req->comment = $row->acr_comment;
return $req;
}
/**
* @param $fields array
* @return UserAccountRequest
*/
public static function newFromArray( array $fields ) {
$req = new self();
$req->id = isset( $fields['id'] )
? (int)$fields['id']
: null; // determined on insertOn()
$req->name = $fields['name'];
$req->realName = $fields['real_name'];
$req->email = $fields['email'];
$req->registration = wfTimestampOrNull( TS_MW, $fields['registration'] );
$req->bio = $fields['bio'];
$req->notes = $fields['notes'];
$req->urls = $fields['urls'];
$req->type = (int)$fields['type'];
$req->areas = is_string( $fields['areas'] )
? self::expandAreas( $fields['areas'] ) // DB format
: $fields['areas']; // already expanded
$req->fileName = strlen( $fields['filename'] )
? $fields['filename']
: null;
$req->fileStorageKey = $fields['storage_key'];
$req->ip = $fields['ip'];
$req->xff = $fields['xff'];
$req->agent = $fields['agent'];
$req->emailToken = $fields['email_token']; // MD5 of token
$req->emailTokenExpires = wfTimestampOrNull( TS_MW, $fields['email_token_expires'] );
// These fields are typically left to default on insertion...
$req->emailAuthTimestamp = isset( $fields['email_authenticated'] )
? wfTimestampOrNull( TS_MW, $fields['email_authenticated'] )
: null;
$req->deleted = isset( $fields['deleted'] )
? $fields['deleted']
: false;
$req->rejectedTimestamp = isset( $fields['rejected'] )
? wfTimestampOrNull( TS_MW, $fields['rejected'] )
: null;
$req->heldTimestamp = isset( $fields['held'] )
? wfTimestampOrNull( TS_MW, $fields['held'] )
: null;
$req->user = isset( $fields['user'] )
? (int)$fields['user']
: 0;
$req->comment = isset( $fields['comment'] )
? $fields['comment']
: '';
return $req;
}
/**
* @param $id int
* @param $from string|null 'dbmaster' to use DB master
* @return UserAccountRequest|null
*/
public static function newFromId( $id, $from = null ) {
$db = ( $from == 'dbmaster' )
? wfGetDB( DB_MASTER )
: wfGetDB( DB_SLAVE );
$row = $db->selectRow( 'account_requests', '*', array( 'acr_id' => $id ), __METHOD__ );
if ( !$row ) {
return null;
}
return self::newFromRow( $row );
}
/**
* @param $name string
* @param $from string|null 'dbmaster' to use DB master
* @return UserAccountRequest|null
*/
public static function newFromName( $name, $from = null ) {
$db = ( $master == 'dbmaster' )
? wfGetDB( DB_MASTER )
: wfGetDB( DB_SLAVE );
$row = $db->selectRow( 'account_requests', '*', array( 'acr_name' => $name ), __METHOD__ );
if ( !$row ) {
return null;
}
return self::newFromRow( $row );
}
/**
* @return int
*/
public function getId() {
return $this->id;
}
/**
* @return string
*/
public function getName() {
return $this->name;
}
/**
* @return sting
*/
public function getRealName() {
return $this->realName;
}
/**
* @return string
*/
public function getEmail() {
return $this->email;
}
/**
* @return string TS_MW timestamp
*/
public function getRegistration() {
return $this->registration;
}
/**
* @return string
*/
public function getBio() {
return $this->bio;
}
/**
* @return string
*/
public function getNotes() {
return $this->notes;
}
/**
* @return array
*/
public function getUrls() {
return $this->urls;
}
/**
* @param $flat string Use 'flat' to get a raw blob back
* @return array|string Flat blob or array from expanded blob
*/
public function getAreas( $flat = 'expanded' ) {
if ( $flat == 'expanded' ) {
return $this->areas;
} elseif ( $flat == 'flat' ) {
return self::flattenAreas( $this->areas );
}
throw new MWException( 'Invalid value for $flat parameter.' );
}
/**
* @return int
*/
public function getType() {
return $this->type;
}
/**
* @return string|null
*/
public function getFileName() {
return $this->fileName;
}
/**
* @return string|null
*/
public function getFileStorageKey() {
return $this->fileStorageKey;
}
/**
* @return string
*/
public function getIP() {
return $this->ip;
}
/**
* @return string
*/
public function getXFF() {
return $this->xff;
}
/**
* @return string
*/
public function getAgent() {
return $this->agent;
}
/**
* @return string
*/
public function getEmailToken() {
return $this->emailToken;
}
/**
* @return string TS_MW timestamp
*/
public function getEmailTokenExpires() {
return $this->emailTokenExpires;
}
/**
* @return string|null TS_MW timestamp
*/
public function getEmailAuthTimestamp() {
return $this->emailAuthTimestamp;
}
/**
* @return bool Request is deleted (either rejected or expired)
*/
public function isDeleted() {
return $this->deleted;
}
/**
* @return string|null TS_MW timestamp
*/
public function getRejectTimestamp() {
return $this->rejectedTimestamp;
}
/**
* @return string|null TS_MW timestamp
*/
public function getHeldTimestamp() {
return $this->heldTimestamp;
}
/**
* @return int User ID
*/
public function getHandlingUser() {
return $this->user;
}
/**
* @return string
*/
public function getHandlingComment() {
return $this->comment;
}
/**
* Try to insert the request into the database
* @return int
*/
public function insertOn() {
$dbw = wfGetDB( DB_MASTER );
# Allow for some fields to be handled automatically...
$acr_id = is_null( $this->id )
? $this->id
: $dbw->nextSequenceValue( 'account_requests_acr_id_seq' );
# Insert into pending requests...
$dbw->insert( 'account_requests',
array(
'acr_id' => $acr_id,
'acr_name' => strval( $this->name ),
'acr_email' => strval( $this->email ),
'acr_real_name' => strval( $this->realName ),
'acr_registration' => $dbw->timestamp( $this->registration ),
'acr_bio' => strval( $this->bio ),
'acr_notes' => strval( $this->notes ),
'acr_urls' => strval( $this->urls ),
'acr_type' => strval( $this->type ),
'acr_areas' => self::flattenAreas( $this->areas ),
'acr_filename' => isset( $this->fileName )
? $this->fileName
: null,
'acr_storage_key' => isset( $this->fileStorageKey )
? $this->fileStorageKey
: null,
'acr_comment' => strval( $this->comment ),
'acr_ip' => strval( $this->ip ), // for spam blocking
'acr_xff' => strval( $this->xff ), // for spam blocking
'acr_agent' => strval( $this->agent ), // for spam blocking
'acr_deleted' => (int)$this->deleted,
'acr_email_token' => strval( $this->emailToken ), // MD5 of token
'acr_email_token_expires' => $dbw->timestamp( $this->emailTokenExpires ),
),
__METHOD__
);
$this->id = $acr_id; // set for accessors
return $this->id;
}
/**
* Mark this request as rejected
* @param $admin User
* @param $timestamp string
* @param $reason string
* @return bool Success
*/
public function markRejected( User $admin, $timestamp, $reason = '' ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'account_requests',
array(
'acr_rejected' => $dbw->timestamp( $timestamp ),
'acr_user' => $admin->getID(),
'acr_comment' => $reason,
'acr_deleted' => 1 ),
array( 'acr_id' => $this->id, 'acr_deleted' => 0 ),
__METHOD__
);
return ( $dbw->affectedRows() > 0 );
}
/**
* Mark this request as held
* @param $admin User
* @param $timestamp string
* @param $reason string
* @return bool Success
*/
public function markHeld( User $admin, $timestamp, $reason = '' ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'account_requests',
array(
'acr_held' => $dbw->timestamp( $timestamp ),
'acr_user' => $admin->getID(),
'acr_comment' => $reason ),
array( 'acr_id' => $this->id, 'acr_held IS NULL', 'acr_deleted' => 0 ),
__METHOD__
);
return ( $dbw->affectedRows() > 0 );
}
/**
* @return bool
* @throws MWException
*/
public function remove() {
if ( !$this->id ) {
throw new MWException( "Account request ID is not set." );
}
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'account_requests', array( 'acr_id' => $this->id ), __METHOD__ );
return ( $dbw->affectedRows() > 0 );
}
/**
* Try to acquire a username in the request queue for insertion
* @return bool
*/
public static function acquireUsername( $name ) {
$dbw = wfGetDB( DB_MASTER );
$conds = array( 'acr_name' => $name );
if ( $dbw->selectField( 'account_requests', '1', $conds, __METHOD__ ) ) {
return false; // already in use
}
return !$dbw->selectField( 'account_requests', '1',
$conds, __METHOD__, array( 'FOR UPDATE' ) ); // acquire LOCK
}
/**
* Try to acquire a e-mail address in the request queue for insertion
* @return bool
*/
public static function acquireEmail( $email ) {
$dbw = wfGetDB( DB_MASTER );
$conds = array( 'acr_email' => $email );
if ( $dbw->selectField( 'account_requests', '1', $conds, __METHOD__ ) ) {
return false; // already in use
}
return !$dbw->selectField( 'account_requests', '1',
$conds, __METHOD__, array( 'FOR UPDATE' ) ); // acquire LOCK
}
/**
* Flatten areas of interest array
* Used by ConfirmAccountsPage
* @param $areas Array
* @todo just serialize()
* @return string
*/
protected static function flattenAreas( array $areas ) {
$flatAreas = '';
foreach ( $areas as $area ) {
$flatAreas .= $area . "\n";
}
return $flatAreas;
}
/**
* Expand areas of interest to array
* Used by ConfirmAccountsPage
* @param $areas string
* @todo just unserialize()
* @return Array
*/
public static function expandAreas( $areas ) {
$list = explode( "\n", $areas );
foreach ( $list as $n => $item ) {
$list[$n] = trim( str_replace( ' ', '_', $item ) );
}
unset( $list[count( $list ) - 1] );
return $list;
}
/**
* Get path relative to zone for an account request attachment file.
* This assures compatibility with the old FileStore sytem.
* @param $key string File storage key
* @return string
*/
public static function relPathFromKey( $key ) {
return "{$key[0]}/{$key[0]}{$key[1]}/{$key[0]}{$key[1]}{$key[2]}/{$key}";
}
}

View file

@ -0,0 +1,39 @@
<?php
/**
* Class containing updater functions for a ConfirmAccount environment
*/
class ConfirmAccountUpdaterHooks {
/**
* @param DatabaseUpdater $updater
* @return bool
*/
public static function addSchemaUpdates( DatabaseUpdater $updater ) {
$base = dirname( __FILE__ );
if ( $updater->getDB()->getType() == 'mysql' ) {
$base = "$base/mysql";
$updater->addExtensionTable( 'account_requests', "$base/ConfirmAccount.sql" );
$updater->addExtensionField( 'account_requests', 'acr_filename', "$base/patch-acr_filename.sql" );
$updater->addExtensionTable( 'account_credentials', "$base/patch-account_credentials.sql" );
$updater->addExtensionField( 'account_requests', 'acr_areas', "$base/patch-acr_areas.sql" );
$updater->addExtensionIndex( 'account_requests', 'acr_email', "$base/patch-email-index.sql" );
$updater->addExtensionField( 'account_requests', 'acr_agent', "$base/patch-acr_agent.sql" );
} elseif ( $updater->getDB()->getType() == 'postgres' ) {
$base = "$base/postgres";
$updater->addExtensionUpdate( array( 'addTable', 'account_requests', "$base/ConfirmAccount.pg.sql", true ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_held', "TIMESTAMPTZ" ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_filename', "TEXT" ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_storage_key', "TEXT" ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_comment', "TEXT NOT NULL DEFAULT ''" ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_type', "INTEGER NOT NULL DEFAULT 0" ) );
$updater->addExtensionUpdate( array( 'addTable', 'account_credentials', "$base/patch-account_credentials.sql", true ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_areas', "TEXT" ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_credentials', 'acd_areas', "TEXT" ) );
$updater->addExtensionUpdate( array( 'addIndex', 'account_requests', 'acr_email', "$base/patch-email-index.sql", true ) );
$updater->addExtensionUpdate( array( 'addPgField', 'account_requests', 'acr_agent', "$base/patch-acr_agent.sql", true ) );
}
return true;
}
}

View file

@ -0,0 +1,113 @@
-- (c) Aaron Schulz, 2007
-- Table structure for table `Confirm account`
-- Replace /*$wgDBprefix*/ with the proper prefix
-- This stores all of our reviews,
-- the corresponding tags are stored in the tag table
CREATE TABLE IF NOT EXISTS /*_*/account_requests (
acr_id int unsigned NOT NULL auto_increment PRIMARY KEY,
-- Usernames must be unique, must not be in the form of
-- an IP address. _Shouldn't_ allow slashes or case
-- conflicts. Spaces are allowed, and are _not_ converted
-- to underscores like titles. See the User::newFromName() for
-- the specific tests that usernames have to pass.
acr_name varchar(255) binary NOT NULL default '',
-- Optional 'real name' to be displayed in credit listings
acr_real_name varchar(255) binary NOT NULL default '',
-- Note: email should be restricted, not public info.
-- Same with passwords.
acr_email tinytext NOT NULL,
-- Initially NULL; when a user's e-mail address has been
-- validated by returning with a mailed token, this is
-- set to the current timestamp.
acr_email_authenticated varbinary(14) default NULL,
-- Randomly generated token created when the e-mail address
-- is set and a confirmation test mail sent.
acr_email_token binary(32),
-- Expiration date for the user_email_token
acr_email_token_expires varbinary(14),
-- A little about this user
acr_bio mediumblob NOT NULL,
-- Private info for reviewers to look at when considering request
acr_notes mediumblob NOT NULL,
-- Links to recognize/identify this user, CSV, may not be public
acr_urls mediumblob NOT NULL,
-- IP address
acr_ip VARCHAR(255) NULL default '',
acr_xff VARCHAR(255) NULL default '',
-- User-Agent header
acr_agent VARCHAR(255) NULL default '',
-- Name of attached file (.pdf,.doc,.txt etc...)
acr_filename VARCHAR(255) NULL,
acr_storage_key VARCHAR(64) NULL,
-- Prospective account access level
acr_type tinyint(255) unsigned NOT NULL default 0,
-- Areas of interest
acr_areas mediumblob NOT NULL,
-- Timestamp of account registration.
acr_registration varbinary(14) NOT NULL,
-- Flag for rejected accounts
acr_deleted bool NOT NULL,
-- Time of rejection (if rejected)
acr_rejected varbinary(14),
-- Time request was put on hold (if held)
acr_held varbinary(14),
-- The user who rejected/held it
acr_user int unsigned NOT NULL default 0,
-- Reason
acr_comment varchar(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/acr_name ON /*_*/account_requests (acr_name);
CREATE UNIQUE INDEX /*i*/acr_email ON /*_*/account_requests (acr_email(255));
CREATE INDEX /*i*/acr_email_token ON /*_*/account_requests (acr_email_token);
CREATE INDEX /*i*/acr_type_del_reg ON /*_*/account_requests (acr_type,acr_deleted,acr_registration);
-- This stores all of credential information
-- When accounts are confirmed, the identity info goes here
CREATE TABLE IF NOT EXISTS /*_*/account_credentials (
-- Revision ID #
acd_id int unsigned NOT NULL auto_increment PRIMARY KEY,
-- Foreign key to user.user_id
acd_user_id int unsigned NOT NULL,
-- Optional 'real name' to be displayed in credit listings
acd_real_name varchar(255) binary NOT NULL default '',
-- Note: email should be restricted, not public info.
-- Same with passwords.
acd_email tinytext NOT NULL,
-- Initially NULL; when a user's e-mail address has been
-- validated by returning with a mailed token, this is
-- set to the current timestamp.
acd_email_authenticated varbinary(14) default NULL,
-- A little about this user
acd_bio mediumblob NOT NULL,
-- Private info for reviewers to look at when considering request
acd_notes mediumblob NOT NULL,
-- Links to recognize/identify this user, CSV, may not be public
acd_urls mediumblob NOT NULL,
-- IP address
acd_ip VARCHAR(255) NULL default '',
acd_xff VARCHAR(255) NULL default '',
-- User-Agent header
acd_agent VARCHAR(255) NULL default '',
-- Name of attached file (.pdf,.doc,.txt etc...)
acd_filename VARCHAR(255) NULL,
acd_storage_key VARCHAR(64) NULL,
-- Areas of interest
acd_areas mediumblob NOT NULL,
-- Timestamp of account registration.
acd_registration varbinary(14) NOT NULL,
-- Timestamp of acceptance
acd_accepted varbinary(14),
-- The user who accepted it
acd_user int unsigned NOT NULL default 0,
-- Reason given in email
acd_comment varchar(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/acd_user_id ON /*_*/account_credentials (acd_user_id,acd_id);

View file

@ -0,0 +1,49 @@
-- (c) Aaron Schulz, 2007
ALTER TABLE /*$wgDBprefix*/account_requests
ADD acr_type tinyint(255) unsigned NOT NULL default 0,
DROP INDEX acr_deleted_reg,
ADD INDEX acr_type_del_reg (acr_type,acr_deleted,acr_registration);
-- This stores all of credential information
-- When accounts are confirmed, the identity info goes here
CREATE TABLE IF NOT EXISTS /*_*/account_credentials (
-- Revision ID #
acd_id int unsigned NOT NULL auto_increment PRIMARY KEY,
-- Foreign key to user.user_id
acd_user_id int unsigned NOT NULL,
-- Optional 'real name' to be displayed in credit listings
acd_real_name varchar(255) binary NOT NULL default '',
-- Note: email should be restricted, not public info.
-- Same with passwords.
acd_email tinytext NOT NULL,
-- Initially NULL; when a user's e-mail address has been
-- validated by returning with a mailed token, this is
-- set to the current timestamp.
acd_email_authenticated varbinary(14) default NULL,
-- A little about this user
acd_bio mediumblob NOT NULL,
-- Private info for reviewers to look at when considering request
acd_notes mediumblob NOT NULL,
-- Links to recognize/identify this user, CSV, may not be public
acd_urls mediumblob NOT NULL,
-- IP address
acd_ip VARCHAR(255) NULL default '',
-- Name of attached file (.pdf,.doc,.txt etc...)
acd_filename VARCHAR(255) NULL,
acd_storage_key VARCHAR(64) NULL,
-- Areas of interest
acd_areas mediumblob NOT NULL,
-- Timestamp of account registration.
acd_registration varbinary(14) NOT NULL,
-- Timestamp of acceptance
acd_accepted varbinary(14),
-- The user who accepted it
acd_user int unsigned NOT NULL default 0,
-- Reason given in email
acd_comment varchar(255) NOT NULL default ''
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/acd_user_id ON /*_*/account_credentials (acd_user_id,acd_id);

View file

@ -0,0 +1,9 @@
-- (c) Aaron Schulz, 2007
ALTER TABLE /*$wgDBprefix*/account_requests
ADD acr_xff VARCHAR(255) NULL default '',
ADD acr_agent VARCHAR(255) NULL default '';
ALTER TABLE /*$wgDBprefix*/account_credentials
ADD acd_xff VARCHAR(255) NULL default '',
ADD acd_agent VARCHAR(255) NULL default '';

View file

@ -0,0 +1,7 @@
-- (c) Aaron Schulz, 2007
ALTER TABLE /*$wgDBprefix*/account_requests
ADD acr_areas mediumblob NOT NULL;
ALTER TABLE /*$wgDBprefix*/account_credentials
ADD acd_areas mediumblob NOT NULL;

View file

@ -0,0 +1,7 @@
-- (c) Aaron Schulz, 2007
ALTER TABLE /*$wgDBprefix*/account_requests
ADD acr_filename VARCHAR(255) NULL,
ADD acr_storage_key VARCHAR(64) NULL,
ADD acr_held binary(14),
ADD acr_comment VARCHAR(255) NULL;

View file

@ -0,0 +1,4 @@
-- (c) Aaron Schulz, 2007
ALTER TABLE /*$wgDBprefix*/account_requests
ADD UNIQUE INDEX acr_email(acr_email(255));

View file

@ -0,0 +1,62 @@
-- (c) Aaron Schulz, 2007
-- Postgres schema for Confirm Account extension
BEGIN;
CREATE SEQUENCE account_requests_acr_id_seq;
CREATE TABLE account_requests (
acr_id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('account_requests_acr_id_seq'),
acr_name TEXT NOT NULL UNIQUE,
acr_real_name TEXT,
acr_email TEXT,
acr_email_token CHAR(32),
acr_email_token_expires TIMESTAMPTZ,
acr_email_authenticated TIMESTAMPTZ,
acr_registration TIMESTAMPTZ,
acr_bio TEXT,
acr_notes TEXT,
acr_urls TEXT,
acr_ip CIDR,
acr_xff TEXT,
acr_agent TEXT,
acr_filename TEXT,
acr_storage_key TEXT,
acr_type INTEGER NOT NULL DEFAULT 0,
acr_areas TEXT,
acr_deleted BOOL NOT NULL DEFAULT 'false',
acr_rejected TIMESTAMPTZ,
acr_held TIMESTAMPTZ,
acr_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
acr_comment TEXT NOT NULL DEFAULT ''
);
CREATE INDEX acr_type_del_reg ON account_requests (acr_type,acr_deleted,acr_registration);
CREATE INDEX acr_email_token ON account_requests (acr_email_token);
CREATE UNIQUE INDEX acr_email ON account_requests (acr_email);
CREATE SEQUENCE account_credentials_acd_id_seq;
CREATE TABLE account_credentials (
acd_id INTEGER NOT NULL DEFAULT nextval('account_credentials_acd_id_seq'),
acd_user_id INTEGER,
acd_real_name TEXT,
acd_email TEXT,
acd_email_authenticated TIMESTAMPTZ,
acd_registration TIMESTAMPTZ,
acd_bio TEXT,
acd_notes TEXT,
acd_urls TEXT,
acd_ip CIDR,
acd_xff TEXT,
acd_agent TEXT,
acd_filename TEXT,
acd_storage_key TEXT,
acd_areas TEXT,
acd_accepted TIMESTAMPTZ,
acd_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
acd_comment TEXT NOT NULL DEFAULT '',
PRIMARY KEY (acd_id, acd_user_id)
);
CREATE UNIQUE INDEX acd_id_index ON account_credentials (acd_id);
COMMIT;

View file

@ -0,0 +1,28 @@
-- (c) Aaron Schulz, 2007
BEGIN;
CREATE SEQUENCE account_credentials_acd_id_seq;
CREATE TABLE account_credentials (
acd_id INTEGER NOT NULL DEFAULT nextval('account_credentials_acd_id_seq'),
acd_user_id INTEGER,
acd_real_name TEXT,
acd_email TEXT,
acd_email_authenticated TIMESTAMPTZ,
acd_registration TIMESTAMPTZ,
acd_bio TEXT,
acd_notes TEXT,
acd_urls TEXT,
acd_ip CIDR,
acd_filename TEXT,
acd_storage_key TEXT,
acd_areas TEXT,
acd_accepted TIMESTAMPTZ,
acd_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL,
acd_comment TEXT NOT NULL DEFAULT '',
PRIMARY KEY (acd_id, acd_user_id)
);
CREATE UNIQUE INDEX acd_id_index ON account_credentials (acd_id);
COMMIT;

View file

@ -0,0 +1,11 @@
BEGIN;
ALTER TABLE account_requests
ADD acr_xff TEXT,
ADD acr_agent TEXT;
ALTER TABLE account_credentials
ADD acd_xff TEXT,
ADD acd_agent TEXT;
COMMIT;

View file

@ -0,0 +1,5 @@
BEGIN;
CREATE UNIQUE INDEX acr_email ON account_requests (acr_email);
COMMIT;

View file

@ -0,0 +1,450 @@
<?php
class AccountConfirmSubmission {
/* User making the confirmation */
protected $admin;
/** @var UserAccountRequest */
protected $accReq;
/* Admin-overridable name and fields filled from request form */
protected $userName;
protected $bio;
protected $type;
/** @var array */
protected $areas;
protected $action;
protected $reason;
public function __construct( User $admin, UserAccountRequest $accReq, array $params ) {
$this->admin = $admin;
$this->accountReq = $accReq;
$this->userName = trim( $params['userName'] );
$this->bio = trim( $params['bio'] );
$this->type = $params['type'];
$this->areas = $params['areas'];
$this->action = $params['action'];
$this->reason = $params['reason'];
}
/**
* Attempt to validate and submit this data to the DB
* @param $context IContextSource
* @return array( true or error key string, html error msg or null )
*/
public function submit( IContextSource $context ) {
# Make sure that basic permissions are checked
if ( !$this->admin->getID() || !$this->admin->isAllowed( 'confirmaccount' ) ) {
return array( 'accountconf_permission_denied', $context->msg( 'badaccess-group0' )->escaped() );
} elseif ( wfReadOnly() ) {
return array( 'accountconf_readonly', $context->msg( 'badaccess-group0' )->escaped() );
}
if ( $this->action === 'spam' ) {
return $this->spamRequest( $context );
} elseif ( $this->action === 'reject' ) {
return $this->rejectRequest( $context );
} elseif ( $this->action === 'hold' ) {
return $this->holdRequest( $context );
} elseif ( $this->action === 'accept' ) {
return $this->acceptRequest( $context );
} else {
return array( 'accountconf_bad_action', $context->msg( 'confirmaccount-badaction' )->escaped() );
}
}
protected function spamRequest( IContextSource $context ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
$ok = $this->accountReq->markRejected( $this->admin, wfTimestampNow(), '' );
if ( $ok ) {
# Clear cache for notice of how many account requests there are
ConfirmAccount::clearAccountRequestCountCache();
}
$dbw->commit();
return array( true, null );
}
protected function rejectRequest( IContextSource $context ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
$ok = $this->accountReq->markRejected( $this->admin, wfTimestampNow(), $this->reason );
if ( $ok ) {
/*
# Make proxy user to email a rejection message :(
$u = User::newFromName( $this->accountReq->getName(), false );
$u->setEmail( $this->accountReq->getEmail() );
# Send out a rejection email...
if ( $this->reason != '' ) {
$emailBody = $context->msg( 'confirmaccount-email-body4',
$u->getName(), $this->reason )->inContentLanguage()->text();
} else {
$emailBody = $context->msg( 'confirmaccount-email-body3',
$u->getName() )->inContentLanguage()->text();
}
$result = $u->sendMail(
$context->msg( 'confirmaccount-email-subj' )->inContentLanguage()->text(),
$emailBody
);
if ( !$result->isOk() ) {
$dbw->rollback();
return array( 'accountconf_mailerror',
$context->msg( 'mailerror' )->rawParams( $context->getOutput()->parse( $result->getWikiText() ) )->text() );
}
# Clear cache for notice of how many account requests there are
*/
ConfirmAccount::clearAccountRequestCountCache();
}
$dbw->commit();
return array( true, null );
}
protected function holdRequest( IContextSource $context ) {
# Make proxy user to email a message
$u = User::newFromName( $this->accountReq->getName(), false );
$u->setEmail( $this->accountReq->getEmail() );
# Pointless without a summary...
if ( $this->reason == '' ) {
return array( 'accountconf_needreason', $context->msg( 'confirmaccount-needreason' )->escaped() );
}
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
# If not already held or deleted, mark as held
$ok = $this->accountReq->markHeld( $this->admin, wfTimestampNow(), $this->reason );
if ( !$ok ) { // already held or deleted?
$dbw->rollback();
return array( 'accountconf_canthold', $context->msg( 'confirmaccount-canthold' )->escaped() );
}
# Send out a request hold email...
$result = $u->sendMail(
$context->msg( 'confirmaccount-email-subj' )->inContentLanguage()->text(),
$context->msg( 'confirmaccount-email-body5', $u->getName(), $this->reason )->inContentLanguage()->text()
);
if ( !$result->isOk() ) {
$dbw->rollback();
return array( 'accountconf_mailerror',
$context->msg( 'mailerror' )->rawParams( $context->getOutput()->parse( $result->getWikiText() ) )->text() );
}
# Clear cache for notice of how many account requests there are
ConfirmAccount::clearAccountRequestCountCache();
$dbw->commit();
return array( true, null );
}
protected function acceptRequest( IContextSource $context ) {
global $wgAuth, $wgAccountRequestTypes, $wgConfirmAccountSaveInfo;
global $wgConfirmAccountRequestFormItems, $wgConfirmAccountFSRepos;
$formConfig = $wgConfirmAccountRequestFormItems; // convience
$accReq = $this->accountReq; // convenience
# Now create user and check if the name is valid
$user = User::newFromName( $this->userName, 'creatable' );
if ( !$user ) {
return array( 'accountconf_invalid_name', $context->msg( 'noname' )->escaped() );
}
# Check if account name is already in use
if ( 0 != $user->idForName() || $wgAuth->userExists( $user->getName() ) ) {
return array( 'accountconf_user_exists', $context->msg( 'userexists' )->escaped() );
}
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
# Make a random password
$p = md5(strtolower($this->userName));
# Insert the new user into the DB...
$tokenExpires = $accReq->getEmailTokenExpires();
$authenticated = $accReq->getEmailAuthTimestamp();
$params = array(
# Set the user's real name
'real_name' => $accReq->getRealName(),
# Set the temporary password
'newpassword' => User::crypt( $p ),
# VERY important to set email now. Otherwise the user
# will have to request a new password at the login screen...
'email' => $accReq->getEmail(),
# Import email address confirmation status
'email_authenticated' => $dbw->timestampOrNull( $authenticated ),
'email_token_expires' => $dbw->timestamp( $tokenExpires ),
'email_token' => $accReq->getEmailToken()
);
$user = User::createNew( $user->getName(), $params );
# Grant any necessary rights (exclude blank or dummy groups)
$group = self::getGroupFromType( $this->type );
if ( $group != '' && $group != 'user' && $group != '*' ) {
$user->addGroup( $group );
}
$acd_id = null; // used for rollback cleanup
# Save account request data to credentials system
if ( $wgConfirmAccountSaveInfo ) {
$key = $accReq->getFileStorageKey();
# Copy any attached files to new storage group
if ( $formConfig['CV']['enabled'] && $key ) {
$repoOld = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
$repoNew = new FSRepo( $wgConfirmAccountFSRepos['accountcreds'] );
$pathRel = UserAccountRequest::relPathFromKey( $key );
$oldPath = $repoOld->getZonePath( 'public' ) . '/' . $pathRel;
$triplet = array( $oldPath, 'public', $pathRel );
$status = $repoNew->storeBatch( array( $triplet ) ); // copy!
if ( !$status->isOK() ) {
$dbw->rollback();
# DELETE new rows in case there was a COMMIT somewhere
$this->acceptRequest_rollback( $dbw, $user->getId(), $acd_id );
return array( 'accountconf_copyfailed',
$context->getOutput()->parse( $status->getWikiText() ) );
}
}
$acd_id = $dbw->nextSequenceValue( 'account_credentials_acd_id_seq' );
# Move request data into a separate table
$dbw->insert( 'account_credentials',
array(
'acd_user_id' => $user->getID(),
'acd_real_name' => $accReq->getRealName(),
'acd_email' => $accReq->getEmail(),
'acd_email_authenticated' => $dbw->timestampOrNull( $authenticated ),
'acd_bio' => $accReq->getBio(),
'acd_notes' => $accReq->getNotes(),
'acd_urls' => $accReq->getUrls(),
'acd_ip' => $accReq->getIP(),
'acd_xff' => $accReq->getXFF(),
'acd_agent' => $accReq->getAgent(),
'acd_filename' => $accReq->getFileName(),
'acd_storage_key' => $accReq->getFileStorageKey(),
'acd_areas' => $accReq->getAreas( 'flat' ),
'acd_registration' => $dbw->timestamp( $accReq->getRegistration() ),
'acd_accepted' => $dbw->timestamp(),
'acd_user' => $this->admin->getID(),
'acd_comment' => $this->reason,
'acd_id' => $acd_id
),
__METHOD__
);
if ( is_null( $acd_id ) ) {
$acd_id = $dbw->insertId(); // set $acd_id to ID inserted
}
}
# Add to global user login system (if there is one)
if ( !$wgAuth->addUser( $user, $p, $accReq->getEmail(), $accReq->getRealName() ) ) {
$dbw->rollback();
# DELETE new rows in case there was a COMMIT somewhere
$this->acceptRequest_rollback( $dbw, $user->getId(), $acd_id );
return array( 'accountconf_externaldberror', $context->msg( 'externaldberror' )->escaped() );
}
# OK, now remove the request from the queue
$accReq->remove();
# Commit this if we make past the CentralAuth system
# and the groups are added. Next step is sending out an
# email, which we cannot take back...
$dbw->commit();
# Prepare a temporary password email...
if ( $this->reason != '' ) {
$msg = "confirmaccount-email-body2-pos{$this->type}";
# If the user is in a group and there is a welcome for that group, use it
if ( $group && !wfEmptyMsg( $msg ) ) {
$ebody = $context->msg( $msg, $user->getName(), $p, $this->reason )->inContentLanguage()->text();
# Use standard if none found...
} else {
$ebody = $context->msg( 'confirmaccount-email-body2',
$user->getName(), $p, $this->reason )->inContentLanguage()->text();
}
} else {
$msg = "confirmaccount-email-body-pos{$this->type}";
# If the user is in a group and there is a welcome for that group, use it
if ( $group && !$context->msg( $msg )->isDisabled() ) {
$ebody = $context->msg( $msg,
$user->getName(), $p, $this->reason )->inContentLanguage()->text();
# Use standard if none found...
} else {
$ebody = $context->msg( 'confirmaccount-email-body',
$user->getName(), $p, $this->reason )->inContentLanguage()->text();
}
}
# Actually send out the email (@TODO: rollback on failure including $wgAuth)
$result = $user->sendMail(
$context->msg( 'confirmaccount-email-subj' )->inContentLanguage()->text(),
$ebody
);
# Update user count
$ssUpdate = new SiteStatsUpdate( 0, 0, 0, 0, 1 );
$ssUpdate->doUpdate();
# Safe to hook/log now...
wfRunHooks( 'AddNewAccount', array( $user, false /* not by email */ ) );
$user->addNewUserLogEntry();
# Clear cache for notice of how many account requests there are
ConfirmAccount::clearAccountRequestCountCache();
# Delete any attached file and don't stop the whole process if this fails
if ( $formConfig['CV']['enabled'] ) {
$key = $accReq->getFileStorageKey();
if ( $key ) {
$repoOld = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
$pathRel = UserAccountRequest::relPathFromKey( $key );
$oldPath = $repoOld->getZonePath( 'public' ) . '/' . $pathRel;
if ( file_exists( $oldPath ) ) {
unlink( $oldPath ); // delete!
}
}
}
# Start up the user's userpages if set to do so.
# Will not append, so previous content will be blanked.
$this->createUserPage( $user );
# Greet the new user if set to do so.
$this->createUserTalkPage( $user );
return array( true, null );
}
/*
* Rollback an account acceptance *before* the request row and attachment are deleted.
* This is mostly here for sanity in case of COMMITs triggered elsewhere.
* http://bugs.mysql.com/bug.php?id=30767 behavoir assumed.
* @param $dbw Database
* @param $user_id int
* @param $acd_id int
* @return void
*/
protected function acceptRequest_rollback( DatabaseBase $dbw, $user_id, $acd_id ) {
$dbw->begin();
# DELETE the user in case something caused a COMMIT already somewhere.
if ( $user_id ) {
$dbw->delete( 'user', array( 'user_id' => $user_id ), __METHOD__ );
$dbw->delete( 'user_groups', array( 'ug_user' => $user_id ), __METHOD__ );
}
# DELETE the new account_credentials row likewise.
if ( $acd_id ) {
$dbw->delete( 'account_credentials', array( 'acd_id' => $acd_id ), __METHOD__ );
}
$dbw->commit();
}
protected static function getGroupFromType( $type ) {
global $wgAccountRequestTypes;
$group = '';
// Format is (type => (subpage par, group key, group text))
if ( isset( $wgAccountRequestTypes[$type][1] ) ) {
$group = $wgAccountRequestTypes[$type][1];
}
return $group;
}
protected static function getAutoTextFromType( $type ) {
global $wgAccountRequestTypes;
$groupText = '';
// Format is (type => (subpage par, group key, group text))
if ( isset( $wgAccountRequestTypes[$type][2] ) ) {
$groupText = $wgAccountRequestTypes[$type][2];
}
return $groupText;
}
protected function createUserPage( User $user ) {
global $wgMakeUserPageFromBio, $wgAutoUserBioText;
global $wgConfirmAccountSortkey, $wgContLang;
$body = ''; // page text
if ( $wgMakeUserPageFromBio ) {
# Add account request bio to userpage
$body .= $this->bio;
# Add any automatic text for all confirmed accounts
if ( $wgAutoUserBioText != '' ) {
$body .= "\n\n{$wgAutoUserBioText}";
}
}
# Add any automatic text for confirmed accounts of this type
$autoText = self::getAutoTextFromType( $this->type );
if ( $autoText != '' ) {
$body .= "\n\n{$autoText}";
}
# Add any areas of interest categories...
foreach ( ConfirmAccount::getUserAreaConfig() as $name => $conf ) {
if ( in_array( $name, $this->areas ) ) {
# General userpage text for anyone with this interest
if ( $conf['userText'] != '' ) {
$body .= $conf['userText'];
}
# Message for users with this interested with the given account type
if ( isset( $conf['grpUserText'][$this->type] )
&& $conf['grpUserText'][$this->type] != '' )
{
$body .= $conf['grpUserText'];
}
}
}
# Set sortkey and use it on userpage. This can be used to
# normalize things like firstname, lastname and so fourth.
if ( !empty( $wgConfirmAccountSortkey ) ) {
$sortKey = preg_replace(
$wgConfirmAccountSortkey[0],
$wgConfirmAccountSortkey[1],
$user->getUserPage()->getText()
);
$body .= "\n{{DEFAULTSORT:{$sortKey}}}";
# Clean up any other categories...
$catNS = $wgContLang->getNSText( NS_CATEGORY );
$replace = '/\[\[' . preg_quote( $catNS ) . ':([^\]]+)\]\]/i'; // [[Category:x]]
$with = "[[{$catNS}:$1|" . str_replace( '$', '\$', $sortKey ) . "]]"; // [[Category:x|sortkey]]
$body = preg_replace( $replace, $with, $body );
}
# Create userpage!
$article = new WikiPage( $user->getUserPage() );
$article->doEdit(
$body,
wfMessage( 'confirmaccount-summary' )->inContentLanguage()->text(),
EDIT_MINOR
);
}
protected function createUserTalkPage( User $user ) {
global $wgAutoWelcomeNewUsers;
if ( $wgAutoWelcomeNewUsers ) {
$msg = "confirmaccount-welc-pos{$this->type}";
$welcome = wfEmptyMsg( $msg )
? wfMessage( 'confirmaccount-welc' )->text()
: wfMessage( $msg )->text(); // custom message
# Add user welcome message!
$article = new WikiPage( $user->getTalkPage() );
$article->doEdit(
"{$welcome} ~~~~",
wfMessage( 'confirmaccount-wsum' )->inContentLanguage()->text(),
EDIT_MINOR,
false,
$this->admin
);
}
}
}

View file

@ -0,0 +1,297 @@
<?php
class AccountRequestSubmission {
/* User making the request */
protected $requester;
/* Desired name and fields filled from form */
protected $userName;
protected $realName;
protected $tosAccepted;
protected $email;
protected $bio;
protected $notes;
protected $urls;
protected $type;
/** @var array */
protected $areas;
protected $registration;
protected $ip;
protected $xff;
protected $agent;
/* File attachment fields */
protected $attachmentSrcName; // user given attachment base name
protected $attachmentPrevName; // user given attachment base name last attempt
protected $attachmentDidNotForget; // user already saw "please re-attach" notice
protected $attachmentSize; // bytes size of file
protected $attachmentTempPath; // tmp path file was uploaded to FS
public function __construct( User $requester, array $params ) {
$this->requester = $requester;
$this->userName = trim( $params['userName'] );
$this->realName = trim( $params['realName'] );
$this->tosAccepted = $params['tosAccepted'];
$this->email = $params['email'];
$this->bio = trim( $params['bio'] );
$this->notes = trim( $params['notes'] );
$this->urls = trim( $params['urls'] );
$this->type = $params['type'];
$this->areas = $params['areas'];
$this->ip = $params['ip'];
$this->xff = $params['xff'];
$this->agent = $params['agent'];
$this->registration = wfTimestamp( TS_MW, $params['registration'] );
$this->attachmentPrevName = $params['attachmentPrevName'];
$this->attachmentSrcName = $params['attachmentSrcName'];
$this->attachmentDidNotForget = $params['attachmentDidNotForget'];
$this->attachmentSize = $params['attachmentSize'];
$this->attachmentTempPath = $params['attachmentTempPath'];
}
/**
* @return string
*/
public function getAttachmentDidNotForget() {
return $this->attachmentDidNotForget;
}
/**
* @return string
*/
public function getAttachtmentPrevName() {
return $this->attachmentPrevName;
}
/**
* Attempt to validate and submit this data to the DB
* @param $context IContextSource
* @return array( true or error key string, html error msg or null )
*/
public function submit( IContextSource $context ) {
global $wgAuth, $wgAccountRequestThrottle, $wgMemc, $wgContLang;
global $wgConfirmAccountRequestFormItems;
$formConfig = $wgConfirmAccountRequestFormItems; // convience
$reqUser = $this->requester;
# Make sure that basic permissions are checked
$block = ConfirmAccount::getAccountRequestBlock( $reqUser );
if ( $block ) {
return array(
'accountreq_permission_denied',
$context->msg( 'badaccess-group0' )->escaped()
);
} elseif ( wfReadOnly() ) {
return array( 'accountreq_readonly', $context->msg( 'badaccess-group0' )->escaped() );
}
# Now create a dummy user ($u) and check if it is valid
if ( $this->userName === '' ) {
return array( 'accountreq_no_name', $context->msg( 'noname' )->escaped() );
}
//before we continue, verify user
$code = sha1($_SERVER['REMOTE_ADDR'] . date('m'));
$data = file_get_contents('http://scratch.mit.edu/site-api/comments/project/10135908/?page=1&salt=' . md5(time())); //add the salt so it doesn't cache
if (!$data) {
return array('api_failed', 'Accessing the API to verify your registration failed. Please try again later.');
return;
}
$success = false;
preg_match_all('%<div id="comments-\d+" class="comment.*?" data-comment-id="\d+">.*?<a href="/users/(.*?)">.*?<div class="content">(.*?)</div>%ms', $data, $matches);
foreach ($matches[2] as $key => $val) {
$user = $matches[1][$key];
$comment = trim($val);
if ($user == $this->userName && $comment == $code) {
$success = true;
break;
}
}
if (!$success) {
return array('no_comment', 'It does not appear you commented the verification code on the specified project. Please try again.');
}
$u = User::newFromName( $this->userName, 'creatable' );
if ( !$u ) {
return array( 'accountreq_invalid_name', $context->msg( 'noname' )->escaped() );
}
# No request spamming...
if ( $wgAccountRequestThrottle && $reqUser->isPingLimitable() ) {
$key = wfMemcKey( 'acctrequest', 'ip', $this->ip );
$value = (int)$wgMemc->get( $key );
if ( $value > $wgAccountRequestThrottle ) {
return array(
'accountreq_throttled',
$context->msg( 'acct_request_throttle_hit', $wgAccountRequestThrottle )->text()
);
}
}
# Make sure user agrees to policy here
if ( $formConfig['TermsOfService']['enabled'] && !$this->tosAccepted ) {
return array(
'acct_request_skipped_tos',
$context->msg( 'requestaccount-agree' )->escaped()
);
}
# Validate email address
/*if ( !Sanitizer::validateEmail( $this->email ) ) {
return array(
'acct_request_invalid_email',
$context->msg( 'invalidemailaddress' )->escaped()
);
}*/
# Check if biography is long enough
/*if ( $formConfig['Biography']['enabled']
&& str_word_count( $this->bio ) < $formConfig['Biography']['minWords'] )
{
$minWords = $formConfig['Biography']['minWords'];
return array(
'acct_request_short_bio',
$context->msg( 'requestaccount-tooshort' )->numParams( $minWords )->text()
);
}*/
# Per security reasons, file dir cannot be pulled from client,
# so ask them to resubmit it then...
# If the extra fields are off, then uploads are off
$allowFiles = $formConfig['CV']['enabled'];
if ( $allowFiles && $this->attachmentPrevName && !$this->attachmentSrcName ) {
# If the user is submitting forgotAttachment as true with no file,
# then they saw the notice and choose not to re-select the file.
# Assume that they don't want to send one anymore.
if ( !$this->attachmentDidNotForget ) {
$this->attachmentPrevName = '';
$this->attachmentDidNotForget = 0;
return array( false, $context->msg( 'requestaccount-resub' )->escaped() );
}
}
# Check if already in use
if ( 0 != $u->idForName() || $wgAuth->userExists( $u->getName() ) ) {
return array(
'accountreq_username_exists',
$context->msg( 'userexists' )->escaped()
);
}
# Set email and real name
//$u->setEmail( $this->email );
//$u->setRealName( $this->realName );
$dbw = wfGetDB( DB_MASTER );
$dbw->begin(); // ready to acquire locks
# Check pending accounts for name use
if ( !UserAccountRequest::acquireUsername( $u->getName() ) ) {
$dbw->rollback();
return array(
'accountreq_username_pending',
$context->msg( 'requestaccount-inuse' )->escaped()
);
}
# Check if someone else has an account request with the same email
/*if ( !UserAccountRequest::acquireEmail( $u->getEmail() ) ) {
$dbw->rollback();
return array(
'acct_request_email_exists',
$context->msg( 'requestaccount-emaildup' )->escaped()
);
}*/
# Process upload...
if ( $allowFiles && $this->attachmentSrcName ) {
global $wgAccountRequestExts, $wgConfirmAccountFSRepos;
$ext = explode( '.', $this->attachmentSrcName );
$finalExt = $ext[count( $ext ) - 1];
# File must have size.
if ( trim( $this->attachmentSrcName ) == '' || empty( $this->attachmentSize ) ) {
$this->attachmentPrevName = '';
$dbw->rollback();
return array( 'acct_request_empty_file', $context->msg( 'emptyfile' )->escaped() );
}
# Look at the contents of the file; if we can recognize the
# type but it's corrupt or data of the wrong type, we should
# probably not accept it.
if ( !in_array( $finalExt, $wgAccountRequestExts ) ) {
$this->attachmentPrevName = '';
$dbw->rollback();
return array(
'acct_request_bad_file_ext',
$context->msg( 'requestaccount-exts' )->escaped()
);
}
$veri = ConfirmAccount::verifyAttachment( $this->attachmentTempPath, $finalExt );
if ( !$veri->isGood() ) {
$this->attachmentPrevName = '';
$dbw->rollback();
return array(
'acct_request_corrupt_file',
$context->msg( 'verification-error' )->escaped()
);
}
# Start a transaction, move file from temp to account request directory.
$repo = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
$key = sha1_file( $this->attachmentTempPath ) . '.' . $finalExt;
$pathRel = UserAccountRequest::relPathFromKey( $key );
$triplet = array( $this->attachmentTempPath, 'public', $pathRel );
$status = $repo->storeBatch( array( $triplet ), FSRepo::OVERWRITE_SAME ); // save!
if ( !$status->isOk() ) {
$dbw->rollback();
return array( 'acct_request_file_store_error',
$context->msg( 'filecopyerror', $this->attachmentTempPath, $pathRel )->escaped() );
}
}
$expires = null; // passed by reference
$token = ConfirmAccount::getConfirmationToken( $u, $expires );
# Insert into pending requests...
$req = UserAccountRequest::newFromArray( array(
'name' => $u->getName(),
'email' => rand(1,10000000) . '@' . rand(1, 10000000) . '.com',
'real_name' => $u->getRealName(),
'registration' => $this->registration,
'bio' => $this->bio,
'notes' => $this->notes,
'urls' => $this->urls,
'filename' => isset( $this->attachmentSrcName )
? $this->attachmentSrcName
: null,
'type' => $this->type,
'areas' => $this->areas,
'storage_key' => isset( $key ) ? $key : null,
'comment' => '',
'email_token' => md5( $token ),
'email_token_expires' => $expires,
'ip' => $this->ip,
'xff' => $this->xff,
'agent' => $this->agent
) );
$req->insertOn();
# Send confirmation, required!
/*$result = ConfirmAccount::sendConfirmationMail( $u, $this->ip, $token, $expires );
if ( !$result->isOK() ) {
$dbw->rollback(); // nevermind
if ( isset( $repo ) && isset( $pathRel ) ) { // remove attachment
$repo->cleanupBatch( array( array( 'public', $pathRel ) ) );
}
$param = $context->getOutput()->parse( $result->getWikiText() );
return array(
'acct_request_mail_failed',
$context->msg( 'mailerror' )->rawParams( $param )->escaped() );
}
$dbw->commit();*/
# Clear cache for notice of how many account requests there are
ConfirmAccount::clearAccountRequestCountCache();
# No request spamming...
if ( $wgAccountRequestThrottle && $reqUser->isPingLimitable() ) {
$ip = $context->getRequest()->getIP();
$key = wfMemcKey( 'acctrequest', 'ip', $ip );
$value = $wgMemc->incr( $key );
if ( !$value ) {
$wgMemc->set( $key, 1, 86400 );
}
}
# Done!
return array( true, null );
}
}

View file

@ -0,0 +1,99 @@
<?php
/**
* Class containing hooked functions for a ConfirmAccount environment
*/
class ConfirmAccountUIHooks {
/**
* @param $template
* @return bool
*/
public static function addRequestLoginText( &$template ) {
$context = RequestContext::getMain();
# Add a link to RequestAccount from UserLogin
if ( !$context->getUser()->isAllowed( 'createaccount' ) ) {
$template->set( 'header', $context->msg( 'requestaccount-loginnotice' )->parseAsBlock() );
$context->getOutput()->addModules( 'ext.confirmAccount' ); // CSS
}
return true;
}
/**
* @param $personal_urls
* @param $title
* @return bool
*/
public static function setRequestLoginLinks( array &$personal_urls, &$title ) {
if ( isset( $personal_urls['anonlogin'] ) ) {
$personal_urls['anonlogin']['text'] = wfMessage( 'nav-login-createaccount' )->escaped();
} elseif ( isset( $personal_urls['login'] ) ) {
$personal_urls['login']['text'] = wfMessage( 'nav-login-createaccount' )->escaped();
}
return true;
}
/**
* @param $user User
* @param $abortError
* @return bool
*/
public static function checkIfAccountNameIsPending( User $user, &$abortError ) {
# If an account is made with name X, and one is pending with name X
# we will have problems if the pending one is later confirmed
if ( !UserAccountRequest::acquireUsername( $user->getName() ) ) {
$abortError = wfMessage( 'requestaccount-inuse' )->escaped();
return false;
}
return true;
}
/**
* Add "x email-confirmed open account requests" notice
* @param $notice
* @return bool
*/
public static function confirmAccountsNotice( OutputPage &$out, Skin &$skin ) {
global $wgConfirmAccountNotice;
$context = $out->getContext();
if ( !$wgConfirmAccountNotice || !$context->getUser()->isAllowed( 'confirmaccount' ) ) {
return true;
}
# Only show on some special pages
$title = $context->getTitle();
if ( !$title->isSpecial( 'Recentchanges' ) && !$title->isSpecial( 'Watchlist' ) ) {
return true;
}
$count = ConfirmAccount::getOpenEmailConfirmedCount( '*' );
if ( $count > 0 ) {
$out->prependHtml(
'<div id="mw-confirmaccount-msg" class="plainlinks mw-confirmaccount-bar">' .
$context->msg( 'confirmaccount-newrequests' )->numParams( $count )->parse() .
'</div>'
);
$out->addModules( 'ext.confirmAccount' ); // CSS
}
return true;
}
/**
* For AdminLinks extension
* @param $admin_links_tree
* @return bool
*/
public static function confirmAccountAdminLinks( &$admin_links_tree ) {
$users_section = $admin_links_tree->getSection( wfMessage( 'adminlinks_users' )->escaped() );
$extensions_row = $users_section->getRow( 'extensions' );
if ( is_null( $extensions_row ) ) {
$extensions_row = new ALRow( 'extensions' );
$users_section->addRow( $extensions_row );
}
$extensions_row->addItem( ALItem::newFromSpecialPage( 'ConfirmAccounts' ) );
$extensions_row->addItem( ALItem::newFromSpecialPage( 'UserCredentials' ) );
return true;
}
}

View file

@ -0,0 +1,52 @@
<?php
/**
* Class containing hooked functions for a ConfirmAccount environment
*/
class ConfirmAccountUISetup {
/**
* Register ConfirmAccount hooks.
* @param $hooks Array $wgHooks (assoc array of hooks and handlers)
* @return void
*/
public static function defineHookHandlers( array &$hooks ) {
# Make sure "login / create account" notice still as "create account"
$hooks['PersonalUrls'][] = 'ConfirmAccountUIHooks::setRequestLoginLinks';
# Add notice of where to request an account at UserLogin
$hooks['UserCreateForm'][] = 'ConfirmAccountUIHooks::addRequestLoginText';
$hooks['UserLoginForm'][] = 'ConfirmAccountUIHooks::addRequestLoginText';
# Status header like "new messages" bar
$hooks['BeforePageDisplay'][] = 'ConfirmAccountUIHooks::confirmAccountsNotice';
# Register admin pages for AdminLinks extension.
$hooks['AdminLinks'][] = 'ConfirmAccountUIHooks::confirmAccountAdminLinks';
}
/**
* Register ConfirmAccount special pages as needed.
* @param $pages Array $wgSpecialPages (list of special pages)
* @param $groups Array $wgSpecialPageGroups (assoc array of special page groups)
* @return void
*/
public static function defineSpecialPages( array &$pages, array &$groups ) {
$pages['RequestAccount'] = 'RequestAccountPage';
$groups['RequestAccount'] = 'login';
$pages['ConfirmAccounts'] = 'ConfirmAccountsPage';
$groups['ConfirmAccounts'] = 'users';
$pages['UserCredentials'] = 'UserCredentialsPage';
$groups['UserCredentials'] = 'users';
}
/**
* Append ConfirmAccount resource module definitions
* @param $modules Array $wgResourceModules
* @return void
*/
public static function defineResourceModules( array &$modules ) {
$modules['ext.confirmAccount'] = array(
'styles' => 'confirmaccount.css',
'localBasePath' => dirname( __FILE__ ) . '/modules',
'remoteExtPath' => 'ConfirmAccount/frontend/modules',
);
}
}

View file

@ -0,0 +1,400 @@
<?php
/**
* Aliases for extension ConfirmAccount
*
* @file
* @ingroup Extensions
*/
$specialPageAliases = array();
/** English (English) */
$specialPageAliases['en'] = array(
'RequestAccount' => array( 'RequestAccount' ),
'ConfirmAccounts' => array( 'ConfirmAccounts' ),
'UserCredentials' => array( 'UserCredentials' ),
);
/** Arabic (العربية) */
$specialPageAliases['ar'] = array(
'RequestAccount' => array( 'طلب_حساب' ),
'ConfirmAccounts' => array( 'تأكيد_الحساب' ),
'UserCredentials' => array( هادات_المستخدم' ),
);
/** Egyptian Spoken Arabic (مصرى) */
$specialPageAliases['arz'] = array(
'RequestAccount' => array( 'طلب_حساب' ),
'ConfirmAccounts' => array( 'تأكيد_الحساب' ),
'UserCredentials' => array( هادات_اليوزر' ),
);
/** Assamese (অসমীয়া) */
$specialPageAliases['as'] = array(
'RequestAccount' => array( 'একাউণ্ট_অনুৰোধ' ),
'ConfirmAccounts' => array( 'একাউণ্ট_নিশ্চিত_কৰক' ),
);
/** Bashkir (башҡортса) */
$specialPageAliases['ba'] = array(
'RequestAccount' => array( 'RequestAccount' ),
);
/** Banjar (Bahasa Banjar) */
$specialPageAliases['bjn'] = array(
'RequestAccount' => array( 'Minta_akun' ),
);
/** Breton (brezhoneg) */
$specialPageAliases['br'] = array(
'RequestAccount' => array( 'GoulennKont' ),
'ConfirmAccounts' => array( 'KadarnaatKont' ),
);
/** Bosnian (bosanski) */
$specialPageAliases['bs'] = array(
'RequestAccount' => array( 'ZahtjevajRacun' ),
'ConfirmAccounts' => array( 'PotvrdiRacun' ),
'UserCredentials' => array( 'KorisnickePotvrde' ),
);
/** German (Deutsch) */
$specialPageAliases['de'] = array(
'RequestAccount' => array( 'Benutzerkonto_beantragen' ),
'ConfirmAccounts' => array( 'Benutzerkonto_bestätigen' ),
'UserCredentials' => array( 'Benutzerangaben' ),
);
/** Zazaki (Zazaki) */
$specialPageAliases['diq'] = array(
'RequestAccount' => array( 'HesabWaştış' ),
'ConfirmAccounts' => array( 'HesabRaştkerdış' ),
'UserCredentials' => array( 'ReferansêKarberan' ),
);
/** Lower Sorbian (dolnoserbski) */
$specialPageAliases['dsb'] = array(
'RequestAccount' => array( 'Póžedanje_na_konto' ),
'ConfirmAccounts' => array( 'Konto_wobkšuśiś' ),
'UserCredentials' => array( 'Wužywarske_pódaśa' ),
);
/** Greek (Ελληνικά) */
$specialPageAliases['el'] = array(
'RequestAccount' => array( 'ΑίτησηΛογαριασμού' ),
'ConfirmAccounts' => array( 'ΕπιβεβαίωσηΛογαριασμού' ),
'UserCredentials' => array( 'ΣυστάσειςΧρήστη' ),
);
/** Esperanto (Esperanto) */
$specialPageAliases['eo'] = array(
'RequestAccount' => array( 'Peti_konton' ),
'ConfirmAccounts' => array( 'Konfirmi_konton' ),
'UserCredentials' => array( 'Datumoj_pri_uzantoj' ),
);
/** Spanish (español) */
$specialPageAliases['es'] = array(
'RequestAccount' => array( 'Pedir_cuenta_de_usuario', 'PedirCuentaUsuario' ),
'ConfirmAccounts' => array( 'Confirmar_cuentas' ),
'UserCredentials' => array( 'Credenciales' ),
);
/** Persian (فارسی) */
$specialPageAliases['fa'] = array(
'RequestAccount' => array( 'درخواست_حساب' ),
'ConfirmAccounts' => array( ایید_حسابها' ),
'UserCredentials' => array( 'شناسهاربری' ),
);
/** Finnish (suomi) */
$specialPageAliases['fi'] = array(
'RequestAccount' => array( 'Pyydä_käyttäjätunnusta' ),
'ConfirmAccounts' => array( 'Varmista_käyttäjätunnus' ),
);
/** French (français) */
$specialPageAliases['fr'] = array(
'RequestAccount' => array( 'Demander_un_compte', 'DemanderUnCompte' ),
'ConfirmAccounts' => array( 'ConfirmerCompte', 'Confirmation_compte', 'ConfirmationCompte' ),
);
/** Franco-Provençal (arpetan) */
$specialPageAliases['frp'] = array(
'RequestAccount' => array( 'Demandar_un_compto', 'DemandarUnCompto' ),
'ConfirmAccounts' => array( 'Confirmar_lo_compto', 'ConfirmarLoCompto', 'Confirmacion_de_compto', 'ConfirmacionDeCompto' ),
'UserCredentials' => array( 'Refèrences_a_l\'usanciér', 'RefèrencesALUsanciér' ),
);
/** Galician (galego) */
$specialPageAliases['gl'] = array(
'RequestAccount' => array( 'Solicitar_unha_conta' ),
'ConfirmAccounts' => array( 'Confirmar_a_conta' ),
'UserCredentials' => array( 'Credenciais_de_usuario' ),
);
/** Swiss German (Alemannisch) */
$specialPageAliases['gsw'] = array(
'RequestAccount' => array( 'Aatrag_stelle_fir_e_Benutzerchonto' ),
'ConfirmAccounts' => array( 'Benutzerchonto_bstetige' ),
);
/** Hebrew (עברית) */
$specialPageAliases['he'] = array(
'RequestAccount' => array( 'בקשת_חשבון' ),
'ConfirmAccounts' => array( ישור_חשבונות' ),
'UserCredentials' => array( 'פרטי_משתמש' ),
);
/** Croatian (hrvatski) */
$specialPageAliases['hr'] = array(
'RequestAccount' => array( 'Zatraži_račun' ),
'ConfirmAccounts' => array( 'Potvrdi_račun' ),
'UserCredentials' => array( 'Suradničke_vjerodajnice' ),
);
/** Upper Sorbian (hornjoserbsce) */
$specialPageAliases['hsb'] = array(
'RequestAccount' => array( 'Konto_požadać' ),
'ConfirmAccounts' => array( 'Konto_potwjerdźić' ),
'UserCredentials' => array( 'Wužywarske_podaća' ),
);
/** Haitian (Kreyòl ayisyen) */
$specialPageAliases['ht'] = array(
'RequestAccount' => array( 'MandKont' ),
'ConfirmAccounts' => array( 'KonfimeKont' ),
'UserCredentials' => array( 'DwaItilizatèYo' ),
);
/** Hungarian (magyar) */
$specialPageAliases['hu'] = array(
'RequestAccount' => array( 'Felhasználói_fiók_igénylése' ),
'ConfirmAccounts' => array( 'Felhasználói_fiók_megerősítése' ),
'UserCredentials' => array( 'Felhasználói_ajánlólevél' ),
);
/** Interlingua (interlingua) */
$specialPageAliases['ia'] = array(
'RequestAccount' => array( 'Requestar_conto' ),
'ConfirmAccounts' => array( 'Confirmar_contos' ),
'UserCredentials' => array( 'Referentias_del_usator' ),
);
/** Indonesian (Bahasa Indonesia) */
$specialPageAliases['id'] = array(
'RequestAccount' => array( 'Minta_akun', 'MintaAkun' ),
'ConfirmAccounts' => array( 'Konfirmasi_akun', 'KonfirmasiAkun' ),
'UserCredentials' => array( 'Kredensial_pengguna', 'KredensialPengguna' ),
);
/** Italian (italiano) */
$specialPageAliases['it'] = array(
'UserCredentials' => array( 'CredenzialiUtente' ),
);
/** Japanese (日本語) */
$specialPageAliases['ja'] = array(
'RequestAccount' => array( 'アカウント申請', 'アカウント登録申請' ),
'ConfirmAccounts' => array( 'アカウント承認', 'アカウントの承認', 'アカウント申請の承認', 'アカウント登録申請の承認' ),
'UserCredentials' => array( '利用者信頼情報' ),
);
/** Georgian (ქართული) */
$specialPageAliases['ka'] = array(
'ConfirmAccounts' => array( 'ანგარიშის_დადასტურება' ),
);
/** Khmer (ភាសាខ្មែរ) */
$specialPageAliases['km'] = array(
'RequestAccount' => array( 'ស្នើសុំគណនី' ),
'ConfirmAccounts' => array( 'បញ្ជាក់ទទួលស្គាល់គណនី' ),
);
/** Korean (한국어) */
$specialPageAliases['ko'] = array(
'RequestAccount' => array( '계정요청' ),
'ConfirmAccounts' => array( '계정인증', '계정승인' ),
'UserCredentials' => array( '계정자격증명' ),
);
/** Colognian (Ripoarisch) */
$specialPageAliases['ksh'] = array(
'RequestAccount' => array( 'Metmaacherzohjang_beaandraare' ),
'ConfirmAccounts' => array( 'Metmaacherzohjang_beshtätejje' ),
'UserCredentials' => array( 'Metmaache-Aanjabe' ),
);
/** Ladino (Ladino) */
$specialPageAliases['lad'] = array(
'RequestAccount' => array( 'Demandar_cuento_de_usador' ),
'ConfirmAccounts' => array( 'AverdadearCuentos' ),
'UserCredentials' => array( 'Letra_de_creença_de_usadores' ),
);
/** Luxembourgish (Lëtzebuergesch) */
$specialPageAliases['lb'] = array(
'RequestAccount' => array( 'Benotzerkont_ufroen' ),
'ConfirmAccounts' => array( 'Benotzerkont_confirméieren' ),
'UserCredentials' => array( 'Benotzerinformatiounen' ),
);
/** Macedonian (македонски) */
$specialPageAliases['mk'] = array(
'RequestAccount' => array( 'ПобарајКорисничкаСметка' ),
'ConfirmAccounts' => array( 'ПотврдаНаКорисничкаСметка' ),
'UserCredentials' => array( 'КорисничкиАкдредитиви' ),
);
/** Malayalam (മലയാളം) */
$specialPageAliases['ml'] = array(
'RequestAccount' => array( 'അഗത്വ_ആവശ്യപ്പെടുക' ),
'ConfirmAccounts' => array( 'അഗത്വ_സ്ഥിരീകരിക്കുക' ),
'UserCredentials' => array( 'ഉപയോക്തൃയോഗ്യത' ),
);
/** Marathi (मराठी) */
$specialPageAliases['mr'] = array(
'RequestAccount' => array( 'खातेविनंती' ),
'ConfirmAccounts' => array( 'खातेनिश्चिती' ),
'UserCredentials' => array( 'सदस्यपरिचयप्त्र' ),
);
/** Malay (Bahasa Melayu) */
$specialPageAliases['ms'] = array(
'ConfirmAccounts' => array( 'Sahkan_akaun', 'Mengesahkan_akaun' ),
);
/** Maltese (Malti) */
$specialPageAliases['mt'] = array(
'RequestAccount' => array( 'RikjestaKont' ),
'ConfirmAccounts' => array( 'KonfermaKont' ),
'UserCredentials' => array( 'KredenzjaliUtent' ),
);
/** Norwegian Bokmål (norsk (bokmål)) */
$specialPageAliases['nb'] = array(
'RequestAccount' => array( 'Etterspør_konto' ),
'ConfirmAccounts' => array( 'Bekreft_konto' ),
'UserCredentials' => array( 'Brukerlegitimasjon' ),
);
/** Nedersaksisch (Nedersaksisch) */
$specialPageAliases['nds-nl'] = array(
'RequestAccount' => array( 'Gebruker_anvragen' ),
'ConfirmAccounts' => array( 'Gebruker_bevestigen' ),
'UserCredentials' => array( 'Gebrukersgetuugschrift' ),
);
/** Dutch (Nederlands) */
$specialPageAliases['nl'] = array(
'RequestAccount' => array( 'GebruikerAanvragen' ),
'ConfirmAccounts' => array( 'GebruikerBevestigen' ),
'UserCredentials' => array( 'Gebruikersattest' ),
);
/** Occitan (occitan) */
$specialPageAliases['oc'] = array(
'RequestAccount' => array( 'DemandarUnCompte', 'Demandar_un_compte' ),
'ConfirmAccounts' => array( 'ConfirmarCompte', 'Confirmacion_compte', 'ConfirmacionCompte' ),
);
/** Polish (polski) */
$specialPageAliases['pl'] = array(
'RequestAccount' => array( 'Prośba_o_utworzenie_konta' ),
'ConfirmAccounts' => array( 'Potwierdzenie_konta' ),
);
/** Portuguese (português) */
$specialPageAliases['pt'] = array(
'RequestAccount' => array( 'Pedir_conta' ),
'ConfirmAccounts' => array( 'Confirmar_contas' ),
'UserCredentials' => array( 'Credenciais_de_utilizador' ),
);
/** Brazilian Portuguese (português do Brasil) */
$specialPageAliases['pt-br'] = array(
'ConfirmAccounts' => array( 'Confirmar_conta' ),
'UserCredentials' => array( 'Credenciais_de_usuário' ),
);
/** Romanian (română) */
$specialPageAliases['ro'] = array(
'RequestAccount' => array( 'Cerere_cont' ),
'ConfirmAccounts' => array( 'Confirmă_conturi' ),
'UserCredentials' => array( 'Detalii_utilizator' ),
);
/** Russian (русский) */
$specialPageAliases['ru'] = array(
'RequestAccount' => array( 'Запросить_учётную_запись' ),
);
/** Sanskrit (संस्कृतम्) */
$specialPageAliases['sa'] = array(
'RequestAccount' => array( 'उपयोजकसंज्ञाविनन्ती' ),
'ConfirmAccounts' => array( 'उपयोजकसंज्ञापुष्टिकरोति' ),
'UserCredentials' => array( 'उपयोजकविश्वासपत्त्र' ),
);
/** Slovak (slovenčina) */
$specialPageAliases['sk'] = array(
'RequestAccount' => array( 'PožiadaťOÚčet' ),
'ConfirmAccounts' => array( 'PotvrdiťÚčty' ),
'UserCredentials' => array( 'PrihlasovacieÚdaje' ),
);
/** Albanian (shqip) */
$specialPageAliases['sq'] = array(
'RequestAccount' => array( 'KërkoLlogari' ),
'ConfirmAccounts' => array( 'KonfirmoLlogaritë' ),
);
/** Swedish (svenska) */
$specialPageAliases['sv'] = array(
'ConfirmAccounts' => array( 'Bekräfta_konto' ),
'UserCredentials' => array( 'Användarnamn_och_lösenord' ),
);
/** Swahili (Kiswahili) */
$specialPageAliases['sw'] = array(
'RequestAccount' => array( 'OmbaAkaunti' ),
'ConfirmAccounts' => array( 'ThibitishaAkaunti' ),
);
/** Thai (ไทย) */
$specialPageAliases['th'] = array(
'ConfirmAccounts' => array( 'ยืนยันบัญชีผู้ใช้' ),
);
/** Tagalog (Tagalog) */
$specialPageAliases['tl'] = array(
'RequestAccount' => array( 'Hilingin_ang_kuwenta', 'HilingKuwenta' ),
'ConfirmAccounts' => array( 'Tiyakin_ang_mga_kuwenta' ),
'UserCredentials' => array( 'Mga_katibayan_ng_katangian_ng_tagagamit' ),
);
/** Turkish (Türkçe) */
$specialPageAliases['tr'] = array(
'RequestAccount' => array( 'Hesapİste' ),
'ConfirmAccounts' => array( 'HesaplarıDoğrula' ),
'UserCredentials' => array( 'KullanıcıReferansları' ),
);
/** Ukrainian (українська) */
$specialPageAliases['uk'] = array(
'RequestAccount' => array( 'Запит_обліковогоапису' ),
);
/** Simplified Chinese (中文(简体)‎) */
$specialPageAliases['zh-hans'] = array(
'RequestAccount' => array( '申请帐户' ),
'ConfirmAccounts' => array( '确认帐户' ),
'UserCredentials' => array( '用户凭据' ),
);
/** Traditional Chinese (中文(繁體)‎) */
$specialPageAliases['zh-hant'] = array(
'RequestAccount' => array( '請求帳戶' ),
'ConfirmAccounts' => array( '確認帳戶' ),
);

View file

@ -0,0 +1,830 @@
<?php
/**
* Internationalisation file for ConfirmAccount extension.
*
* @file
* @ingroup Extensions
*/
$messages = array();
$messages['en'] = array(
# Site message for admins
'confirmaccount-newrequests' => '\'\'\'$1\'\'\' open e-mail confirmed [[Special:ConfirmAccounts|account {{PLURAL:$1|request is pending|requests are pending}}]]. \'\'\'Your attention is needed!\'\'\'',
# Add to Special:Login
'requestaccount-loginnotice' => 'To obtain a user account, you must \'\'\'[[Special:RequestAccount|request one]]\'\'\'.',
# User rights descriptions
'right-confirmaccount' => 'View the [[Special:ConfirmAccounts|queue with requested accounts]]',
'right-requestips' => 'View requester\'s IP addresses while processing requested accounts',
'right-lookupcredentials' => 'View [[Special:UserCredentials|user credentials]]',
);
/** Message documentation (Message documentation)
* @author Bennylin
* @author EugeneZelenko
* @author Jon Harald Søby
* @author Lejonel
* @author McDutchie
* @author Purodha
* @author Siebrand
* @author The Evil IP address
*/
$messages['qqq'] = array(
'confirmaccount-newrequests' => 'Notice for account reviewers when there are account requests from users with a confirmed e-mail address. Parameters:
* $1 is the number of open account requests matching given criteria.',
'right-confirmaccount' => '{{doc-right|confirmaccount}}',
'right-requestips' => '{{doc-right|requestips}}',
'right-lookupcredentials' => '{{doc-right|lookupcredentials}}',
);
/** Arabic (العربية)
* @author Ciphers
* @author DRIHEM
* @author Meno25
* @author OsamaK
* @author ترجمان05
*/
$messages['ar'] = array(
'confirmaccount-newrequests' => "'''$1''' تم تأكيد البريد الإلكتروني المفتوح [[Special:ConfirmAccounts|هناك {{PLURAL:$1|حساب في الإنتظار|طلبات في الإنتظار}}]]. '''أنتباهك مطلوب!'''",
'requestaccount-loginnotice' => "للحصول على حساب، يجب عليك '''[[Special:RequestAccount|أن تطلب حسابًا]]'''.",
'right-confirmaccount' => 'عرض [[Special:ConfirmAccounts|طابور الحسابات المطلوبة]]',
'right-requestips' => 'عرض عنوان آيبي الطالب أثناء العمل على الحسابات المطلوبة',
'right-lookupcredentials' => 'رؤية [[Special:UserCredentials|شهادات المستخدم]]',
);
/** Egyptian Spoken Arabic (مصرى)
* @author Meno25
*/
$messages['arz'] = array(
'confirmaccount-newrequests' => "{{PLURAL:$1|يوجد|يوجد}} حاليا '''$1'''
{{PLURAL:$1|[[Special:ConfirmAccounts|طلب حساب]]|[[Special:ConfirmAccounts|طلب حساب]]}} مفتوح قيد الانتظار.", # Fuzzy
'requestaccount-loginnotice' => "للحصول على حساب، يجب عليك '''[[Special:RequestAccount|طلب واحد]]'''.",
);
/** Asturian (asturianu)
* @author Xuacu
*/
$messages['ast'] = array(
'confirmaccount-newrequests' => "Anguaño hai '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|solicitú de cuenta pendiente|solicitúes de cuentes pendientes}}]]. '''Fai falta la to atención!'''",
'requestaccount-loginnotice' => "Pa tener una cuenta d'usuariu, tienes de '''[[Special:RequestAccount|solicitar una]]'''.",
'right-confirmaccount' => 'Ver la [[Special:ConfirmAccounts|cola de solicitúes de cuentes]]',
'right-requestips' => 'Ver la direición IP del solicitante al procesar les solicitúes de cuentes',
'right-lookupcredentials' => 'Ver les [[Special:UserCredentials|credenciales del usuariu]]',
);
/** Belarusian (Taraškievica orthography) (беларуская (тарашкевіца))
* @author EugeneZelenko
* @author Jim-by
* @author Renessaince
* @author Zedlik
*/
$messages['be-tarask'] = array(
'confirmaccount-newrequests' => "Чакаецца апрацоўка '''$1'''
[[Special:ConfirmAccounts|{{PLURAL:$1|запыту на стварэньне рахунку|запытаў на стварэньне рахунку|запытаў на стварэньне рахунку}}]]. '''Зьвярніце Вашую ўвагу!'''",
'requestaccount-loginnotice' => "Каб атрымаць рахунак, Вам неабходна '''[[Special:RequestAccount|падаць запыт]]'''.",
'right-confirmaccount' => 'прагляд [[Special:ConfirmAccounts|запытаў на стварэньне рахункаў]]',
'right-requestips' => 'прагляд IP-адрасоў з якіх паступалі запыты на стварэньне рахункаў',
'right-lookupcredentials' => 'прагляд [[Special:UserCredentials|пасьведчаньняў ўдзельнікаў]]',
);
/** Bulgarian (български)
* @author DCLXVI
* @author Spiritia
*/
$messages['bg'] = array(
'requestaccount-loginnotice' => "За да получите потребителска сметка, необходимо е да '''[[Special:RequestAccount|изпратите заявка]]'''.",
);
/** Breton (brezhoneg)
* @author Fohanno
* @author Fulup
* @author Y-M D
*/
$messages['br'] = array(
'confirmaccount-newrequests' => "Er mare-mañ ez eus '''$1''' [[Special:ConfirmAccounts|goulenn kont{{PLURAL:$1||}}]] o vont en-dro.", # Fuzzy
'requestaccount-loginnotice' => "Evit kaout ur gont implijer e rankit '''[[Special:RequestAccount|goulenn unan]]'''.",
'right-confirmaccount' => "Gwelet [[Special:ConfirmAccounts|lostad ar c'hontoù goulennet]]",
'right-requestips' => "Gwelet chomlec'hioù IP ar c'houlennerien pa vez pledet gant goulennoù krouiñ kontoù nevez.",
'right-lookupcredentials' => 'Gwelet [[Special:UserCredentials|daveennoù an implijerien]]',
);
/** Bosnian (bosanski)
* @author CERminator
*/
$messages['bs'] = array(
'requestaccount-loginnotice' => "Da biste korisnički račun, morate '''[[Special:RequestAccount|zahtijevati jedan]]'''.",
);
/** Czech (česky)
* @author Jkjk
* @author Li-sung
* @author Matěj Grabovský
* @author Mormegil
*/
$messages['cs'] = array(
'requestaccount-loginnotice' => "Chcete-li získat uživatelský účet, je třeba o něj '''[[Special:RequestAccount|požádat]]'''.",
);
/** Danish (dansk)
* @author Kaare
*/
$messages['da'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|åben kontoanmodning|åbne kontoanmodninger}} med bekræftet e-mail [[Special:ConfirmAccounts| venter på behandling]]. '''Din opmærksomhed er påkrævet!'''",
'requestaccount-loginnotice' => "For at få en brugerkonto, skal du '''[[Special:RequestAccount|anmode om en]]'''.",
'right-confirmaccount' => 'Vis [[Special:ConfirmAccounts|kontoanmodningskøen]]',
'right-requestips' => 'Vis anmoderers IP-adresse mens der behandles kontoanmodninger',
'right-lookupcredentials' => 'Vis [[Special:UserCredentials|brugeroplysninger]]',
);
/** German (Deutsch)
* @author Als-Holder
* @author Kghbln
* @author Leithian
* @author MF-Warburg
* @author Pill
* @author Purodha
* @author Raimond Spekking
* @author Revolus
* @author Rrosenfeld
* @author The Evil IP address
* @author Umherirrender
*/
$messages['de'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|offener, E-Mail bestätigter Benutzerkontenantrag wartet]]|[[Special:ConfirmAccounts|offene, E-Mail bestätigte Benutzerkontenanträge warten]]}} auf Bearbeitung. '''Bitte kümmere dich darum.'''",
'requestaccount-loginnotice' => "Um ein neues Benutzerkonto zu erhalten, musst du es '''[[Special:RequestAccount|beantragen]]'''.",
'right-confirmaccount' => 'Die [[Special:ConfirmAccounts|Warteschlange der angefragten Benutzerkonten]] sehen',
'right-requestips' => 'Die IP-Adresse des Anfragers für ein Benutzerkonto sehen',
'right-lookupcredentials' => '[[Special:UserCredentials|Benutzerempfehlungsschreiben]] sehen',
);
/** German (formal address) (Deutsch (Sie-Form))
* @author Imre
* @author Kghbln
* @author The Evil IP address
* @author Umherirrender
*/
$messages['de-formal'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|offener, E-Mail bestätigter Benutzerkontenantrag wartet]]|[[Special:ConfirmAccounts|offene, E-Mail bestätigte Benutzerkontenanträge warten]]}} auf Bearbeitung. '''Bitte kümmern Sie sich darum.'''",
'requestaccount-loginnotice' => "Um ein neues Benutzerkonto zu erhalten, müssen Sie es '''[[Special:RequestAccount|beantragen]]'''.",
);
/** Zazaki (Zazaki)
* @author Erdemaslancan
*/
$messages['diq'] = array(
'right-confirmaccount' => '[[Special:ConfirmAccounts|Grub da hesab waştena]] vineno',
'right-lookupcredentials' => '[[Special:UserCredentials|Referansanê karberan]] vineno',
);
/** Lower Sorbian (dolnoserbski)
* @author Michawiki
*/
$messages['dsb'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|pśez e-mail wobkšuśone|pśez e-mail wobkšuśonej|pśez e-mail wobkšuśone|pśez e-mail wobkšuśonych }} [[Special:ConfirmAccounts|{{PLURAL:$1|póžedanje na konto jo njedocynjone|póžedani na konśe stej njedocynjonej| póžedanja na konta su njedocynjone|póžedanjow na konta jo njedocynjone}}]]. '''Pšosym staraj wó to!'''",
'requestaccount-loginnotice' => "Aby dostał wužywarske konto, musyš '''[[Special:RequestAccount|póžedanje na nje stajiś]]'''.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|Cakański rěd z pominanymi kontami]] se woglědaś',
'right-requestips' => 'IP-adrese póžadarja se woglědaś, mjaztym až se pominane konta pśeźěłuju',
'right-lookupcredentials' => '[[Special:UserCredentials|Wužywarske wopšawnjeńki]] se woglědaś',
);
/** Esperanto (Esperanto)
* @author Amikeco
* @author Michawiki
* @author Yekrats
*/
$messages['eo'] = array(
'requestaccount-loginnotice' => "Akiri uzanto-konton, vi devas '''[[Special:RequestAccount|peti ĝin]]'''.",
);
/** Spanish (español)
* @author Armando-Martin
* @author BicScope
* @author Crazymadlover
* @author Fitoschido
* @author Imre
* @author Lin linao
* @author Locos epraix
* @author Pertile
* @author Sanbec
* @author Translationista
*/
$messages['es'] = array(
'confirmaccount-newrequests' => "'''$1''' correo electrónico abierto ha confirmado que [[Special:ConfirmAccounts|{{PLURAL:$1|solicitud de cuenta está pendiente|solicitudes de cuenta están pendientes}}]]. '''Se necesita su atención!'''",
'requestaccount-loginnotice' => "Para obtener una cuenta de usuario, debes '''[[Special:RequestAccount|solicitar una]]'''.",
'right-confirmaccount' => 'Consulte la [[Special:ConfirmAccounts|cola de solicitudes de cuenta]]',
'right-requestips' => 'Ver la dirección IP del solicitante mientras se procesan las solicitudes de cuenta',
'right-lookupcredentials' => 'Ver las [[Special:UserCredentials|credenciales del usuario]]',
);
/** Finnish (suomi)
* @author Centerlink
* @author Cimon Avaro
* @author Crt
* @author Jaakonam
* @author Mobe
* @author Nike
* @author Str4nd
* @author Taleman
* @author Varusmies
*/
$messages['fi'] = array(
'confirmaccount-newrequests' => "Nyt on '''$1''' {{PLURAL:$1|avoin|avointa}} {{PLURAL:$1|[[Special:ConfirmAccounts|pyyntö]]|[[Special:ConfirmAccounts|pyyntöä]]}} käsiteltävänä.", # Fuzzy
'requestaccount-loginnotice' => "Saadaksesi käyttäjätunnuksen on tehtävä '''[[Special:RequestAccount|käyttäjätunnuspyyntö]]'''.",
'right-confirmaccount' => 'Nähdä [[Special:ConfirmAccounts|listan pyydetyistä tunnuksista]]',
'right-requestips' => 'Nähdä hakijan IP-osoitteet käyttäjätilejä käsiteltäessä',
'right-lookupcredentials' => 'Nähdä [[Special:UserCredentials|käyttäjän luotettavuustiedot]]',
);
/** French (français)
* @author Crochet.david
* @author Dereckson
* @author Grondin
* @author IAlex
* @author Louperivois
* @author McDutchie
* @author Meithal
* @author Peter17
* @author PieRRoMaN
* @author Sherbrooke
* @author Urhixidur
* @author Zetud
*/
$messages['fr'] = array(
'confirmaccount-newrequests' => "Il y a actuellement '''$1''' [[Special:ConfirmAccounts|demande{{PLURAL:$1||s}} de compte]] en cours. '''Votre attention est nécessaire !'''",
'requestaccount-loginnotice' => "Pour obtenir un compte utilisateur, vous devez en faire '''[[Special:RequestAccount|la demande]]'''.",
'right-confirmaccount' => 'Voir la [[Special:ConfirmAccounts|file des demandes de compte]]',
'right-requestips' => 'Voir les adresses IP des demandeurs lors du traitement des demandes de nouveau comptes',
'right-lookupcredentials' => 'Voir les [[Special:UserCredentials|références des utilisateurs]]',
);
/** Franco-Provençal (arpetan)
* @author ChrisPtDe
*/
$messages['frp'] = array(
'confirmaccount-newrequests' => "Ora, y at '''$1''' [[Special:ConfirmAccounts|demand{{PLURAL:$1|a|es}} de compto usanciér]] en cors. '''Voutra atencion est nècèssèra !'''",
'requestaccount-loginnotice' => "Por avêr un compto usanciér, vos en dête fâre la '''[[Special:RequestAccount|demanda]]'''.",
);
/** Galician (galego)
* @author Alma
* @author Elisardojm
* @author Toliño
* @author Xosé
*/
$messages['gl'] = array(
'confirmaccount-newrequests' => "Actualmente hai '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|solicitude de conta pendente|solicitudes de contas pendentes}}]]. '''Cómpre a súa atención!'''",
'requestaccount-loginnotice' => "Para obter unha conta de usuario ten que '''[[Special:RequestAccount|solicitar unha]]'''.",
'right-confirmaccount' => 'Ver a [[Special:ConfirmAccounts|cola coas solicitudes de contas]]',
'right-requestips' => 'Ver os enderezos IP que solicitan contas',
'right-lookupcredentials' => 'Ver as [[Special:UserCredentials|credenciais de usuario]]',
);
/** Swiss German (Alemannisch)
* @author Als-Chlämens
* @author Als-Holder
*/
$messages['gsw'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|ufige, E-Mail bstätigte Benutzerkontenaatrag wartet]]|[[Special:ConfirmAccounts|ufigi, E-Mail bstätigti Benutzerkontenaaträg warten]]}} uf Bearbeitig. '''Bitte due dich drum chümmre.'''",
'requestaccount-loginnotice' => "Go ne nej Benutzerkonto iberchu muesch e '''[[Special:RequestAccount|Aatrag stelle]]'''.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|Lischt mit beaatraite Benutzerkonte]] aaluege',
'right-requestips' => 'D IP-Adräss vum Aatragsteller aaluege, derwylscht dr Aatrag bearbeitet wird',
'right-lookupcredentials' => '[[Special:UserCredentials|Zyygnis vum Benutzer]] aaluege',
);
/** Hebrew (עברית)
* @author Amire80
* @author Rotemliss
* @author StuB
* @author YaronSh
*/
$messages['he'] = array(
'confirmaccount-newrequests' => "יש {{PLURAL:$1|[[Special:ConfirmAccounts|בקשה פתוחה ממתינה '''אחת''' לפתוח חשבון]], עם כתובת דואר אלקטרוני מאושרת שממתינה|'''$1''' [[Special:ConfirmAccounts|בקשות פתוחות לפתוח חשבונות]], עם כתובות דואר אלקטרוני מאושרות שממתינות}} לאישור. ''תשומת לבך נדרשת!''",
'requestaccount-loginnotice' => "כדי לקבל חשבון משתמש, עליכם '''[[Special:RequestAccount|לבקש אחד כזה]]'''.",
'right-confirmaccount' => 'צפייה ב[[Special:ConfirmAccounts|תור עם החשבונות הדרושים]]',
'right-requestips' => 'לצפות בכתובות IP של המבקשים בזמן עיבוד בקשות לפתוח חשבון',
'right-lookupcredentials' => 'צפייה ב[[Special:UserCredentials|הרשאות המשתמש]]',
);
/** Hindi (हिन्दी)
* @author Kaustubh
* @author Kiranmayee
* @author आलोक
*/
$messages['hi'] = array(
'requestaccount-loginnotice' => "सदस्य खाता पाने के लिये आप अपनी '''[[Special:RequestAccount|माँग पंजिकृत करें]]'''।",
);
/** Croatian (hrvatski)
* @author Dalibor Bosits
* @author Dnik
* @author Ex13
* @author SpeedyGonsales
*/
$messages['hr'] = array(
'confirmaccount-newrequests' => "u tijeku '''$1''' e-mailom {{PLURAL:$1|potvrđen [[Special:ConfirmAccounts|zahtjev za računom]]|potvrđenih [[Special:ConfirmAccounts|zahtjeva za računom]]}}", # Fuzzy
'requestaccount-loginnotice' => "Da bi dobili suradnički račun, trebate ga '''[[Special:RequestAccount|zatražiti]]'''.",
);
/** Upper Sorbian (hornjoserbsce)
* @author Michawiki
*/
$messages['hsb'] = array(
'confirmaccount-newrequests' => "{{PLURAL:$1|Čaka|Čakatej|Čakaja|Čaka}} tuchwilu '''$1''' přez e-mejlu [[Special:ConfirmAccounts|{{PLURAL:$1|wobkrućene kontowe požadanje|wobkrućenej kontowej požadani|wobkrućene kontowe požadanja|wobkrućenych kontowych požadanjow}}]]. '''Prošu staraj so wo to!'''",
'requestaccount-loginnotice' => "Zo by wužiwarske konto dóstał, dyrbiš wo nje '''[[Special:RequestAccount|prosyć]]'''.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|Čakanski rynk z požadanymi kontami]] sej wobhladać',
'right-requestips' => 'IP-adresy požadarja sej wobhladać, mjeztym zo so požadane konta předźěłuja',
'right-lookupcredentials' => '[[Special:UserCredentials|Wužiwarske woprawnjenki]] sej wobhladać',
);
/** Hungarian (magyar)
* @author Dani
* @author Dj
* @author Dorgan
* @author Glanthor Reviol
* @author Tgr
*/
$messages['hu'] = array(
'confirmaccount-newrequests' => "'''$1''' e-mail megerősített [[Special:ConfirmAccounts| fiók kérés van függőben]]. '''Figyelmet igényel!'''",
'requestaccount-loginnotice' => "Ha felhasználói fiókot szeretnél, akkor '''[[Special:RequestAccount|kérned kell egyet]]'''.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|kért felhasználói fiókok várakozási sorának]] megtekintése',
'right-requestips' => 'az igénylők IP-címeinek megtekintése a kért fiókok feldolgozása közben',
'right-lookupcredentials' => '[[Special:UserCredentials|felhasználói azonosító információk]] megjelenítése',
);
/** Interlingua (interlingua)
* @author McDutchie
*/
$messages['ia'] = array(
'confirmaccount-newrequests' => "Es pendente '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|requesta|requestas}} de conto]] aperte e confirmate via e-mail. '''Tu attention es necessari!'''",
'requestaccount-loginnotice' => "Pro obtener un conto de usator, tu debe '''[[Special:RequestAccount|requestar un]]'''.",
'right-confirmaccount' => 'Vider le [[Special:ConfirmAccounts|cauda con requestas de conto]]',
'right-requestips' => 'Vider le adresses IP del requestatores durante le tractamento de requestas de conto',
'right-lookupcredentials' => 'Vider le [[Special:UserCredentials|credentiales de usatores]]',
);
/** Indonesian (Bahasa Indonesia)
* @author Bennylin
* @author Irwangatot
* @author IvanLanin
* @author Iwan Novirion
* @author Rex
*/
$messages['id'] = array(
'confirmaccount-newrequests' => "Terdapat '''$1''' antrean [[Special:ConfirmAccounts|{{PLURAL:$1|permintaan|permintaan}} akun]] yang surelnya telah dikonfirmasi.", # Fuzzy
'requestaccount-loginnotice' => "Untuk mendapatkan sebuah akun pengguna, Anda harus '''[[Special:RequestAccount|mengajukannya]]'''.",
'right-confirmaccount' => 'Lihat [[Special:ConfirmAccounts|antrean peminta akun]]',
'right-requestips' => 'Lihat Alamat IP pemohon selama proses permohonan akun',
'right-lookupcredentials' => 'Lihat [[Special:UserCredentials|pengguna Kredensial]]',
);
/** Icelandic (íslenska)
* @author S.Örvarr.S
* @author Ævar Arnfjörð Bjarmason
*/
$messages['is'] = array(
'confirmaccount-newrequests' => "'''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|notandabeðni|notandabeðnir}}]] {{PLURAL:$1|með staðfest netfang bíður samþykkis|með staðfest netföng bíða samþykkis}}", # Fuzzy
'requestaccount-loginnotice' => "Ef þú ert ekki þegar með aðgang verður þú að '''[[Special:RequestAccount|sækja um einn slíkan]]'''.",
);
/** Italian (italiano)
* @author Beta16
* @author Darth Kule
* @author Melos
* @author Pietrodn
* @author Stefano-c
*/
$messages['it'] = array(
'confirmaccount-newrequests' => "'''$1''' e-mail di conferma [[Special:ConfirmAccounts|per account {{PLURAL:$1|è|sono}} in attesa]]. '''È necessaria la tua attenzione!'''",
'requestaccount-loginnotice' => "Per ottenere un account utente, è necessario '''[[Special:RequestAccount|richiederne uno]]'''.",
'right-confirmaccount' => 'Visualizza la [[Special:ConfirmAccounts|coda gli account richiesti]]',
'right-requestips' => 'Visualizza gli indirizzi IP del richiedente mentre processa gli account richiesti',
'right-lookupcredentials' => 'Visualizza [[Special:UserCredentials|credenziali utente]]',
);
/** Japanese (日本語)
* @author Aotake
* @author Fryed-peach
* @author JtFuruhata
* @author Schu
* @author Shirayuki
* @author 青子守歌
*/
$messages['ja'] = array(
'confirmaccount-newrequests' => "現在、'''$1個'''のメール認証済み{{PLURAL:$1|[[Special:ConfirmAccounts|アカウント申請]]}}が承認待ちになっています。'''注意が必要です!'''",
'requestaccount-loginnotice' => "利用者アカウントを取得するには、'''[[Special:RequestAccount|アカウント登録申請]]'''をしてください。",
'right-confirmaccount' => '[[Special:ConfirmAccounts|アカウント申請キュー]]を閲覧',
'right-requestips' => 'アカウント申請の処理中に申請者のIPアドレスを閲覧',
'right-lookupcredentials' => '[[Special:UserCredentials|利用者信頼情報]]を閲覧',
);
/** Jamaican Creole English (Patois)
* @author Yocahuna
*/
$messages['jam'] = array(
'confirmaccount-newrequests' => "'''$1''' opn e-miel-kanfoerm [[Special:ConfirmAccounts|akount {{PLURAL:$1|rikwes|rikwes}}]] pendin", # Fuzzy
'requestaccount-loginnotice' => "Fi abtien a yuuza akount, yu fi '''[[Special:RequestAccount|rikwes wan]]'''.",
);
/** Javanese (Basa Jawa)
* @author Meursault2004
* @author Pras
*/
$messages['jv'] = array(
'requestaccount-loginnotice' => "Supaya bisa olèh rékening panganggo, panjenengan kudu '''[[Special:RequestAccount|nyuwun iku]]'''.",
);
/** Khmer (ភាសាខ្មែរ)
* @author Chhorran
* @author Lovekhmer
* @author Sovichet
* @author Thearith
* @author គីមស៊្រុន
* @author វ័ណថារិទ្ធ
*/
$messages['km'] = array(
'requestaccount-loginnotice' => "ដើម្បីទទួលបានគណនីអ្នកប្រើប្រាស់ អ្នកត្រូវតែ'''[[Special:RequestAccount|ស្នើសុំគណនី]]'''។",
);
/** Colognian (Ripoarisch)
* @author Purodha
*/
$messages['ksh'] = array(
'confirmaccount-newrequests' => '{{PLURAL:$1|Ein|\'\'\'$1\'\'\'|Kein}} unjedonn [[Special:ConfirmAccounts|{{PLURAL:$1|Aanfrooch|Aanfroore|Aanfroore}}]] met beschtääteschte <i lang="en">e-mail</i>-Addräß {{PLURAL:$1|es|sin|sin}} am waade.',
'requestaccount-loginnotice' => "Öm ene Zohjang ze krijje, donn '''[[Special:RequestAccount|noh einem froore]]'''.",
'right-confirmaccount' => 'De [[Special:ConfirmAccounts|Schlang met de aanjefroochte Zohjäng]] beloore',
'right-requestips' => 'De jewönschte Neu_Metmaacher ier <code lang="en">IP-</code>Addräß aanloore beim Aanfroore beärbeede',
'right-lookupcredentials' => 'De [[Special:UserCredentials|Nohwiise]] för Metmaacher aanloore',
);
/** Luxembourgish (Lëtzebuergesch)
* @author Les Meloures
* @author Robby
*/
$messages['lb'] = array(
'confirmaccount-newrequests' => "'''$1''' open, per E-Mail confirméiert, [[Special:ConfirmAccounts|account {{PLURAL:$1|Ufro|Ufroen}}]] déi drop {{PLURAL:$1|waart|waarden}} beäntwert ze ginn. '''Är Mataarbecht gëtt gebraucht!'''",
'requestaccount-loginnotice' => "Fir e Benotzerkont ze kréien, musst Dir '''[[Special:RequestAccount|een ufroen]]'''.",
'right-confirmaccount' => "D'[[Special:ConfirmAccounts|Queue mat den ugefrote Benotzerkonte]] kucken",
'right-requestips' => "D'IP-Adress vun där d'Ufro koum uweise wann d'Ufro fir e Benotzerkont verschafft gëtt",
'right-lookupcredentials' => '[[Special:UserCredentials|Referenze vun de Benotzer]] kucken',
);
/** Lezghian (лезги)
* @author Migraghvi
*/
$messages['lez'] = array(
'requestaccount-loginnotice' => 'Иштиракчидин аккаунт къачун патал квез ам [[Special:RequestAccount|тIалабиз герек я]] .',
);
/** Limburgish (Limburgs)
* @author Pahles
*/
$messages['li'] = array(
'confirmaccount-newrequests' => "Dao {{PLURAL:$1|steit|stoon}} '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|gebroekersaanvraog|gebroekersaanvraoge}}]] aope. '''Dien aandach is nujig!'''",
'requestaccount-loginnotice' => "Um 'n gebroekersaccount te kriege mós te '''[[Special:RequestAccount|'ne aanvraog doon]]'''",
'right-confirmaccount' => '[[Special:CorfirmAccounts|Wachrie mit gebroekersaanvraoge]] betrachte', # Fuzzy
'right-requestips' => "De IP-adresse van aanvraogers betrachte bie 't verwirke van gebroekersaanvraage",
'right-lookupcredentials' => '[[Special:UserCredentials|Gebroekersreferenties]] betrachte',
);
/** Basa Banyumasan (Basa Banyumasan)
* @author StefanusRA
*/
$messages['map-bms'] = array(
'confirmaccount-newrequests' => "Ana '''$1''' antrean [[Special:ConfirmAccounts|{{PLURAL:$1|penjalukan|penjalukan}} akun]] sing imel-e uwis dikonfirmasi. '''Gageyan diproses!'''",
'requestaccount-loginnotice' => "Ben teyeng nduwe akun panganggo, Rika kudu '''[[Special:RequestAccount|njaluk akun]]'''.",
'right-confirmaccount' => 'Deleng [[Special:ConfirmAccounts|antrean penjalukan akun]]',
'right-requestips' => 'Deleng Alamat IP-ne sing njaluk akun selama proses penjalukan akun',
'right-lookupcredentials' => 'Deleng [[Special:UserCredentials|panganggo Kredensial]]',
);
/** Macedonian (македонски)
* @author Bjankuloski06
* @author Brest
*/
$messages['mk'] = array(
'confirmaccount-newrequests' => "Има '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|отворено барање за сметка|отворени барања за сметка}}]] во исчекување. '''Потребно е вашето внимание!'''",
'requestaccount-loginnotice' => "За да добиете корисничка сметка, морате да '''[[Special:RequestAccount|поднесете барање]]'''.",
'right-confirmaccount' => 'Погледајте ја [[Special:ConfirmAccounts|редицата со побарани сметки]]',
'right-requestips' => 'Прегледување на IP-адресите на барателот при работата на побарани сметки',
'right-lookupcredentials' => 'Погледајте ги [[Special:UserCredentials|препораките за корисникот]]',
);
/** Malayalam (മലയാളം)
* @author Jacob.jose
* @author Junaidpv
* @author Praveenp
* @author Shijualex
*/
$messages['ml'] = array(
'confirmaccount-newrequests' => "ഇമെയിൽ വിലാസം സ്ഥിരീകരിക്കപ്പെട്ട '''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|അംഗത്വത്തിനായുള്ള അഭ്യർത്ഥന]]|[[Special:ConfirmAccounts|അംഗത്വത്തിനായുള്ള അഭ്യർത്ഥനകൾ]]}} പെൻ‌ഡിംങ്ങാണ്‌.", # Fuzzy
'requestaccount-loginnotice' => "ഉപയോക്തൃ അംഗത്വം ലഭിക്കുന്നതിനായി താങ്കൾ '''[[Special:RequestAccount|ഉപയോക്തൃഅംഗത്വത്തിനായി അഭ്യർത്ഥിക്കണം]]'''.",
);
/** Marathi (मराठी)
* @author Htt
* @author Kaustubh
* @author Mahitgar
*/
$messages['mr'] = array(
'confirmaccount-newrequests' => "'''$1''' इमेल पत्ता तपासलेला आहे {{PLURAL:$1|[[Special:ConfirmAccounts|खात्याची मागणी]]|[[Special:ConfirmAccounts|खात्यांची मागणी]]}} शिल्लक", # Fuzzy
'requestaccount-loginnotice' => "सदस्य खाते मिळविण्यासाठी तुम्ही तुमची '''[[Special:RequestAccount|मागणी नोंदवा]]'''.",
);
/** Malay (Bahasa Melayu)
* @author Anakmalaysia
*/
$messages['ms'] = array(
'confirmaccount-newrequests' => "'''$1''' [[Special:ConfirmAccounts|permintaan akaun]] yang disahkan oleh pembukaan e-mel sedang menunggu. '''Perhatian anda diperlukan!'''",
'requestaccount-loginnotice' => "Untuk memperoleh akaun pengguna, anda mesti '''[[Special:RequestAccount|membuat permohonan]]'''.",
'right-confirmaccount' => 'Melihat [[Special:ConfirmAccounts|baris gilir dengan akaun-akaun yang dimohon]]',
'right-requestips' => 'Melihat alamat-alamat IP pemohon ketika memproseskan akaun-akaun yang dimohon',
'right-lookupcredentials' => 'Melihat [[Special:UserCredentials|kelayakan pengguna]]',
);
/** Maltese (Malti)
* @author Chrisportelli
*/
$messages['mt'] = array(
'confirmaccount-newrequests' => "'''$1''' indirizzi elettroniċi ta' konferma [[Special:ConfirmAccounts|kull kont {{PLURAL:$1hija|huma}} pendenti]]. '''L-attenzjoni tiegħek hija neċessarja!'''",
'requestaccount-loginnotice' => "Sabiex tikseb kont tal-utent, trid '''[[Special:RequestAccount|titlob wieħed]]'''.",
'right-confirmaccount' => "Jara l-[[Special:ConfirmAccounts|kju ta' kontijiet rikjesti]]",
'right-requestips' => 'Jara l-indirizz IP tar-rikjedent waqt li jipproċessa l-kontijiet rikjesti',
'right-lookupcredentials' => 'Jara l-[[Special:UserCredentials|kredenzjali tal-utent]]',
);
/** Norwegian Bokmål (norsk (bokmål))
* @author Event
* @author Harald Khan
* @author Laaknor
* @author Nghtwlkr
*/
$messages['nb'] = array(
'confirmaccount-newrequests' => "Det er foreløpig '''$1''' {{PLURAL:$1|åpen [[Special:ConfirmAccounts|kontoforespørsel]]|åpne [[Special:ConfirmAccounts|kontoforespørsler]]}}.", # Fuzzy
'requestaccount-loginnotice' => "For å få en brukerkonto må du '''[[Special:RequestAccount|etterspørre en]]'''.",
'right-confirmaccount' => 'Vis [[Special:ConfirmAccounts|køen av kontosøknader]]',
'right-requestips' => 'Vis søkerenes IP-adresser mens man behandler kontosøknadene',
'right-lookupcredentials' => 'Vis [[Special:UserCredentials|brukerattester]]',
);
/** Dutch (Nederlands)
* @author Annabel
* @author SPQRobin
* @author Siebrand
*/
$messages['nl'] = array(
'confirmaccount-newrequests' => "Er {{PLURAL:$1|staat|staan}} '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|gebruikersaanvraag|gebruikersaanvragen}}]] open. '''Uw aandacht is nodig!'''",
'requestaccount-loginnotice' => "Om een gebruiker te krijgen, moet u '''[[Special:RequestAccount|een aanvraag doen]]'''.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|Wachtrij met gebruikersaanvragen]] bekijken',
'right-requestips' => 'De IP-adressen van aanvragers bekijken bij het verwerken bij het verwerken van gebruikersaanvragen',
'right-lookupcredentials' => '[[Special:UserCredentials|gebruikersreferenties]] bekijken',
);
/** Norwegian Nynorsk (norsk (nynorsk))
* @author Gunnernett
* @author Harald Khan
* @author Jon Harald Søby
* @author Njardarlogar
*/
$messages['nn'] = array(
'confirmaccount-newrequests' => "Det finst for tida {{PLURAL:$1|'''éin''' open [[Special:ConfirmAccounts|kontoførespurnad]]|'''$1''' opne [[Special:ConfirmAccounts|kontoførespurnader]]}}.", # Fuzzy
'requestaccount-loginnotice' => "For å få ein brukarkonto må du '''[[Special:RequestAccount|be om ein]]'''.",
'right-confirmaccount' => 'Vis [[Special:ConfirmAccounts|køen av kontosøknader]]',
'right-requestips' => 'Vis søkjaren sine IP-adresser medan kontosøknadene er til handsaming',
'right-lookupcredentials' => 'Vis [[Special:UserCredentials|brukarattestar]]',
);
/** Occitan (occitan)
* @author Cedric31
*/
$messages['oc'] = array(
'confirmaccount-newrequests' => "Actualament i a '''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|demanda de compte]]|[[Special:ConfirmAccounts|demandas de compte]]}} en cors.", # Fuzzy
'requestaccount-loginnotice' => "Per obténer un compte d'utilizaire, vos ne cal far '''[[Special:RequestAccount|la demanda]]'''.",
'right-confirmaccount' => 'Vejatz la [[Special:ConfirmAccounts|fila de las demandas de compte]]',
'right-requestips' => 'Vejatz las adreças IP dels demandaires al moment del tractament de las demandas de comptes novèls',
'right-lookupcredentials' => 'Vejatz las [[Special:UserCredentials|referéncias dels utilizaires]]',
);
/** Polish (polski)
* @author Derbeth
* @author Equadus
* @author Leinad
* @author Maikking
* @author Masti
* @author McMonster
* @author Sp5uhe
* @author ToSter
* @author Wpedzich
*/
$messages['pl'] = array(
'confirmaccount-newrequests' => "{{PLURAL:$1|Jest '''$1''' [[Special:ConfirmAccounts|oczekujący wniosek]]|Są '''$1''' [[Special:ConfirmAccounts|oczekujące wnioski]]|Jest '''$1''' [[Special:ConfirmAccounts|oczekujących wniosków]]}}, z potwierdzonym adresem email. '''Konieczna jest Twoja ingerencja!'''",
'requestaccount-loginnotice' => "By uzyskać konto użytkownika musisz '''[[Special:RequestAccount|złożyć wniosek]]'''.",
'right-confirmaccount' => 'Przeglądanie [[Special:ConfirmAccounts|kolejki z wnioskami o założenie konta]]',
'right-requestips' => 'Przeglądanie adresów IP wnioskodawców podczas przetwarzania ich wniosków o założenie konta',
'right-lookupcredentials' => 'Przeglądanie [[Special:UserCredentials|referencji użytkowników]]',
);
/** Piedmontese (Piemontèis)
* @author Borichèt
* @author Bèrto 'd Sèra
* @author Dragonòt
*/
$messages['pms'] = array(
'confirmaccount-newrequests' => "'''$1''' mëssagi ch'a speto [[Special:ConfirmAccounts|{{PLURAL:$1|d'arcesta ëd cont confermà|d'arceste ëd cont confermà}}]]. '''A-i é dabzògn ëd soa atension!'''",
'requestaccount-loginnotice' => "Për deurb-se un sò cont utent, a venta '''[[Special:RequestAccount|ch<nowiki>'</nowiki>a në ciama un]]'''.",
'right-confirmaccount' => 'Vardé la [[Special:ConfirmAccounts|coa con ij cont ciamà]]',
'right-requestips' => "Vardé j'adrësse IP dël ciamant durant ël tratament dij cont ciamà",
'right-lookupcredentials' => 'Visualisa [[Special:UserCredentials|credensiaj utent]]',
);
/** Portuguese (português)
* @author Giro720
* @author Hamilton Abreu
* @author Lijealso
* @author Malafaya
* @author Waldir
*/
$messages['pt'] = array(
'confirmaccount-newrequests' => "{{PLURAL:$1|'''um''' [[Special:ConfirmAccounts|pedido de conta]]|'''$1''' [[Special:ConfirmAccounts|pedidos de conta]]}} em aberto com correio electrónico confirmado. '''É necessária a sua atenção!'''",
'requestaccount-loginnotice' => "Para obter uma conta de utilizador, deverá '''[[Special:RequestAccount|pedi-la]]'''.",
'right-confirmaccount' => 'Ver a [[Special:ConfirmAccounts|fila de contas pedidas]]',
'right-requestips' => 'Ver os endereços IP do requerente ao processar contas pedidas',
'right-lookupcredentials' => 'Ver [[Special:UserCredentials|credenciais de utilizador]]',
);
/** Brazilian Portuguese (português do Brasil)
* @author Eduardo.mps
* @author Giro720
* @author Helder.wiki
* @author Heldergeovane
* @author Luckas Blade
* @author 555
*/
$messages['pt-br'] = array(
'confirmaccount-newrequests' => "Há, neste momento, '''$1''' [[Special:ConfirmAccounts|{{PLURAL:$1|solicitação|solicitações}} pendentes de contas]]. '''Seus cuidados são necessários!''",
'requestaccount-loginnotice' => "Para ter uma conta de usuário, será necessário '''[[Special:RequestAccount|solicitá-la]]'''.",
'right-confirmaccount' => 'Ver a [[Special:ConfirmAccounts|fila de contas solicitadas]]',
'right-requestips' => 'Ver os endereços IP do requerente durante a gestão de contas pedidas',
'right-lookupcredentials' => 'Ver [[Special:UserCredentials|credenciais de usuário]]',
);
/** Russian (русский)
* @author Ferrer
* @author Ignatus
* @author Kaganer
* @author Kv75
* @author Lockal
* @author MaxSem
* @author Rubin
* @author Sasha Blashenkov
* @author Александр Сигачёв
*/
$messages['ru'] = array(
'confirmaccount-newrequests' => "$1 {{PLURAL:$1|[[Special:ConfirmAccounts|открытое письмо подтверждено]]|[[Special:ConfirmAccounts|открытых письма подтверждены]]|[[Special:ConfirmAccounts|открытых писем подтверждены]]}}. '''Обратите ваше внимание!'''",
'requestaccount-loginnotice' => 'Чтобы получить учётную запись, вы должны её [[Special:RequestAccount|запросить]].',
'right-confirmaccount' => 'просмотр [[Special:ConfirmAccounts|запросов на создание учётных записей]]',
'right-requestips' => 'Просмотр IP-адресов авторов запросов на создание учётных записей',
'right-lookupcredentials' => 'просмотр [[Special:UserCredentials|удостоверяющей информации об участниках]]',
);
/** Slovak (slovenčina)
* @author Helix84
* @author Teslaton
*/
$messages['sk'] = array(
'confirmaccount-newrequests' => "Momentálne {{PLURAL:$1|je jedna otvorená|sú '''$1''' otvorené|je '''$1''' otvorených}} [[Special:ConfirmAccounts|{{PLURAL:$1|žiadosť o účet|žiadosti o účet|žiadostí o účet}}]]. '''Vyžaduje sa vaša pozornosť!'''",
'requestaccount-loginnotice' => "Aby ste dostali používateľský účet, musíte '''[[Special:RequestAccount|oň požiadať]]'''.",
'right-confirmaccount' => 'Zobraziť [[Special:ConfirmAccounts|front žiadostí o účet]]',
'right-requestips' => 'Zobraziť IP adresu žiadateľa pri spracovaní žiadostí o účet',
'right-lookupcredentials' => 'Zobraziť [[Special:UserCredentials|údaje používateľa]]',
);
/** Seeltersk (Seeltersk)
* @author Pyt
*/
$messages['stq'] = array(
'confirmaccount-newrequests' => "'''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|eepenen, E-Mail bestäätigden Benutserkontenandraach täift]]|[[Special:ConfirmAccounts|eepene, E-Mail bestäätigde Benutserkontenandraage täiwe]]}} ap Beoarbaidenge.", # Fuzzy
'requestaccount-loginnotice' => "Uum n näi Benutserkonto tou kriegen, moast du
der uum '''[[{{ns:special}}:RequestAccount|fräigje]]'''.", # Fuzzy
);
/** Sundanese (Basa Sunda)
* @author Irwangatot
* @author Kandar
*/
$messages['su'] = array(
'requestaccount-loginnotice' => "Pikeun miboga rekening pamaké, anjeun kudu '''[[Special:RequestAccount|daptar heula]]'''.",
);
/** Swedish (svenska)
* @author Boivie
* @author Diupwijk
* @author Fluff
* @author Jon Harald Søby
* @author Lejonel
* @author M.M.S.
* @author Najami
* @author Per
* @author WikiPhoenix
*/
$messages['sv'] = array(
'confirmaccount-newrequests' => "'''$1''' öppnade e-post bekräftade att [[Special:ConfirmAccounts|{{PLURAL:$1|kontoansökning väntar på att behandlas|kontoansökningar väntar på att behandlas}}]]. '''Din uppmärksamhet krävs!'''",
'requestaccount-loginnotice' => "För att få ett användarkonto måste du '''[[Special:RequestAccount|ansöka om det]]'''.",
'right-confirmaccount' => 'Visa [[Special:ConfirmAccounts|kön av kontoansökningar]]',
'right-requestips' => 'Visa sökandens IP-adress vid behandling av kontoansökningar',
'right-lookupcredentials' => 'Visa [[Special:UserCredentials|användaruppgifter]]',
);
/** Telugu (తెలుగు)
* @author Chaduvari
* @author Kiranmayee
* @author Veeven
* @author వైజాసత్య
*/
$messages['te'] = array(
'confirmaccount-newrequests' => "ప్రస్తుతం '''$1''' {{PLURAL:$1|[[Special:ConfirmAccounts|ఖాతా అభ్యర్థన]]|[[Special:ConfirmAccounts|ఖాతా అభ్యర్థనలు]]}} వేచి{{PLURAL:$1|వుంది|వున్నాయి}}.", # Fuzzy
'requestaccount-loginnotice' => "ఖాతా పొందడానికి, మీరు తప్పనిసరిగా '''[[Special:RequestAccount|అభ్యర్థించాలి]]'''.",
);
/** Tajik (Cyrillic script) (тоҷикӣ)
* @author Ibrahim
*/
$messages['tg-cyrl'] = array(
'requestaccount-loginnotice' => "Барои дастрас кардани ҳисоби корбарӣ, шумо бояд '''[[Special:RequestAccount|дархост]]''' кунед.",
);
/** Tajik (Latin script) (tojikī)
* @author Liangent
*/
$messages['tg-latn'] = array(
'requestaccount-loginnotice' => "Baroi dastras kardani hisobi korbarī, şumo bojad '''[[Special:RequestAccount|darxost]]''' kuned.",
);
/** Thai (ไทย)
* @author Ans
* @author Harley Hartwell
* @author Octahedron80
* @author Passawuth
*/
$messages['th'] = array(
'requestaccount-loginnotice' => "เพื่อที่จะได้มาซึ่งบัญชีผู้ใช้ใหม่ คุณต้อง'''[[Special:RequestAccount|ทำการขอบัญชีผู้ใช้]]'''",
);
/** Tagalog (Tagalog)
* @author AnakngAraw
*/
$messages['tl'] = array(
'confirmaccount-newrequests' => "'''$1''' bukas na e-liham ang natiyak [[Special:ConfirmAccounts|ang akawnt na {{PLURAL:$1|hiniling ay nakabinbin|mga hiniling ay nakabinbin}}]]. '''Kailangan ang pagpansin mo!'''",
'requestaccount-loginnotice' => "Upang makatanggap ng isang akawnt ng tagagamit, dapat kang '''[[Special:RequestAccount|humiling ng isa]]'''.",
'right-confirmaccount' => 'Tingnan ang [[Special:ConfirmAccounts|pila na may hinihiling na mga akawnt]]',
'right-requestips' => 'Tingnan ang mga adres ng IP ng humihiling habang isinasagawa ang hinihiling na mga akawnt',
'right-lookupcredentials' => 'Tingnan ang [[Special:UserCredentials|mga kredensyal ng tagagamit]]',
);
/** Turkish (Türkçe)
* @author Homonihilis
* @author Karduelis
* @author Mach
* @author Suelnur
* @author Vito Genovese
*/
$messages['tr'] = array(
'confirmaccount-newrequests' => "'''$1''' açık e-postası doğrulanmış [[Special:ConfirmAccounts|hesap {{PLURAL:$1|istek|istek}}]] beklemede", # Fuzzy
'requestaccount-loginnotice' => "Bir kullanıcı hesabı almak için, '''[[Special:RequestAccount|istekte bulunmanız]]''' gerekmektedir.",
'right-confirmaccount' => '[[Special:ConfirmAccounts|Hesap istekleri grubunu]] görür',
'right-requestips' => 'İstenen hesaplarla ilgili işlem yaparken istek sahibinin IP adresini görür',
'right-lookupcredentials' => '[[Special:UserCredentials|Kullanıcı referanslarını]] görür',
);
/** Cantonese (粵語)
*/
$messages['yue'] = array(
'requestaccount-loginnotice' => "要拎一個用戶戶口,你一定要'''[[Special:RequestAccount|請求一個]]'''。",
);
/** Simplified Chinese (中文(简体)‎)
* @author Chenxiaoqino
* @author Hydra
* @author Kuailong
* @author Mark85296341
* @author Wilsonmess
*/
$messages['zh-hans'] = array(
'requestaccount-loginnotice' => "要取得个用户账户,您一定要'''[[Special:RequestAccount|请求一个]]'''。",
'right-confirmaccount' => '查看 [[Special:ConfirmAccounts|请求帐户的队列]]',
'right-requestips' => '在处理请求的帐户查看请求者的 IP 地址',
'right-lookupcredentials' => '查看 [[Special:UserCredentials|用户凭据]]',
);
/** Traditional Chinese (中文(繁體)‎)
* @author Mark85296341
* @author Waihorace
*/
$messages['zh-hant'] = array(
'confirmaccount-newrequests' => "'''$1'''開啟電郵確認[[Special:ConfirmAccounts|{{PLURAL:$1|帳戶請求|多個帳戶請求}}]]待審中", # Fuzzy
'requestaccount-loginnotice' => "要取得個使用者帳號,您一定要'''[[Special:RequestAccount|請求一個]]'''。",
'right-confirmaccount' => '查看[[Special:ConfirmAccounts|待審帳戶隊列]]',
'right-requestips' => '在處理帳戶請求時查看請求者的IP地址',
'right-lookupcredentials' => '查看[[Special:UserCredentials|用戶憑據]]',
);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/* RC pending account request notice */
.mw-confirmaccount-bar {
padding: 3px;
margin: 5px;
border: 1px solid #990000;
background-color: #f9f9f9;
}
.mw-confirmaccount-type-0 {
background-color: #f0fff0;
}
.mw-confirmaccount-body-0 {
background-color: #f9f9f9;
}
.mw-confirmaccount-type-1 {
background-color: #f0ffff;
}
.mw-confirmaccount-body-1 {
background-color: #f9f9f9;
}

View file

@ -0,0 +1,846 @@
<?php
class ConfirmAccountsPage extends SpecialPage {
protected $queueType = -1;
protected $acrID = 0;
protected $file = '';
protected $showHeld = false;
protected $showRejects = false;
protected $showStale = false;
/** @var UserAccountRequest */
protected $accountReq;
protected $reqUsername;
protected $reqType;
protected $reqBio;
/** @var array */
protected $reqAreas;
protected $submitType;
protected $reason;
function __construct() {
parent::__construct( 'ConfirmAccounts', 'confirmaccount' );
}
function execute( $par ) {
global $wgAccountRequestTypes;
$reqUser = $this->getUser();
$request = $this->getRequest();
if ( !$reqUser->isAllowed( 'confirmaccount' ) ) {
throw new PermissionsError( 'confirmaccount' );
} elseif ( !$reqUser->getID() ) {
throw new PermissionsError( 'user' );
}
$this->setHeaders();
# Use the special page param to act as a super type.
# Convert this to its integer form.
$this->queueType = -1;
foreach ( $wgAccountRequestTypes as $i => $params ) {
if ( $params[0] === $par ) {
$this->queueType = $i;
break;
}
}
# User account request ID
$this->acrID = $request->getIntOrNull( 'acrid' );
# Attachment file name to view
$this->file = $request->getVal( 'file' );
# Held requests hidden by default
$this->showHeld = $request->getBool( 'wpShowHeld' );
# Show stale requests
$this->showStale = $request->getBool( 'wpShowStale' );
# For viewing rejected requests (stale requests count as rejected)
$this->showRejects = $request->getBool( 'wpShowRejects' );
// Showing a file
if ( $this->file ) {
$this->showFile( $this->file );
return; // nothing else to do
// Showing or confirming an account request
} elseif ( $this->acrID ) {
# Load areas user plans to be active in...
$this->reqAreas = array();
foreach ( ConfirmAccount::getUserAreaConfig() as $name => $conf ) {
$formName = "wpArea-" . htmlspecialchars( str_replace( ' ', '_', $name ) );
$this->reqAreas[$name] = $request->getInt( $formName, -1 );
}
# Load in the UserAccountRequest obj
$this->loadAccountRequest( $this->acrID, $request->wasPosted() );
if ( $request->wasPosted() ) {
# For renaming to alot for collisions with other local requests
# that were accepted and added to some global $wgAuth system first
$this->reqUsername = trim( $request->getText( 'wpNewName' ) );
# For changing the position recieved by requester
$this->reqType = $request->getIntOrNull( 'wpType' );
if ( !isset( $wgAccountRequestTypes[$this->reqType] ) ) {
$this->reqType = null;
}
# For removing private info or such from bios
$this->reqBio = $request->getText( 'wpNewBio' );
# Action the admin is taking and why
$this->submitType = $request->getVal( 'wpSubmitType' );
$this->reason = $request->getText( 'wpReason' );
# Check if this is a valid submission...
$token = $request->getVal( 'wpEditToken' );
if ( $reqUser->matchEditToken( $token, $this->acrID ) ) {
$this->doAccountConfirmSubmit();
} else {
$this->showAccountConfirmForm( $this->msg( 'sessionfailure' )->escaped() );
}
} else {
$this->showAccountConfirmForm();
}
// Showing all account requests in a queue
} elseif ( $this->queueType != -1 ) {
$this->showList();
// Showing all account request queues
} else {
$this->showQueues();
}
// Show what queue we are in and links to the others
$this->addQueueSubtitleLinks();
$this->getOutput()->addModules( 'ext.confirmAccount' ); // CSS
}
protected function addQueueSubtitleLinks() {
$titleObj = $this->getFullTitle();
# Show other sub-queue links. Grey out the current one.
# When viewing a request, show them all.
if ( $this->acrID || $this->showStale || $this->showRejects || $this->showHeld ) {
$listLink = Linker::linkKnown(
$titleObj,
$this->msg( 'confirmaccount-showopen' )->escaped() );
} else {
$listLink = $this->msg( 'confirmaccount-showopen' )->escaped();
}
if ( $this->acrID || !$this->showHeld ) {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
Linker::makeKnownLinkObj(
$titleObj,
$this->msg( 'confirmaccount-showheld' )->escaped(),
'wpShowHeld=1'
)
) );
} else {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
$this->msg( 'confirmaccount-showheld' )->escaped()
) );
}
if ( $this->acrID || !$this->showRejects ) {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
Linker::makeKnownLinkObj( $titleObj,
$this->msg( 'confirmaccount-showrej' )->escaped(),
'wpShowRejects=1'
)
) );
} else {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
$this->msg( 'confirmaccount-showrej' )->escaped()
) );
}
if ( $this->acrID || !$this->showStale ) {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
Linker::makeKnownLinkObj( $titleObj,
$this->msg( 'confirmaccount-showexp' )->escaped(),
'wpShowStale=1'
)
) );
} else {
$listLink = $this->getLanguage()->pipeList( array(
$listLink,
$this->msg( 'confirmaccount-showexp' )->escaped()
) );
}
# Say what queue we are in...
if ( $this->queueType != -1 ) {
$viewall = Linker::makeKnownLinkObj(
$this->getTitle(), $this->msg( 'confirmaccount-all' )->escaped() );
$this->getOutput()->setSubtitle(
"<strong>" . $this->msg( 'confirmaccount-type' )->escaped() . " <i>" .
$this->msg( "confirmaccount-type-{$this->queueType}" )->escaped() .
"</i></strong> [{$listLink}] <strong>{$viewall}</strong>" );
}
}
protected function showQueues() {
global $wgAccountRequestTypes;
$out = $this->getOutput();
$out->addWikiMsg( 'confirmaccount-maintext' );
$out->wrapWikiMsg( "<p><strong>$1</strong></p>", 'confirmaccount-types' );
# List each queue and some information about it...
$out->addHTML( '<ul>' );
foreach ( $wgAccountRequestTypes as $i => $params ) {
$titleObj = SpecialPage::getTitleFor( 'ConfirmAccounts', $params[0] );
$counts = ConfirmAccount::getOpenRequestCount( $i );
$open = '<b>';
$open .= Linker::makeKnownLinkObj(
$titleObj,
$this->msg( 'confirmaccount-q-open' )->escaped(),
'wpShowHeld=0'
);
$open .= '</b> [' . $counts['open'] . ']';
$held = Linker::makeKnownLinkObj(
$titleObj,
$this->msg( 'confirmaccount-q-held' )->escaped(),
'wpShowHeld=1'
);
$held .= ' [' . $counts['held'] . ']';
$rejects = Linker::makeKnownLinkObj(
$titleObj,
$this->msg( 'confirmaccount-q-rej' )->escaped(),
'wpShowRejects=1'
);
$rejects .= ' [' . $counts['rejected'] . ']';
$stale = '<i>';
$stale .= Linker::makeKnownLinkObj(
$titleObj,
$this->msg( 'confirmaccount-q-stale' )->escaped(),
'wpShowStale=1'
);
$stale .= '</i>';
$out->addHTML( "<li><i>" . $this->msg( "confirmaccount-type-$i" )->escaped() . "</i>" );
$out->addHTML( $this->msg( 'word-separator' )->plain() );
$params = $this->getLanguage()->pipeList( array( $open, $held, $rejects, $stale ) );
$out->addHTML( $this->msg( 'parentheses' )->rawParams( $params )->escaped() );
$out->addHTML( '</li>' );
}
$out->addHTML( '</ul>' );
}
/**
* @param $msg string
*/
protected function showAccountConfirmForm( $msg = '' ) {
global $wgAccountRequestTypes;
$out = $this->getOutput();
$reqUser = $this->getUser();
$titleObj = $this->getFullTitle();
$accountReq = $this->accountReq; // convenience
if ( !$accountReq || $accountReq->isDeleted() && !$this->showRejects ) {
$out->addHTML( $this->msg( 'confirmaccount-badid' )->escaped() );
$out->returnToMain( true, $titleObj );
return;
}
# Output any failure message
if ( $msg != '' ) {
$out->addHTML( '<div class="errorbox">' . $msg . '</div><div class="visualClear"></div>' );
}
$out->addWikiMsg( 'confirmaccount-text' );
$rejectTimestamp = $accountReq->getRejectTimestamp();
$heldTimestamp = $accountReq->getHeldTimestamp();
$reason = strlen( $accountReq->getHandlingComment() )
? htmlspecialchars( $accountReq->getHandlingComment() )
: $this->msg( 'confirmaccount-noreason' )->escaped();
$adminId = $accountReq->getHandlingUser();
if ( $rejectTimestamp ) {
$datim = $this->getLanguage()->timeanddate( $rejectTimestamp, true );
$date = $this->getLanguage()->date( $rejectTimestamp, true );
$time = $this->getLanguage()->time( $rejectTimestamp, true );
# Auto-rejected requests have a user ID of zero
if ( $adminId ) {
$out->addHTML( '<p><b>' . $this->msg( 'confirmaccount-reject',
User::whoIs( $adminId ), $datim, $date, $time )->parse() . '</b></p>' );
$out->addHTML( '<p><strong>' . $this->msg( 'confirmaccount-rational' )->escaped() . '</strong><i> ' .
$reason . '</i></p>' );
} else {
$out->addHTML( "<p><i> $reason </i></p>" );
}
} elseif ( $heldTimestamp ) {
$datim = $this->getLanguage()->timeanddate( $heldTimestamp, true );
$date = $this->getLanguage()->date( $heldTimestamp, true );
$time = $this->getLanguage()->time( $heldTimestamp, true );
$out->addHTML( '<p><b>' . $this->msg( 'confirmaccount-held',
User::whoIs( $adminId ), $datim, $date, $time )->parse() . '</b></p>' );
$out->addHTML( '<p><strong>' . $this->msg( 'confirmaccount-rational' )->escaped() . '</strong><i> ' .
$reason . '</i></p>' );
}
$form = Xml::openElement( 'form', array( 'method' => 'post', 'name' => 'accountconfirm',
'action' => $titleObj->getLocalUrl() ) );
$form .= "<fieldset>";
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-user' )->escaped() . '</legend>';
$form .= '<table cellpadding=\'4\'>';
$form .= "<tr><td>" . Xml::label( $this->msg( 'username' )->text(), 'wpNewName' ) . "</td>";
$form .= "<td>" . Xml::input( 'wpNewName', 30, $this->reqUsername, array( 'id' => 'wpNewName' ) ) . "</td></tr>\n";
$econf = '';
if ( $accountReq->getEmailAuthTimestamp() ) {
$econf = ' <strong>' . $this->msg( 'confirmaccount-econf' )->escaped() . '</strong>';
}
$form .= "<tr><td>" . $this->msg( 'confirmaccount-email' )->escaped() . "</td>";
$form .= "<td>" . htmlspecialchars( $accountReq->getEmail() ) . $econf . "</td></tr>\n";
if ( count( $wgAccountRequestTypes ) > 1 ) {
$options = array();
$form .= "<tr><td><strong>" . $this->msg( 'confirmaccount-reqtype' )->escaped() . "</strong></td><td>";
foreach ( $wgAccountRequestTypes as $i => $params ) {
$options[] = Xml::option( $this->msg( "confirmaccount-pos-$i" )->text(), $i, ( $i == $this->reqType ) );
}
$form .= Xml::openElement( 'select', array( 'name' => "wpType" ) );
$form .= implode( "\n", $options );
$form .= Xml::closeElement( 'select' ) . "\n";
$form .= "</td></tr>\n";
}
$form .= '</table></fieldset>';
$userAreas = ConfirmAccount::getUserAreaConfig();
if ( $this->hasItem( 'AreasOfInterest' ) && count( $userAreas ) > 0 ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-areas' )->escaped() . '</legend>';
$form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
$form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
$count = 0;
foreach ( $userAreas as $name => $conf ) {
$count++;
if ( $count > 5 ) {
$form .= "</tr><tr valign='top'>";
$count = 1;
}
$formName = "wpArea-" . htmlspecialchars( str_replace( ' ', '_', $name ) );
if ( $conf['project'] != '' ) {
$pg = Linker::linkKnown(
Title::newFromText( $conf['project'] ),
$this->msg( 'requestaccount-info' )->escaped()
);
} else {
$pg = '';
}
$form .= "<td>" .
Xml::checkLabel( $name, $formName, $formName, $this->reqAreas[$name] > 0 ) .
" {$pg}</td>\n";
}
$form .= "</tr></table></div>";
$form .= '</fieldset>';
}
if ( $this->hasItem( 'Biography' ) || $this->hasItem( 'RealName' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-person' )->escaped() . '</legend>';
if ( $this->hasItem( 'RealName' ) ) {
$form .= '<table cellpadding=\'4\'>';
$form .= "<tr><td>" . $this->msg( 'confirmaccount-real' )->escaped() . "</td>";
$form .= "<td>" . htmlspecialchars( $accountReq->getRealName() ) . "</td></tr>\n";
$form .= '</table>';
}
if ( $this->hasItem( 'Biography' ) ) {
$form .= "<p>" . $this->msg( 'confirmaccount-bio' )->escaped() . "\n";
$form .= "<textarea tabindex='1' name='wpNewBio' id='wpNewBio' rows='12' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
htmlspecialchars( $this->reqBio ) .
"</textarea></p>\n";
}
$form .= '</fieldset>';
}
if ( $this->hasItem( 'CV' ) || $this->hasItem( 'Notes' ) || $this->hasItem( 'Links' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-other' )->escaped() . '</legend>';
if ( $this->hasItem( 'CV' ) ) {
$form .= '<p>' . $this->msg( 'confirmaccount-attach' )->escaped() . ' ';
if ( $accountReq->getFileName() !== null ) {
$form .= Linker::makeKnownLinkObj( $titleObj,
htmlspecialchars( $accountReq->getFileName() ),
'file=' . $accountReq->getFileStorageKey() );
} else {
$form .= $this->msg( 'confirmaccount-none-p' )->escaped();
}
}
if ( $this->hasItem( 'Notes' ) ) {
$form .= "</p><p>" . $this->msg( 'confirmaccount-notes' )->escaped() . "\n";
$form .= "<textarea tabindex='1' readonly='readonly' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%'>" .
htmlspecialchars( $accountReq->getNotes() ) .
"</textarea></p>\n";
}
if ( $this->hasItem( 'Links' ) ) {
$form .= "<p>" . $this->msg( 'confirmaccount-urls' )->escaped() . "</p>\n";
$form .= self::parseLinks( $accountReq->getUrls() );
}
$form .= '</fieldset>';
}
if ( $reqUser->isAllowed( 'requestips' ) ) {
$blokip = SpecialPage::getTitleFor( 'Block' );
$link = Linker::makeKnownLinkObj(
$blokip,
$this->msg( 'blockip' )->escaped(),
'ip=' . $accountReq->getIP() . '&wpCreateAccount=1'
);
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-ip' )->escaped() . '</legend>';
$wordSeparator = $this->msg( 'word-separator' )->plain();
$form .= "<p>";
// @todo FIXME: Bad i18n. Should probably be something like
// "confirmaccount-ip $1 ($2)" to get rid of this mess.
$form .= $this->msg( 'confirmaccount-ip' )->escaped();
$form .= $wordSeparator;
$form .= htmlspecialchars( $accountReq->getIP() );
$form .= $wordSeparator;
$form .= $this->msg( 'parentheses' )->rawParams( $link )->escaped();
$form .= "</p>\n";
if ( $accountReq->getXFF() ) {
$form .= "<p>" . $this->msg( 'confirmaccount-xff' )->escaped() .
$wordSeparator . htmlspecialchars( $accountReq->getXFF() ) . "</p>\n";
}
if ( $accountReq->getAgent() ) {
$form .= "<p>" . $this->msg( 'confirmaccount-agent' )->escaped() .
$wordSeparator . htmlspecialchars( $accountReq->getAgent() ) . "</p>\n";
}
$form .= '</fieldset>';
}
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-legend' )->escaped() . '</legend>';
$form .= "<strong>" . $this->msg( 'confirmaccount-confirm' )->parse() . "</strong>\n";
$form .= "<table cellpadding='5'><tr>";
$form .= "<td>" . Xml::radio( 'wpSubmitType', 'accept', $this->submitType == 'accept',
array( 'id' => 'submitCreate', 'onclick' => 'document.getElementById("wpComment").style.display="block"' ) );
$form .= ' ' . Xml::label( $this->msg( 'confirmaccount-create' )->text(), 'submitCreate' ) . "</td>\n";
$form .= "<td>" . Xml::radio( 'wpSubmitType', 'reject', $this->submitType == 'reject',
array( 'id' => 'submitDeny', 'onclick' => 'document.getElementById("wpComment").style.display="block"' ) );
$form .= ' ' . Xml::label( $this->msg( 'confirmaccount-deny' )->text(), 'submitDeny' ) . "</td>\n";
$form .= "<td>" . Xml::radio( 'wpSubmitType', 'hold', $this->submitType == 'hold',
array( 'id' => 'submitHold', 'onclick' => 'document.getElementById("wpComment").style.display="block"' ) );
$form .= ' ' . Xml::label( $this->msg( 'confirmaccount-hold' )->text(), 'submitHold' ) . "</td>\n";
$form .= "<td>" . Xml::radio( 'wpSubmitType', 'spam', $this->submitType == 'spam',
array( 'id' => 'submitSpam', 'onclick' => 'document.getElementById("wpComment").style.display="none"' ) );
$form .= ' ' . Xml::label( $this->msg( 'confirmaccount-spam' )->text(), 'submitSpam' ) . "</td>\n";
$form .= "</tr></table>";
$form .= "<div id='wpComment'><p>" . $this->msg( 'confirmaccount-reason' )->escaped() . "</p>\n";
$form .= "<p><textarea name='wpReason' id='wpReason' rows='3' cols='80' style='width:80%; display=block;'>" .
htmlspecialchars( $this->reason ) . "</textarea></p></div>\n";
$form .= "<p>" . Xml::submitButton( $this->msg( 'confirmaccount-submit' )->text() ) . "</p>\n";
$form .= '</fieldset>';
$form .= Html::Hidden( 'title', $titleObj->getPrefixedDBKey() ) . "\n";
$form .= Html::Hidden( 'action', 'reject' );
$form .= Html::Hidden( 'acrid', $accountReq->getId() );
$form .= Html::Hidden( 'wpShowRejects', $this->showRejects );
$form .= Html::Hidden( 'wpEditToken', $reqUser->getEditToken( $accountReq->getId() ) ) . "\n";
$form .= Xml::closeElement( 'form' );
$out->addHTML( $form );
global $wgMemc;
# Set a key to who is looking at this request.
# Have it expire in 10 minutes...
$key = wfMemcKey( 'acctrequest', 'view', $accountReq->getId() );
$wgMemc->set( $key, $reqUser->getID(), 60 * 10 );
}
protected function hasItem( $name ) {
global $wgConfirmAccountRequestFormItems;
return $wgConfirmAccountRequestFormItems[$name]['enabled'];
}
/**
* Show a private file requested by the visitor.
* @param $key string
*/
protected function showFile( $key ) {
global $wgConfirmAccountFSRepos;
$out = $this->getOutput();
$request = $this->getRequest();
$out->disable();
# We mustn't allow the output to be Squid cached, otherwise
# if an admin previews a private image, and it's cached, then
# a user without appropriate permissions can toddle off and
# nab the image, and Squid will serve it
$request->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
$request->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
$request->response()->header( 'Pragma: no-cache' );
$repo = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
$path = $repo->getZonePath( 'public' ) . '/' .
UserAccountRequest::relPathFromKey( $key );
$repo->streamFile( $path );
}
protected function doAccountConfirmSubmit() {
if ( !$this->accountReq ) {
$this->showAccountConfirmForm( $this->msg( 'confirmaccount-badid' )->escaped() );
return;
}
# Build submission object...
$areaSet = array(); // make a simple list of interests
foreach ( $this->reqAreas as $area => $val ) {
if ( $val > 0 ) {
$areaSet[] = $area;
}
}
$submission = new AccountConfirmSubmission(
$this->getUser(),
$this->accountReq,
array(
'userName' => $this->reqUsername,
'bio' => $this->reqBio,
'type' => $this->reqType,
'areas' => $areaSet,
'action' => $this->submitType,
'reason' => $this->reason
)
);
# Actually submit!
list( $status, $msg ) = $submission->submit( $this->getContext() );
# Check for error messages
if ( $status !== true ) {
$this->showAccountConfirmForm( $msg );
return;
}
# Done!
$this->showSuccess( $this->submitType, $this->reqUsername, (array)$msg );
}
/**
* Get requested account request row and load some fields
* @param $id int
* @param $wasPosted bool
* @return void
*/
protected function loadAccountRequest( $id, $wasPosted ) {
$from = $wasPosted ? 'dbmaster' : 'dbslave';
$this->accountReq = UserAccountRequest::newFromId( $id, $from );
# Check if parameters are to be overridden
if ( $this->accountReq ) {
$this->reqUsername = ( $this->reqUsername != '' )
? $this->reqUsername // overriden by admin
: $this->accountReq->getName();
$this->reqBio = ( $this->reqBio != '' )
? $this->reqBio // overriden by admin
: $this->accountReq->getBio();
$this->reqType = !is_null( $this->reqType )
? $this->reqType // overriden by admin
: $this->accountReq->getType();
$origAreas = $this->accountReq->getAreas();
foreach ( $this->reqAreas as $area => $within ) {
# If admin didn't set any of these checks, go back to how the user set them.
# On GET requests, the admin probably didn't set anything.
if ( $within == -1 ) {
if ( in_array( $area, $origAreas ) ) {
$this->reqAreas[$area] = 1;
} else {
$this->reqAreas[$area] = 0;
}
}
}
}
}
/**
* Extract a list of all recognized HTTP links in the text.
* @param string $text
* @return string $linkList, list of clickable links
*/
public static function parseLinks( $text ) {
# Don't let this get flooded
$max = 10;
$count = 0;
$linkList = '';
# Normalize space characters
$text = str_replace( array( "\r", "\t" ), array( "\n", " " ), htmlspecialchars( $text ) );
# Split out each line as a link
$lines = explode( "\n", $text );
foreach ( $lines as $line ) {
$links = explode( " ", $line, 2 );
$link = $links[0];
# Any explanation text is not part of the link...
$extra = isset( $links[1] ) ? ' ' . $links[1] : '';
if ( strpos( $link, '.' ) ) {
// @FIXME: other protocals
$link = ( strpos( $link, 'http://' ) === false ) ? 'http://' . $link : $link;
$linkList .= "<li><a href='$link'>$link</a>$extra</li>\n";
}
$count++;
if ( $count >= $max )
break;
}
if ( $linkList == '' ) {
$linkList = wfMessage( 'confirmaccount-none-p' )->escaped();
} else {
$linkList = "<ul>{$linkList}</ul>";
}
return $linkList;
}
/**
* @param $submitType string
* @param $name string User name
* @param $errors array
*/
protected function showSuccess( $submitType, $name = null, $errors = array() ) {
$out = $this->getOutput();
$out->setPagetitle( $this->msg( 'actioncomplete' )->escaped() );
if ( $this->submitType == 'accept' ) {
$out->addWikiMsg( 'confirmaccount-acc', $name );
} elseif ( $this->submitType == 'reject' || $this->submitType == 'spam' ) {
$out->addWikiMsg( 'confirmaccount-rej' );
} else {
$out->redirect( $this->getFullTitle()->getFullUrl() );
return;
}
# Output any errors
foreach ( $errors as $error ) {
$out->addHTML( '<p>' . $error . '</p>' );
}
# Give link to see other requests
$out->returnToMain( true, $this->getFullTitle() );
}
protected function showList() {
$out = $this->getOutput();
# Output the list
$pager = new ConfirmAccountsPager( $this, array(),
$this->queueType, $this->showRejects, $this->showHeld, $this->showStale );
if ( $pager->getNumRows() ) {
if ( $this->showStale ) {
$out->addWikiMsg( 'confirmaccount-list3' );
} elseif ( $this->showRejects ) {
$out->addWikiMsg( 'confirmaccount-list2' );
} else {
$out->addWikiMsg( 'confirmaccount-list' );
}
$out->addHTML( $pager->getNavigationBar() );
$out->addHTML( $pager->getBody() );
$out->addHTML( $pager->getNavigationBar() );
} else {
if ( $this->showRejects ) {
$out->addWikiMsg( 'confirmaccount-none-r' );
} elseif ( $this->showStale ) {
$out->addWikiMsg( 'confirmaccount-none-e' );
} elseif ( $this->showHeld ) {
$out->addWikiMsg( 'confirmaccount-none-h' );
} else {
$out->addWikiMsg( 'confirmaccount-none-o' );
}
}
# Every 30th view, prune old deleted items
if ( 0 == mt_rand( 0, 29 ) ) {
ConfirmAccount::runAutoMaintenance();
}
}
/**
* @param $row
* @return string
*/
public function formatRow( $row ) {
global $wgMemc;
if ( $this->showRejects || $this->showStale ) {
$link = Linker::makeKnownLinkObj(
$this->getFullTitle(),
$this->msg( 'confirmaccount-review' )->escaped(),
'acrid=' . (int)$row->acr_id . '&wpShowRejects=1' );
} else {
$link = Linker::makeKnownLinkObj(
$this->getFullTitle(),
$this->msg( 'confirmaccount-review' )->escaped(),
'acrid=' . (int)$row->acr_id );
}
$time = $this->getLanguage()->timeanddate( wfTimestamp( TS_MW, $row->acr_registration ), true );
$r = "<li class='mw-confirmaccount-type-{$this->queueType}'>";
$r .= $time . " (<strong>{$link}</strong>)";
# Auto-rejected accounts have a user ID of zero
if ( $row->acr_rejected && $row->acr_user ) {
$datim = $this->getLanguage()->timeanddate( wfTimestamp( TS_MW, $row->acr_rejected ), true );
$date = $this->getLanguage()->date( wfTimestamp( TS_MW, $row->acr_rejected ), true );
$time = $this->getLanguage()->time( wfTimestamp( TS_MW, $row->acr_rejected ), true );
$r .= ' <b>' . $this->msg( 'confirmaccount-reject', $row->user_name, $datim, $date, $time )->parse() . '</b>';
} elseif ( $row->acr_held && !$row->acr_rejected ) {
$datim = $this->getLanguage()->timeanddate( wfTimestamp( TS_MW, $row->acr_held ), true );
$date = $this->getLanguage()->date( wfTimestamp( TS_MW, $row->acr_held ), true );
$time = $this->getLanguage()->time( wfTimestamp( TS_MW, $row->acr_held ), true );
$r .= ' <b>' . $this->msg( 'confirmaccount-held', User::whoIs( $row->acr_user ), $datim, $date, $time )->parse() . '</b>';
}
# Check if someone is viewing this request
$key = wfMemcKey( 'acctrequest', 'view', $row->acr_id );
$value = $wgMemc->get( $key );
if ( $value ) {
$r .= ' <b>' . $this->msg( 'confirmaccount-viewing', User::whoIs( $value ) )->parse() . '</b>';
}
$r .= "<br /><table class='mw-confirmaccount-body-{$this->queueType}' cellspacing='1' cellpadding='3' border='1' width='100%'>";
if ( $this->hasItem( 'UserName' ) ) {
$r .= '<tr><td><strong>' . $this->msg( 'confirmaccount-name' )->escaped() . '</strong></td><td width=\'100%\'>' .
htmlspecialchars( $row->acr_name ) . '</td></tr>';
}
if ( $this->hasItem( 'RealName' ) ) {
$hasCV = $row->acr_filename
? ' <strong>' . $this->msg( 'confirmaccount-withcv' )->escaped() . '</strong>'
: '';
$r .= '<tr><td><strong>' . $this->msg( 'confirmaccount-real-q' )->escaped() . '</strong></td><td width=\'100%\'>' .
htmlspecialchars( $row->acr_real_name ) . $hasCV . '</td></tr>';
}
$econf = $row->acr_email_authenticated
? ' <strong>' . $this->msg( 'confirmaccount-econf' )->escaped() . '</strong>'
: '';
$r .= '<tr><td><strong>' . $this->msg( 'confirmaccount-email-q' )->escaped() . '</strong></td><td width=\'100%\'>' .
htmlspecialchars( $row->acr_email ) . $econf . '</td></tr>';
# Truncate this, blah blah...
$bio = htmlspecialchars( $row->acr_bio );
$preview = $this->getLanguage()->truncate( $bio, 400, '' );
if ( strlen( $preview ) < strlen( $bio ) ) {
$preview = substr( $preview, 0, strrpos( $preview, ' ' ) );
$preview .= " . . .";
}
$r .= '<tr><td><strong>' . $this->msg( 'confirmaccount-bio-q' )->escaped() .
'</strong></td><td width=\'100%\'><i>' . $preview . '</i></td></tr>';
$r .= '</table>';
$r .= '</li>';
return $r;
}
}
/**
* Query to list out pending accounts
*/
class ConfirmAccountsPager extends ReverseChronologicalPager {
public $mForm, $mConds;
function __construct(
$form, $conds, $type, $rejects = false, $showHeld = false, $showStale = false
) {
$this->mForm = $form;
$this->mConds = $conds;
$this->mConds['acr_type'] = $type;
$this->rejects = $rejects;
$this->stale = $showStale;
if ( $rejects || $showStale ) {
$this->mConds['acr_deleted'] = 1;
} else {
$this->mConds['acr_deleted'] = 0;
if ( $showHeld ) {
$this->mConds[] = 'acr_held IS NOT NULL';
} else {
$this->mConds[] = 'acr_held IS NULL';
}
}
parent::__construct();
# Treat 20 as the default limit, since each entry takes up 5 rows.
$urlLimit = $this->mRequest->getInt( 'limit' );
$this->mLimit = $urlLimit ? $urlLimit : 20;
}
/**
* @return Title
*/
function getTitle() {
return $this->mForm->getFullTitle();
}
/**
* @param $row
* @return string
*/
function formatRow( $row ) {
return $this->mForm->formatRow( $row );
}
/**
* @return string
*/
function getStartBody() {
if ( $this->getNumRows() ) {
return '<ul>';
} else {
return '';
}
}
/**
* @return string
*/
function getEndBody() {
if ( $this->getNumRows() ) {
return '</ul>';
} else {
return '';
}
}
/**
* @return array
*/
function getQueryInfo() {
$conds = $this->mConds;
$tables = array( 'account_requests' );
$fields = array( 'acr_id', 'acr_name', 'acr_real_name', 'acr_registration', 'acr_held',
'acr_user', 'acr_email', 'acr_email_authenticated', 'acr_bio', 'acr_notes',
'acr_urls', 'acr_filename', 'acr_type', 'acr_rejected' );
# Stale requests have a user ID of zero
if ( $this->stale ) {
$conds[] = 'acr_user = 0';
} elseif ( $this->rejects ) {
$conds[] = 'acr_user != 0';
$tables[] = 'user';
$conds[] = 'acr_user = user_id';
$fields[] = 'user_name';
$fields[] = 'acr_rejected';
}
return array(
'tables' => $tables,
'fields' => $fields,
'conds' => $conds
);
}
/**
* @return string
*/
function getIndexField() {
return 'acr_registration';
}
}

View file

@ -0,0 +1,397 @@
<?php
class RequestAccountPage extends SpecialPage {
protected $mUsername; // string
protected $mRealName; // string
protected $mEmail; // string
protected $mBio; // string
protected $mNotes; // string
protected $mUrls; // string
protected $mToS; // bool
protected $mType; // integer
/** @var Array */
protected $mAreas;
protected $mPrevAttachment; // string
protected $mForgotAttachment; // bool
protected $mSrcName; // string
protected $mFileSize; // integer
protected $mTempPath; // string
function __construct() {
parent::__construct( 'RequestAccount' );
}
function execute( $par ) {
global $wgAccountRequestTypes;
$reqUser = $this->getUser();
$request = $this->getRequest();
$block = ConfirmAccount::getAccountRequestBlock( $reqUser );
if ( $block ) {
throw new UserBlockedError( $block );
} elseif ( wfReadOnly() ) {
throw new ReadOnlyError();
}
$this->setHeaders();
//$this->mRealName = trim( $request->getText( 'wpRealName' ) );
# We may only want real names being used
$this->mUsername = !$this->hasItem( 'UserName' )
? $this->mRealName
: $request->getText( 'wpUsername' );
$this->mUsername = trim( $this->mUsername );
# CV/resume attachment...
if ( $this->hasItem( 'CV' ) ) {
$this->initializeUpload( $request );
$this->mPrevAttachment = $request->getText( 'attachment' );
$this->mForgotAttachment = $request->getBool( 'forgotAttachment' );
}
# Other identifying fields...
$this->mEmail = trim( $request->getText( 'wpEmail' ) );
//$this->mBio = $this->hasItem( 'Biography' ) ? $request->getText( 'wpBio', '' ) : '';
$this->mNotes = $this->hasItem( 'Notes' ) ? $request->getText( 'wpNotes', '' ) : '';
//$this->mUrls = $this->hasItem( 'Links' ) ? $request->getText( 'wpUrls', '' ) : '';
# Site terms of service...
$this->mToS = $this->hasItem( 'TermsOfService' ) ? $request->getBool( 'wpToS' ) : false;
# Which account request queue this belongs in...
$this->mType = $request->getInt( 'wpType' );
$this->mType = isset( $wgAccountRequestTypes[$this->mType] ) ? $this->mType : 0;
# Load areas user plans to be active in...
$this->mAreas = array();
if ( $this->hasItem( 'AreasOfInterest' ) ) {
foreach ( ConfirmAccount::getUserAreaConfig() as $name => $conf ) {
$formName = "wpArea-" . htmlspecialchars( str_replace( ' ', '_', $name ) );
$this->mAreas[$name] = $request->getInt( $formName, -1 );
}
}
# We may be confirming an email address here
$emailCode = $request->getText( 'wpEmailToken' );
$action = $request->getVal( 'action' );
if ( $request->wasPosted()
&& $reqUser->matchEditToken( $request->getVal( 'wpEditToken' ) ) )
{
$this->mPrevAttachment = $this->mPrevAttachment
? $this->mPrevAttachment
: $this->mSrcName;
$this->doSubmit();
} elseif ( $action == 'confirmemail' ) {
$this->confirmEmailToken( $emailCode );
} else {
$this->showForm();
}
$this->getOutput()->addModules( 'ext.confirmAccount' ); // CSS
}
protected function showForm( $msg = '', $forgotFile = 0 ) {
global $wgAccountRequestTypes, $wgMakeUserPageFromBio;
$reqUser = $this->getUser();
$this->mForgotAttachment = $forgotFile;
$out = $this->getOutput();
$out->setPagetitle( $this->msg( "requestaccount" )->escaped() );
# Output failure message if any
if ( $msg ) {
$out->addHTML( '<div class="errorbox">' . $msg . '</div><div class="visualClear"></div>' );
}
# Give notice to users that are logged in
if ( $reqUser->getID() ) {
$out->addWikiMsg( 'requestaccount-dup' );
}
$out->addWikiMsg( 'requestaccount-text' );
$form = Xml::openElement( 'form', array( 'method' => 'post', 'name' => 'accountrequest',
'action' => $this->getTitle()->getLocalUrl(), 'enctype' => 'multipart/form-data' ) );
$form .= '<fieldset><legend>' . $this->msg( 'requestaccount-leg-user' )->escaped() . '</legend>';
$form .= $this->msg( 'requestaccount-acc-text' )->parseAsBlock() . "\n";
$form .= '<table cellpadding=\'4\'>';
if ( $this->hasItem( 'UserName' ) ) {
$form .= "<tr><td>" . Xml::label( $this->msg( 'username' )->text(), 'wpUsername' ) . "</td>";
$form .= "<td>" . Xml::input( 'wpUsername', 30, $this->mUsername, array( 'id' => 'wpUsername' ) ) . "</td></tr>\n";
} else {
$form .= "<tr><td>" . $this->msg( 'username' )->escaped() . "</td>";
$form .= "<td>" . $this->msg( 'requestaccount-same' )->escaped() . "</td></tr>\n";
}
//$form .= "<tr><td>" . Xml::label( $this->msg( 'requestaccount-email' )->text(), 'wpEmail' ) . "</td>";
//$form .= "<td>" . Xml::input( 'wpEmail', 30, $this->mEmail, array( 'id' => 'wpEmail' ) ) . "</td></tr>\n";
if ( count( $wgAccountRequestTypes ) > 1 ) {
$form .= "<tr><td>" . $this->msg( 'requestaccount-reqtype' )->escaped() . "</td><td>";
$options = array();
foreach ( $wgAccountRequestTypes as $i => $params ) {
$options[] = Xml::option( $this->msg( "requestaccount-level-$i" )->text(), $i, ( $i == $this->mType ) );
}
$form .= Xml::openElement( 'select', array( 'name' => "wpType" ) );
$form .= implode( "\n", $options );
$form .= Xml::closeElement( 'select' ) . "\n";
$form .= '</td></tr>';
}
$form .= '</table></fieldset>';
$userAreas = ConfirmAccount::getUserAreaConfig();
if ( $this->hasItem( 'AreasOfInterest' ) && count( $userAreas ) > 0 ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'requestaccount-leg-areas' )->escaped() . '</legend>';
$form .= $this->msg( 'requestaccount-areas-text' )->parseAsBlock() . "\n";
$form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
$form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
$count = 0;
foreach ( $userAreas as $name => $conf ) {
$count++;
if ( $count > 5 ) {
$form .= "</tr><tr valign='top'>";
$count = 1;
}
$formName = "wpArea-" . htmlspecialchars( str_replace( ' ', '_', $name ) );
if ( $conf['project'] != '' ) {
$pg = Linker::link( Title::newFromText( $conf['project'] ),
$this->msg( 'requestaccount-info' )->escaped(), array(), array(), "known" );
} else {
$pg = '';
}
$form .= "<td>" .
Xml::checkLabel( $name, $formName, $formName, $this->mAreas[$name] > 0 ) .
" {$pg}</td>\n";
}
$form .= "</tr></table></div>";
$form .= '</fieldset>';
}
/*if ( $this->hasItem( 'Biography' ) || $this->hasItem( 'RealName' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'requestaccount-leg-person' )->escaped() . '</legend>';
if ( $this->hasItem( 'RealName' ) ) {
$form .= '<table cellpadding=\'4\'>';
$form .= "<tr><td>" . Xml::label( $this->msg( 'requestaccount-real' )->text(), 'wpRealName' ) . "</td>";
$form .= "<td>" . Xml::input( 'wpRealName', 35, $this->mRealName, array( 'id' => 'wpRealName' ) ) . "</td></tr>\n";
$form .= '</table>';
}
if ( $this->hasItem( 'Biography' ) ) {
if ( $wgMakeUserPageFromBio ) {
$form .= $this->msg( 'requestaccount-bio-text-i' )->parseAsBlock() . "\n";
}
$form .= $this->msg( 'requestaccount-bio-text' )->parseAsBlock() . "\n";
$form .= "<p>" . $this->msg( 'requestaccount-bio' )->parse() . "\n";
$form .= "<textarea tabindex='1' name='wpBio' id='wpBio' rows='12' cols='80' style='width:100%; background-color:#f9f9f9;'>" .
htmlspecialchars( $this->mBio ) . "</textarea></p>\n";
}
$form .= '</fieldset>';
}*/
if ( $this->hasItem( 'CV' ) || $this->hasItem( 'Notes' ) || $this->hasItem( 'Links' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'requestaccount-leg-other' )->escaped() . '</legend>';
$form .= $this->msg( 'requestaccount-ext-text' )->parseAsBlock() . "\n";
if ( $this->hasItem( 'Notes' ) ) {
$form .= "<p>" . $this->msg( 'requestaccount-notes' )->escaped() . "\n";
$form .= "<textarea tabindex='1' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%;background-color:#f9f9f9;'>" .
htmlspecialchars( $this->mNotes ) .
"</textarea></p>\n";
}
$form .= '</fieldset>';
}
if ( $this->hasItem( 'TermsOfService' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'requestaccount-leg-tos' )->escaped() . '</legend>';
$form .= "<p>" . Xml::check( 'wpToS', $this->mToS, array( 'id' => 'wpToS' ) ) .
' <label for="wpToS">' . $this->msg( 'requestaccount-tos' )->parse() . "</label></p>\n";
$form .= '</fieldset>';
}
//Scratch user verification
$form .= '<fieldset>';
$form .= '<legend>User verification</legend>';
$form .= '<p>Please go to the <a href="http://scratch.mit.edu/projects/10135908/">user verification project</a> and comment the following code:<br /><b>' . sha1($_SERVER['REMOTE_ADDR'] . date('m')) . '</b></p>' . "\n";
$form .= '</fieldset>';
# FIXME: do this better...
global $wgConfirmAccountCaptchas, $wgCaptchaClass, $wgCaptchaTriggers;
if ( $wgConfirmAccountCaptchas && isset( $wgCaptchaClass )
&& $wgCaptchaTriggers['createaccount'] && !$reqUser->isAllowed( 'skipcaptcha' ) )
{
$captcha = new $wgCaptchaClass;
# Hook point to add captchas
$form .= '<fieldset>';
$form .= $this->msg( 'captcha-createaccount' )->parseAsBlock();
$form .= $captcha->getForm();
$form .= '</fieldset>';
}
$form .= Html::Hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n";
$form .= Html::Hidden( 'wpEditToken', $reqUser->getEditToken() ) . "\n";
$form .= Html::Hidden( 'attachment', $this->mPrevAttachment ) . "\n";
$form .= Html::Hidden( 'forgotAttachment', $this->mForgotAttachment ) . "\n";
$form .= "<p>" . Xml::submitButton( $this->msg( 'requestaccount-submit' )->text() ) . "</p>";
$form .= Xml::closeElement( 'form' );
$out->addHTML( $form );
$out->addWikiMsg( 'requestaccount-footer' );
}
protected function hasItem( $name ) {
global $wgConfirmAccountRequestFormItems;
return $wgConfirmAccountRequestFormItems[$name]['enabled'];
}
protected function doSubmit() {
# Now create a dummy user ($u) and check if it is valid
$name = trim( $this->mUsername );
$u = User::newFromName( $name, 'creatable' );
if ( !$u ) {
$this->showForm( $this->msg( 'noname' )->escaped() );
return;
}
# Set some additional data so the AbortNewAccount hook can be
# used for more than just username validation
$u->setEmail( $this->mEmail );
$u->setRealName( $this->mRealName );
# FIXME: Hack! If we don't want captchas for requests, temporarily turn it off!
global $wgConfirmAccountCaptchas, $wgCaptchaTriggers;
if ( !$wgConfirmAccountCaptchas && isset( $wgCaptchaTriggers ) ) {
$old = $wgCaptchaTriggers['createaccount'];
$wgCaptchaTriggers['createaccount'] = false;
}
$abortError = '';
if ( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) {
// Hook point to add extra creation throttles and blocks
wfDebug( "RequestAccount::doSubmit: a hook blocked creation\n" );
$this->showForm( $abortError );
return;
}
# Set it back!
if ( !$wgConfirmAccountCaptchas && isset( $wgCaptchaTriggers ) ) {
$wgCaptchaTriggers['createaccount'] = $old;
}
# Build submission object...
$areaSet = array(); // make a simple list of interests
foreach ( $this->mAreas as $area => $val ) {
if ( $val > 0 ) {
$areaSet[] = $area;
}
}
$submission = new AccountRequestSubmission(
$this->getUser(),
array(
'userName' => $name,
'realName' => $this->mRealName,
'tosAccepted' => $this->mToS,
'email' => $this->mEmail,
'bio' => $this->mBio,
'notes' => $this->mNotes,
'urls' => $this->mUrls,
'type' => $this->mType,
'areas' => $areaSet,
'registration' => wfTimestampNow(),
'ip' => $this->getRequest()->getIP(),
'xff' => $this->getRequest()->getHeader( 'X-Forwarded-For' ),
'agent' => $this->getRequest()->getHeader( 'User-Agent' ),
'attachmentPrevName' => $this->mPrevAttachment,
'attachmentSrcName' => $this->mSrcName,
'attachmentDidNotForget' => $this->mForgotAttachment, // confusing name :)
'attachmentSize' => $this->mFileSize,
'attachmentTempPath' => $this->mTempPath
)
);
# Actually submit!
list( $status, $msg ) = $submission->submit( $this->getContext() );
# Account for state changes
$this->mForgotAttachment = $submission->getAttachmentDidNotForget();
$this->mPrevAttachment = $submission->getAttachtmentPrevName();
# Check for error messages
if ( $status !== true ) {
$this->showForm( $msg );
return;
}
# Done!
$this->showSuccess();
}
protected function showSuccess() {
$out = $this->getOutput();
$out->setPagetitle( $this->msg( "requestaccount" )->escaped() );
$out->addWikiMsg( 'requestaccount-sent' );
$out->addHTML(' If your request is accepted, your password will be <b>' . md5(strtolower(Title::newFromText($this->mUsername))) . '</b>.');
$out->returnToMain();
}
/**
* Initialize the uploaded file from PHP data
* @param $request WebRequest
*/
protected function initializeUpload( $request ) {
$file = new WebRequestUpload( $request, 'wpUploadFile' );
$this->mTempPath = $file->getTempName();
$this->mFileSize = $file->getSize();
$this->mSrcName = $file->getName();
}
/**
* (a) Try to confirm an email address via a token
* (b) Notify $wgConfirmAccountContact on success
* @param $code string The token
* @return void
*/
protected function confirmEmailToken( $code ) {
global $wgConfirmAccountContact, $wgPasswordSender, $wgPasswordSenderName;
$reqUser = $this->getUser();
$out = $this->getOutput();
# Confirm if this token is in the pending requests
$name = ConfirmAccount::requestNameFromEmailToken( $code );
if ( $name !== false ) {
# Send confirmation email to prospective user
ConfirmAccount::confirmEmail( $name );
# Send mail to admin after e-mail has been confirmed
if ( $wgConfirmAccountContact != '' ) {
$target = new MailAddress( $wgConfirmAccountContact );
$source = new MailAddress( $wgPasswordSender, $wgPasswordSenderName );
$title = SpecialPage::getTitleFor( 'ConfirmAccounts' );
$subject = $this->msg( 'requestaccount-email-subj-admin' )->inContentLanguage()->escaped();
$body = $this->msg(
'requestaccount-email-body-admin', $name )->rawParams( $title->getFullUrl() )->inContentLanguage()->escaped();
# Actually send the email...
$result = UserMailer::send( $target, $source, $subject, $body );
if ( !$result->isOK() ) {
wfDebug( "Could not sent email to admin at $target\n" );
}
}
$out->addWikiMsg( 'request-account-econf' );
$out->returnToMain();
} else {
# Maybe the user confirmed after account was created...
$user = User::newFromConfirmationCode( $code );
if ( is_object( $user ) ) {
if ( $user->confirmEmail() ) {
$message = $reqUser->isLoggedIn()
? 'confirmemail_loggedin'
: 'confirmemail_success';
$out->addWikiMsg( $message );
if ( !$reqUser->isLoggedIn() ) {
$title = SpecialPage::getTitleFor( 'Userlogin' );
$out->returnToMain( true, $title->getPrefixedUrl() );
}
} else {
$out->addWikiMsg( 'confirmemail_error' );
}
} else {
$out->addWikiMsg( 'confirmemail_invalid' );
}
}
}
}

View file

@ -0,0 +1,233 @@
<?php
class UserCredentialsPage extends SpecialPage {
protected $target, $file;
function __construct() {
parent::__construct( 'UserCredentials', 'lookupcredentials' );
}
public function userCanExecute( User $user ) {
global $wgConfirmAccountSaveInfo;
return $wgConfirmAccountSaveInfo && parent::userCanExecute( $user );
}
function execute( $par ) {
$out = $this->getOutput();
$request = $this->getRequest();
$reqUser = $this->getUser();
if ( !$this->userCanExecute( $this->getUser() ) ) {
throw new PermissionsError( 'lookupcredentials' );
}
$this->setHeaders();
# A target user
$this->target = $request->getText( 'target' );
# Attachments
$this->file = $request->getVal( 'file' );
if ( $this->file ) {
$this->showFile( $this->file );
} elseif ( $this->target ) {
$this->showForm();
$this->showCredentials();
} else {
$this->showForm();
}
$out->addModules( 'ext.confirmAccount' ); // CSS
}
function showForm() {
global $wgScript;
$out = $this->getOutput();
$username = str_replace( '_', ' ', $this->target );
$form = Xml::openElement( 'form', array( 'name' => 'stablization', 'action' => $wgScript, 'method' => 'get' ) );
$form .= "<fieldset><legend>" . $this->msg( 'usercredentials-leg' )->escaped() . "</legend>";
$form .= "<table><tr>";
$form .= "<td>" . Html::Hidden( 'title', $this->getTitle()->getPrefixedText() ) . "</td>";
$form .= "<td>" . $this->msg( "usercredentials-user" )->escaped() . "</td>";
$form .= "<td>" . Xml::input( 'target', 35, $username, array( 'id' => 'wpUsername' ) ) . "</td>";
$form .= "<td>" . Xml::submitButton( $this->msg( 'go' )->text() ) . "</td>";
$form .= "</tr></table>";
$form .= "</fieldset></form>\n";
$out->addHTML( $form );
}
function showCredentials() {
$reqUser = $this->getUser();
$out = $this->getOutput();
$titleObj = SpecialPage::getTitleFor( 'UserCredentials' );
$row = $this->getAccountData();
if ( !$row ) {
$out->addHTML( $this->msg( 'usercredentials-badid' )->escaped() );
return;
}
$out->addWikiMsg( 'usercredentials-text' );
$user = User::newFromName( $this->target );
$list = array();
foreach ( $user->getGroups() as $group ) {
$list[] = User::makeGroupLinkHTML(
$group,
User::getGroupMember( $group, $user->getName() )
);
}
$grouplist = '';
if ( count( $list ) > 0 ) {
$grouplist = '<tr><td>' . $this->msg( 'usercredentials-member' )->escaped() . '</td><td>' . implode( ', ', $list ) . '</td></tr>';
}
$form = "<fieldset>";
$form .= '<legend>' . $this->msg( 'usercredentials-leg-user' )->escaped() . '</legend>';
$form .= '<table cellpadding=\'4\'>';
$form .= "<tr><td>" . $this->msg( 'username' )->escaped() . "</td>";
$form .= "<td>" . Linker::makeLinkObj( $user->getUserPage(), htmlspecialchars( $user->getUserPage()->getText() ) ) . "</td></tr>\n";
$econf = $row->acd_email_authenticated ? ' <strong>' . $this->msg( 'confirmaccount-econf' )->escaped() . '</strong>' : '';
$form .= "<tr><td>" . $this->msg( 'usercredentials-email' )->escaped() . "</td>";
$form .= "<td>" . htmlspecialchars( $row->acd_email ) . $econf . "</td></tr>\n";
$form .= $grouplist;
$form .= '</table></fieldset>';
$areaSet = UserAccountRequest::expandAreas( $row->acd_areas );
$userAreas = ConfirmAccount::getUserAreaConfig();
if ( count( $userAreas ) > 0 ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'confirmaccount-leg-areas' )->escaped() . '</legend>';
$form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>";
$form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>";
$count = 0;
$att = array( 'disabled' => 'disabled' );
foreach ( $userAreas as $name => $conf ) {
$count++;
if ( $count > 5 ) {
$form .= "</tr><tr valign='top'>";
$count = 1;
}
$formName = "wpArea-" . htmlspecialchars( str_replace( ' ', '_', $name ) );
if ( $conf['project'] != '' ) {
$pg = Linker::linkKnown(
Title::newFromText( $name ),
$this->msg( 'requestaccount-info' )->escaped()
);
} else {
$pg = '';
}
$form .= "<td>" .
Xml::checkLabel( $name, $formName, $formName, in_array( $formName, $areaSet ), $att ) .
" {$pg}</td>\n";
}
$form .= "</tr></table></div>";
$form .= '</fieldset>';
}
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'usercredentials-leg-person' )->escaped() . '</legend>';
$form .= '<table cellpadding=\'4\'>';
$form .= "<tr><td>" . $this->msg( 'usercredentials-real' )->escaped() . "</td>";
$form .= "<td>" . htmlspecialchars( $row->acd_real_name ) . "</td></tr>\n";
$form .= '</table>';
$form .= "<p>" . $this->msg( 'usercredentials-bio' )->escaped() . "</p>";
$form .= "<p><textarea tabindex='1' readonly='readonly' name='wpBio' id='wpNewBio' rows='10' cols='80' style='width:100%'>" .
htmlspecialchars( $row->acd_bio ) .
"</textarea></p>\n";
$form .= '</fieldset>';
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'usercredentials-leg-other' )->escaped() . '</legend>';
if ( $this->hasItem( 'CV' ) || $this->hasItem( 'Notes' ) || $this->hasItem( 'Links' ) ) {
$form .= '<p>' . $this->msg( 'usercredentials-attach' )->escaped() . ' ';
if ( $row->acd_filename ) {
$form .= Linker::makeKnownLinkObj( $titleObj, htmlspecialchars( $row->acd_filename ),
'file=' . $row->acd_storage_key );
} else {
$form .= $this->msg( 'confirmaccount-none-p' )->escaped();
}
$form .= "</p><p>" . $this->msg( 'usercredentials-notes' )->escaped() . "</p>\n";
$form .= "<p><textarea tabindex='1' readonly='readonly' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%'>" .
htmlspecialchars( $row->acd_notes ) .
"</textarea></p>\n";
$form .= "<p>" . $this->msg( 'usercredentials-urls' )->escaped() . "</p>\n";
$form .= ConfirmAccountsPage::parseLinks( $row->acd_urls );
}
$form .= '</fieldset>';
if ( $reqUser->isAllowed( 'requestips' ) ) {
$form .= '<fieldset>';
$form .= '<legend>' . $this->msg( 'usercredentials-leg-ip' )->escaped() . '</legend>';
$form .= "<p>" . $this->msg( 'usercredentials-ip' )->escaped() .
" " . htmlspecialchars( $row->acd_ip ) . "</p>\n";
if ( $row->acd_xff ) {
$form .= "<p>" . $this->msg( 'usercredentials-xff' )->escaped() .
" " . htmlspecialchars( $row->acd_xff ) . "</p>\n";
}
if ( $row->acd_agent ) {
$form .= "<p>" . $this->msg( 'usercredentials-agent' )->escaped() .
" " . htmlspecialchars( $row->acd_agent ) . "</p>\n";
}
$form .= '</fieldset>';
}
$out->addHTML( $form );
}
protected function hasItem( $name ) {
global $wgConfirmAccountRequestFormItems;
return $wgConfirmAccountRequestFormItems[$name]['enabled'];
}
/**
* Show a private file requested by the visitor.
* @param $key string
* @return void
*/
function showFile( $key ) {
global $wgConfirmAccountFSRepos;
$out = $this->getOutput();
$request = $this->getRequest();
$out->disable();
# We mustn't allow the output to be Squid cached, otherwise
# if an admin previews a private image, and it's cached, then
# a user without appropriate permissions can toddle off and
# nab the image, and Squid will serve it
$request->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
$request->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
$request->response()->header( 'Pragma: no-cache' );
$repo = new FSRepo( $wgConfirmAccountFSRepos['accountcreds'] );
$path = $repo->getZonePath( 'public' ) . '/' .
UserAccountRequest::relPathFromKey( $key );
$repo->streamFile( $path );
}
function getAccountData() {
$uid = User::idFromName( $this->target );
if ( !$uid )
return false;
# For now, just get the first revision...
$dbr = wfGetDB( DB_SLAVE );
$row = $dbr->selectRow( 'account_credentials', '*',
array( 'acd_user_id' => $uid ),
__METHOD__,
array( 'ORDER BY' => 'acd_user_id,acd_id ASC' ) );
return $row;
}
}