mirror of
https://github.com/scratchfoundation/swiki-confirmaccount.git
synced 2024-12-04 21:01:02 -05:00
487 lines
12 KiB
PHP
487 lines
12 KiB
PHP
<?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}";
|
|
}
|
|
}
|