Version 4.7.23
This commit is contained in:
1 parent
7124a02564
commit
25ddeb65d6
1791 files changed
+76990
-44452
No files matched your search
@@ -10,6 +10,8 @@
|
||||
|
||||
namespace IPS\core\modules\admin\members;
|
||||
|
||||
use IPS\Text\Encrypt;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
@@ -123,6 +125,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'core_members.email<>?', '' ) ), $forceIndex );
|
||||
$table->langPrefix = 'members_';
|
||||
$table->keyField = 'member_id';
|
||||
|
||||
/* Columns we need */
|
||||
$table->include = array( 'photo', 'name', 'email', 'joined', 'group_name' );
|
||||
@@ -196,7 +199,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$options = array( '' => "");
|
||||
}
|
||||
|
||||
if( \count( $field->options['options'] ) )
|
||||
if( \is_array( $field->options['options'] ) AND \count( $field->options['options'] ) )
|
||||
{
|
||||
foreach ( $field->options['options'] as $option )
|
||||
{
|
||||
@@ -2530,7 +2533,9 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C114/9', 404, '' );
|
||||
}
|
||||
$member->failed_logins = array();
|
||||
/* Remove login failures */
|
||||
\IPS\Db::i()->delete( 'core_login_failures', [ 'login_member_id=?', $member->member_id ] );
|
||||
$member->failed_login_count = 0;
|
||||
$member->failed_mfa_attempts = 0;
|
||||
$mfaDetails = $member->mfa_details;
|
||||
if ( isset( $mfaDetails['_lockouttime'] ) )
|
||||
@@ -2682,25 +2687,31 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
if ( !$row['user_verified'] )
|
||||
{
|
||||
$plainTextKey = '';
|
||||
if( !empty( $row['security_key'] ) )
|
||||
{
|
||||
$plainTextKey = Encrypt::fromTag( $row['security_key'] )->decrypt();
|
||||
}
|
||||
|
||||
/* Lost Pass */
|
||||
if ( $row['lost_pass'] )
|
||||
{
|
||||
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $row['vid'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $row['vid'], $plainTextKey ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
/* New Reg */
|
||||
elseif ( $row['new_reg'] )
|
||||
{
|
||||
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( $member, $row['vid'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( $member, $row['vid'], $plainTextKey ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
/* Email Change */
|
||||
elseif ( $row['email_chg'] )
|
||||
{
|
||||
\IPS\Email::buildFromTemplate( 'core', 'email_change', array( $member, $row['vid'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
\IPS\Email::buildFromTemplate( 'core', 'email_change', array( $member, $row['vid'], $plainTextKey ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
/* Forgot security answers */
|
||||
elseif ( $row['forgot_security'] )
|
||||
{
|
||||
\IPS\Email::buildFromTemplate( 'core', 'forgotSecurityAnswers', array( $member, $row['vid'] ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
\IPS\Email::buildFromTemplate( 'core', 'mfaRecovery', array( $member, $row['vid'], $plainTextKey ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3028,7 +3039,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__deleted_guest_content', array( $values['guest_name_to_delete'] => FALSE ) );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=moderation&controller=spam&searchResult=guest_captcha" ), 'deleted' );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=moderation&controller=spam" ), 'deleted' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output = $form;
|
||||
@@ -3573,7 +3584,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$matrix->rows[] = array( 'import_column' => $header, 'import_as' => $value );
|
||||
$matrix->rows[] = array( 'import_column' => htmlspecialchars( $header, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ), 'import_as' => $value );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3634,7 +3645,11 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
fseek( $fh, $mrData['currentPosition'] );
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
begin:
|
||||
$line = fgetcsv( $fh );
|
||||
$count++;
|
||||
|
||||
/* Are we done/ */
|
||||
if ( !$line )
|
||||
@@ -3883,6 +3898,12 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Email::buildFromTemplate( 'core', 'admin_reg', array( $member, $member->members_bitoptions['password_reset_forced'], md5( \IPS\SUITE_UNIQUE_KEY . $member->email . $member->real_name ) ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
|
||||
}
|
||||
|
||||
/* If we haven't hit our limit, go again. */
|
||||
if ( $count <= 100 )
|
||||
{
|
||||
goto begin;
|
||||
}
|
||||
|
||||
/* Continue */
|
||||
$mrData['currentPosition'] = ftell( $fh );
|
||||
fclose( $fh );
|
||||
@@ -4128,9 +4149,9 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$mrData['count'] = $query->first();
|
||||
}
|
||||
|
||||
/* Compile query */
|
||||
$query = \IPS\Db::i()->select( implode( ',', $select ), 'core_members', $where, 'core_members.member_id', array( $mrData['offset'], $doPerLoop ) );
|
||||
|
||||
/* Compile member_id query. Just getting the member_ids first is more efficient on larger tables */
|
||||
$query = \IPS\Db::i()->select( 'core_members.member_id', 'core_members', $where, 'core_members.member_id', array( $mrData['offset'], $doPerLoop ) );
|
||||
|
||||
/* Run callbacks */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'MemberFilter', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
@@ -4145,36 +4166,73 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
}
|
||||
|
||||
/* Finished? */
|
||||
if ( !$query->count() )
|
||||
/* Get the IDs */
|
||||
$memberIds = iterator_to_array( $query );
|
||||
|
||||
/* Nothing to do? */
|
||||
if ( ! count( $memberIds ) )
|
||||
{
|
||||
if( \count( $mrData['removedData'] ) AND ( !isset( $wizardData['includeInsecure'] ) OR !$wizardData['includeInsecure'] ) )
|
||||
{
|
||||
$_SESSION['removedData'] = $mrData['removedData'];
|
||||
}
|
||||
|
||||
/* Finish here as we got everything */
|
||||
\IPS\Output::i()->redirect( $baseUrl->setQueryString( array( 'buildDone' => 1 ) ) );
|
||||
}
|
||||
|
||||
|
||||
/* Now prepare the actual query to get all the data */
|
||||
$where[] = [ \IPS\Db::i()->in( 'core_members.member_id', $memberIds ) ];
|
||||
$dataQuery = \IPS\Db::i()->select( implode( ',', $select ), 'core_members', $where, 'core_members.member_id' );
|
||||
|
||||
/* Run callbacks */
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'MemberFilter', TRUE, 'core' ) as $key => $extension )
|
||||
{
|
||||
if( method_exists( $extension, 'queryCallback' ) )
|
||||
{
|
||||
/* Grab our fields and add to the form */
|
||||
if( !empty( $wizardData['filters'][ $key ] ) )
|
||||
{
|
||||
$data = $wizardData['filters'][ $key ];
|
||||
$extension->queryCallback( $data, $dataQuery );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Open file */
|
||||
$fh = fopen( $wizardData['file'], 'a' );
|
||||
|
||||
|
||||
/* Run */
|
||||
foreach ( $query as $member )
|
||||
$done = 0;
|
||||
foreach ( $dataQuery as $member )
|
||||
{
|
||||
$dataToWrite = $this->_getDataToWriteCsv( $member, $wizardData, $mrData );
|
||||
|
||||
$done++; /* This is here because the query fetched 2500 but fewer than 2500 may be processed throwing the last bit out */
|
||||
|
||||
if( $dataToWrite === FALSE )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* Write */
|
||||
fputcsv( $fh, $dataToWrite );
|
||||
}
|
||||
|
||||
|
||||
/* Close and loop */
|
||||
fclose( $fh );
|
||||
|
||||
if ( $done < $doPerLoop )
|
||||
{
|
||||
if( \count( $mrData['removedData'] ) AND ( !isset( $wizardData['includeInsecure'] ) OR !$wizardData['includeInsecure'] ) )
|
||||
{
|
||||
$_SESSION['removedData'] = $mrData['removedData'];
|
||||
}
|
||||
|
||||
/* Just finish here as we got everything */
|
||||
\IPS\Output::i()->redirect( $baseUrl->setQueryString( array( 'buildDone' => 1 ) ) );
|
||||
}
|
||||
|
||||
$mrData['offset'] += $doPerLoop;
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('export_members_processing'), ( $mrData['offset'] > $mrData['count'] ) ? 100 : ( 100 / $mrData['count'] ) * $mrData['offset'] );
|
||||
},
|
||||
@@ -4289,7 +4347,14 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( mb_substr( $column, 0, 7 ) == 'pfield_' )
|
||||
{
|
||||
$fieldId = mb_substr( $column, 7 );
|
||||
$valueToWrite = $member[ 'field_' . $fieldId ] ? \IPS\core\ProfileFields\Field::load( $fieldId )->displayValue( $member[ 'field_' . $fieldId ], FALSE, 0, NULL, TRUE, ',' ) : '';
|
||||
|
||||
/* If this is a Checkbox or YesNo field, then we can't use the displayValue() as it will just come out as a hashed string, and the CSV file can be large, so just replace these at generation time rather than parsing the entire file. */
|
||||
$field = \IPS\core\ProfileFields\Field::load( $fieldId );
|
||||
|
||||
$valueToWrite = match( $field->type ) {
|
||||
'YesNo', 'Checkbox' => (bool) $member[ 'field_' . $fieldId ] ? \IPS\Member::loggedIn()->language()->get('yes') : \IPS\Member::loggedIn()->language()->get('no'),
|
||||
default => $member[ 'field_' . $fieldId ] ? \IPS\core\ProfileFields\Field::load( $fieldId )->displayValue( $member[ 'field_' . $fieldId ], FALSE, 0, NULL, TRUE, ',' ) : ''
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user