Version 4.7.0
This commit is contained in:
1 parent
517a5e1f70
commit
8ba7d43898
1933 files changed
+65613
-11332
No files matched your search
@@ -41,14 +41,22 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Some advanced search links may bring us here */
|
||||
\IPS\Output::i()->bypassCsrfKeyCheck = true;
|
||||
|
||||
|
||||
$forceIndex = 'joined';
|
||||
|
||||
/* Yeah, this is the level of hackery we've gotten to. Millions of rows in core_members is hard work */
|
||||
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter == 'members_filter_validating' )
|
||||
{
|
||||
$forceIndex = NULL;
|
||||
}
|
||||
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'email<>?', '' ) ), 'joined' );
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'email<>?', '' ) ), $forceIndex );
|
||||
$table->langPrefix = 'members_';
|
||||
|
||||
|
||||
/* Columns we need */
|
||||
$table->include = array( 'photo', 'name', 'email', 'joined', 'group_name' );
|
||||
if ( \IPS\core\Achievements\Rank::getStore() )
|
||||
if ( \IPS\Settings::i()->achievements_enabled AND \IPS\core\Achievements\Rank::getStore() )
|
||||
{
|
||||
$table->include[] = 'achievements_points';
|
||||
$table->widths['achievements_points'] = '17';
|
||||
@@ -153,20 +161,26 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
array(
|
||||
'select' => 'm.row_id',
|
||||
'from' => array( 'core_admin_permission_rows', 'm' ),
|
||||
'where' => "m.row_id=core_members.member_id AND m.row_id_type='member'" ),
|
||||
array(
|
||||
'select' => 'g.row_id',
|
||||
'from' => array( 'core_admin_permission_rows', 'g' ),
|
||||
'where' => array( 'g.row_id', \IPS\Db::i()->select( 'row_id', array( 'core_admin_permission_rows', 'sub' ), array( "((sub.row_id=core_members.member_group_id OR FIND_IN_SET( sub.row_id, core_members.mgroup_others ) ) AND sub.row_id_type='group') AND g.row_id_type='group'" ), NULL, array( 0, 1 ) ) ) )
|
||||
'where' => "( m.row_id_type='group' and ( m.row_id=core_members.member_group_id OR FIND_IN_SET( m.row_id, core_members.mgroup_others ) ) or ( m.row_id=core_members.member_id AND m.row_id_type='member' ))",
|
||||
'type' => 'STRAIGHT_JOIN' )
|
||||
);
|
||||
|
||||
|
||||
/* Makes query less efficient */
|
||||
if ( $table->filter !== 'members_filter_administrators' )
|
||||
{
|
||||
unset( $table->joins[2] );
|
||||
unset( $table->joins[3] );
|
||||
}
|
||||
|
||||
if ( $table->filter !== 'members_filter_validating' )
|
||||
{
|
||||
unset( $table->joins[0] );
|
||||
}
|
||||
|
||||
if ( ! isset( \IPS\Request::i()->advanced_search_submitted ) )
|
||||
{
|
||||
unset( $table->joins[1] );
|
||||
}
|
||||
|
||||
/* Ranks */
|
||||
$rankOptions = array( '' => 'any' );
|
||||
foreach( \IPS\core\Achievements\Rank::getStore() as $rank )
|
||||
@@ -256,7 +270,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'members_filter_banned' => 'temp_ban<>0',
|
||||
'members_filter_spam' => \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ),
|
||||
'members_filter_validating' => '( v.lost_pass=0 AND v.forgot_security=0 AND v.vid IS NOT NULL )',
|
||||
'members_filter_administrators' => '( m.row_id IS NOT NULL OR g.row_id IS NOT NULL )'
|
||||
'members_filter_administrators' => '(1=1)' // We use a straight join when this filter is activated, so there's no additional where needed
|
||||
);
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( "email <> '' and name=''" ) )->first() )
|
||||
@@ -272,9 +286,25 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Custom parsers */
|
||||
$table->parsers = array(
|
||||
'email' => function( $val, $row )
|
||||
'email' => function( $val, &$row )
|
||||
{
|
||||
if ( $row['vid'] )
|
||||
if ( ! array_key_exists( 'vid', $row ) )
|
||||
{
|
||||
/* Grab the data if need be */
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
if ( $member->members_bitoptions['validating'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
$validating = \IPS\Db::i()->select( '*', 'core_validating', [ 'member_id=?', $member->member_id ] )->first();
|
||||
$row = array_merge( $validating, $row );
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $row['vid'] ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberEmailCell( \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberValidatingCell( $val, \IPS\Member::constructFromData( $row )->validatingDescription( $row ) ) );
|
||||
}
|
||||
@@ -384,7 +414,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['approve'] = array(
|
||||
'icon' => 'check-circle',
|
||||
'title' => 'approve',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=approve&id=' . $member->member_id )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=approve&id=' . $member->member_id . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'id' => "{$member->member_id}-approve",
|
||||
'data' => array(
|
||||
'bubble' => '',
|
||||
@@ -393,7 +423,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['ban'] = array(
|
||||
'icon' => 'times',
|
||||
'title' => 'ban',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=ban&id=' . $member->member_id . '&permban=1' )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=ban&id=' . $member->member_id . '&permban=1' . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'id' => "{$member->member_id}-ban",
|
||||
'data' => array(
|
||||
'bubble' => '',
|
||||
@@ -405,7 +435,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['resend_email'] = array(
|
||||
'icon' => 'envelope-o',
|
||||
'title' => 'resend_validation_email',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=resendEmail&id=' . $member->member_id )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=resendEmail&id=' . $member->member_id . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'data' => array( 'doajax' => '' ),
|
||||
'id' => "{$member->member_id}-resend",
|
||||
);
|
||||
@@ -423,7 +453,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['unlock'] = array(
|
||||
'icon' => 'unlock',
|
||||
'title' => 'unlock',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=unlock&id=' . $member->member_id )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=unlock&id=' . $member->member_id . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'data' => array( 'bubble' => '' )
|
||||
);
|
||||
}
|
||||
@@ -431,7 +461,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['view'] = array(
|
||||
'icon' => 'search',
|
||||
'title' => 'view',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ) . $member->member_id,
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' . $member->member_id . $this->getSafeUrlFromFilters() ),
|
||||
);
|
||||
|
||||
if ( !\IPS\Request::i()->_groupFilter )
|
||||
@@ -443,7 +473,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['flag'] = array(
|
||||
'icon' => 'flag',
|
||||
'title' => 'spam_flag',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=spam&id=' . $member->member_id . '&status=1' )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=spam&id=' . $member->member_id . '&status=1' . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'hidden' => $member->members_bitoptions['bw_is_spammer'],
|
||||
'id' => "{$member->member_id}-flag",
|
||||
'data' => array(
|
||||
@@ -453,7 +483,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['unflag'] = array(
|
||||
'icon' => 'flag ipsType_spammer',
|
||||
'title' => 'spam_unflag',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=spam&id=' . $member->member_id . '&status=0' )->csrf(),
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=spam&id=' . $member->member_id . '&status=0' . $this->getSafeUrlFromFilters() )->csrf(),
|
||||
'hidden' => !$member->members_bitoptions['bw_is_spammer'],
|
||||
'id' => "{$member->member_id}-unflag",
|
||||
'data' => array(
|
||||
@@ -468,7 +498,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$return['delete'] = array(
|
||||
'icon' => 'times-circle',
|
||||
'title' => 'delete',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=delete&id=' ) . $member->member_id,
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=delete&id=' . $member->member_id . $this->getSafeUrlFromFilters() ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'delete_member', FALSE, array( 'sprintf' => $member->name ) ) ),
|
||||
);
|
||||
}
|
||||
@@ -569,6 +599,25 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->output .= (string) $table;
|
||||
}
|
||||
|
||||
protected function toggleDataLayerPii()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' );
|
||||
|
||||
$member = \IPS\Member::load( \IPS\Request::i()->id );
|
||||
if ( $member->isAdmin() )
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'member_edit_admin' );
|
||||
}
|
||||
|
||||
if ( $member->member_id )
|
||||
{
|
||||
$member->datalayer_collect_pii = (bool) !$member->datalayer_collect_pii;
|
||||
$member->save();
|
||||
}
|
||||
$_SESSION['member_datalayer_changed'] = 1;
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' . \IPS\Request::i()->id ?? 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune members
|
||||
*
|
||||
@@ -1180,6 +1229,12 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
$history = \IPS\Theme::i()->getTemplate('memberprofile')->history( $member, $history, $historyFilters );
|
||||
}
|
||||
|
||||
if ( isset( $_SESSION['member_datalayer_changed'] ) )
|
||||
{
|
||||
\IPS\Output::i()->inlineMessage = 'Saved';
|
||||
unset( $_SESSION['member_datalayer_changed'] );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'members/view.css', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_members.js', 'core' ) );
|
||||
@@ -1343,7 +1398,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$form = new \IPS\Helpers\Form;
|
||||
|
||||
// This looks weird, but we only want this showing here, and not anywhere else 'password' is used as a form key.
|
||||
\IPS\Member::loggedIn()->language()->words['password_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member', NULL, array( 'sprintf' => array( $member->acpUrl()->csrf()->setQueryString( 'do', 'forcePassReset' ), \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member_confirmmsg' ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['password_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member', FALSE, array( 'sprintf' => array( $member->acpUrl()->csrf()->setQueryString( 'do', 'forcePassReset' ), \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member_confirmmsg' ) ) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Password( 'password', '', TRUE, array( 'protect' => TRUE, 'confirm' => 'password_confirm', 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'minimumStrength' => 1, 'bypassProfanity' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_ALL ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', '', TRUE, array( 'protect' => TRUE, 'bypassProfanity' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_ALL ) ) );
|
||||
@@ -1470,7 +1525,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* If we have external login handlers, we need to show an interstitual page indicating that with caveats. */
|
||||
if ( \count( $externals ) )
|
||||
{
|
||||
$msg = \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member_external', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $externals ) ) ) );
|
||||
$msg = \IPS\Member::loggedIn()->language()->addToStack( 'force_password_reset_member_external', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $externals ) ) ) );
|
||||
$form = new \IPS\Helpers\Form( 'form', 'reset_password' );
|
||||
$form->hiddenValues['id'] = $member->member_id;
|
||||
$form->addMessage( $msg, 'ipsMessage ipsMessage_warning' );
|
||||
@@ -2940,6 +2995,26 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->output = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a partial query string based on any filters or sort options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSafeUrlFromFilters(): string
|
||||
{
|
||||
$extraUrlParams = [];
|
||||
|
||||
foreach( [ 'filter', 'sortby', 'sortdirection' ] as $param )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$param ) )
|
||||
{
|
||||
$extraUrlParams[ $param ] = \IPS\Request::i()->$param;
|
||||
}
|
||||
}
|
||||
|
||||
return \count( $extraUrlParams ) ? '&' . http_build_query( $extraUrlParams ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Member
|
||||
*
|
||||
@@ -2990,7 +3065,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Handle Submissions */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplog__members_deleted', array( $member->name => FALSE ) );
|
||||
\IPS\Session::i()->log( 'acplog__members_deleted_id', array( $member->name => FALSE, $member->member_id => FALSE ) );
|
||||
|
||||
switch( $values['member_deletion_content'] )
|
||||
{
|
||||
@@ -3007,7 +3082,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
break;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal("app=core&module=members&controller=members"), 'deleted' );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal("app=core&module=members&controller=members" . $this->getSafeUrlFromFilters() ), 'deleted' );
|
||||
}
|
||||
|
||||
/* Display Form */
|
||||
@@ -3841,8 +3916,8 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->parseFileObjectUrls( $csv );
|
||||
$csv = \IPS\Output::i()->replaceEmojiWithImages( $csv );
|
||||
|
||||
/* Excel requires this for non-ASCII characters to show properly */
|
||||
$csv = \chr(255) . \chr(254) . mb_convert_encoding( $csv, 'UTF-16LE', 'UTF-8' );
|
||||
/* Excel requires a BOM this for non-ASCII characters to show properly */
|
||||
$csv = \chr(0xEF) . \chr(0xBB) . \chr(0xBF) . $csv;
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__exported_member_list' );
|
||||
\IPS\Output::i()->sendOutput( $csv, 200, 'text/csv', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', \IPS\Member::loggedIn()->language()->get('member_pl') . '.csv' ) ), FALSE, FALSE, FALSE, FALSE );
|
||||
@@ -3886,6 +3961,8 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'last_post' => 'last_post',
|
||||
'birthday' => 'import_birthday',
|
||||
'allow_admin_mails' => 'import_allow_admin_mails',
|
||||
'achievements_points' => 'achievement_points',
|
||||
'member_rank' => "members_member_rank_id",
|
||||
);
|
||||
if ( \IPS\Settings::i()->signatures_enabled )
|
||||
{
|
||||
@@ -4072,7 +4149,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Write */
|
||||
fputcsv( $fh, $dataToWrite, "\t" );
|
||||
fputcsv( $fh, $dataToWrite );
|
||||
}
|
||||
|
||||
/* Close and loop */
|
||||
@@ -4176,6 +4253,16 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$valueToWrite = '';
|
||||
}
|
||||
break;
|
||||
case 'member_rank':
|
||||
if( $rank = \IPS\core\Achievements\Rank::fromPoints( $member['achievements_points'] ) )
|
||||
{
|
||||
$valueToWrite = \IPS\Member::loggedIn()->language()->get( 'core_member_rank_' . $rank->_id );
|
||||
}
|
||||
else
|
||||
{
|
||||
$valueToWrite = '';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( mb_substr( $column, 0, 7 ) == 'pfield_' )
|
||||
@@ -4263,7 +4350,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$wizardData['file'] = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
$fh = fopen( $wizardData['file'], 'w' );
|
||||
|
||||
fputcsv( $fh, $this->_getExportCsvHeaders( $wizardData ), "\t" );
|
||||
fputcsv( $fh, $this->_getExportCsvHeaders( $wizardData ) );
|
||||
fclose( $fh );
|
||||
|
||||
return $wizardData;
|
||||
@@ -4559,7 +4646,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
try
|
||||
{
|
||||
$recognize = \IPS\core\Achievements\Recognize::load( $row['recognize'] );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'acp_badge_from_recognize', NULL, [ 'sprintf' => [ $recognize->content()->url(), $recognize->content()->indefiniteArticle() ] ] );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'acp_badge_from_recognize', FALSE, [ 'sprintf' => [ $recognize->content()->url(), $recognize->content()->indefiniteArticle() ] ] );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
@@ -4628,7 +4715,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
return $node->manually_awarded;
|
||||
},
|
||||
'disabledIds' => iterator_to_array( \IPS\Db::i()->select( 'id', 'core_member_badges', [ 'member=?', $member->member_id ] ) ),
|
||||
'disabledIds' => iterator_to_array( \IPS\Db::i()->select( 'badge', 'core_member_badges', [ '`member`=?', $member->member_id ] ) ),
|
||||
'url' => $member->acpUrl()->setQueryString('do', 'addBadge')
|
||||
] ) );
|
||||
|
||||
|
||||
Reference in new issue
Block a user