Invision Power Services, Inc. * @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc. * @license http://www.invisionpower.com/legal/standards/ * @package IPS Social Suite * @since 21 Mar 2013 * @version SVN_VERSION_NUMBER */ namespace IPS\core\modules\admin\members; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * Manage Members */ class _members extends \IPS\Dispatcher\Controller { /** * Manage Members * * @return void */ protected function manage() { /* Create the table */ $table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'name<>? AND email<>?', '', '' ) ), NULL, 'joined' ); $table->langPrefix = 'members_'; /* Columns we need */ $table->include = array( 'photo', 'name', 'email', 'joined', 'group_name', 'ip_address' ); $table->mainColumn = 'name'; $table->noSort = array( 'photo' ); /* Default sort options */ $table->sortBy = $table->sortBy ?: 'joined'; $table->sortDirection = $table->sortDirection ?: 'desc'; /* Groups for advanced filter (need to do it this way because array_merge renumbers the result */ $groups = array( '' => 'any_group' ); $joinFields = array( 'core_members.member_id as member_id' ); foreach ( \IPS\Member\Group::groups() as $k => $v ) { $groups[ $k ] = $v->name; } $fieldsToAdd = array(); /* Profile fields */ foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\STAFF ) as $group => $fields ) { /* Header */ \IPS\Member::loggedIn()->language()->words[ "members_core_pfieldgroups_{$group}" ] = \IPS\Member::loggedIn()->language()->addToStack( "core_pfieldgroups_{$group}", FALSE ); /* Fields */ foreach ( $fields as $id => $field ) { /* Alias the lang keys */ $realLangKey = "core_pfield_{$id}"; $fakeLangKey = "members_field_{$id}"; \IPS\Member::loggedIn()->language()->words[ $fakeLangKey ] = \IPS\Member::loggedIn()->language()->addToStack( $realLangKey, FALSE ); /* Work out the object type so we can show the appropriate field */ $type = get_class( $field ); $helper = NULL; switch ( $type ) { case 'IPS\Helpers\Form\Text': case 'IPS\Helpers\Form\Tel': case 'IPS\Helpers\Form\Editor': case 'IPS\Helpers\Form\Email': case 'IPS\Helpers\Form\TextArea': case 'IPS\Helpers\Form\Url': $helper = \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT; break; case 'IPS\Helpers\Form\Date': $helper = \IPS\Helpers\Table\SEARCH_DATE_RANGE; break; case 'IPS\Helpers\Form\Number': $helper = \IPS\Helpers\Table\SEARCH_NUMERIC; break; case 'IPS\Helpers\Form\Select': case 'IPS\Helpers\Form\Radio': $options = array( '' => ""); if( count( $field->options['options'] ) ) { foreach ($field->options['options'] as $option) { $options[$option] = $option; } } $helper = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $options ) ); break; } if ( $helper ) { $fieldsToAdd[ "field_{$id}" ] = $helper; } /* Set fields we need for the table joins below */ $joinFields[] = "field_{$id}"; } } /* Joins */ $table->joins = array( array( 'select' => 'v.vid, v.coppa_user, v.lost_pass, v.new_reg, v.email_chg, v.user_verified, v.spam_flag', 'from' => array( 'core_validating', 'v' ), 'where' => 'v.member_id=core_members.member_id AND v.lost_pass != 1' ), array( 'select' => implode( ',', $joinFields ), 'from' => array( 'core_pfields_content', 'p' ), 'where' => 'p.member_id=core_members.member_id' ), 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' => "( g.row_id=core_members.member_group_id OR FIND_IN_SET( g.row_id, core_members.mgroup_others ) ) AND g.row_id_type='group'" ), ); /* Makes query less efficient */ if ( $table->filter !== 'members_filter_administrators' ) { unset( $table->joins[2] ); unset( $table->joins[3] ); } /* Search */ $table->quickSearch = 'name'; $table->advancedSearch = array( 'name' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT, 'member_id' => array( \IPS\Helpers\Table\SEARCH_NUMERIC, array(), function( $v ){ switch ( $v[0] ) { case 'gt': return array( "core_members.member_id>?", (float) $v[1] ); case 'lt': return array( "core_members.member_id \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT, 'ip_address' => array( \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT, array(), function( $val ) { return array( "core_members.ip_address LIKE ?", '%' . $val . '%' ); } ), 'member_group_id' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $groups ), function( $val ) { return array( 'member_group_id=? OR FIND_IN_SET( ?, mgroup_others )', $val, $val ); } ), 'joined' => \IPS\Helpers\Table\SEARCH_DATE_RANGE, 'member_last_post' => \IPS\Helpers\Table\SEARCH_DATE_RANGE, 'last_visit' => \IPS\Helpers\Table\SEARCH_DATE_RANGE, 'member_posts' => \IPS\Helpers\Table\SEARCH_NUMERIC, ); if( count( $fieldsToAdd ) ) { $table->advancedSearch[ "core_pfieldgroups_{$group}" ] = \IPS\Helpers\Table\HEADER; $table->advancedSearch = array_merge( $table->advancedSearch, $fieldsToAdd ); } /* Filters */ $table->filters = array( 'members_filter_banned' => 'temp_ban<>0', 'members_filter_locked' => 'failed_login_count>=' . (int) \IPS\Settings::i()->ipb_bruteforce_attempts, 'members_filter_spam' => \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ), 'members_filter_validating' => '( v.lost_pass=0 AND v.vid IS NOT NULL )', 'members_filter_administrators' => '( m.row_id IS NOT NULL OR g.row_id IS NOT NULL )' ); /* Custom parsers */ $table->parsers = array( 'email' => function( $val, $row ) { if ( $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 ) ) ); } else { return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberEmailCell( htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) ); } }, 'photo' => function( $val, $row ) { return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::constructFromData( $row ), 'mini' ); }, 'joined' => function( $val, $row ) { return \IPS\DateTime::ts( $val )->localeDate(); }, 'group_name' => function( $val, $row ) { $secondary = \IPS\Member::constructFromData( $row )->groups; foreach( $secondary as $k => $v ) { if( $v == $row['member_group_id'] or $v == 0 ) { unset( $secondary[ $k ] ); continue; } $secondary[ $k ] = \IPS\Member\Group::load( $v ); } return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->groupCell( \IPS\Member\Group::load( $row['member_group_id'] ), $secondary ); }, 'ip_address' => function( $val, $row ) { if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_ip' ) ) { return "{$val}"; } return $val; }, 'member_last_post' => function( $val, $row ) { return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack( 'never' ); }, 'last_visit' => function( $val, $row ) { return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack( 'never' ); }, 'name' => function( $val, $row ) { return "" . htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . ""; }, ); /* Specify the buttons */ if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_add' ) ) { $table->rootButtons = array( 'add' => array( 'icon' => 'plus', 'title' => 'members_add', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=add' ), 'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('members_add') ) ) ); } $table->rowButtons = function( $row ) { $member = \IPS\Member::constructFromData( $row ); $return = array(); if ( isset( $row['vid'] ) and $row['vid'] and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_validating' ) ) { $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, 'id' => "{$member->member_id}-approve", 'data' => array( 'bubble' => '', ) ); $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', 'id' => "{$member->member_id}-ban", 'data' => array( 'bubble' => '', ) ); if ( !$row['user_verified'] ) { $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, 'data' => array( 'doajax' => '' ), 'id' => "{$member->member_id}-resend", ); } } if ( $row['failed_login_count'] >= (int) \IPS\Settings::i()->ipb_bruteforce_attempts and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_locked' ) ) { $return['unlock'] = array( 'icon' => 'unlock', 'title' => 'unlock', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=unlock&id=' ) . $member->member_id, 'data' => array( 'bubble' => '' ) ); } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) and ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit_admin' ) or !$member->isAdmin() ) ) { $return['edit'] = array( 'icon' => 'pencil', 'title' => 'edit', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' ) . $member->member_id, 'hotkey' => 'e' ); if ( $member->member_id != \IPS\Member::loggedIn()->member_id ) { $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', 'hidden' => $member->members_bitoptions['bw_is_spammer'], 'id' => "{$member->member_id}-flag", 'data' => array( 'confirm' => '', ) ); $return['unflag'] = array( 'icon' => 'flag-o', 'title' => 'spam_unflag', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=spam&id=' ) . $member->member_id . '&status=0', 'hidden' => !$member->members_bitoptions['bw_is_spammer'], 'id' => "{$member->member_id}-unflag", 'data' => array( 'confirm' => '', ) ); } } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) and ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete_admin' ) or !$member->isAdmin() ) and $member->member_id != \IPS\Member::loggedIn()->member_id ) { $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, 'data' => array( 'delete' => '' ), ); } return $return; }; /* Display */ if( \IPS\Request::i()->advanced_search_submitted OR \IPS\Request::i()->quicksearch ) { $link = ' ' . \IPS\Member::loggedIn()->language()->addToStack('member_view_full_list') . ''; if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) OR \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) ) { $query = http_build_query( array( 'members_name' => \IPS\Request::i()->quicksearch ?: NULL, //'members_member_id' => ( \IPS\Request::i()->members_member_id[0] != 'any' ) ? \IPS\Request::i()->members_member_id[1] : 0, 'members_member_id' => \IPS\Request::i()->members_member_id, 'members_email' => \IPS\Request::i()->members_email, 'members_ip_address' => \IPS\Request::i()->members_ip_address, 'members_member_group_id' => \IPS\Request::i()->members_member_group_id, 'members_joined' => \IPS\Request::i()->members_joined, 'members_last_post' => \IPS\Request::i()->members_last_post, 'members_last_visit' => \IPS\Request::i()->members_last_visit, 'members_posts' => \IPS\Request::i()->members_posts, 'filter' => \IPS\Request::i()->filter, ) ); if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) ) { $link .= ' — ' . \IPS\Member::loggedIn()->language()->addToStack( 'member_search_prune' ) . ''; } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) ) { $link .= ' — ' . \IPS\Member::loggedIn()->language()->addToStack( 'member_search_move' ) . ''; } } $table->extraHtml = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'member_search_results' ) . $link, 'info', NULL, FALSE ); } \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('members'); \IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'members', (string) $table ); } /** * Prune members * * @return void */ public function massManage() { switch( \IPS\Request::i()->action ) { case 'prune': \IPS\Dispatcher::i()->checkAcpPermission( 'member_delete' ); break; case 'move': \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' ); break; } $where = array(); if ( \IPS\Request::i()->members_name ) { $where[] = array( "name LIKE CONCAT( '%', ?, '%' )", \IPS\Request::i()->members_name ); } if ( isset( \IPS\Request::i()->members_member_id ) AND isset( \IPS\Request::i()->members_member_id[1] ) AND \IPS\Request::i()->members_member_id[1] ) { switch ( \IPS\Request::i()->members_member_id[0] ) { case 'gt': $where[] = array( "core_members.member_id>?", \IPS\Request::i()->members_member_id[1] ); break; case 'lt': $where[] = array( "core_members.member_idmembers_member_id[1] ); break; case 'eq': $where[] = array( "core_members.member_id=?", \IPS\Request::i()->members_member_id[1] ); break; } } if ( \IPS\Request::i()->members_email ) { $where[] = array( "email LIKE CONCAT( '%', ?, '%' )", \IPS\Request::i()->members_email ); } if ( \IPS\Request::i()->members_ip_address ) { $where[] = array( 'ip_address=?', (string) \IPS\Request::i()->members_ip_address ); } if ( \IPS\Request::i()->members_member_group_id ) { $adminGroups = array(); foreach( \IPS\Member\Group::groups( TRUE, FALSE ) AS $k => $group ) { if ( $group->g_access_cp ) { $adminGroups[] = $group->g_id; } } /* We do a generic permissions check here, then later on when the process is actually running, we check each individual one to make sure we don't do something we shouldn't do */ if ( ( ( \IPS\Request::i()->action === 'prune' AND \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete_admin' ) ) OR ( \IPS\Request::i()->action === 'move' AND ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit_admin' ) OR \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin1' ) OR \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin2' ) ) ) ) OR !in_array( \IPS\Request::i()->members_member_group_id, $adminGroups ) ) { $where[] = array( 'member_group_id=? OR FIND_IN_SET( ?, mgroup_others )', (int) \IPS\Request::i()->members_member_group_id,(int) \IPS\Request::i()->members_member_group_id ); } } if ( \IPS\Request::i()->members_joined['start'] AND \IPS\Request::i()->members_joined['end'] ) { $start = new \IPS\DateTime( \IPS\Request::i()->members_joined['start'] ); $end = new \IPS\DateTime( \IPS\Request::i()->members_joined['end'] ); $where[] = array( 'joined BETWEEN ? AND ?', $start->getTimestamp(), $end->getTimestamp() ); } if ( \IPS\Request::i()->members_last_post['start'] AND \IPS\Request::i()->members_last_post['end'] ) { $start = new \IPS\DateTime( \IPS\Request::i()->members_last_post['start'] ); $end = new \IPS\DateTime( \IPS\Request::i()->members_last_post['end'] ); $where[] = array( 'member_last_post BETWEEN ? AND ?', $start->getTimestamp(), $end->getTimestamp() ); } if ( \IPS\Request::i()->members_last_visit['start'] AND isset( \IPS\Request::i()->members_last_visit['end'] ) ) { $start = new \IPS\DateTime( \IPS\Request::i()->members_last_visit['start'] ); $end = new \IPS\DateTime( \IPS\Request::i()->members_last_visit['end'] ); $where[] = array( 'last_visit BETWEEN ? AND ?', $start->getTimestamp(), $end->getTimestamp() ); } if ( ( isset( \IPS\Request::i()->members_posts[0] ) AND \IPS\Request::i()->members_posts[0] != 'any' ) AND isset( \IPS\Request::i()->members_posts[1] ) ) { switch( \IPS\Request::i()->members_posts[0] ) { case 'gt': $operator = '>'; break; case 'lt': $operator = '<'; break; case 'eq': $operator = '='; break; } $where[] = array( 'posts'.$operator.'?', (int) \IPS\Request::i()->members_posts[1] ); } if( isset( \IPS\Request::i()->filter ) ) { switch ( \IPS\Request::i()->filter ) { case 'members_filter_banned': $where[] = array( 'temp_ban<>0' ); break; case 'members_filter_locked': $where[] = array( 'failed_login_count>=' . (int) \IPS\Settings::i()->ipb_bruteforce_attempts ); break; case 'members_filter_spam': $where[] = array( \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ) ); break; case 'members_filter_validating': $where[] = array( '( v.lost_pass=0 AND v.vid IS NOT NULL )' ); break; case 'members_filter_administrators': $where[] = array( '( m.row_id IS NOT NULL OR g.row_id IS NOT NULL )' ); break; } } if ( !count( $where ) ) { if ( \IPS\Request::i()->action === 'prune' ) { \IPS\Output::i()->error( 'member_prune_no_results', '2C114/E', 404, '' ); } else { \IPS\Output::i()->error( 'member_move_no_results', '2C114/G', 404, '' ); } } /* Unset any previous session data */ $_SESSION['members_manage_where'] = $where; $_SESSION['members_manage_action'] = \IPS\Request::i()->action; if ( \IPS\Request::i()->action === 'prune' ) { $count = \IPS\Db::i()->select( 'COUNT(*) AS count', 'core_members', $where )->first(); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->confirmMassAction( $count, 'prune' ); \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_prune_confirm' ); } else { $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Select( 'move_to_group', NULL, TRUE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal' ) ) ); if ( $values = $form->values() ) { $group = \IPS\Member\Group::load( $values['move_to_group'] ); if ( $group->g_access_cp AND !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin2' ) ) { \IPS\Output::i()->error( 'member_move_admin_group', '2C114/H', 403, '' ); } $count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $_SESSION['members_manage_where'] )->first(); $_SESSION['members_manage_group'] = $group->g_id; \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->confirmMassAction( $count, 'move', $group ); \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_move_confirm' ); } else { \IPS\Output::i()->output = $form; \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_search_move' ); } } } /** * Move Members * * @return void */ public function doMove() { \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' ); $cycle = 1; $group = $_SESSION['members_manage_group']; $self = $this; \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'moving_members' ); \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=doMove" ), function( $data ) use ( $cycle, $group, $self ) { $newGroup = \IPS\Member\Group::load( $group ); if ( !is_array( $data ) ) { $data = array( 'done' => 0, 'total' => 0, 'group' => $newGroup->g_id ); } $select = \IPS\Db::i()->select( '*', 'core_members', $_SESSION['members_manage_where'], 'member_id ASC', array( $data['done'], $cycle ), NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS ); if ( $data['total'] == 0 ) { $data['total'] = $select->count( TRUE ); } if ( !$select->count() ) { return NULL; } foreach( $select AS $row ) { try { $member = \IPS\Member::constructFromData( $row ); /* Let's leave our own account alone */ if ( $member->member_id == \IPS\Member::loggedIn()->member_id ) { throw new \OutOfBoundsException; } /* Is this member an admin? */ if ( $member->isAdmin() AND ( !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit_admin' ) OR !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin1' ) ) ) { throw new \OutOfBoundsException; } /* Member is already in this group? */ if ( $member->inGroup( $newGroup ) ) { $extraGroups = array_filter( explode( ',', $member->mgroup_others ) ); $self->mgroup_others = implode( ',', array_diff( $extraGroups, array( $newGroup->g_id ) ) ); } $member->member_group_id = $newGroup->g_id; $member->save(); } catch( \Exception $e ) { } } $data['done'] += $cycle; return array( $data, \IPS\Member::loggedIn()->language()->addToStack( 'moving_members' ), ( $data['done'] / $data['total'] ) * 100 ); }, function () use ( $group ) { $newGroup = \IPS\Member\Group::load( $group ); $_SESSION['members_manage_where'] = NULL; $_SESSION['members_manage_action'] = NULL; $_SESSION['members_manage_group'] = NULL; \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members&advanced_search_submitted=1&csrfKey=' . \IPS\Session::i()->csrfKey . '&members_member_group_id=' . $newGroup->g_id ) ); } ); } /** * Prune members * * @return void */ public function doPrune() { \IPS\Dispatcher::i()->checkAcpPermission( 'member_delete' ); $cycle = 1; \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'pruning_members' ); \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=doPrune" ), function ( $data ) use ( $cycle ) { $select = \IPS\Db::i()->select( '*', 'core_members', $_SESSION['members_manage_where'], 'member_id ASC', array( 0, $cycle ), NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS ); $total = $select->count( TRUE ); if ( !$select->count() ) { return NULL; } if( !is_array( $data ) ) { $data = array( 'total' => $total, 'done' => 0 ); } foreach( $select AS $row ) { try { $member = \IPS\Member::constructFromData( $row ); if ( $member->member_id == \IPS\Member::loggedIn()->member_id OR ( $member->isAdmin() AND !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete_admin' ) ) ) { throw new \OutOfBoundsException; } $member->delete(); } catch( \Exception $e ) {} } $data['done'] += $cycle; return array( $data, \IPS\Member::loggedIn()->language()->addToStack('pruning_members'), ( $data['done'] / $data['total'] ) * 100 ); }, function() { $_SESSION['members_manage_where'] = NULL; $_SESSION['members_manage_action'] = NULL; \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members" ), 'completed' ); } ); } /** * Add Member * * @return void */ public function add() { /* Check permissions */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_add' ); /* Build form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Text( 'username', NULL, TRUE, array( 'accountUsername' => TRUE ) ) ); $form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE ) ); $form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'maxLength' => 150, 'accountEmail' => TRUE ) ) ); $form->add( new \IPS\Helpers\Form\Select( 'group', \IPS\Settings::i()->member_group, TRUE, array( 'options' => \IPS\Member\Group::groups( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_add_admin' ), FALSE ), 'parse' => 'normal' ) ) ); $form->add( new \IPS\Helpers\Form\Select( 'secondary_groups', array(), FALSE, array( 'options' => \IPS\Member\Group::groups( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_add_admin' ), FALSE ), 'multiple' => TRUE, 'parse' => 'normal' ) ) ); foreach ( \IPS\Lang::languages() as $lang ) { $languages[ $lang->id ] = $lang->title; } $form->add( new \IPS\Helpers\Form\Select( 'language', NULL, TRUE, array( 'options' => $languages ) ) ); $themes = array( 0 => 'skin_none' ); foreach( \IPS\Theme::themes() as $theme ) { $themes[ $theme->id ] = $theme->_title; } $form->add( new \IPS\Helpers\Form\Select( 'skin', NULL, TRUE, array( 'options' => $themes ) ) ); $form->add( new \IPS\Helpers\Form\YesNo( 'member_add_confirmemail', TRUE ) ); if( \IPS\Settings::i()->use_coppa ) { $form->add( new \IPS\Helpers\Form\YesNo( 'member_add_coppa_user', FALSE, FALSE, array(), NULL, NULL, NULL, 'member_add_coppa_user' ) ); } /* Handle submissions */ if ( $values = $form->values() ) { $member = new \IPS\Member; $member->name = $values['username']; $member->email = $values['email_address']; $member->member_group_id = $values['group']; $member->mgroup_others = implode( ',', $values['secondary_groups'] ); $member->language = $values['language']; $member->skin = $values['skin']; $member->members_pass_salt = $member->generateSalt(); $member->members_pass_hash = $member->encryptedPassword( $values['password'] ); if( \IPS\Settings::i()->use_coppa ) { $member->members_bitoptions['coppa_user'] = ( $values['member_add_coppa_user'] ) ?: FALSE; } $member->save(); /* Reset statistics */ \IPS\Widget::deleteCaches( 'stats', 'core' ); \IPS\Session::i()->log( 'acplog__members_created', array( $member->name => FALSE ) ); if ( $values['member_add_confirmemail'] ) { \IPS\Email::buildFromTemplate( 'core', 'admin_reg', array( $member, $values['password'] ) )->send( $member ); } \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' . $member->member_id ), 'saved' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'members_add' ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'members_add', $form, FALSE ); } /** * Edit Member * * @return void */ public function edit() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' ); /* Load Member */ $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( !$member->member_id ) { \IPS\Output::i()->error( 'node_error', '2C114/1', 404, '' ); } if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit_admin' ); } /* Get extensions */ $extensions = \IPS\Application::allExtensions( 'core', 'MemberForm', FALSE, 'core', 'BasicInformation', TRUE ); /* Build form */ \IPS\Output::i()->sidebar['actions'] = array(); $form = new \IPS\Helpers\Form; foreach ( $extensions as $k => $class ) { $form->addTab( 'member__' . $k ); $class->process( $form, $member ); if ( method_exists( $class, 'actionButtons' ) ) { \IPS\Output::i()->sidebar['actions'] = array_merge( \IPS\Output::i()->sidebar['actions'], $class->actionButtons( $member ) ); } } /* Delete button */ if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) and ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete_admin' ) or !$member->isAdmin() ) and $member->member_id != \IPS\Member::loggedIn()->member_id ) { \IPS\Output::i()->sidebar['actions']['delete'] = array( 'title' => 'delete', 'icon' => 'times-circle', 'link' => \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=delete&id={$member->member_id}" ), 'data' => array( 'delete' => '' ) ); } /* Approve */ if ( $member->members_bitoptions['validating'] and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_validating' ) ) { \IPS\Output::i()->sidebar['actions']['approve'] = array( 'title' => 'approve', 'icon' => 'check-circle', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=approve&id=' ) . $member->member_id, 'id' => "{$member->member_id}-approve", 'data' => array( 'bubble' => '' ) ); } /* Handle submissions */ if ( $values = $form->values() ) { foreach ( $extensions as $class ) { $class->save( $values, $member ); } $member->save(); /* Edited member, so clear widget caches (stats, widgets that contain photos, names and so on) */ \IPS\Widget::deleteCaches(); \IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' . $member->member_id ), 'saved' ); } \IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'members/member.css', 'core', 'admin' ) ); \IPS\Output::i()->title = $member->name; \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('members')->editMember( $member, $form, ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_photo' ) and ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_photo_admin' ) or !$member->isAdmin() ) ), \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_ip' ) ); } /** * Change Password * * @return void */ protected function password() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' ); /* Load Member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_edit_admin' ); } } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/2', 404, '' ); } /* Show Form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Password( 'password', '', TRUE, array( 'confirm' => 'password_confirm' ) ) ); $form->add( new \IPS\Helpers\Form\Password( 'password_confirm', '', TRUE ) ); /* Handle submissions */ if ( $values = $form->values() ) { foreach ( \IPS\Login::handlers( TRUE ) as $handler ) { try { $handler->changePassword( $member, $values['password'] ); } catch( \BadMethodCallException $e ){} } \IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } /* Display */ \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'password', $form, FALSE ); } /** * Change Photo * * @return void */ public function photo() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_photo' ); /* Load member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_photo_admin' ); } } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/3', 404, '' ); } /* What options do we have? */ $options = array( 'custom' => 'member_photo_upload', 'url' => 'member_photo_url' ); $toggles = array( 'custom' => array( 'member_photo_upload' ), 'url' => array( 'member_photo_url' ) ); $extra = array(); if ( \IPS\Settings::i()->allow_gravatars ) { $options['gravatar'] = 'member_photo_gravatar'; $extra[] = new \IPS\Helpers\Form\Email( 'photo_gravatar_email', $member->pp_gravatar, FALSE, array( 'maxLength' => 255, 'placeholder' => $member->email ), NULL, NULL, NULL, 'member_photo_gravatar' ); $toggles['gravatar'] = array( 'member_photo_gravatar' ); } foreach ( \IPS\core\ProfileSync\ProfileSyncAbstract::services() as $key => $class ) { $obj = new $class( $member ); if ( $obj->connected() ) { $langKey = 'profilesync__' . $key; $options[ 'sync-' . $key ] = \IPS\Member::loggedIn()->language()->addToStack('member_photo_sync', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $langKey ) ) ) ); } } $options['none'] = 'member_photo_none'; /* Build Form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Radio( 'pp_photo_type', $member->pp_photo_type, TRUE, array( 'options' => $options, 'toggles' => $toggles ) ) ); $customVal = NULL; if ( $member->pp_photo_type === 'custom' ) { $customVal = \IPS\File::get( 'core_Profile', $member->pp_main_photo ); } $photoVars = explode( ':', $member->group['g_photo_max_vars'] ); $form->add( new \IPS\Helpers\Form\Upload( 'member_photo_upload', $customVal, FALSE, array( 'image' => array( 'maxWidth' => $photoVars[1], 'maxHeight' => $photoVars[2] ), 'storageExtension' => 'core_Profile' ), NULL, NULL, NULL, 'member_photo_upload' ) ); $form->add( new \IPS\Helpers\Form\Url( 'member_photo_url', NULL, FALSE, array( 'file' => 'core_Profile', 'allowedMimes' => 'image/*' ), NULL, NULL, NULL, 'member_photo_url' ) ); foreach ( $extra as $element ) { $form->add( $element ); } /* Handle submissions */ if ( $values = $form->values() ) { $member->pp_photo_type = $values['pp_photo_type'] === 'none' ? NULL : $values['pp_photo_type']; /* Save main photo */ switch ( $values['pp_photo_type'] ) { case 'custom': if ( $values['member_photo_upload'] ) { $member->pp_photo_type = 'custom'; $member->pp_main_photo = NULL; $member->pp_main_photo = (string) $values['member_photo_upload']; $member->pp_thumb_photo = (string) $values['member_photo_upload']->thumbnail( 'core_Profile', \IPS\PHOTO_THUMBNAIL_SIZE, \IPS\PHOTO_THUMBNAIL_SIZE, TRUE ); $member->photo_last_update = time(); } break; case 'url': $member->pp_photo_type = 'custom'; $member->pp_main_photo = NULL; $member->pp_main_photo = (string) $values['member_photo_url']; $member->photo_last_update = time(); break; case 'none': $member->pp_main_photo = NULL; $member->members_bitoptions['bw_disable_gravatar'] = 1; $member->photo_last_update = NULL; break; default: if ( mb_substr( $values['pp_photo_type'], 0, 5 ) === 'sync-' ) { $class = 'IPS\core\ProfileSync\\' . mb_substr( $values['pp_photo_type'], 5 ); $obj = new $class( $member ); $obj->save( array( 'profilesync_photo' => TRUE ) ); } } /* Save */ $member->save(); \IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'photo', $form, FALSE ); } /** * Find IP Addresses * * @return void */ public function ip() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'membertools_ip' ); /* Load Member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/5', 404, '' ); } /* Init Table */ $ips = $member->ipAddresses(); $table = new \IPS\Helpers\Table\Custom( $ips, \IPS\Http\Url::internal( "app=core&module=members&controller=members&id={$member->member_id}&do=ip" ) ); $table->langPrefix = 'members_iptable_'; $table->mainColumn = 'ip'; $table->sortBy = $table->sortBy ?: 'last'; $table->quickSearch = 'ip'; /* Parsers */ $table->parsers = array( 'first' => function( $val ) { return \IPS\DateTime::ts( $val )->localeDate(); }, 'last' => function( $val ) { return \IPS\DateTime::ts( $val )->localeDate(); }, ); /* Buttons */ $table->rowButtons = function( $row ) { return array( 'view' => array( 'icon' => 'search', 'title' => 'see_uses', 'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=ip&ip=' ) . $row['ip'], ), ); }; /* Display */ \IPS\Output::i()->title = $member->name; \IPS\Output::i()->breadcrumb[] = array( "app=core&module=members&controller=members&do=edit&id={$member->member_id}", $member->name ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'menu__core_members_ip', (string) $table ); } /** * Photo Resize * * @return void */ public function photoResize() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_photo' ); /* Load member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/3', 404, '' ); } if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_photo_admin' ); } /* Get photo */ $image = \IPS\File::get( 'core_Profile', $member->pp_main_photo ); /* Build Form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\WidthHeight( 'member_photo_resize', NULL, TRUE, array( 'image' => $image ) ) ); /* Handle submissions */ if ( $values = $form->values() ) { /* Create new file */ $original = \IPS\File::get( 'core_Profile', $member->pp_main_photo ); $image = \IPS\Image::create( $original->contents() ); $image->resize( $values['member_photo_resize'][0], $values['member_photo_resize'][1] ); /* Save the new */ $member->pp_main_photo = \IPS\File::create( 'core_Profile', $original->filename, (string) $image ); $member->pp_thumb_photo = (string) $member->pp_main_photo->thumbnail( 'core_Profile', \IPS\PHOTO_THUMBNAIL_SIZE, \IPS\PHOTO_THUMBNAIL_SIZE, TRUE ); $member->save(); /* Delete the original */ $original->delete(); /* Log and redirect */ \IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'member_photo_resize', $form, FALSE ); } /** * Unlock * * @return void */ public function unlock() { try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/9', 404, '' ); } $member->failed_logins = array(); $member->save(); \IPS\Session::i()->log( 'acplog__members_unlocked', array( $member->name => FALSE ) ); if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( 'OK' ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } } /** * View Display Name History * * @return void */ public function viewDnameHistory() { try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/D', 404, '' ); } $table = new \IPS\Helpers\Table\Db( 'core_dnames_change', \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=viewDnameHistory&id={$member->member_id}" ), array( 'dname_member_id=?', (int) $member->member_id ) ); $table->include = array( 'dname_previous', 'dname_current', 'dname_date', 'dname_ip_address' ); $table->noSort = array( 'dname_previous', 'dname_current', 'dname_date', 'dname_ip_address' ); $table->parsers = array( 'dname_date' => function( $value ) { return \IPS\DateTime::ts( $value )->localeDate(); }, ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->viewDnameHistory( (string) $table, $member ); } /** * Clear Display Name History * * @return void */ public function clearDnameHistory() { try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/C', 404, '' ); } \IPS\Db::i()->delete( 'core_dnames_change', array( 'dname_member_id=?', (int) $member->member_id ) ); if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( 'OK' ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'dname_history_cleared' ); } } /** * Flag as spammer * * @return void */ public function spam() { try { $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( $member->member_id == \IPS\Member::loggedIn()->member_id or $member->modPermission() or $member->isAdmin() ) { throw new \OutOfRangeException; } } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/8', 404, '' ); } if ( \IPS\Request::i()->status ) { $member->flagAsSpammer(); \IPS\Session::i()->log( 'modlog__spammer_flagged', array( $member->name => FALSE ) ); } else { $member->unflagAsSpammer(); \IPS\Session::i()->log( 'modlog__spammer_flagged', array( $member->name => FALSE ) ); } if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( 'OK' ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), ( \IPS\Request::i()->status ? 'account_flagged' : 'account_unflagged' ) ); } } /** * Approve * * @return void */ public function approve() { try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/A', 404, '' ); } $member->validate(); /* Log */ \IPS\Session::i()->log( 'acplog__members_approved', array( $member->name => FALSE ) ); if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( 'OK' ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'account_approved' ); } } /** * Resend Validation Email * * @return void */ public function resendEmail() { /* Load Member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/B', 404, '' ); } /* Send */ foreach ( \IPS\Db::i()->select( '*', 'core_validating', array( 'member_id=?', $member->member_id ) ) as $row ) { if ( !$row['user_verified'] ) { /* Lost Pass */ if ( $row['lost_pass'] ) { \IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $row['vid'] ) )->send( $member ); } /* New Reg */ elseif ( $row['new_reg'] ) { \IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( $member, $row['vid'] ) )->send( $member ); } /* Email Change */ elseif ( $row['email_chg'] ) { \IPS\Email::buildFromTemplate( 'core', 'email_change', array( $member, $row['vid'] ) )->send( $member ); } } } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( \IPS\Member::loggedIn()->language()->get('validation_email_resent') ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'validation_email_resent' ); } } /** * Merge * * @return void */ public function merge() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'members_merge' ); /* Load first member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/6', 404, '' ); } /* Build form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Member( 'member_merge', NULL, TRUE ) ); $form->add( new \IPS\Helpers\Form\Select( 'member_merge_keep', 1, TRUE, array( 'options' => array( 1 => \IPS\Member::loggedIn()->language()->addToStack( 'member_merge_keep_1', FALSE, array( 'sprintf' => array( $member->name ) ) ), 2 => 'member_merge_keep_2' ) ) ) ); /* Merge */ if ( $values = $form->values() ) { /* Which account are we keeping */ if ( $values['member_merge_keep'] == 1 ) { $accountToKeep = $member; $accountToDelete = $values['member_merge']; } else { $accountToDelete = $member; $accountToKeep = $values['member_merge']; } /* Do it */ try { $accountToKeep->merge( $accountToDelete ); } catch( \InvalidArgumentException $e ) { \IPS\Output::i()->error( $e->getMessage(), '3C114/J', 403, '' ); } /* Delete the account */ $accountToDelete->delete( FALSE ); /* Log */ \IPS\Session::i()->log( 'acplog__members_merge', array( $accountToKeep->name => FALSE, $accountToDelete->name ) ); /* Boink */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$accountToKeep->member_id}" ), 'saved' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'merge', $form, FALSE ); } /** * Ban * * @return void */ public function ban() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_ban' ); /* Load member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_ban_admin' ); } if ( $member->member_id == \IPS\Member::loggedIn()->member_id ) { throw new \OutOfRangeException; } } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/7', 404, '' ); } /* Just do it? */ if ( \IPS\Request::i()->permban ) { $member->temp_ban = -1; $member->save(); /* Login handler callback */ foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler ) { try { $handler->banAccount( $member, TRUE ); } catch( \Exception $e ){} } if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->json( 'OK' ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'account_approved' ); } } else { /* Get existing banned IPs */ $bannedIps = iterator_to_array( \IPS\Db::i()->select( 'ban_content', 'core_banfilters', array( 'ban_type=?', 'ip' ) )->setKeyField( 'ban_content' ) ); /* Build form */ $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Date( 'member_ban_until', $member->temp_ban, FALSE, array( 'time' => TRUE, 'unlimited' => -1, 'unlimitedLang' => 'permanently', 'unlimitedToggles' => $member->temp_ban == -1 ? array() : array( 'member_ban_group', 'member_ban_ips' ), 'unlimitedToggleOn' => FALSE, ), NULL, NULL, NULL, 'member_ban_until' ) ); if ( $member->temp_ban === 0 ) { $form->add( new \IPS\Helpers\Form\Select( 'member_ban_group', $member->member_group_id, FALSE, array( 'options' => \IPS\Member\Group::groups( FALSE, FALSE ), 'parse' => 'normal' ), NULL, NULL, NULL, 'member_ban_group' ) ); $memberIps = array_keys( $member->ipAddresses() ); $form->add( new \IPS\Helpers\Form\Select( 'member_ban_ips', array_intersect( $memberIps, $bannedIps ), FALSE, array( 'options' => $memberIps, 'multiple' => TRUE ), NULL, NULL, NULL, 'member_ban_ips' ) ); } /* Ban */ if ( $values = $form->values() ) { $_existingValue = $member->temp_ban; if ( $values['member_ban_until'] === -1 ) { $member->temp_ban = -1; } elseif ( !$values['member_ban_until'] ) { $member->temp_ban = 0; } else { $member->temp_ban = $values['member_ban_until']->getTimestamp(); } if ( isset( $values['member_ban_group'] ) ) { $member->member_group_id = $values['member_ban_group']; } if ( isset( $values['member_ban_ips'] ) ) { foreach ( $memberIps as $ip ) { if ( in_array( $ip, $values['member_ban_ips'] ) and !in_array( $ip, $bannedIps ) ) { \IPS\DB::i()->insert( 'core_banfilters', array( 'ban_type' => 'ip', 'ban_content' => $ip, 'ban_date' => time(), 'ban_reason' => $member->name ) ); } elseif ( !in_array( $ip, $values['member_ban_ips'] ) and in_array( $ip, $bannedIps ) ) { \IPS\Db::i()->delete( 'core_banfilters', array( 'ban_content=? AND ban_type=?', $ip, 'ip' ) ); } } unset( \IPS\Data\Store::i()->bannedIpAddresses ); } $member->save(); /* Login handler callback */ if( ( $_existingValue == 0 AND $member->temp_ban == -1 ) OR ( $_existingValue == -1 AND $member->temp_ban == 0 ) ) { foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler ) { try { $handler->banAccount( $member, ( $member->temp_ban == -1 ) ? TRUE : FALSE ); } catch( \Exception $e ){} } } \IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'ban', $form, FALSE ); } } /** * Login as member * * @return void */ public function login() { \IPS\Dispatcher::i()->checkAcpPermission( 'member_login' ); /* Load Member and Admin*/ $member = \IPS\Member::load( \IPS\Request::i()->id ); $admin = \IPS\Member::loggedIn(); /* Generate a hash and store it in \IPS\Data\Store */ $key = md5( uniqid() ); \IPS\Data\Store::i()->admin_login_as_user = $key; /* Log It */ \IPS\Session::i()->log( 'acplog__members_loginas', array( $member->name => FALSE ) ); /* Redirect to front controller to update session */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login&do=loginas&admin={$admin->member_id}&id={$member->member_id}&key={$key}", 'front' ) ); } /** * Delete Content * * @return void */ public function deleteContent() { \IPS\Dispatcher::i()->checkAcpPermission( 'membertools_delete' ); /* Load Member */ $member = \IPS\Member::load( \IPS\Request::i()->id ); /* Build form */ $form = new \IPS\Helpers\Form('delete_content', 'delete'); $form->add( new \IPS\Helpers\Form\Radio( 'hide_or_delete_content', NULL, TRUE, array( 'options' => array( 'hide' => 'hide', 'delete' => 'delete' ) ) ) ); if ( $values = $form->values() ) { $member->hideOrDeleteAllContent( $values['hide_or_delete_content'] ); \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'deleted' ); } /* Display */ if ( \IPS\Request::i()->isAjax() ) { \IPS\Output::i()->outputTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core' ), 'blankTemplate' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'deletecontent', $form, FALSE ); } /** * Delete Guest Content * * @return void */ public function deleteGuestContent() { \IPS\Dispatcher::i()->checkAcpPermission( 'membertools_delete' ); $form = new \IPS\Helpers\Form; $form->add( new \IPS\Helpers\Form\Text( 'guest_name_to_delete', NULL, TRUE ) ); if ( $values = $form->values() ) { $classes = array(); foreach ( \IPS\Content::routedClasses( FALSE, TRUE ) as $class ) { if ( isset( $class::$databaseColumnMap['author'] ) and isset( $class::$databaseColumnMap['author_name'] ) ) { \IPS\Task::queue( 'core', 'MemberContent', array( 'member_id' => 0, 'name' => $values['guest_name_to_delete'], 'class' => $class, 'action' => 'delete' ) ); } } \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=membersettings&controller=spam&searchResult=guest_captcha" ), 'deleted' ); } \IPS\Output::i()->output = $form; } /** * Delete * * @return void */ public function delete() { /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_delete' ); /* Load member */ try { $member = \IPS\Member::load( \IPS\Request::i()->id ); if ( $member->isAdmin() ) { \IPS\Dispatcher::i()->checkAcpPermission( 'member_delete_admin' ); } if( $member->member_id == \IPS\Member::loggedIn()->member_id ) { throw new \OutOfRangeException; } } catch ( \OutOfRangeException $e ) { \IPS\Output::i()->error( 'node_error', '2C114/7', 404, '' ); } /* Delete */ \IPS\Session::i()->log( 'acplog__members_deleted', array( $member->name => FALSE ) ); $member->delete(); /* Boink */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members" ), 'deleted' ); } /** * Admin Details * * @return void */ public function adminDetails() { $details = array( 'username' => \IPS\Member::loggedIn()->name, 'email_address' => \IPS\Member::loggedIn()->email, 'password' => \IPS\Member::loggedIn()->language()->addToStack('password_hidden'), ); \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('change_details'); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members', 'core' )->adminDetails( $details ); } /** * Admin Password * * @return void */ protected function adminPassword() { $form = new \IPS\Helpers\Form( 'form' ); $form->add( new \IPS\Helpers\Form\Password( 'current_password', '', TRUE, array( 'validateFor' => \IPS\Member::loggedIn() ) ) ); $form->add( new \IPS\Helpers\Form\Password( 'new_password', '', TRUE ) ); $form->add( new \IPS\Helpers\Form\Password( 'confirm_new_password', '', TRUE, array( 'confirm' => 'new_password' ) ) ); if ( $values = $form->values() ) { /* Save it */ foreach ( \IPS\Login::handlers( TRUE ) as $handler ) { try { $handler->changePassword( \IPS\Member::loggedIn(), $values['new_password'] ); } catch( \BadMethodCallException $e ) {} } /* Log */ \IPS\Session::i()->log( 'acplogs__admin_pass_updated' ); /* Redirect */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=adminDetails" ), 'saved' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( \IPS\Member::loggedIn()->language()->addToStack('change_password'), $form, FALSE ); } /** * Admin Email * * @return void */ public function adminEmail() { $form = new \IPS\Helpers\Form( 'form' ); $form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array() ) ); if ( $values = $form->values() ) { /* Save it */ if ( $values['email_address'] != \IPS\Member::loggedIn()->email ) { foreach ( \IPS\Login::handlers( TRUE ) as $handler ) { try { $handler->changeEmail( \IPS\Member::loggedIn(), \IPS\Member::loggedIn()->email, $values['email_address'] ); } catch( \BadMethodCallException $e ) {} } } /* Log */ \IPS\Session::i()->log( 'acplogs__admin_email_updated' ); /* Redirect */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=adminDetails" ), 'saved' ); } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( \IPS\Member::loggedIn()->language()->addToStack('change_email'), $form, FALSE ); } /** * Recount Content Item Count * * @return void */ public function recountContent() { if ( !\IPS\Request::i()->prompt ) { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=reset&do=posts' ) ); } /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_recount_content' ); /* Load Member */ $member = \IPS\Member::load( \IPS\Request::i()->id ); /* Rebuild */ $member->recountContent(); /* redirect */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } /** * Recount Reputation Count * * @return void */ public function recountReputation() { if ( !\IPS\Request::i()->prompt ) { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=reset&do=rep' ) ); } /* Check permission */ \IPS\Dispatcher::i()->checkAcpPermission( 'member_recount_content' ); /* Load Member */ $member = \IPS\Member::load( \IPS\Request::i()->id ); /* Rebuild */ $member->recountReputation(); /* redirect */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), 'saved' ); } }