Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

@@ -1,6 +1,6 @@
<?php
/**
* @brief memberactivity
* @brief Community Activity
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
@@ -18,9 +18,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* memberactivity
* Community Activity
*/
class _memberactivity extends \IPS\Dispatcher\Controller
class _communityactivity extends \IPS\Dispatcher\Controller
{
/**
* Execute
@@ -29,7 +29,7 @@ class _memberactivity extends \IPS\Dispatcher\Controller
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'memberactivity_manage' );
\IPS\Dispatcher::i()->checkAcpPermission( 'communityactivity_manage' );
parent::execute();
}
@@ -42,7 +42,7 @@ class _memberactivity extends \IPS\Dispatcher\Controller
protected function manage()
{
$chart = new \IPS\Helpers\Chart\Callback(
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=memberactivity' ),
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=communityactivity' ),
array( $this, 'getResults' ),
'',
array(
@@ -67,7 +67,7 @@ class _memberactivity extends \IPS\Dispatcher\Controller
return;
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_memberactivity');
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_communityactivity');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'stats' )->activitymessage();
\IPS\Output::i()->output .= (string) $chart;
}
@@ -82,8 +82,29 @@ class _memberactivity extends \IPS\Dispatcher\Controller
{
/* Get results */
$results = array();
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_search_index', 'index_date_updated', 'index_author', $chart ) );
if ( \IPS\Settings::i()->search_method == 'mysql' )
{
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_search_index', 'index_date_updated', 'index_author', $chart ) );
}
else
{
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter' ) as $contentRouter )
{
foreach ( $contentRouter->classes as $class )
{
if ( isset( $class::$databaseColumnMap['author'] ) )
{
$results = array_replace_recursive( $results, $this->getSqlResults(
$class::$databaseTable,
$class::$databasePrefix . ( isset( $class::$databaseColumnMap['updated'] ) ? $class::$databaseColumnMap['updated'] : $class::$databaseColumnMap['date'] ),
$class::$databasePrefix . $class::$databaseColumnMap['author'],
$chart
) );
}
}
}
}
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_reputation_index', 'rep_date', 'member_id', $chart ) );
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_follow', 'follow_added', 'follow_member_id', $chart ) );
@@ -140,7 +161,7 @@ class _memberactivity extends \IPS\Dispatcher\Controller
/* First we need to get search index activity */
$fromUnixTime = "FROM_UNIXTIME( IFNULL( {$date}, 0 ) )";
if ( !$chart->timezoneError and \IPS\Member::loggedIn()->timezone and in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
if ( !$chart->timezoneError and \IPS\Member::loggedIn()->timezone and in_array( \IPS\Member::loggedIn()->timezone, \IPS\DateTime::getTimezoneIdentifiers() ) )
{
$fromUnixTime = "CONVERT_TZ( {$fromUnixTime}, @@session.time_zone, '" . \IPS\Db::i()->escape_string( \IPS\Member::loggedIn()->timezone ) . "' )";
}
@@ -133,6 +133,13 @@ class _keywords extends \IPS\Dispatcher\Controller
try
{
$class = $data['class'];
/* Check that the class exists */
if( !class_exists( $class ) )
{
throw new \InvalidArgumentException;
}
$item = $class::load( $data['id'] );
return $item->author()->link();
@@ -149,6 +156,13 @@ class _keywords extends \IPS\Dispatcher\Controller
try
{
$class = $data['class'];
/* Check that the class exists */
if( !class_exists( $class ) )
{
throw new \InvalidArgumentException;
}
$item = $class::load( $data['id'] );
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, ( $item instanceof \IPS\Content\Comment ) ? $item->item()->mapped('title') : $item->mapped('title'), TRUE );
@@ -162,7 +176,7 @@ class _keywords extends \IPS\Dispatcher\Controller
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_keywords');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table, TRUE, 'ipsPad ipsSpacer_top' );
}
/**
@@ -0,0 +1,186 @@
<?php
/**
* @brief reactions
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 19 Jan 2018
*/
namespace IPS\core\modules\admin\activitystats;
/* 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;
}
/**
* reactions
*/
class _reactions extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'reactionsstats_manage' );
parent::execute();
}
/**
* Reaction statistics
*
* @return void
*/
protected function manage()
{
$tabs = array(
'type' => 'stats_reactions_by_type',
'app' => 'stats_reactions_by_app',
'list' => 'stats_reactions_top_content',
'givers' => 'stats_reactions_top_givers',
'getters' => 'stats_reactions_top_receivers',
);
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'type';
if ( $activeTab === 'type' OR $activeTab === 'app' )
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=reactions&tab=" . $activeTab ), 'core_reputation_index', 'rep_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde', '#b09be4', '#eec766', '#9fc973', '#e291bf', '#55c1a6', '#5fb9da' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
),
'PieChart',
'monthly',
array( 'start' => 0, 'end' => 0 ),
array(),
$activeTab
);
if ( $activeTab === 'type' )
{
$chart->groupBy = 'reaction';
foreach( \IPS\Content\Reaction::roots() as $reaction )
{
$chart->addSeries( $reaction->_title, 'number', 'COUNT(*)', TRUE, $reaction->id );
}
}
else
{
$chart->groupBy = 'app';
foreach( \IPS\Application::roots() as $app )
{
$chart->addSeries( $app->_title, 'number', 'COUNT(*)', TRUE, $app->directory );
}
}
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart', 'PieChart' );
}
else
{
/* Database table helpers don't support grouping, so we will manually fetch the results and then let the table helper display */
$contentWhere = array();
$idToRatingMap = array();
if( $activeTab == 'list' )
{
$query = \IPS\Db::i()->select( 'MAX(id) as id, SUM(rep_rating) as rating', 'core_reputation_index', NULL, 'rating DESC', array( 0, 20 ), array( 'app', 'type', 'type_id' ) );
}
elseif( $activeTab == 'givers' )
{
$query = \IPS\Db::i()->select( 'MAX(id) as id, SUM(rep_rating) as rating', 'core_reputation_index', NULL, 'rating DESC', array( 0, 20 ), array( 'member_id' ) );
}
else
{
$query = \IPS\Db::i()->select( 'MAX(id) as id, SUM(rep_rating) as rating', 'core_reputation_index', NULL, 'rating DESC', array( 0, 20 ), array( 'member_received' ) );
}
foreach( $query as $reputation )
{
$contentWhere[] = $reputation['id'];
$idToRatingMap[ $reputation['id'] ] = $reputation['rating'];
}
/* Create the table */
$chart = new \IPS\Helpers\Table\Db( 'core_reputation_index', \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=reactions&type=list' ), array( \IPS\Db::i()->in( 'id', $contentWhere ) ) );
$chart->quickSearch = NULL;
/* Columns we need */
if( $activeTab == 'list' )
{
$chart->langPrefix = 'reactstats_';
$chart->include = array( 'type_id', 'rep_date', 'member_id', 'rating' );
$chart->mainColumn = 'type_id';
}
else
{
$chart->langPrefix = 'reactstatsm_';
$column = ( $activeTab == 'givers' ) ? 'member_id' : 'member_received';
$chart->include = array( $column, 'rep_date', 'rating' );
$chart->mainColumn = $column;
}
$chart->noSort = array( 'member_id', 'type_id', 'rep_date', 'rating' );
$chart->sortBy = $chart->sortBy ?: 'rating';
$chart->sortDirection = $chart->sortDirection ?: 'desc';
/* Custom parsers */
$chart->parsers = array(
'rep_date' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->localeDate();
},
'member_id' => function( $val, $row )
{
return \IPS\Member::load( $val )->link();
},
'member_received' => function( $val, $row )
{
return \IPS\Member::load( $val )->link();
},
'rating' => function( $val, $row ) use ( $idToRatingMap )
{
/* Return the reputation total */
return $idToRatingMap[ $row['id'] ];
},
'type_id' => function( $val, $row )
{
$class = $row['rep_class'];
try
{
$item = $class::load( $row['type_id'] );
return \IPS\Theme::i()->getTemplate( 'activitystats' )->contentCell( $item );
}
catch( \Exception $e )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'unavailable' );
}
},
);
}
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = (string) $chart;
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_reactions');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, (string) $chart, \IPS\Http\Url::internal( "app=core&module=activitystats&controller=reactions" ), 'tab', '', 'ipsPad' );
}
}
}
@@ -0,0 +1,76 @@
<?php
/**
* @brief Tag Usage
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 24 Jan 2018
*/
namespace IPS\core\modules\admin\activitystats;
/* 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;
}
/**
* Tag Usage
*/
class _tags extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'tagsusage_manage' );
parent::execute();
}
/**
* Show a graph of tag usage
*
* @return void
*/
protected function manage()
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=tags" ), 'core_tags', 'tag_added', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
),
'AreaChart',
'daily',
array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) ), 'end' => 0 )
);
$chart->groupBy = 'tag_text';
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart', 'PieChart' );
$where = $chart->where;
$where[] = array( "tag_added>?", 0 );
if ( $chart->start )
{
$where[] = array( "tag_added>?", $chart->start->getTimestamp() );
}
if ( $chart->end )
{
$where[] = array( "tag_added<?", $chart->end->getTimestamp() );
}
foreach( \IPS\Db::i()->select( 'tag_text', 'core_tags', $where, NULL, NULL, array( 'tag_text' ) ) as $tag )
{
$chart->addSeries( $tag, 'number', 'COUNT(*)', TRUE, $tag );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_tags');
\IPS\Output::i()->output = (string) $chart;
}
}
@@ -28,7 +28,7 @@ class _api extends \IPS\Dispatcher\Controller
* @return void
*/
public function __call( $method, $args )
{
{
/* Check htaccess is correct */
if ( \IPS\Settings::i()->use_friendly_urls and \IPS\Settings::i()->htaccess_mod_rewrite )
{
@@ -63,6 +63,10 @@ class _api extends \IPS\Dispatcher\Controller
/* Work out tabs */
$tabs = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'oauth_manage' ) )
{
$tabs['oauth'] = 'oauth_clients';
}
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_manage' ) )
{
$tabs['apiKeys'] = 'api_keys';
@@ -93,30 +97,18 @@ class _api extends \IPS\Dispatcher\Controller
$class->execute();
$output = \IPS\Output::i()->output;
if ( $method !== 'manage' or \IPS\Request::i()->isAjax() )
{
return;
}
\IPS\Output::i()->output = '';
if ( \IPS\Request::i()->isCgi() )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'api_url_key_notice', 'information' );
}
/* Help button */
\IPS\Output::i()->sidebar['actions']['help'] = array(
'icon' => 'question-circle',
'title' => 'help',
'link' => \IPS\Http\Url::ips( 'docs/restapi' ),
'target' => 'blank'
);
/* Output */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/api.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_system.js', 'core', 'admin' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_applications_api');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'rest_and_oauth_blurb' );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $output, \IPS\Http\Url::internal( "app=core&module=applications&controller=api" ) );
}
@@ -32,6 +32,11 @@ class _apiKeys extends \IPS\Node\Controller
*/
public $_descriptionHtml = TRUE;
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
/**
* Execute
*
@@ -43,4 +48,15 @@ class _apiKeys extends \IPS\Node\Controller
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/api.css', 'core', 'admin' ) );
parent::execute();
}
/**
* View List (checks endpoints are available on https)
*
* @return void
*/
protected function manage()
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'api_keys_blurb', TRUE, TRUE );
return parent::manage();
}
}
@@ -57,14 +57,32 @@ class _apiLogs extends \IPS\Dispatcher\Controller
},
'api_key' => function( $val, $row )
{
try
$apiKey = NULL;
$client = NULL;
$member = NULL;
if ( $row['api_key'] )
{
return \IPS\Api\Key::load( $val )->_title;
try
{
$apiKey = \IPS\Api\Key::load( $row['api_key'] );
}
catch ( \OutOfRangeException $e ) { }
}
catch ( \OutOfRangeException $e )
if ( $row['client_id'] )
{
return \IPS\Theme::i()->getTemplate('api')->apiKey( $val );
try
{
$client = \IPS\Api\OAuthClient::load( $row['client_id'] );
}
catch ( \OutOfRangeException $e ) { }
if ( $row['member_id'] )
{
$member = \IPS\Member::load( $row['member_id'] );
}
}
return \IPS\Theme::i()->getTemplate('api')->apiLogCredentials( $row, $apiKey, $client, $member );
},
'response_code' => function( $val )
{
@@ -62,7 +62,7 @@ class _apiReference extends \IPS\Dispatcher\Controller
if ( isset( $endpoints[ $selected ]['details']['reqapiparam'] ) )
{
$params = array_map( function( $v ) {
$v[4] = TRUE;
$v[4] = 'required';
return $v;
}, $endpoints[ $selected ]['details']['reqapiparam'] );
}
@@ -71,6 +71,22 @@ class _apiReference extends \IPS\Dispatcher\Controller
$params = array_merge( $params, $endpoints[ $selected ]['details']['apiparam'] );
}
$exceptions = isset( $endpoints[ $selected ]['details']['throws'] ) ? $endpoints[ $selected ]['details']['throws'] : NULL;
if ( isset( $endpoints[ $selected ]['details']['apimemberonly'] ) )
{
$exceptions[] = array(
'3S290/C',
'MEMBER_ONLY',
\IPS\Member::loggedIn()->language()->addToStack('api_endpoint_member_only_err')
);
}
if ( isset( $endpoints[ $selected ]['details']['apiclientonly'] ) )
{
$exceptions[] = array(
'3S290/D',
'CLIENT_ONLY',
\IPS\Member::loggedIn()->language()->addToStack('api_endpoint_client_only_err')
);
}
$response = NULL;
$return = array_filter( $endpoints[ $selected ]['details']['return'][0] );
@@ -81,11 +97,11 @@ class _apiReference extends \IPS\Dispatcher\Controller
{
foreach ( $endpoints[ $selected ]['details']['apiresponse'] as $data )
{
if ( !in_array( $data[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
if ( mb_strpos( $data[0], '|' ) === FALSE AND !in_array( $data[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
{
if ( mb_substr( $data[0], 0, 1 ) == '[' )
{
if ( !in_array( mb_substr( $data[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
if ( !in_array( mb_substr( $data[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
{
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( mb_substr( $data[0], 1, -1 ) ) );
}
@@ -126,7 +142,7 @@ class _apiReference extends \IPS\Dispatcher\Controller
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
$additionalClasses[ mb_strtolower( mb_substr( $class, mb_strrpos( $class, '\\' ) + 1 ) ) ] = \IPS\Theme::i()->getTemplate('api')->referenceTable( $decoded['details']['apiresponse'] );
}
$content = \IPS\Theme::i()->getTemplate('api')->referenceEndpoint( $endpoints[ $selected ], $params, $exceptions, $response, $additionalClasses );
}
@@ -160,11 +176,11 @@ class _apiReference extends \IPS\Dispatcher\Controller
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
foreach ( $decoded['details']['apiresponse'] as $response )
{
if ( !in_array( $response[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
if ( mb_strpos( $response[0], '|' ) === FALSE AND !in_array( $response[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
{
if ( mb_substr( $response[0], 0, 1 ) == '[' )
{
if ( !in_array( mb_substr( $response[0], 1, -1 ), $return ) and !in_array( mb_substr( $response[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
if ( !in_array( mb_substr( $response[0], 1, -1 ), $return ) and !in_array( mb_substr( $response[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object', 'array' ) ) )
{
$return = array_merge( $return, $this->_getAdditionalClasses( mb_substr( $response[0], 1, -1 ) ) );
}
@@ -235,7 +235,9 @@ class _applications extends \IPS\Node\Controller
*/
public function updateCheck()
{
\IPS\Task::constructFromData( \IPS\Db::i()->select( '*', 'core_tasks', array( 'app=? AND `key`=?', 'core', 'updatecheck' ) )->first() )->run();
$task = \IPS\Task::constructFromData( \IPS\Db::i()->select( '*', 'core_tasks', array( 'app=? AND `key`=?', 'core', 'updatecheck' ) )->first() );
$task->type = 'manual';
$task->run();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=applications" ), 'update_check_complete' );
}
@@ -629,6 +631,7 @@ class _applications extends \IPS\Node\Controller
}
catch( \PharException $e )
{
\IPS\Log::log( $e, 'phar' );
\IPS\Output::i()->error( 'app_no_phar', '4C133/7', 403, '' );
}
@@ -1242,7 +1245,7 @@ class _applications extends \IPS\Node\Controller
/* Work out tab */
$tab = \IPS\Request::i()->tab ?: 'details';
$activeTabContents = call_user_func( array( $this, '_show' . ucfirst( $tab ) ), $application );
$activeTabContents = call_user_func( array( $this, '_show' . mb_ucfirst( $tab ) ), $application );
/* If this is an AJAX request, just return tab contents */
if( \IPS\Request::i()->isAjax() && \IPS\Request::i()->tab and !isset( \IPS\Request::i()->ajaxValidate ) )
@@ -1376,6 +1379,7 @@ class _applications extends \IPS\Node\Controller
}
catch( \PharException $e )
{
\IPS\Log::log( $e, 'phar' );
\IPS\Output::i()->error( 'application_notvalid', '1C133/9', 403, '' );
}
catch( \UnexpectedValueException $e )
@@ -1413,7 +1417,8 @@ class _applications extends \IPS\Node\Controller
}
else
{
@chmod( $f->getPathname(), \IPS\IPS_FILE_PERMISSION );
/* If this is a .php file in the /interface/ folder it will be called via web directly. We cannot set permissions too high though or it won't execute in many environments */
@chmod( $f->getPathname(), ( mb_strpos( $f->getPathname(), '/interface/' ) !== FALSE AND mb_strtolower( $f->getExtension() ) == 'php' ) ? \IPS\FILE_PERMISSION_NO_WRITE : \IPS\IPS_FILE_PERMISSION );
}
}
}
@@ -1546,20 +1551,4 @@ class _applications extends \IPS\Node\Controller
return $table;
}
/**
* Toggle Enabled/Disable
*
* @return void
*/
protected function enableToggle()
{
/* Clear templates to rebuild automatically */
\IPS\Theme::deleteCompiledTemplate();
/* Invalidate disk templates */
\IPS\Theme::resetAllCacheKeys();
parent::enableToggle();
}
}
@@ -80,11 +80,11 @@ class _developer extends \IPS\Dispatcher\Controller
/* Work out output */
if ( $pos = mb_strpos( $this->activeTab, '-' ) )
{
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( mb_substr( $this->activeTab, 0, $pos ) ) ), mb_substr( $this->activeTab, $pos + 1 ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( mb_substr( $this->activeTab, 0, $pos ) ) ), mb_substr( $this->activeTab, $pos + 1 ) );
}
else
{
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
}
/* If this is an AJAX request, just return it */
@@ -483,6 +483,9 @@ class _developer extends \IPS\Dispatcher\Controller
$position = array();
foreach( \IPS\Request::i()->ajax_order as $id => $parent )
{
/* We have to fudge children "ids" to prevent conflicts in the array */
$id = str_replace( 's@', '', $id );
if ( !isset( $order[ $parent ] ) )
{
$order[ $parent ] = array();
@@ -496,13 +499,30 @@ class _developer extends \IPS\Dispatcher\Controller
{
$order = array( \IPS\Request::i()->root ?: 'null' => \IPS\Request::i()->order );
}
/* Sort */
$_menu = $menu;
$menu = $menu;
$menu = array();
if( isset( $order['null'] ) )
{
foreach( $order['null'] as $key => $position )
{
foreach ( $_menu as $_parent => $_items )
{
if ( $key == $_parent )
{
$menu[ $_parent ] = $_menu[ $_parent ];
break;
}
}
}
}
foreach ( $order as $parent => $items )
{
if ( array_key_exists( $parent, $menu ) )
if ( $parent === NULL OR array_key_exists( $parent, $_menu ) )
{
$menu[ $parent ] = array();
foreach ( $items as $key => $position )
@@ -511,7 +531,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
if ( array_key_exists( $key, $_items ) )
{
$menu[ $parent ][ $key ] = $_menu[ $_parent ][ $key ];
$menu[ $parent ][ $key ] = $_menu[ $_parent ][ $key ];
break;
}
}
@@ -576,7 +596,7 @@ class _developer extends \IPS\Dispatcher\Controller
foreach ( $menu[ $k ] as $id => $row )
{
$lang = "menu__{$appKey}_{$k}_{$id}";
$rows[ $id ] = \IPS\Theme::i()->getTemplate( 'trees' )->row( $url, $id, \IPS\Member::loggedIn()->language()->addToStack( $lang ), FALSE, array(
$rows[ 's@' . $id ] = \IPS\Theme::i()->getTemplate( 'trees' )->row( $url, 's@' . $id, \IPS\Member::loggedIn()->language()->addToStack( $lang ), FALSE, array(
'edit' => array(
'icon' => 'pencil',
'title' => 'edit',
@@ -608,7 +628,7 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function menuForm()
{
/* Current Manu */
/* Current Menu */
$menu = $this->_getJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/acpmenu.json" );
/* Get module and controllers */
@@ -723,7 +743,7 @@ class _developer extends \IPS\Dispatcher\Controller
/* Sort */
uasort( $this->restrictions[ $id[0] ][ $id[1] ], function( $a, $b ) use ( $order ) {
return $order[ str_replace( '_', '~', $a ) ] - $order[ str_replace( '_', '~', $b ) ];
return ( isset( $order[ str_replace( '_', '~', $a ) ] ) ? $order[ str_replace( '_', '~', $a ) ] : 0 ) - ( isset( $order[ str_replace( '_', '~', $b ) ] ) ? $order[ str_replace( '_', '~', $b ) ] : 0 );
});
/* Write */
@@ -1103,7 +1123,7 @@ class _developer extends \IPS\Dispatcher\Controller
isset( $values['model_name'] ) ? $values['model_name'] : NULL,
isset( $values['database_table_name'] ) ? $values['database_table_name'] : NULL,
),
file_get_contents( \IPS\ROOT_PATH . "/applications/core/data/defaults/Controller" . ucfirst( $values['type'] ) . '.txt' )
file_get_contents( \IPS\ROOT_PATH . "/applications/core/data/defaults/Controller" . mb_ucfirst( $values['type'] ) . '.txt' )
);
/* If this isn't an IPS app, strip out our header */
@@ -1125,7 +1145,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
$menu = $this->_getJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/acpmenu.json" );
$menu[ $module->key ][ $values['filename'] ] = array(
'tab' => $values['acpmenu_tab'][0],
'tab' => $values['acpmenu_tab'],
'controller' => $values['filename'],
'do' => '',
'restriction' => $restriction
@@ -1496,6 +1516,7 @@ class _developer extends \IPS\Dispatcher\Controller
unset( $_definition['comment'] );
unset( $_definition['engine'] );
unset( $_definition['collation'] );
unset( $_definition['reporting'] );
try
{
$localDefinition = $this->_getTableDefinition( $definition['name'] );
@@ -1605,6 +1626,14 @@ class _developer extends \IPS\Dispatcher\Controller
}
) );
if ( in_array( $this->application->directory, \IPS\Application::$ipsApps ) )
{
$output->add( new \IPS\Helpers\Form\Select( 'database_table_reporting', isset( $definition['reporting'] ) ? $definition['reporting'] : 'none', FALSE, array( 'options' => array(
'none' => 'database_table_reporting_none',
'count' => 'database_table_reporting_count',
) ) ) );
}
/* Handle submissions */
if ( $values = $output->values() )
{
@@ -1628,6 +1657,12 @@ class _developer extends \IPS\Dispatcher\Controller
}
}
/* Changed reporting? */
if ( !isset( $definition['reporting'] ) or $values['database_table_reporting'] !== $definition['reporting'] )
{
$schemaJson[ $definition['name'] ]['reporting'] = $values['database_table_reporting'];
}
/* Renamed table? */
$values['database_table_name'] = "{$this->application->directory}_{$values['database_table_name']}";
if ( $values['database_table_name'] !== $definition['name'] )
@@ -1639,7 +1674,7 @@ class _developer extends \IPS\Dispatcher\Controller
unset( $schemaJson[ $definition['name'] ] );
$definition['name'] = $values['database_table_name'];
}
/* Run queries */
foreach ( $queries as $query )
{
@@ -2487,7 +2522,7 @@ class _developer extends \IPS\Dispatcher\Controller
/* Use local database */
if ( \IPS\Request::i()->local )
{
{
foreach ( $localDefinition['columns'] as $i => $data )
{
if ( $data['type'] == 'BIT' )
@@ -2500,6 +2535,14 @@ class _developer extends \IPS\Dispatcher\Controller
{
$schema[ \IPS\Request::i()->_name ]['inserts'] = $schemaDefinition['inserts'];
}
if ( isset( $schemaDefinition['engine'] ) )
{
$schema[ \IPS\Request::i()->_name ]['engine'] = $schemaDefinition['engine'];
}
else
{
unset( $schema[ \IPS\Request::i()->_name ]['engine'] );
}
$this->_writeSchema( $schema );
}
/* Use schema file */
@@ -2755,8 +2798,16 @@ class _developer extends \IPS\Dispatcher\Controller
$form->langPrefix = 'dev_settings_';
$form->columns = array(
'key' => array( 'Text', NULL, TRUE ),
'default' => array( 'Text' )
'default' => array( 'Text' ),
);
if ( in_array( $this->application->directory, \IPS\Application::$ipsApps ) )
{
$form->columns['report'] = array( 'Select', 'none', FALSE, array( 'options' => array(
'none' => 'dev_settings_none',
'full' => 'dev_settings_full',
'bool' => 'dev_settings_bool',
) ) );
}
$form->rows = $settings;
if ( $form->values() !== FALSE )
@@ -2804,7 +2855,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
return strnatcmp( $a['key'], $b['key'] );
} );
$this->_writeJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/settings.json", $save );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=settings" ) );
}
@@ -3694,6 +3745,21 @@ class _developer extends \IPS\Dispatcher\Controller
case 'changeColumn':
unset( $queriesJson[ $i ]['params'][0]['columns'][ $query['params'][1] ] );
$queriesJson[ $i ]['params'][0]['columns'][ $query['params'][2]['name'] ] = $query['params'][2];
/* Fix references to the column name in indexes */
if ( isset( $queriesJson[ $i ]['params'][0]['indexes'] ) )
{
foreach( $queriesJson[ $i ]['params'][0]['indexes'] as $indexName => $indexDefinition )
{
foreach( $indexDefinition['columns'] as $_idx => $columnName )
{
if( $columnName == $query['params'][1] )
{
$queriesJson[ $i ]['params'][0]['indexes'][ $indexName ]['columns'][ $_idx ] = $query['params'][2]['name'];
}
}
}
}
$added = TRUE;
break;
@@ -157,7 +157,7 @@ class _menu extends \IPS\Dispatcher\Controller
{
if ( !$field->htmlId )
{
$field->htmlId = md5( uniqid() );
$field->htmlId = md5( mt_rand() );
}
$toggles[ $key ][ $field->name ] = $field->htmlId;
@@ -0,0 +1,430 @@
<?php
/**
* @brief OAuth Clients
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 29 Apr 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\applications;
/* 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;
}
/**
* OAuth Clients
*/
class _oauth extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = 'IPS\Api\OAuthClient';
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'oauth_manage' );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/api.css', 'core', 'admin' ) );
return parent::execute();
}
/**
* View List (checks endpoints are available on https)
*
* @return void
*/
protected function manage()
{
if ( \IPS\OAUTH_REQUIRES_HTTPS and mb_substr( \IPS\Settings::i()->base_url, 0, 8 ) !== 'https://' )
{
try
{
$response = \IPS\Http\Url::external( 'https://' . mb_substr( \IPS\Settings::i()->base_url, 7 ) )->request()->get();
}
catch ( \IPS\Http\Request\Exception $e )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms' )->blurb( \IPS\CIC ? 'oauth_https_warning_cic' : 'oauth_https_warning', TRUE, TRUE );
return;
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'oauth_clients_blurb', TRUE, TRUE );
return parent::manage();
}
/**
* View Client Details
*
* @return void
*/
protected function view()
{
try
{
$client = \IPS\Api\OAuthClient::load( \IPS\Request::i()->client_id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C362/1', 404, '' );
}
$secret = NULL;
if ( isset( \IPS\Request::i()->newSecret ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'oauth_secrets' ) )
{
$secret = \IPS\Login::generateRandomString( 48 );
$client->client_secret = password_hash( $secret, PASSWORD_DEFAULT );
$client->brute_force = NULL;
$client->save();
\IPS\Session::i()->log( 'acplogs__oauth_new_secret', array( 'core_oauth_client_' . $client->client_id => TRUE ) );
}
\IPS\Output::i()->sidebar['actions'] = $client->getButtons( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$client->client_id}" ) );
unset( \IPS\Output::i()->sidebar['actions']['view'] );
$bruteForce = NULL;
if ( $client->brute_force and $bruteForce = json_decode( $client->brute_force, TRUE ) )
{
$data = array();
foreach ( $bruteForce as $ipAddress => $fails )
{
$data[] = array(
'ip_address' => $ipAddress,
'fails' => $fails
);
}
$bruteForce = new \IPS\Helpers\Table\Custom( $data, \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$client->client_id}" ) );
$bruteForce->langPrefix = 'oauth_brute_force_';
$bruteForce->rowButtons = function( $row ) use ( $client ) {
$return = array();
$return['ban'] = array(
'icon' => 'ban',
'title' => 'oauth_brute_force_ban',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=bfRemove&ban=1&client_id={$client->client_id}" )->setQueryString( 'ip', $row['ip_address'] )
);
if ( $row['fails'] >= 3 )
{
$return['unlock'] = array(
'icon' => 'unlock',
'title' => 'oauth_brute_force_unlock',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=bfRemove&client_id={$client->client_id}" )->setQueryString( 'ip', $row['ip_address'] )
);
}
return $return;
};
}
\IPS\Output::i()->title = $client->_title;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('api')->oauthSecret( $client, $secret, $bruteForce );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=api&tab=oauth" ), 'oauth_clients' );
\IPS\Output::i()->breadcrumb[] = array( NULL, $client->_title );
}
/**
* Remove IP Address from bruteforce
*
* @return void
*/
protected function bfRemove()
{
try
{
$client = \IPS\Api\OAuthClient::load( \IPS\Request::i()->client_id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C362/4', 404, '' );
}
if ( \IPS\Request::i()->ip and \IPS\Request::i()->ban )
{
\IPS\Db::i()->insert( 'core_banfilters', array(
'ban_type' => 'ip',
'ban_content' => \IPS\Request::i()->ip,
'ban_date' => time(),
'ban_reason' => 'OAuth',
) );
unset( \IPS\Data\Store::i()->bannedIpAddresses );
\IPS\Session::i()->log( 'acplog__ban_created', array( 'ban_filter_ip_select' => TRUE, \IPS\Request::i()->ip => FALSE ) );
}
else
{
\IPS\Session::i()->log( 'acplogs__oauth_unlock_ip', array( \IPS\Request::i()->ip => FALSE, 'core_oauth_client_' . $client->client_id => TRUE ) );
}
$bruteForce = json_decode( $client->brute_force, TRUE );
unset( $bruteForce[ \IPS\Request::i()->ip ] );
$client->brute_force = json_encode( $bruteForce );
$client->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$client->client_id}" ) );
}
/**
* View Authorizations
*
* @return void
*/
protected function tokens()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'oauth_tokens' );
$client = NULL;
$member = NULL;
try
{
if ( isset( \IPS\Request::i()->client_id ) )
{
$client = \IPS\Api\OAuthClient::load( \IPS\Request::i()->client_id );
$baseUrl = \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens&client_id={$client->client_id}" );
}
else
{
$member = \IPS\Member::load( \IPS\Request::i()->member_id );
if ( !$member->member_id )
{
throw new \OutOfRangeException;
}
$baseUrl = \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens&member_id={$member->member_id}" );
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C362/3', 404, '' );
}
$table = new \IPS\Helpers\Table\Db( 'core_oauth_server_access_tokens', $baseUrl, array( $client ? array( 'client_id=?', $client->client_id ) : array( 'member_id=?', $member->member_id ) ) );
$table->langPrefix = 'oauth_authorization_';
$table->include = array();
$table->advancedSearch = array();
if ( $client )
{
$table->include[] = 'member_id';
$table->advancedSearch['member_id'] = \IPS\Helpers\Table\SEARCH_MEMBER;
}
else
{
$table->include[] = 'client_id';
}
$table->include[] = 'issued';
$table->include[] = 'status';
$table->advancedSearch['issued'] = \IPS\Helpers\Table\SEARCH_DATE_RANGE;
if ( !$client or $client->access_token_length )
{
$table->include[] = 'access_token_expires';
$table->advancedSearch['access_token_expires'] = \IPS\Helpers\Table\SEARCH_DATE_RANGE;
}
if ( !$client or ( $client->use_refresh_tokens and $client->refresh_token_length ) )
{
$table->include[] = 'refresh_token_expires';
$table->advancedSearch['refresh_token_expires'] = \IPS\Helpers\Table\SEARCH_DATE_RANGE;
}
if ( !$client or ( $client->scopes and json_decode( $client->scopes ) ) )
{
$table->include[] = 'scope';
}
$table->noSort = array( 'status', 'scope' );
$table->sortBy = $table->sortBy ?: 'issued';
$table->parsers = array(
'client_id' => function( $val ) {
try
{
$client = \IPS\Api\OAuthClient::load( $val );
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$client->client_id}" ), FALSE, $client->_title, FALSE );
}
catch ( \Exception $e )
{
return '';
}
},
'member_id' => function( $val ) {
if ( $val )
{
$member = \IPS\Member::load( $val );
if ( $member->member_id )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( $member, 'tiny' ) . \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( $member, 'tiny' );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('deleted_member');
}
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('oauth_client_credentials');
}
},
'issued' => function( $val ) {
return \IPS\DateTime::ts( $val );
},
'access_token_expires' => function( $val ) {
if ( $val )
{
return \IPS\DateTime::ts( $val );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('never');
}
},
'refresh_token_expires' => function( $val, $row ) {
if ( \IPS\Api\OAuthClient::load( $row['client_id'] )->use_refresh_tokens )
{
if ( $val )
{
return \IPS\DateTime::ts( $val );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('never');
}
}
else
{
return '';
}
},
'status' => function( $val, $row ) {
return \IPS\Theme::i()->getTemplate('api')->oauthStatus( $row, \IPS\Api\OAuthClient::load( $row['client_id'] )->use_refresh_tokens );
},
'scope' => function( $val ) {
if ( $val )
{
return implode( '<br>', json_decode( $val ) );
}
else
{
return '';
}
}
);
$table->rowButtons = function( $row ) use ( $client ) {
return array(
'revoke' => array(
'icon' => 'times-circle',
'title' => 'oauth_app_revoke',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=revokeToken&client_id={$row['client_id']}&member_id={$row['member_id']}&token={$row['access_token']}" )->setQueryString( 'r', $client ? 'c' : 'm' ),
'data' => array( 'delete' => '' )
)
);
};
$revokeAllLink = $client ? \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=revokeAllTokens&client_id={$client->client_id}" ) : \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=revokeAllTokens&member_id={$member->member_id}" );
$table->rootButtons = array(
'revoke' => array(
'icon' => 'times-circle',
'title' => 'oauth_revoke_all_tokens',
'link' => $revokeAllLink,
'data' => array( 'confirm' => '' )
)
);
\IPS\Output::i()->output = $table;
if ( $client )
{
\IPS\Output::i()->title = $client->_title;
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=api&tab=oauth" ), 'oauth_clients' );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$client->client_id}" ), $client->_title );
\IPS\Output::i()->breadcrumb[] = array( NULL, 'oauth_view_authorizations' );
}
else
{
\IPS\Output::i()->title = $member->name;
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), $member->name );
\IPS\Output::i()->breadcrumb[] = array( NULL, 'oauth_member_authorizations' );
}
}
/**
* Revoke Authorizations
*
* @return void
*/
protected function revokeToken()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'oauth_tokens' );
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'client_id=? AND access_token=?', \IPS\Request::i()->client_id, \IPS\Request::i()->token ) );
\IPS\Session::i()->log( 'acplogs__oauth_revoke_token', array( 'core_oauth_client_' . \IPS\Request::i()->client_id => TRUE ) );
if ( \IPS\Request::i()->r === 'c' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens" )->setQueryString( 'client_id', \IPS\Request::i()->client_id ) );
}
elseif ( \IPS\Request::i()->r === 'p' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=view" )->setQueryString( 'id', \IPS\Request::i()->client_id ) );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens" )->setQueryString( 'member_id', \IPS\Request::i()->member_id ) );
}
}
/**
* Revoke ALL Authorizations
*
* @return void
*/
protected function revokeAllTokens()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'oauth_tokens' );
if ( \IPS\Request::i()->member_id )
{
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'member_id=?', \IPS\Request::i()->member_id ) );
\IPS\Session::i()->log( 'acplogs__oauth_revoke_member', array( \IPS\Member::load( \IPS\Request::i()->member_id )->name => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens" )->setQueryString( 'member_id', \IPS\Request::i()->member_id ) );
}
else
{
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'client_id=?', \IPS\Request::i()->client_id ) );
\IPS\Session::i()->log( 'acplogs__oauth_revoke_client', array( 'core_oauth_client_' . $client->client_id => TRUE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=tokens" )->setQueryString( 'client_id', \IPS\Request::i()->client_id ) );
}
}
/**
* Redirect after save
*
* @param \IPS\Node\Model $old A clone of the node as it was before or NULL if this is a creation
* @param \IPS\Node\Model $new The node now
* @param string $lastUsedTab The tab last used in the form
* @return void
*/
protected function _afterSave( \IPS\Node\Model $old = NULL, \IPS\Node\Model $new, $lastUsedTab = FALSE )
{
if ( $new->_clientSecret )
{
\IPS\Output::i()->title = $new->_title;
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=api&tab=oauth" ), 'oauth_clients' );
\IPS\Output::i()->breadcrumb[] = array( NULL, $new->_title );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('api')->oauthSecret( $new, $new->_clientSecret, NULL );
\IPS\Output::i()->sidebar['actions'] = $new->getButtons( \IPS\Http\Url::internal( "app=core&module=applications&controller=oauth&do=view&client_id={$new->client_id}" ) );
unset( \IPS\Output::i()->sidebar['actions']['view'] );
}
else
{
return parent::_afterSave( $old, $new, $lastUsedTab );
}
}
}
@@ -5,7 +5,7 @@
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 25 Jul 2013␍
* @since 25 Jul 2013
*/
namespace IPS\core\modules\admin\applications;
@@ -84,10 +84,8 @@ class _plugins extends \IPS\Node\Controller
$disabledPlugins[] = $plugin->id;
}
}
\IPS\Settings::i()->disable_all_plugins = implode( ',', $disabledPlugins );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Settings::i()->disable_all_plugins ), array( 'conf_key=?', 'disable_all_plugins' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'disable_all_plugins' => implode( ',', $disabledPlugins ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins' ) );
}
@@ -110,10 +108,8 @@ class _plugins extends \IPS\Node\Controller
}
catch ( \Exception $e ) {}
}
\IPS\Settings::i()->disable_all_plugins = '';
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'disable_all_plugins' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'disable_all_plugins' => '' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins' ) );
}
@@ -295,7 +291,7 @@ class _plugins extends \IPS\Node\Controller
if ( !$plugin->location )
{
$directory = \mb_strtolower( preg_replace( '#[^a-zA-Z0-9_]#', '', $plugin->name ) );
$plugin->location = file_exists( \IPS\ROOT_PATH . "/plugins/" . $directory ) ? 'p' . mb_substr( md5( uniqid() ), 0, 10 ) : $directory;
$plugin->location = file_exists( \IPS\ROOT_PATH . "/plugins/" . $directory ) ? 'p' . mb_substr( md5( mt_rand() ), 0, 10 ) : $directory;
}
$plugin->version_long = $xml->getAttribute('version_long');
@@ -380,7 +376,7 @@ class _plugins extends \IPS\Node\Controller
while ( $xml->read() and $xml->name == 'hook' )
{
/* Make up a filename */
$filename = $xml->getAttribute( 'filename' ) ?: md5( uniqid() . mt_rand() );
$filename = $xml->getAttribute( 'filename' ) ?: md5( mt_rand() );
/* Insert into DB */
$insertId = \IPS\Db::i()->insert( 'core_hooks', array( 'plugin' => $plugin->id, 'type' => $xml->getAttribute('type'), 'class' => $xml->getAttribute('class'), 'filename' => $filename ) );
@@ -444,7 +440,7 @@ class _plugins extends \IPS\Node\Controller
\IPS\Db::i()->insert( 'core_sys_conf_settings', $inserts , TRUE );
}
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->clearCache();
break;
/* Settings code */
@@ -1001,7 +997,7 @@ class _plugins extends \IPS\Node\Controller
/* Get tab contents */
$activeTab = \IPS\Request::i()->tab ?: 'hooks';
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( $activeTab ) ), $plugin );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $activeTab ) ), $plugin );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $activeTabContents;
@@ -1111,7 +1107,7 @@ class _plugins extends \IPS\Node\Controller
/* Fix if/foreach/for tags...htmlspecialchars the content in case there is a -> which will break things */
$code = preg_replace_callback( '/\{\{(if|foreach|for)\s+?(.+?)\}\}/i', function( $matches )
{
return '<' . $matches[1] . ' code="' . htmlspecialchars( $matches[2], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . '">';
return '<' . $matches[1] . ' code="' . htmlspecialchars( $matches[2], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . '">';
}, $code );
/* Fix ending if/foreach/for tags */
@@ -1120,7 +1116,7 @@ class _plugins extends \IPS\Node\Controller
/* Fix regular template tags such as url to htmlspecialchars the content */
$code = preg_replace_callback( '/\{([a-z]+?=([\'"]).+?\\2 ?+)}/', function( $matches )
{
return htmlspecialchars( $matches[0], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE );
return htmlspecialchars( $matches[0], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE );
}, $code );
/* Strip any raw replacement tags remaining */
@@ -1136,7 +1132,7 @@ class _plugins extends \IPS\Node\Controller
}
/* Fix embedded single quotes */
$code = preg_replace_callback( '/=\'([^\']+?){.+?}([^\']+?)\'/', function( $matches )
$code = preg_replace_callback( '/=\'([^\']*?){.+?}([^\']*?)\'/', function( $matches )
{
return "=''";
}, $code );
@@ -1144,7 +1140,7 @@ class _plugins extends \IPS\Node\Controller
/* Ensure attributes with variable data are encoded before the cheeky DOM parser gets to it */
$code = preg_replace_callback( '/=([\'"])(\{.+?\})([\'"])/', function( $matches )
{
return "=" . $matches[1] . htmlspecialchars( $matches[2], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . $matches[3];
return "=" . $matches[1] . htmlspecialchars( $matches[2], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $matches[3];
}, $code );
/* Now load the HTML - doctype necessary sometimes */
@@ -1156,7 +1152,7 @@ class _plugins extends \IPS\Node\Controller
/**
* Get the CSS selector for a node
*
* @param DOMNode $node The node
* @param \DOMNode $node The node
* @return string
*/
public static function getSelector( \DOMNode $node )
@@ -1269,7 +1265,7 @@ class _plugins extends \IPS\Node\Controller
\IPS\Db::i()->delete( 'core_sys_conf_settings', \IPS\Db::i()->in( 'conf_key', $delete ) );
}
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->clearCache();
\file_put_contents( $file, json_encode( array_filter( array_values( $values ), function ( $v )
{
@@ -1567,7 +1563,7 @@ class _plugins extends \IPS\Node\Controller
\IPS\Db::i()->insert( 'core_sys_conf_settings', $inserts , TRUE );
}
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->clearCache();
}
}
@@ -1844,7 +1840,7 @@ class _plugins extends \IPS\Node\Controller
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C145/B', 404, '' ); //@todo duplicate error code
\IPS\Output::i()->error( 'node_error', '2C145/M', 404, '' );
}
/* Work out tab */
@@ -303,7 +303,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
}
/* Display */
$email = \IPS\Email::buildFromContent( $mail->subject, $content, NULL, \IPS\Email::TYPE_BULK )->setUnsubscribe( 'core', 'unsubscribeBulk' );
$email = \IPS\Email::buildFromContent( $mail->subject, \IPS\Email::staticParseTextForEmail( $content, \IPS\Member::loggedIn()->language() ), NULL, \IPS\Email::TYPE_BULK )->setUnsubscribe( 'core', 'unsubscribeBulk' );
\IPS\Output::i()->sendOutput( $email->compileContent( 'html', \IPS\Member::loggedIn() ) );
}
@@ -425,7 +425,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
function()
{
/* We don't have to do anything special because BulkMailer will have already updated the task and disabled the bulk mail */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'bm_sparkpost_sent' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'bm_sent_succesfull' );
}
);
}
+101 -37
View File
@@ -49,6 +49,10 @@ class _clubs extends \IPS\Dispatcher\Controller
$table->include = array( 'name', 'type', 'members', 'owner', 'created' );
$table->langPrefix = 'club_';
$table->parsers = array(
'name' => function( $value, $row )
{
return \IPS\Theme::i()->getTemplate('clubs')->name( $value, $row );
},
'type' => function( $value ) {
return \IPS\Theme::i()->getTemplate('clubs')->privacy( $value );
},
@@ -56,22 +60,26 @@ class _clubs extends \IPS\Dispatcher\Controller
return \IPS\DateTime::ts( $value );
},
'members' => function( $value, $row ) {
$link = \IPS\Http\Url::internal( "app=core&module=clubs&controller=view&id={$row['id']}&do=members", 'front', 'clubs_view', array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) );
return \IPS\Theme::i()->getTemplate('clubs')->members( $value, $link );
if ( $row['type'] !== \IPS\Member\Club::TYPE_PUBLIC )
{
$link = \IPS\Http\Url::internal( "app=core&module=clubs&controller=view&id={$row['id']}&do=members", 'front', 'clubs_view', array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) );
return \IPS\Theme::i()->getTemplate('clubs')->members( $value, $link );
}
return '';
},
'owner' => function( $value ) {
return \IPS\Theme::i()->getTemplate('clubs')->owner( \IPS\Member::load( $value ) );
},
'_highlight' => function( $row ) {
if ( !$row['approved'] )
{
return 'ipsModerated';
}
return NULL;
}
);
$table->noSort = array( 'privacy', 'owner' );
$table->sortBy = $table->sortBy ?: 'members';
$table->filters = array(
'club_type_' . \IPS\Member\Club::TYPE_PUBLIC => array( 'type=?', \IPS\Member\Club::TYPE_PUBLIC ),
'club_type_' . \IPS\Member\Club::TYPE_OPEN => array( 'type=?', \IPS\Member\Club::TYPE_OPEN ),
'club_type_' . \IPS\Member\Club::TYPE_CLOSED => array( 'type=?', \IPS\Member\Club::TYPE_CLOSED ),
'club_type_' . \IPS\Member\Club::TYPE_PRIVATE => array( 'type=?', \IPS\Member\Club::TYPE_PRIVATE )
);
$table->quickSearch = 'name';
$table->advancedSearch = array(
'name' => \IPS\Helpers\Table\SEARCH_QUERY_TEXT,
@@ -79,14 +87,56 @@ class _clubs extends \IPS\Dispatcher\Controller
'owner' => \IPS\Helpers\Table\SEARCH_MEMBER,
'created' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
);
if ( \IPS\Settings::i()->clubs_require_approval )
{
$table->filters = array(
'pending_approval' => 'approved=0'
);
$table->advancedSearch['type'] = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
\IPS\Member\Club::TYPE_PUBLIC => 'club_type_' . \IPS\Member\Club::TYPE_PUBLIC,
\IPS\Member\Club::TYPE_OPEN => 'club_type_' . \IPS\Member\Club::TYPE_OPEN,
\IPS\Member\Club::TYPE_CLOSED => 'club_type_' . \IPS\Member\Club::TYPE_CLOSED,
\IPS\Member\Club::TYPE_PRIVATE => 'club_type_' . \IPS\Member\Club::TYPE_PRIVATE,
\IPS\Member\Club::TYPE_READONLY => 'club_type_' . \IPS\Member\Club::TYPE_READONLY,
), 'multiple' => TRUE ) );
}
else
{
$table->filters = array(
'club_type_' . \IPS\Member\Club::TYPE_PUBLIC => array( 'type=?', \IPS\Member\Club::TYPE_PUBLIC ),
'club_type_' . \IPS\Member\Club::TYPE_OPEN => array( 'type=?', \IPS\Member\Club::TYPE_OPEN ),
'club_type_' . \IPS\Member\Club::TYPE_CLOSED => array( 'type=?', \IPS\Member\Club::TYPE_CLOSED ),
'club_type_' . \IPS\Member\Club::TYPE_PRIVATE => array( 'type=?', \IPS\Member\Club::TYPE_PRIVATE ),
'club_type_' . \IPS\Member\Club::TYPE_READONLY => array( 'type=?', \IPS\Member\Club::TYPE_READONLY )
);
}
$table->rowButtons = function( $row ) {
$return = array(
'open' => array(
'title' => 'view',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=view&id={$row['id']}", 'front', 'clubs_view', array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) ),
'target'=> '_blank'
)
$return = array();
if ( !$row['approved'] )
{
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_edit' ) )
{
$return['approve'] = array(
'title' => 'approve',
'icon' => 'check',
'link' => \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs&do=approve&id={$row['id']}")
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_delete' ) )
{
$return['delete'] = array(
'title' => 'delete',
'icon' => 'times',
'link' => \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs&do=delete&id={$row['id']}"),
'data' => \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs_node_map', array( 'club_id=?', $row['id'] ) )->first() ? array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('delete') ) : array( 'delete' => '' )
);
}
}
$return['open'] = array(
'title' => 'view',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=view&id={$row['id']}", 'front', 'clubs_view', array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) ),
'target'=> '_blank'
);
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_edit' ) )
{
@@ -96,7 +146,7 @@ class _clubs extends \IPS\Dispatcher\Controller
'link' => \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs&do=edit&id={$row['id']}")
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_delete' ) )
if ( !isset( $return['delete'] ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_delete' ) )
{
$return['delete'] = array(
'title' => 'delete',
@@ -107,25 +157,7 @@ class _clubs extends \IPS\Dispatcher\Controller
}
return $return;
};
/* Settings Button */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'fields_manage' ) )
{
\IPS\Output::i()->sidebar['actions']['settings'] = array(
'icon' => 'cog',
'title' => 'clubs_custom_fields',
'link' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=clubs&controller=fields" ),
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'clubs', 'clubs_settings_manage' ) )
{
\IPS\Output::i()->sidebar['actions']['fields'] = array(
'icon' => 'cog',
'title' => 'settings',
'link' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=clubs&controller=settings" ),
);
}
/* Display */
\IPS\Output::i()->output = (string) $table;
}
@@ -244,6 +276,38 @@ class _clubs extends \IPS\Dispatcher\Controller
}
}
/**
* Approve
*
* @return void
*/
protected function approve()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'clubs_edit' );
/* Load Club */
try
{
$club = \IPS\Member\Club::load( \IPS\Request::i()->id );
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2C352/8', 404, '' );
}
/* Approve */
$club->approved = TRUE;
$club->save();
/* Redirect */
$target = \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs");
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', array( 'approved=0 AND id!=?', $club->id ) )->first() )
{
$target = $target->setQueryString( 'filter', 'pending_approval' );
}
\IPS\Output::i()->redirect( $target, "approved" );
}
/**
* Delete
*
@@ -277,7 +341,7 @@ class _clubs extends \IPS\Dispatcher\Controller
{
return array_key_exists( 'add', $node->permissionTypes() );
}, 'clubs' => TRUE ) );
$field->label = $data['name'];
$field->label = htmlspecialchars( $data['name'] );
$form->add( $field );
}
catch ( \Exception $e ) {}
@@ -41,7 +41,25 @@ class _settings extends \IPS\Dispatcher\Controller
protected function manage()
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_enabled_setting', \IPS\Settings::i()->clubs, FALSE, array( 'togglesOn' => array( 'clubs_default_sort', 'clubs_header', 'clubs_locations', 'clubs_modperms', 'clubs_require_approval' ) ) ) );
$form->addHeader( 'club_settings' );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_enabled_setting', \IPS\Settings::i()->clubs, FALSE, array( 'togglesOn' => array( 'clubs_default_sort', 'clubs_header', 'clubs_locations', 'clubs_modperms', 'clubs_require_approval', 'form_header_club_display_settings', 'form_header_club_moderation', 'clubs_default_view', 'clubs_allow_view_change', 'club_nodes_in_apps', 'form_header_clubs_paid_settings', 'clubs_paid_on' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_require_approval', \IPS\Settings::i()->clubs_require_approval, FALSE, array(), NULL, NULL, NULL, 'clubs_require_approval' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_locations', \IPS\Settings::i()->clubs_locations, FALSE, array(), NULL, NULL, NULL, 'clubs_locations' ) );
if ( \IPS\Application::appIsEnabled( 'nexus' ) )
{
$form->addHeader( 'clubs_paid_settings' );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_paid_on', \IPS\Settings::i()->clubs_paid_on, FALSE, array( 'togglesOn' => array( 'clubs_paid_tax', 'clubs_paid_commission', 'clubs_paid_transfee', 'clubs_paid_gateways' ) ), NULL, NULL, NULL, 'clubs_paid_on' ) );
$form->add( new \IPS\Helpers\Form\Node( 'clubs_paid_tax', \IPS\Settings::i()->clubs_paid_tax ?:0, FALSE, array( 'class' => '\IPS\nexus\Tax', 'zeroVal' => 'do_not_tax' ), NULL, NULL, NULL, 'clubs_paid_tax' ) );
$form->add( new \IPS\Helpers\Form\Number( 'clubs_paid_commission', \IPS\Settings::i()->clubs_paid_commission, FALSE, array( 'min' => 0, 'max' => 100 ), NULL, NULL, '%', 'clubs_paid_commission' ) );
$form->add( new \IPS\nexus\Form\Money( 'clubs_paid_transfee', \IPS\Settings::i()->clubs_paid_transfee, FALSE, array(), NULL, NULL, NULL, 'clubs_paid_transfee' ) );
$form->add( new \IPS\Helpers\Form\Node( 'clubs_paid_gateways', \IPS\Settings::i()->clubs_paid_gateways, FALSE, array( 'class' => '\IPS\nexus\Gateway', 'zeroVal' => 'no_restriction', 'multiple' => TRUE ), NULL, NULL, NULL, 'clubs_paid_gateways' ) );
}
$form->addHeader( 'club_display_settings' );
$form->add( new \IPS\Helpers\Form\Radio( 'clubs_default_view', \IPS\Settings::i()->clubs_default_view, FALSE, array( 'options' => array(
'grid' => 'club_view_grid',
'list' => 'club_view_list',
) ), NULL, NULL, NULL, 'clubs_default_view' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_allow_view_change', \IPS\Settings::i()->clubs_allow_view_change, FALSE, array(), NULL, NULL, NULL, 'clubs_allow_view_change' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'clubs_default_sort', \IPS\Settings::i()->clubs_default_sort, FALSE, array( 'options' => array(
'last_activity' => 'clubs_sort_last_activity',
'members' => 'clubs_sort_members',
@@ -53,7 +71,11 @@ class _settings extends \IPS\Dispatcher\Controller
'full' => 'clubs_header_full',
'sidebar' => 'clubs_header_sidebar',
) ), NULL, NULL, NULL, 'clubs_header' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_locations', \IPS\Settings::i()->clubs_locations, FALSE, array(), NULL, NULL, NULL, 'clubs_locations' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'club_nodes_in_apps', \IPS\Settings::i()->club_nodes_in_apps, FALSE, array( 'options' => array(
'0' => 'club_nodes_in_apps_off',
'1' => 'club_nodes_in_apps_on',
) ), NULL, NULL, NULL, 'club_nodes_in_apps' ) );
$form->addHeader( 'club_moderation' );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'clubs_modperms', explode( ',', \IPS\Settings::i()->clubs_modperms ), FALSE, array( 'options' => array(
'pin' => 'club_modperm_pin',
'unpin' => 'club_modperm_unpin',
@@ -70,17 +92,21 @@ class _settings extends \IPS\Dispatcher\Controller
'delete' => 'club_modperm_delete',
'split_merge' => 'club_modperm_split_merge',
) ), NULL, NULL, NULL, 'clubs_modperms' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_require_approval', \IPS\Settings::i()->clubs_require_approval, FALSE, array(), NULL, NULL, NULL, 'clubs_require_approval' ) );
if ( $values = $form->values() )
{
{
$values['clubs'] = $values['clubs_enabled_setting'];
unset( $values['clubs_enabled_setting'] );
$values['clubs_modperms'] = implode( ',', $values['clubs_modperms'] );
$values['clubs_modperms'] = implode( ',', $values['clubs_modperms'] );
if ( \IPS\Application::appIsEnabled( 'nexus' ) )
{
$values['clubs_paid_tax'] = $values['clubs_paid_tax'] ? $values['clubs_paid_tax']->id : 0;
$values['clubs_paid_gateways'] = is_array( $values['clubs_paid_gateways'] ) ? implode( ',', array_keys( $values['clubs_paid_gateways'] ) ) : $values['clubs_paid_gateways'];
}
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplog__club_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=clubs&controller=clubs') );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=clubs&controller=settings') );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_clubs_settings');
@@ -135,14 +135,14 @@ class _ajax extends \IPS\Dispatcher\Controller
{
$templateBits = $skinSet->getRawTemplates( $t_app, $t_location, $t_group, \IPS\Theme::RETURN_ALL );
$templateBit = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ][ $t_location ][ $t_group ][ $t_name ] : null;
$templateBit['template_content'] = htmlentities( $templateBit['template_content'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
$templateBit['template_content'] = htmlentities( $templateBit['template_content'], ENT_DISALLOWED, 'UTF-8', TRUE );
}
else
{
$templateNames = $skinSet->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT );
$templateBits = $skinSet->getRawCss( $t_app, $t_location, $t_group, \IPS\Theme::RETURN_ALL );
$templateBit = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ][ $t_location ][ $t_group ][ $t_name ] : null;
$templateBit['css_content'] = htmlentities( $templateBit['css_content'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
$templateBit['css_content'] = htmlentities( $templateBit['css_content'], ENT_DISALLOWED, 'UTF-8', TRUE );
}
if ( $templateBit !== null )
@@ -182,12 +182,12 @@ class _ajax extends \IPS\Dispatcher\Controller
{
foreach ( $templates as $template )
{
$uniqueIds[] = "'" . $template['template_unique_key'] . "'";
$uniqueIds[] = md5( $template['template_app'] . ',' . $template['template_location'] . ',' . $template['template_group'] . ',' . $template['template_name'] );
}
}
}
}
$where[] = array( 'template_unique_key IN (' . implode( ',' , $uniqueIds ) . ')' );
$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', template_app, template_location, template_group, template_name ) )", $uniqueIds ) );
}
if ( in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
{
@@ -221,7 +221,7 @@ class _ajax extends \IPS\Dispatcher\Controller
$where,
'template_location, template_group, template_name, theorder desc'
);
$return = array();
foreach( $select as $result )
{
@@ -269,12 +269,12 @@ class _ajax extends \IPS\Dispatcher\Controller
{
foreach ( $templates as $template )
{
$uniqueIds[] = "'" . $template['css_unique_key'] . "'";
$uniqueIds[] = md5( $template['css_set_id'] . ',' . $template['css_app'] . ',' . $template['css_location'] . ',' . $template['css_path'] . ',' . $template['css_name'] );
}
}
}
}
$where[] = array( 'css_unique_key IN (' . implode( ',' , $uniqueIds ) . ')' );
$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', css_set_id, css_app, css_location, css_path, css_name ) )", $uniqueIds ) );
}
if ( in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
{
@@ -48,8 +48,13 @@ class _emails extends \IPS\Dispatcher\Controller
$table->quickSearch = 'template_name';
$table->limit = 100;
/* Primary Sort */
$table->primarySortBy = 'template_pinned';
$table->primarySortDirection = 'desc';
/* Default sort options */
$table->noSort = array( 'template_name' );
$table->sortBy = $table->sortBy ?: 'template_id';
$table->sortDirection = $table->sortDirection ?: 'desc';
$table->quickSearch = function( $val )
@@ -61,7 +66,7 @@ class _emails extends \IPS\Dispatcher\Controller
}
else
{
return "`template_name` LIKE '%{$val}%'";
return "`template_name` LIKE '%" . \IPS\Db::i()->escape_string( $val ) . "%'";
}
};
@@ -175,11 +180,18 @@ class _emails extends \IPS\Dispatcher\Controller
if ( $values = $form->values() )
{
/* Open XML file */
$xml = \IPS\Xml\SimpleXML::loadFile( $values['email_template_file'] );
if( !count($xml->template) )
try
{
\IPS\Output::i()->error( 'email_template_badform', '1S128/4', 403, '' );
$xml = \IPS\Xml\SimpleXML::loadFile( $values['email_template_file'] );
if( !count($xml->template) )
{
\IPS\Output::i()->error( 'email_template_badform', '1S128/4', 403, '' );
}
}
catch( \InvalidArgumentException $e )
{
\IPS\Output::i()->error( 'email_template_badform', '1C373/1', 403, '' );
}
foreach( $xml->template as $template )
@@ -205,8 +205,7 @@ class _themes extends \IPS\Node\Controller
else
{
/* Toggle the setting */
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 0 ), array( 'conf_key=?', 'theme_designers_mode' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'theme_designers_mode' => 0 ) );
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=manage' ), 'saved' );
@@ -376,7 +375,7 @@ class _themes extends \IPS\Node\Controller
$_SESSION['theme_dev_import'] = $toImport;
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('theme_dev_import', FALSE, array( 'sprintf' => array( $theme->_title, ucfirst( $app ) ) ) ) );
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('theme_dev_import', FALSE, array( 'sprintf' => array( $theme->_title, mb_ucfirst( $app ) ) ) ) );
}
else
{
@@ -412,8 +411,7 @@ class _themes extends \IPS\Node\Controller
unset( $_SESSION['theme_dev_import'] );
/* Toggle the setting */
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 0 ), array( 'conf_key=?', 'theme_designers_mode' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'theme_designers_mode' => 0 ) );
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=manage' ), 'completed' );
@@ -457,8 +455,7 @@ class _themes extends \IPS\Node\Controller
if ( ! $needsBuilding )
{
/* Toggle the setting */
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 1 ), array( 'conf_key=?', 'theme_designers_mode' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'theme_designers_mode' => 1 ) );
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=manage' ), 'completed' );
@@ -591,8 +588,7 @@ class _themes extends \IPS\Node\Controller
function()
{
/* Toggle the setting */
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 1 ), array( 'conf_key=?', 'theme_designers_mode' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'theme_designers_mode' => 1 ) );
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=manage' ), 'completed' );
@@ -828,7 +824,7 @@ class _themes extends \IPS\Node\Controller
\IPS\Member::loggedIn()->language()->words['core_theme_resource_name_choice_o_filename_desc'] = sprintf( \IPS\Member::loggedIn()->language()->get('core_theme_resource_name_choice_o_filename_desc'), $current['resource_name'] );
}
$form->add( new \IPS\Helpers\Form\Upload( 'core_theme_resource_filename', ( isset( $current['resource_filename'] ) ? \IPS\File::get( 'core_Theme', $current['resource_filename'] ) : NULL ), FALSE, array( 'obscure' => FALSE, 'maxFileSize' => 1.2, 'storageExtension' => 'core_Theme', 'storageContainer' => 'set_resources_' . $set->_id ), NULL, NULL, NULL, 'core_theme_resource_filename' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'core_theme_resource_filename', ( isset( $current['resource_filename'] ) ? \IPS\File::get( 'core_Theme', $current['resource_filename'] ) : NULL ), TRUE, array( 'obscure' => FALSE, 'maxFileSize' => 1.2, 'storageExtension' => 'core_Theme', 'storageContainer' => 'set_resources_' . $set->_id ), NULL, NULL, NULL, 'core_theme_resource_filename' ) );
if ( $values = $form->values() )
{
@@ -865,7 +861,7 @@ class _themes extends \IPS\Node\Controller
\IPS\Db::i()->select( '*', 'core_theme_resources', array( 'resource_set_id=? and resource_path=? and resource_location=? and resource_app=? and resource_name=?', $set->_id, $save['resource_path'], $save['resource_location'], $save['resource_app'], $save['resource_name'] ) )->first();
$ext = mb_substr( $save['resource_name'], ( mb_strrpos( $save['resource_name'], '.' ) + 1 ) );
$save['resource_name'] = mb_substr( $save['resource_name'], 0, ( mb_strrpos( $save['resource_name'], '.' ) ) ) . '_' . uniqid() . '.' . $ext;
$save['resource_name'] = mb_substr( $save['resource_name'], 0, ( mb_strrpos( $save['resource_name'], '.' ) ) ) . '_' . mt_rand() . '.' . $ext;
}
catch( \UnderflowException $ex ) { }
@@ -894,6 +890,8 @@ class _themes extends \IPS\Node\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=resources&set_id=' . $set->_id ), 'saved' );
}
\IPS\Theme::setThemeCustomized( $set->_id );
/* Display */
$title = \IPS\Member::loggedIn()->language()->addToStack('theme_custom_resources_page_title', FALSE, array( 'sprintf' => array( $set->_title ) ) );
@@ -1053,7 +1051,7 @@ class _themes extends \IPS\Node\Controller
{
$_SESSION['theme_import'] = array( 'css' => array(), 'isNewSet' => false );
/* Save snaphot */
/* Save snapshot */
\IPS\Theme::load( \IPS\Request::i()->id )->saveHistorySnapshot();
/* Wipe clean conflicts */
@@ -1122,7 +1120,7 @@ class _themes extends \IPS\Node\Controller
}
}
/* Start impoprting */
/* Start importing */
$data = array( 'apps' => array() );
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('processing') );
}
@@ -1220,6 +1218,7 @@ class _themes extends \IPS\Node\Controller
$location = $xml->getAttribute('template_location');
$group = $xml->getAttribute('template_group');
$name = $xml->getAttribute('template_name');
$isMaster = \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( 'template_app=? and template_location=? and template_group=? and template_name=? and template_set_id=0 and template_added_to=0', $appKey, $location, $group, $name ) )->first();
if ( isset( $templates[ $appKey ][ $location ][ $group ][ $name ] ) AND $templates[ $appKey ][ $location ][ $group ][ $name ]['template_user_edited'] )
{
@@ -1249,11 +1248,10 @@ class _themes extends \IPS\Node\Controller
'template_content' => $xml->readString(),
'template_updated' => time(),
'template_removable' => 1,
'template_user_added' => 0,
'template_user_added' => $isMaster ? 0 : 1,
'template_user_edited'=> 0,
'template_version' => $version,
'template_added_to' => \IPS\Request::i()->id,
'template_unique_key' => md5( \IPS\Request::i()->id . ';' . $appKey . ';' . $location . ';' . $group . ';' . mb_strtolower( $name ) )
'template_added_to' => \IPS\Request::i()->id
) );
}
break;
@@ -1262,6 +1260,9 @@ class _themes extends \IPS\Node\Controller
$path = $xml->getAttribute('css_path');
$name = $xml->getAttribute('css_name');
$isMaster = \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', array( 'css_app=? and css_location=? and css_path=? and css_name=? and css_set_id=0 and css_added_to=0', $appKey, $location, $path, $name ) )->first();
if ( isset( $css[ $appKey ][ $location ][ $path ][ $name ] ) AND $css[ $appKey ][ $location ][ $path ][ $name ]['css_user_edited'] )
{
/* Keep this */
@@ -1286,7 +1287,7 @@ class _themes extends \IPS\Node\Controller
$edited = 0;
$addedTo = \IPS\Request::i()->id;
if ( in_array( $name, $masterCss[ $appKey ][ $location ][ $path ] ) )
if ( $isMaster )
{
$edited = time();
$addedTo = 0;
@@ -1303,8 +1304,7 @@ class _themes extends \IPS\Node\Controller
'css_content' => $xml->readString(),
'css_version' => $version,
'css_user_edited'=> $edited,
'css_added_to' => $addedTo,
'css_unique_key' => md5( \IPS\Request::i()->id . ';' . $xml->getAttribute('css_app') . ';' . $xml->getAttribute('css_location') . ';' . $xml->getAttribute('css_path') . ';' . $xml->getAttribute('css_name') )
'css_added_to' => $addedTo
), true );
}
break;
@@ -1464,6 +1464,8 @@ class _themes extends \IPS\Node\Controller
$app->installThemeSettings( true );
}
\IPS\Theme::setThemeCustomized( $set->id );
/* Conflicts to fix? */
if ( \IPS\Db::i()->select( 'count(*)', 'core_theme_conflict', array( 'conflict_set_id=?', \IPS\Request::i()->id ) )->first() )
{
@@ -1979,7 +1981,7 @@ class _themes extends \IPS\Node\Controller
/* Templates */
$templates = $themeSet->getRawTemplates( $appDir, '', '', \IPS\Theme::RETURN_ALL );
if ( count( $templates[ $appDir->directory ] ) )
if ( isset( $templates[ $appDir->directory ] ) AND count( $templates[ $appDir->directory ] ) )
{
foreach( $templates[ $appDir->directory ] as $loc => $lv )
{
@@ -2360,7 +2362,8 @@ class _themes extends \IPS\Node\Controller
if ( $values = $form->values() )
{
$id = intval( \IPS\Request::i()->id );
$save = array( 'app' => $values['theme_template_app'],
$save = array( 'set_id' => $id,
'app' => $values['theme_template_app'],
'location' => $values['theme_template_location'],
'group' => ( $values['theme_template_group_type'] == 'existing' ) ? $values['theme_template_group_existing'] : $values['theme_template_group_new'],
'name' => $values['theme_template_name'],
@@ -2468,6 +2471,11 @@ class _themes extends \IPS\Node\Controller
{
\IPS\Output::i()->error( 'node_error', '3S121/1', 500, '' );
}
catch( \UnderflowException $ex )
{
/* This means the template to delete was not found - so we really don't need to worry about the error */
$template = array();
}
if ( isset( $template['app'] ) )
{
@@ -2531,8 +2539,14 @@ class _themes extends \IPS\Node\Controller
}
catch( \OutOfRangeException $ex )
{
\IPS\Log::log( $ex, 'template_error' );
\IPS\Output::i()->error( 'node_error', '3S121/2', 500, '' );
}
catch( \UnderflowException $ex )
{
\IPS\Log::log( $ex, 'template_error' );
\IPS\Output::i()->error( 'node_error', '3C163/I', 500, '' );
}
catch( \InvalidArgumentException $ex )
{
$msg = $ex->getMessage();
@@ -2758,7 +2772,7 @@ class _themes extends \IPS\Node\Controller
{
$customVersion = \IPS\Db::i()->select( '*', 'core_theme_templates', array( 'template_id=?', (int) \IPS\Request::i()->t_item_id ) )->first();
$rawTemplates = \IPS\Theme::master()->getRawTemplates( $customVersion['template_app'], $customVersion['template_location'], $customVersion['template_group'], \IPS\Theme::RETURN_ALL, TRUE );
$original = $rawTemplates[ $customVersion['template_app'] ][ $customVersion['template_location'] ][ $customVersion['template_group'] ][ $customVersion['template_name'] ]['template_content'];
$original = isset( $rawTemplates[ $customVersion['template_app'] ][ $customVersion['template_location'] ][ $customVersion['template_group'] ][ $customVersion['template_name'] ] ) ? $rawTemplates[ $customVersion['template_app'] ][ $customVersion['template_location'] ][ $customVersion['template_group'] ][ $customVersion['template_name'] ]['template_content'] : '';
}
\IPS\Output::i()->json( $original );
@@ -413,7 +413,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
}
$form->add( new \IPS\Helpers\Form\YesNo( 'theme_custom_setting_conditional', $id ? $current['sc_condition'] : FALSE, FALSE, array( 'togglesOn' => array( 'theme_custom_setting_condition' ) ), NULL, NULL, NULL, 'theme_custom_setting_conditional' ) );
$form->add( new \IPS\Helpers\Form\CodeMirror( 'theme_custom_setting_condition', '<?php' . "\n\n" . ( ( $id and $current['sc_condition'] ) ? $current['sc_condition'] : 'return TRUE;' ), FALSE, array( 'mode' => 'php' ), NULL, NULL, NULL, 'theme_custom_setting_condition' ) );
$form->add( new \IPS\Helpers\Form\Codemirror( 'theme_custom_setting_condition', '<?php' . "\n\n" . ( ( $id and $current['sc_condition'] ) ? $current['sc_condition'] : 'return TRUE;' ), FALSE, array( 'mode' => 'php' ), NULL, NULL, NULL, 'theme_custom_setting_condition' ) );
if ( $values = $form->values() )
{
@@ -51,18 +51,140 @@ class _search extends \IPS\Dispatcher\Controller
);
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Number( 'search_index_timeframe', \IPS\Settings::i()->search_index_timeframe, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'all' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_suffix'), 'search_index_timeframe' ) );
$form->addHeader('search_method');
$form->add( new \IPS\Helpers\Form\Radio( 'search_method', \IPS\Settings::i()->search_method, FALSE, array(
'options' => array(
'mysql' => 'search_method_mysql',
'elastic' => 'search_method_elastic'
),
'toggles' => array(
'mysql' => array( 'search_index_timeframe' ),
'elastic' => array( 'search_elastic_server', 'search_elastic_index', 'search_elastic_analyzer', 'search_decay', 'search_elastic_self_boost' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'search_elastic_server', \IPS\Settings::i()->search_elastic_server, NULL, array( 'placeholder' => 'http://localhost:9200' ), function( $val )
{
if( \IPS\Request::i()->search_method != 'elastic' )
{
return;
}
if( !( $val instanceof \IPS\Http\Url ) )
{
throw new \DomainException('form_url_error');
}
$requiredVersion = '5.5.0';
try
{
$response = $val->request()->get()->decodeJson();
}
catch ( \Exception $e )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('search_elastic_server_error', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) ) );
}
if ( !isset( $response['version']['number'] ) )
{
throw new \DomainException('search_elastic_server_no_version');
}
if ( version_compare( $response['version']['number'], $requiredVersion, '<' ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('search_elastic_server_unsupported_version', FALSE, array( 'sprintf' => array( $requiredVersion, $response['version']['number'] ) ) ) );
}
}, NULL, NULL, 'search_elastic_server' ) );
$form->add( new \IPS\Helpers\Form\Text( 'search_elastic_index', \IPS\Settings::i()->search_elastic_index, NULL, array( 'regex' => '/^[A-Z0-9_]*$/i' ), NULL, NULL, NULL, 'search_elastic_index' ) );
$form->add( new \IPS\Helpers\Form\Select( 'search_elastic_analyzer', \IPS\Settings::i()->search_elastic_analyzer, FALSE, array( 'options' => array(
'standard' => 'elastic_analyzer_standard',
'arabic' => 'elastic_analyzer_arabic',
'armenian' => 'elastic_analyzer_armenian',
'basque' => 'elastic_analyzer_basque',
'brazilian' => 'elastic_analyzer_brazilian',
'bulgarian' => 'elastic_analyzer_bulgarian',
'catalan' => 'elastic_analyzer_catalan',
'cjk' => 'elastic_analyzer_cjk',
'czech' => 'elastic_analyzer_czech',
'danish' => 'elastic_analyzer_danish',
'dutch' => 'elastic_analyzer_dutch',
'english' => 'elastic_analyzer_english',
'finnish' => 'elastic_analyzer_finnish',
'french' => 'elastic_analyzer_french',
'galician' => 'elastic_analyzer_galician',
'german' => 'elastic_analyzer_german',
'greek' => 'elastic_analyzer_greek',
'hindi' => 'elastic_analyzer_hindi',
'hungarian' => 'elastic_analyzer_hungarian',
'indonesian' => 'elastic_analyzer_indonesian',
'irish' => 'elastic_analyzer_irish',
'italian' => 'elastic_analyzer_italian',
'latvian' => 'elastic_analyzer_latvian',
'lithuanian' => 'elastic_analyzer_lithuanian',
'norwegian' => 'elastic_analyzer_norwegian',
'persian' => 'elastic_analyzer_persian',
'portuguese' => 'elastic_analyzer_portuguese',
'romanian' => 'elastic_analyzer_romanian',
'russian' => 'elastic_analyzer_russian',
'sorani' => 'elastic_analyzer_sorani',
'spanish' => 'elastic_analyzer_spanish',
'swedish' => 'elastic_analyzer_swedish',
'turkish' => 'elastic_analyzer_turkish',
'thai' => 'elastic_analyzer_thai',
) ), NULL, NULL, NULL, 'search_elastic_analyzer' ) );
$form->addHeader('search_options');
$form->add( new \IPS\Helpers\Form\Radio( 'search_default_operator', \IPS\Settings::i()->search_default_operator, FALSE, array( 'options' => array(
'or' => 'search_default_operator_or',
'and' => 'search_default_operator_and',
) ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_default_operator_prefix') ) );
$form->add( new \IPS\Helpers\Form\Number( 'search_title_boost', \IPS\Settings::i()->search_title_boost, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'search_title_boost_unlimited' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_title_boost_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_title_boost_suffix'), 'search_title_boost' ) );
$form->add( new \IPS\Helpers\Form\Custom( 'search_decay', array( \IPS\Settings::i()->search_decay_days, \IPS\Settings::i()->search_decay_factor ), FALSE, array(
'getHtml' => function( $field ) {
return \IPS\Theme::i()->getTemplate( 'settings' )->searchDecay( isset( $field->value[0] ) ? $field->value[0] : 0, isset( $field->value[1] ) ? $field->value[1] : 0 );
}
), NULL, NULL, NULL, 'search_decay' ) );
$form->add( new \IPS\Helpers\Form\Number( 'search_elastic_self_boost', \IPS\Settings::i()->search_elastic_self_boost, FALSE, array( 'unlimited' => floatval( 0 ), 'unlimitedLang' => 'do_not_boost', 'decimals' => 1 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_elastic_self_boost_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_elastic_self_boost_suffix'), 'search_elastic_self_boost' ) );
$form->add( new \IPS\Helpers\Form\Number( 'search_index_timeframe', \IPS\Settings::i()->search_index_timeframe, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'search_index_timeframe_unlimited' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_suffix'), 'search_index_timeframe' ) );
if ( $values = $form->values() )
{
$engine = \IPS\Settings::i()->search_method;
$indexPrune = \IPS\Settings::i()->search_index_timeframe;
$analyzer = \IPS\Settings::i()->search_elastic_analyzer;
if ( isset( $values['search_decay'][2] ) )
{
$values['search_decay_days'] = 0;
$values['search_decay_factor'] = 0;
}
else
{
$values['search_decay_days'] = $values['search_decay'][0];
$values['search_decay_factor'] = $values['search_decay'][1];
}
unset( $values['search_decay'] );
if( $engine != $values['search_method'] )
{
try
{
\IPS\Content\Search\Index::i()->prune();
}
catch( \Exception $e )
{
\IPS\Log::log( $e, 'search_index_prune' );
}
}
/* Go ahead and save... */
$form->saveAsSettings();
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__search_settings' );
/* And re-index if setting updated */
if( $indexPrune != $values['search_index_timeframe'] )
if( $engine != $values['search_method'] or ( $values['search_method'] == 'elastic' and $values['search_elastic_analyzer'] != $analyzer ) )
{
/* We pass TRUE to the i() method to ensure we get a new instance, otherwise the old instance cached from the previous prune call will be used */
\IPS\Content\Search\Index::i( TRUE )->init();
\IPS\Content\Search\Index::i()->rebuild();
}
elseif( $indexPrune != $values['search_index_timeframe'] )
{
\IPS\Content\Search\Index::i()->rebuild();
}
@@ -41,24 +41,62 @@ class _emoticons extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_editor_emoticons');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'customization' )->emoticons( $this->_getEmoticons() );
$tabs = array(
'standard' => 'standard_emoji',
'custom' => 'custom_emoji',
);
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'standard';
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'editor', 'emoticons_edit' ) )
if ( $activeTab == 'standard' )
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_customization.js', 'core', 'admin') );
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') )
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Radio( 'emoji_style', \IPS\Settings::i()->emoji_style, FALSE, array(
'options' => array(
'native' => 'emoji_style_native',
'twemoji' => 'emoji_style_twemoji',
'emojione' => 'emoji_style_emojione',
'disabled' => 'emoji_style_disabled',
),
'toggles' => array(
'native' => array( 'emoji_shortcodes', 'emoji_ascii' ),
'twemoji' => array( 'emoji_shortcodes', 'emoji_ascii' ),
'emojione' => array( 'emoji_shortcodes', 'emoji_ascii' ),
),
) ) );
\IPS\Member::loggedIn()->language()->get( 'emoji_style_native' ); // We need to preload the word before we can add more text to it.
\IPS\Member::loggedIn()->language()->words['emoji_style_native'] .= "<br><div class='ipsType_large ipsSpacer_top ipsSpacer_half'><span class='ipsEmoji'>😀</span><span class='ipsEmoji'>😉</span><span class='ipsEmoji'>😂</span><span class='ipsEmoji'>😍</span><span class='ipsEmoji'>🤘</span><span class='ipsEmoji'>🤦‍♀️</span><span class='ipsEmoji'>🤷‍♂️</span><span class='ipsEmoji'>🍿</span><span class='ipsEmoji'>🚀</span><span class='ipsEmoji'>🎉</span><span class='ipsEmoji'>🏳️‍🌈</span></div>"; // Have to do this here because if we try to put it in the actual language string, that will cause an error if not utf8mb4
$form->add( new \IPS\Helpers\Form\YesNo( 'emoji_shortcodes', \IPS\Settings::i()->emoji_shortcodes, FALSE, array(), NULL, NULL, NULL, 'emoji_shortcodes' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'emoji_ascii', \IPS\Settings::i()->emoji_ascii, FALSE, array(), NULL, NULL, NULL, 'emoji_ascii' ) );
if ( $values = $form->values() )
{
$values['emoji_cache'] = time();
$form->saveAsSettings( $values );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=standard' ), 'saved' );
}
$activeTabContents = $form;
}
else
{
$activeTabContents = \IPS\Theme::i()->getTemplate( 'global' )->message( 'emoji_utf8mb4_required', 'error', NULL, TRUE, TRUE );
}
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'editor', 'emoticons_add' ) )
else
{
\IPS\Output::i()->sidebar['actions'] = array(
'add' => array(
'primary' => TRUE,
'icon' => 'plus-circle',
'title' => 'emoticons_add',
'link' => \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&do=add' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('emoticons_add') )
),
);
$activeTabContents = \IPS\Theme::i()->getTemplate( 'customization' )->emoticons( $this->_getEmoticons() );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_editor_emoticons');
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_customization.js', 'core', 'admin') );
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $activeTabContents;
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=editor&controller=emoticons" ) );
}
}
@@ -107,7 +145,7 @@ class _emoticons extends \IPS\Dispatcher\Controller
if ( $values['emoticons_add_group'] === 'create' )
{
$position = 0;
$setId = md5( uniqid() );
$setId = mt_rand();
\IPS\Lang::saveCustom( 'core', "core_emoticon_group_{$setId}", $values['emoticons_add_newgroup'] );
\IPS\Session::i()->log( 'acplog__emoticon_group_created', array( "core_emoticon_group_{$setId}" => TRUE ) );
}
@@ -185,14 +223,15 @@ class _emoticons extends \IPS\Dispatcher\Controller
}
}
unset( \IPS\Data\Store::i()->emoticons );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'emoji_cache' ) );
unset( \IPS\Data\Store::i()->settings );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplog__emoticons_added', array( "core_emoticon_group_{$setId}" => TRUE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=custom' ), 'saved' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'emoticons_add', $form, FALSE );
@@ -242,11 +281,32 @@ class _emoticons extends \IPS\Dispatcher\Controller
$setPos++;
}
}
unset( \IPS\Data\Store::i()->emoticons );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'emoji_cache' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Output::i()->json( 'OK' );
return;
}
// Do we need to unsquash any values?
// Squashed values are json_encoded by javascript to prevent us exceeding max_post_vars
// If 'squashedField' isn't in the request it might indicate the user didn't have JS enabled
if ( isset( \IPS\Request::i()->emoticons_squashed ) )
{
if ( isset( \IPS\Request::i()->emoticons_squashed ) )
{
$unsquashed = json_decode( \IPS\Request::i()->emoticons_squashed, TRUE );
foreach( $unsquashed as $key => $value )
{
\IPS\Request::i()->$key = $value;
}
unset( \IPS\Request::i()->emoticons_squashed );
}
}
$emoticons = $this->_getEmoticons( FALSE );
foreach ( \IPS\Request::i()->emo as $id => $data )
@@ -284,14 +344,15 @@ class _emoticons extends \IPS\Dispatcher\Controller
}
}
unset( \IPS\Data\Store::i()->emoticons );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'emoji_cache' ) );
unset( \IPS\Data\Store::i()->settings );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplog__emoticons_edited' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=custom' ), 'saved' );
}
/**
@@ -327,14 +388,15 @@ class _emoticons extends \IPS\Dispatcher\Controller
\IPS\Session::i()->log( 'acplog__emoticon_deleted' );
unset( \IPS\Data\Store::i()->emoticons );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'emoji_cache' ) );
unset( \IPS\Data\Store::i()->settings );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
}
catch ( \UnderflowException $e ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=custom' ), 'saved' );
}
/**
@@ -364,12 +426,13 @@ class _emoticons extends \IPS\Dispatcher\Controller
\IPS\Db::i()->delete( 'core_emoticons', array( 'emo_set=?', $set ) );
\IPS\Lang::deleteCustom( 'core', 'core_emoticon_group_'. $set );
unset( \IPS\Data\Store::i()->emoticons );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'emoji_cache' ) );
unset( \IPS\Data\Store::i()->settings );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=custom' ), 'saved' );
}
/**
@@ -389,7 +452,7 @@ class _emoticons extends \IPS\Dispatcher\Controller
{
\IPS\Lang::saveCustom( 'core', \IPS\Request::i()->key, $values['emoticons_add_newgroup'] );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=emoticons&tab=custom' ), 'saved' );
}
if( \IPS\Request::i()->isAjax() )
@@ -56,7 +56,7 @@ class _settings extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Work out output */
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
/* If this is an AJAX request, just return it */
if( \IPS\Request::i()->isAjax() )
@@ -107,7 +107,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
}
}
$dummy = new \IPS\Helpers\Form\Editor( 'editor', NULL, FALSE, array( 'autoSaveKey' => md5( uniqid() ), 'allButtons' => TRUE ) );
$dummy = new \IPS\Helpers\Form\Editor( 'editor', NULL, FALSE, array( 'autoSaveKey' => md5( mt_rand() ), 'allButtons' => TRUE ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_editor_toolbar');
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_customization.js', 'core', 'admin') );
@@ -156,8 +156,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
}
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $save ) ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_toolbars' => json_encode( $save ) ) );
}
/**
@@ -172,10 +171,22 @@ class _toolbar extends \IPS\Dispatcher\Controller
$current = json_decode( \IPS\Settings::i()->ckeditor_permissions, TRUE );
/* Get areas */
$areas = array_combine( array_keys( \IPS\Application::allExtensions( 'core', 'EditorLocations', FALSE ) ), array_map( function( $v )
{
return 'editor__' . $v;
}, array_keys( \IPS\Application::allExtensions( 'core', 'EditorLocations', FALSE ) ) ) );
$filteredAreas = array_filter(
\IPS\Application::allExtensions( 'core', 'EditorLocations', FALSE ),
function( $elem ) {
return ( !isset( $elem::$buttonLocation ) OR $elem::$buttonLocation !== FALSE );
}
);
$areas = array_combine(
array_keys( $filteredAreas ),
array_map(
function( $v )
{
return 'editor__' . $v;
},
array_keys( $filteredAreas )
)
);
/* Build Form */
$b64Button = base64_encode( $button );
@@ -255,8 +266,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
'groups' => $values['editor_permission_groups'],
'areas' => $values['editor_permission_areas'],
);
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $current ) ), array( 'conf_key=?', 'ckeditor_permissions' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_permissions' => json_encode( $current ) ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -308,14 +318,13 @@ class _toolbar extends \IPS\Dispatcher\Controller
if ( $values = $form->values() )
{
/* Write */
$key = 'custom-' . md5( uniqid() );
$key = 'custom-' . md5( mt_rand() );
$this->_saveCustomPlugin( $key, $values );
/* Save */
$extraPlugins = explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins );
$extraPlugins[] = $key;
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -461,8 +470,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
$extraPlugins = explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins );
$extraPlugins[] = $name;
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -540,8 +548,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
$settingClasses = \IPS\Settings::i()->editor_allowed_classes ? explode( ',', \IPS\Settings::i()->editor_allowed_classes ) : array();
$settingClasses = array_unique( array_merge( $settingClasses, $cssClasses ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => implode( ',', $settingClasses ) ), array( 'conf_key=?', 'editor_allowed_classes' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'editor_allowed_classes' => implode( ',', $settingClasses ) ) );
}
/* Figure out data-controllers classes */
@@ -563,8 +570,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
$settingControllers = \IPS\Settings::i()->editor_allowed_datacontrollers ? explode( ',', \IPS\Settings::i()->editor_allowed_datacontrollers ) : array();
$settingControllers = array_unique( array_merge( $settingControllers, $dataControllers ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => implode( ',', $settingControllers ) ), array( 'conf_key=?', 'editor_allowed_datacontrollers' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'editor_allowed_datacontrollers' => implode( ',', $settingControllers ) ) );
}
$attributes = json_encode( $attributes );
@@ -791,8 +797,7 @@ JS;
unset( $extraPlugins[ $k ] );
}
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => implode( ',', array_filter( array_unique( $extraPlugins ) ) ) ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -850,11 +855,10 @@ JS;
}
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => '' ) );
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_toolbars' => '' ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -769,6 +769,9 @@ class _languages extends \IPS\Node\Controller
$data = array( 'apps' => array(), 'id' => $insertId );
return array( $data, \IPS\Member::loggedIn()->language()->get('processing') );
}
/* Only import language strings from applications we have installed */
$applications = array_keys( \IPS\Application::applications() );
/* Move to correct app */
$appKey = NULL;
@@ -777,7 +780,7 @@ class _languages extends \IPS\Node\Controller
while ( $xml->read() )
{
$appKey = $xml->getAttribute('key');
if ( !array_key_exists( $appKey, $data['apps'] ) )
if ( !array_key_exists( $appKey, $data['apps'] ) AND in_array( $appKey, $applications ) )
{
/* Get version */
$version = $xml->getAttribute('version');
@@ -940,7 +943,8 @@ class _languages extends \IPS\Node\Controller
{
\IPS\Member::updateAllMembers( array( 'language' => \IPS\Request::i()->id ) );
}
\IPS\Session::i()->log( 'acplogs__members_language_reset', array( \IPS\Lang::load( \IPS\Request::i()->id )->title => FALSE ) );
\IPS\Session::i()->log( 'acplogs__members_language_reset', array( \IPS\Lang::load( \IPS\Request::i()->id ?: \IPS\Lang::defaultLanguage() )->title => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages' ), 'reset' );
}
@@ -56,7 +56,7 @@ class _devices extends \IPS\Dispatcher\Controller
$userAgent = $device->userAgent();
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_names_device', FALSE, array( 'sprintf' => array( $member->name, $userAgent->platform ) ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members" ), 'members' );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), $member->name );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=view&id={$member->member_id}" ), $member->name );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=devices&do=member&id={$member->member_id}" ), 'members_devices' );
\IPS\Output::i()->breadcrumb[] = array( NULL, $userAgent );
@@ -137,7 +137,7 @@ class _devices extends \IPS\Dispatcher\Controller
'view' => array(
'title' => 'view',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit' )->setQueryString( 'id', $row['member_id'] ),
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view' )->setQueryString( 'id', $row['member_id'] ),
),
);
};
@@ -234,7 +234,7 @@ class _devices extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->deviceTable( $table );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_names_devices', FALSE, array( 'sprintf' => array( $member->name ) ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members" ), 'members' );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=edit&id={$member->member_id}" ), $member->name );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=view&id={$member->member_id}" ), $member->name );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=members&controller=devices&do=member&id={$member->member_id}" ), 'members_devices' );
}
@@ -247,11 +247,15 @@ class _devices extends \IPS\Dispatcher\Controller
{
try
{
$device = \IPS\Member\Device::loadAndAuthenticate( \IPS\Request::i()->device, \IPS\Member::load( \IPS\Request::i()->member ) );
$member = \IPS\Member::load( \IPS\Request::i()->member );
$device = \IPS\Member\Device::loadAndAuthenticate( \IPS\Request::i()->device, $member );
$device->login_key = NULL;
$device->save();
\IPS\Db::i()->delete( 'core_sessions', array( 'member_id=? AND browser=?', $device->member_id, $device->user_agent ) );
$member->logHistory( 'core', 'login', array( 'type' => 'logout', 'device' => $device->device_key ) );
\IPS\Session::i()->log( 'acplog__members_disabled_autologin', array( $member->name => FALSE ) );
\IPS\Session\Store::i()->deleteByMember( $device->member_id, $device->user_agent );
}
catch ( \Exception $e ) { }
@@ -65,7 +65,8 @@ class _groups extends \IPS\Dispatcher\Controller
{
if ( $row['g_id'] == \IPS\Settings::i()->guest_group )
{
$onlineGuests = \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', array( 'login_type=? AND running_time>?', \IPS\Session\Front::LOGIN_TYPE_GUEST, \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ) )->first();
$onlineGuests = \IPS\Session\Store::i()->getOnlineUsers( \IPS\Session\Store::ONLINE_GUESTS | \IPS\Session\Store::ONLINE_COUNT_ONLY );
return \IPS\Member::loggedIn()->language()->addToStack( 'online_guests', FALSE, array( 'pluralize' => array( $onlineGuests ) ) );
}
@@ -88,8 +89,20 @@ class _groups extends \IPS\Dispatcher\Controller
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=groups&do=form' ),
);
}
/* Show an extra warning if we are going to delete a group that Commerce intends to move subscribers back to */
if( \IPS\Db::i()->checkForColumn( 'core_members', 'cm_return_group' ) )
{
$warnGroups = array();
try
{
$warnGroups = iterator_to_array( \IPS\Db::i()->select( 'DISTINCT(cm_return_group)', 'core_members' ) );
}
catch( \Exception $e ){}
}
$table->rowButtons = function( $row )
$table->rowButtons = function( $row ) use ( $warnGroups )
{
$return = array();
@@ -137,7 +150,9 @@ class _groups extends \IPS\Dispatcher\Controller
'icon' => 'times-circle',
'title' => 'delete',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=groups&do=delete&id=' ) . $row['g_id'],
'data' => \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'member_group_id=?', $row['g_id'] ) )->first() ? array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( "core_group_{$row['g_id']}" ) ) : array( 'delete' => '' ),
'data' => \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'member_group_id=?', $row['g_id'] ) )->first() ?
array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( "core_group_{$row['g_id']}" ) ) :
array( 'delete' => '', 'delete-warning' => ( in_array( $row['g_id'], $warnGroups ) ) ? \IPS\Member::loggedIn()->language()->addToStack( "nexus_dont_delete_group", FALSE, array( 'sprintf' => array( \IPS\Member\Group::load( \IPS\Settings::i()->member_group )->name ) ) ) : '' ),
);
}
@@ -300,7 +315,19 @@ class _groups extends \IPS\Dispatcher\Controller
if ( isset( $current[ $class::$permApp ][ $class::$permType ] ) )
{
$matrix->rows = call_user_func( $callback, $current[ $class::$permApp ][ $class::$permType ], $group );
try
{
$matrix->rows = call_user_func( $callback, $current[ $class::$permApp ][ $class::$permType ], $group );
}
catch( \UnderflowException $e )
{
if( $e->getCode() != 199 )
{
throw $e;
}
\IPS\Output::i()->error( 'generic_error', '4T382/1', 500, $e->getMessage() );
}
}
/* Add the matrix */
@@ -358,7 +385,7 @@ class _groups extends \IPS\Dispatcher\Controller
/* Copy */
$newGroup = clone $group;
\IPS\Session::i()->log( 'acplog__groups_copied', array( $newGroup->name => FALSE ) );
\IPS\Session::i()->log( 'acplog__groups_copied', array( "core_group_". $newGroup->g_id => TRUE ) );
/* And redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=groups&do=form&id={$newGroup->g_id}" ) );
@@ -372,17 +399,15 @@ class _groups extends \IPS\Dispatcher\Controller
public function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'groups_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Load group */
try
{
$group = \IPS\Member\Group::load( \IPS\Request::i()->id );
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'member_group_id=?', $group->g_id ) )->first();
/* Any members in it? */
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'member_group_id=?', $group->g_id ) )->first() )
if ( $count )
{
/* Create the options, but don't let the admin move members in the group back into this same group */
$groupOptions = \IPS\Member\Group::groups( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin2' ), FALSE );
@@ -402,6 +427,11 @@ class _groups extends \IPS\Dispatcher\Controller
return;
}
}
else
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
}
/* remove this from members secondary groups column */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', \IPS\Db::i()->findInSet( 'mgroup_others', array( $group->g_id ) ) ), 'IPS\Member') AS $member )
@@ -416,11 +446,13 @@ class _groups extends \IPS\Dispatcher\Controller
}
}
$member->mgroup_others = implode( ',', array_filter( $secondaryGroups ) );
$member->save();
\IPS\Db::i()->update( 'core_members', array( 'mgroup_others' => implode( ',', array_filter( $secondaryGroups ) ) ), array( 'member_id=?', $member->member_id ) );
}
\IPS\Session::i()->log( 'acplog__groups_deleted', array( $group->name => FALSE ) );
$name = $group->name;
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $name );
\IPS\Session::i()->log( 'acplog__groups_deleted', array( $name => FALSE ) );
$group->delete();
}
catch ( \OutOfRangeException $e )
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,122 @@
<?php
/**
* @brief Profile Completion
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 04 Jan 2018
*/
namespace IPS\core\modules\admin\membersettings;
/* 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;
}
/**
* Profile Completion
*/
class _profilecompletion extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\Member\ProfileStep';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profilefields_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
public function manage()
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->profileCompleteBlurb();
parent::manage();
}
/**
* Enable quick registration
*
* @return void
*/
public function enableQuickRegister()
{
\IPS\Settings::i()->changeValues( array( 'quick_register' => 1 ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=profilecompletion' ), 'profile_complete_quick_register_off_enabled' );
}
/**
* Add Step Form
*
* @return void
*/
public function form()
{
$form = new \IPS\Helpers\Form;
if ( isset( \IPS\Request::i()->id ) )
{
try
{
$step = \IPS\Member\ProfileStep::load( \IPS\Request::i()->id );
}
catch( \OutOFRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C360/1', 404, '' );
}
}
else
{
$step = new \IPS\Member\ProfileStep;
}
$step->form( $form );
if ( $values = $form->values() )
{
$values = $step->formatFormValues( $values );
$step->extension = \IPS\Member\ProfileStep::findExtensionFromAction( $values['step_completion_act'] );
if ( isset( $values['step_required'] ) )
{
$step->required = $values['step_required'];
}
else
{
$step->required = FALSE;
}
$step->completion_act = $values['step_completion_act'];
$step->subcompletion_act = $values['step_subcompletion_act'];
$step->save();
$step->postSaveForm( $values );
if ( method_exists( $step->extension, 'postAcpSave' ) )
{
$step->extension->postAcpSave( $step, $values );
}
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 & ~" . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['profile_completed'] ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles&tab=profilecompletion" ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'profile_completion' );
\IPS\Output::i()->output = $form;
}
}
@@ -0,0 +1,64 @@
<?php
/**
* @brief Profile Fields and Settings
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 09 Apr 2013
*/
namespace IPS\core\modules\admin\membersettings;
/* 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;
}
/**
* Profile Fields and Settings
*/
class _profilefields extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\core\ProfileFields\Group';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profilefields_manage' );
parent::execute();
}
/**
* Get Root Buttons
*
* @return array
*/
public function _getRootButtons()
{
$nodeClass = $this->nodeClass;
if ( $nodeClass::canAddRoot() )
{
$add = array(
'icon' => 'plus',
'title' => 'add',
'link' => $this->url->setQueryString( 'do', 'form' ),
'data' => ( $nodeClass::$modalForms ? array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add') ) : array() )
);
return array( 'add' => $add );
}
return array();
}
}
@@ -1,11 +1,11 @@
<?php
/**
* @brief Profile Fields and Settings
* @brief Profile settings gateway
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 09 Apr 2013
* @since 08 Jan 2018
*/
namespace IPS\core\modules\admin\membersettings;
@@ -18,326 +18,51 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* Profile Fields and Settings
* Profile settings gateway
*/
class _profiles extends \IPS\Node\Controller
class _profiles extends \IPS\Dispatcher\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\core\ProfileFields\Group';
/**
* Execute
* Call
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profilefields_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
protected function manage()
public function __call( $method, $args )
{
/* Init */
$activeTab = \IPS\Request::i()->tab ?: 'fields';
$activeTabContents = '';
$tabs = array( 'fields' => 'profile_fields' );
$activeTab = \IPS\Request::i()->tab ?: 'profilefields';
$activeTabContents = '';
$tabs = array();
/* Add a tab for fields and completion */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'profilesfields_manage' ) )
{
$tabs['profilefields'] = 'profile_fields';
$tabs['profilecompletion'] = 'profile_completion';
}
/* Add a tab for settings */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'profiles_manage' ) )
{
$tabs['settings'] = 'profile_settings';
$tabs['completion'] = 'profile_completion';
}
$method = '_tab' . ucwords( $activeTab );
if ( method_exists( $this, $method ) )
{
$activeTabContents = (string) $this->$method();
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('module__core_profile');
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $activeTabContents;
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles" ) );
}
}
/**
* Fields Tab
*
* @return string
*/
protected function _tabFields()
{
parent::manage();
return \IPS\Output::i()->output;
}
/**
* Settings Tab
*
* @return \IPS\Helpers\Form
*/
protected function _tabSettings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profiles_manage' );
$form = new \IPS\Helpers\Form;
$form->addHeader( 'photos' );
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_gravatars', \IPS\Settings::i()->allow_gravatars ) );
if( \IPS\Image::canWriteText() )
{
$form->add( new \IPS\Helpers\Form\Radio( 'letter_photos', \IPS\Settings::i()->letter_photos, FALSE, array( 'options' => array( 'default' => 'letterphoto_default', 'letters' => 'letterphoto_letters' ) ) ) );
$tabs['profilesettings'] = 'profile_settings';
}
$form->addHeader( 'usernames' );
$form->add( new \IPS\Helpers\Form\Custom( 'user_name_length', array( \IPS\Settings::i()->min_user_name_length, \IPS\Settings::i()->max_user_name_length ), FALSE, array(
'getHtml' => function( $field ) {
return \IPS\Theme::i()->getTemplate('members')->usernameLengthSetting( $field->name, $field->value );
}
),
function( $val )
{
if ( $val[0] < 1 )
{
throw new \DomainException('user_name_length_too_low');
}
if ( $val[1] > 255 )
{
throw new \DomainException('user_name_length_too_high');
}
if ( $val[0] > $val[1] )
{
throw new \DomainException('user_name_length_no_match');
}
} ) );
$form->add( new \IPS\Helpers\Form\Text( 'username_characters', \IPS\Settings::i()->username_characters, FALSE, array( 'max' => 255 ) ) );
$form->addHeader( 'signatures' );
$form->add( new \IPS\Helpers\Form\YesNo( 'signatures_enabled', \IPS\Settings::i()->signatures_enabled ) );
$form->addHeader( 'statuses_profile_comments' );
$form->add( new \IPS\Helpers\Form\YesNo( 'profile_comments', \IPS\Settings::i()->profile_comments, FALSE, array( 'togglesOn' => array( 'profile_comment_approval' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'profile_comment_approval', \IPS\Settings::i()->profile_comment_approval, FALSE, array(), NULL, NULL, NULL, 'profile_comment_approval' ) );
$form->addHeader( 'profile_settings_birthdays' );
$form->add( new \IPS\Helpers\Form\Radio( 'profile_birthday_type', \IPS\Settings::i()->profile_birthday_type, TRUE, array(
'options' => array( 'public' => 'profile_birthday_type_public', 'private' => 'profile_birthday_type_private', 'none' => 'profile_birthday_type_none' )
), NULL, NULL, NULL, 'profile_birthday_type' ) );
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'profiles', 'member_history_prune' ) )
{
$form->addHeader( 'profile_member_history' );
$form->add( new \IPS\Helpers\Form\Number( 'prune_member_history', \IPS\Settings::i()->prune_member_history, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'prune_member_history' ) );
}
$form->addHeader( 'profile_settings_ignore' );
$form->add( new \IPS\Helpers\Form\YesNo( 'ignore_system_on', \IPS\Settings::i()->ignore_system_on, FALSE, array(), NULL, NULL, NULL, 'ignore_system_on' ) );
if ( $values = $form->values() )
{
$values['min_user_name_length'] = $values['user_name_length'][0];
$values['max_user_name_length'] = $values['user_name_length'][1];
unset( $values['user_name_length'] );
/* Route */
$classname = 'IPS\core\modules\admin\membersettings\\' . $activeTab;
$class = new $classname;
$class->url = \IPS\Http\Url::internal("app=core&module=membersettings&controller=profiles&tab={$activeTab}");
$class->execute();
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplog__profile_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=settings' ), 'saved' );
}
return $form;
}
/**
* Completion Tab
*
* @return \IPS\Helpers\Form
*/
protected function _tabCompletion()
{
/* Is the quick register function disabled? */
if ( ! \IPS\Settings::i()->quick_register )
{
return \IPS\Theme::i()->getTemplate( 'members' )->quickRegisterDisabled();
}
$table = new \IPS\Helpers\Table\Db( 'core_profile_steps', \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=completion' ) );
$table->langPrefix = 'profile_acp_table_';
$table->include = array( 'step_extension', 'step_required' );
$table->rootButtons = array(
array(
'icon' => 'plus',
'title' => 'add',
'link' => \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles&do=step" )
)
);
$table->parsers = array(
'step_extension' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'members' )->profileCompleteTitle( $row );
},
'step_required' => function( $val ) {
if ( $val )
{
return '&#10003;';
}
else
{
return '&#10007;';
}
}
);
$table->rowButtons = function( $row )
{
return array(
'edit' => array(
'title' => 'edit',
'icon' => 'pencil',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&do=step&id=' . $row['step_id'] )
),
'delete' => array(
'title' => 'delete',
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&do=deleteStep&id=' . $row['step_id'] ),
'data' => array( 'delete' => '' )
),
);
};
$output = \IPS\Output::i()->output;
return \IPS\Theme::i()->getTemplate( 'members' )->profileCompleteBlurb() . $table;
}
/**
* Enable quick registration
*
* @return void
*/
public function enableQuickRegister()
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 1 ), array( 'conf_key=?', 'quick_register' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=completion' ), 'profile_complete_quick_register_off_enabled' );
}
/**
* Add Step Form
*
* @return void
*/
public function step()
{
$form = new \IPS\Helpers\Form;
if ( isset( \IPS\Request::i()->id ) )
if ( $method !== 'manage' or \IPS\Request::i()->isAjax() )
{
try
{
$step = \IPS\Member\ProfileStep::load( \IPS\Request::i()->id );
}
catch( \OutOFRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C360/1', 404, '' );
}
return;
}
else
{
$step = new \IPS\Member\ProfileStep;
}
$step->form( $form );
if ( $values = $form->values() )
{
$values = $step->formatFormValues( $values );
$step->extension = \IPS\Member\ProfileStep::findExtensionFromAction( $values['step_completion_act'] );
if ( isset( $values['step_required'] ) )
{
$step->required = $values['step_required'];
}
else
{
$step->required = FALSE;
}
$step->completion_act = $values['step_completion_act'];
$step->subcompletion_act = $values['step_subcompletion_act'];
$step->save();
$step->postSaveForm( $values );
if ( method_exists( $step->extension, 'postAcpSave' ) )
{
$step->extension->postAcpSave( $step, $values );
}
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 & ~" . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['profile_completed'] ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles&tab=completion" ), 'saved' );
}
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=completion' ), \IPS\Member::loggedIn()->language()->addToStack('profile_completion') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'profile_completion' );
\IPS\Output::i()->output = $form;
}
/**
* Delete Step
*
* @return void
*/
public function deleteStep()
{
try
{
$step = \IPS\Member\ProfileStep::load( \IPS\Request::i()->id );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C360/2', 404, '' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$step->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles&tab=completion" ), 'deleted' );
}
/**
* Get Root Buttons
*
* @return array
*/
public function _getRootButtons()
{
$nodeClass = $this->nodeClass;
if ( $nodeClass::canAddRoot() )
{
$add = array(
'icon' => 'plus',
'title' => 'add',
'link' => $this->url->setQueryString( 'do', 'form' ),
'data' => ( $nodeClass::$modalForms ? array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add') ) : array() )
);
return array( 'add' => $add );
}
return array();
\IPS\Output::i()->output = '';
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('module__core_profile');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $output, \IPS\Http\Url::internal( "app=core&module=membersettings&controller=profiles" ) );
}
}
@@ -0,0 +1,120 @@
<?php
/**
* @brief Profile Settings
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 08 Jan 2018
*/
namespace IPS\core\modules\admin\membersettings;
/* 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;
}
/**
* Profile Settings
*/
class _profilesettings extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profiles_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
public function manage()
{
$form = new \IPS\Helpers\Form;
$form->addHeader( 'photos' );
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_gravatars', \IPS\Settings::i()->allow_gravatars ) );
if( \IPS\Image::canWriteText() )
{
$form->add( new \IPS\Helpers\Form\Radio( 'letter_photos', \IPS\Settings::i()->letter_photos, FALSE, array( 'options' => array( 'default' => 'letterphoto_default', 'letters' => 'letterphoto_letters' ) ) ) );
}
$form->addHeader( 'usernames' );
$form->add( new \IPS\Helpers\Form\Custom( 'user_name_length', array( \IPS\Settings::i()->min_user_name_length, \IPS\Settings::i()->max_user_name_length ), FALSE, array(
'getHtml' => function( $field ) {
return \IPS\Theme::i()->getTemplate('members')->usernameLengthSetting( $field->name, $field->value );
}
),
function( $val )
{
if ( $val[0] < 1 )
{
throw new \DomainException('user_name_length_too_low');
}
if ( $val[1] > 255 )
{
throw new \DomainException('user_name_length_too_high');
}
if ( $val[0] > $val[1] )
{
throw new \DomainException('user_name_length_no_match');
}
} ) );
$form->add( new \IPS\Helpers\Form\Text( 'username_characters', \IPS\Settings::i()->username_characters, FALSE, array( 'max' => 255 ) ) );
$form->addHeader( 'signatures' );
$form->add( new \IPS\Helpers\Form\YesNo( 'signatures_enabled', \IPS\Settings::i()->signatures_enabled ) );
/* Status updates */
$options = array(
0 => 'status_updates_disabled',
1 => 'status_updates_enabled_nomem',
2 => 'status_updates_enabled_mem'
);
$default = \IPS\Settings::i()->profile_comments ? ( \IPS\Settings::i()->status_updates_mem_enable ? 2 : 1 ) : 0;
$form->addHeader( 'statuses_profile_comments' );
$form->add( new \IPS\Helpers\Form\Radio( 'profile_comments', $default, FALSE, array( 'options' => $options, 'toggles' => array( 1 => array( 'profile_comment_approval' ), 2 => array( 'profile_comment_approval' ) ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'profile_comment_approval', \IPS\Settings::i()->profile_comment_approval, FALSE, array(), NULL, NULL, NULL, 'profile_comment_approval' ) );
$form->addHeader( 'profile_settings_birthdays' );
$form->add( new \IPS\Helpers\Form\Radio( 'profile_birthday_type', \IPS\Settings::i()->profile_birthday_type, TRUE, array(
'options' => array( 'public' => 'profile_birthday_type_public', 'private' => 'profile_birthday_type_private', 'none' => 'profile_birthday_type_none' )
), NULL, NULL, NULL, 'profile_birthday_type' ) );
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'profiles', 'member_history_prune' ) )
{
$form->addHeader( 'profile_member_history' );
$form->add( new \IPS\Helpers\Form\Number( 'prune_member_history', \IPS\Settings::i()->prune_member_history, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'prune_member_history' ) );
}
$form->addHeader( 'profile_settings_ignore' );
$form->add( new \IPS\Helpers\Form\YesNo( 'ignore_system_on', \IPS\Settings::i()->ignore_system_on, FALSE, array(), NULL, NULL, NULL, 'ignore_system_on' ) );
if ( $values = $form->values() )
{
$values['min_user_name_length'] = $values['user_name_length'][0];
$values['max_user_name_length'] = $values['user_name_length'][1];
unset( $values['user_name_length'] );
$values['status_updates_mem_enable'] = ( $values['profile_comments'] == 2 ) ? 1 : 0;
$values['profile_comments'] = ( $values['profile_comments'] > 0 ) ? 1 : 0;
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplog__profile_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=profiles&tab=profilesettings' ), 'saved' );
}
\IPS\Output::i()->output = (string) $form;
}
}
@@ -1,97 +0,0 @@
<?php
/**
* @brief Registration
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 18 Jul 2013
*/
namespace IPS\core\modules\admin\membersettings;
/* 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;
}
/**
* Registration
*/
class _registration extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'registration_manage' );
parent::execute();
}
/**
* General Member Settings
*
* @return void
*/
protected function manage()
{
$form = $this->getSettingsForm();
if ( $values = $form->values() )
{
if ( isset( $values['allowed_reg_email'] ) and is_array( $values['allowed_reg_email'] ) )
{
$values['allowed_reg_email'] = implode( ',', $values['allowed_reg_email'] );
}
if ( $values['use_coppa'] OR $values['minimum_age'] )
{
$values['quick_register'] = 0;
}
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__general_settings' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('membersettings_registration_title');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'membersettings_registration_title', $form );
}
/**
* Get the settings form
*
* @return \IPS\Helpers\Form
*/
protected function getSettingsForm()
{
$form = new \IPS\Helpers\Form;
$form->addHeader('registration');
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_reg', \IPS\Settings::i()->allow_reg, FALSE, array( 'togglesOn' => array( 'quick_register', 'new_reg_notify', 'reg_auth_type', 'form_header_coppa', 'use_coppa' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'quick_register', \IPS\Settings::i()->quick_register, FALSE, array(), NULL, NULL, NULL, 'quick_register' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'new_reg_notify', \IPS\Settings::i()->new_reg_notify, FALSE, array(), NULL, NULL, NULL, 'new_reg_notify' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'reg_auth_type', \IPS\Settings::i()->reg_auth_type, TRUE, array(
'options' => array( 'user' => 'reg_auth_type_user', 'admin' => 'reg_auth_type_admin', 'admin_user' => 'reg_auth_type_admin_user', 'none' => 'reg_auth_type_none' ),
'toggles' => array( 'user' => array( 'validate_day_prune' ), 'admin_user' => array( 'validate_day_prune' ) )
), NULL, NULL, NULL, 'reg_auth_type' ) );
$form->add( new \IPS\Helpers\Form\Number( 'validate_day_prune', \IPS\Settings::i()->validate_day_prune, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'validate_day_prune' ) );
$form->add( new \IPS\Helpers\Form\Stack( 'allowed_reg_email', explode( ',', \IPS\Settings::i()->allowed_reg_email ), FALSE, array(), NULL, NULL, NULL ) );
$form->addHeader('age_requirements');
$form->add( new \IPS\Helpers\Form\Number( 'minimum_age', \IPS\Settings::i()->minimum_age, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'any_age', 'unlimitedToggles' => array( 'quick_register' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'use_coppa', \IPS\Settings::i()->use_coppa, FALSE, array( 'togglesOn' => array( 'coppa_fax', 'coppa_address' ), 'togglesOff' => array( 'quick_register' ) ), NULL, NULL, NULL, 'use_coppa' ) );
$form->add( new \IPS\Helpers\Form\Tel( 'coppa_fax', \IPS\Settings::i()->coppa_fax, FALSE, array(), NULL, NULL, NULL, 'coppa_fax' ) );
$form->add( new \IPS\Helpers\Form\Address( 'coppa_address', \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->coppa_address ), FALSE, array(), NULL, NULL, NULL, 'coppa_address' ) );
return $form;
}
}
@@ -123,7 +123,7 @@ class _reputation extends \IPS\Node\Controller
}
$member = \IPS\Member::constructFromData( \IPS\Db::i()->select( '*', 'core_members', $where, 'member_id ASC', 1 )->first() );
$names[ $member->member_id ] = '<a>' . htmlentities( $member->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . '</a>';
$names[ $member->member_id ] = '<a>' . htmlentities( $member->name, ENT_DISALLOWED, 'UTF-8', FALSE ) . '</a>';
}
catch ( \Exception $e )
{
@@ -176,6 +176,7 @@ class _reputation extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form();
$form->add( new \IPS\Helpers\Form\YesNo( 'reputation_leaderboard_on', \IPS\Settings::i()->reputation_leaderboard_on, FALSE, array( 'togglesOn' => array( 'reputation_leaderboard_default_tab', 'form_header_leaderboard_tabs_leaderboard', 'reputation_show_days_won_trophy', 'reputation_timezone', 'form_header_leaderboard_tabs_members', 'reputation_top_members_overview', 'reputation_overview_max_members', 'reputation_top_members_filters', 'reputation_max_members' ) ), NULL, NULL, NULL, 'reputation_leaderboard_on' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'reputation_leaderboard_default_tab', \IPS\Settings::i()->reputation_leaderboard_default_tab, FALSE, array( 'options' => array( 'leaderboard' => 'leaderboard_tabs_leaderboard', 'history' => 'leaderboard_tabs_history', 'members' => 'leaderboard_tabs_members' ) ), NULL, NULL, NULL, 'reputation_leaderboard_default_tab' ) );
$form->add( new \IPS\Helpers\Form\Select( 'leaderboard_excluded_groups', \IPS\Settings::i()->leaderboard_excluded_groups, FALSE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal', 'multiple' => TRUE ), NULL, NULL, NULL, 'leaderboard_excluded_groups' ) );
$form->addHeader('leaderboard_tabs_leaderboard');
$form->add( new \IPS\Helpers\Form\YesNo( 'reputation_show_days_won_trophy', \IPS\Settings::i()->reputation_show_days_won_trophy, FALSE, array( 'togglesOn' => array() ), NULL, NULL, NULL, 'reputation_show_days_won_trophy' ) );
$form->add( new \IPS\Helpers\Form\Timezone( 'reputation_timezone', \IPS\Settings::i()->reputation_timezone, FALSE, array(), NULL, NULL, NULL, 'reputation_timezone' ) );
@@ -0,0 +1,91 @@
<?php
/**
* @brief reportedContent
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 07 Dec 2017
*/
namespace IPS\core\modules\admin\moderation;
/* 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;
}
/**
* reportedContent
*/
class _reportedContent extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\core\Reports\Rules';
/**
* Execute
*
* @return void
*/
public function execute()
{
/* Add a button for settings */
\IPS\Output::i()->sidebar['actions'] = array(
'settings' => array(
'title' => 'reportedContent_settings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=reportedContent&do=settings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('reportedContent_settings') )
),
'types' => array(
'title' => 'reportedContent_types',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=reportedContentTypes' )
)
);
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb( 'automaticmoderation_blurb' );
if ( ! \IPS\Settings::i()->automoderation_enabled )
{
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('forms')->blurb( 'automaticmoderation_disabled_blurb' );
}
\IPS\Dispatcher::i()->checkAcpPermission( 'reportedContent_manage' );
parent::execute();
}
/**
* Profile Settings
*
* @return void
*/
protected function settings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'reportedContent_manage' );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'automoderation_enabled', \IPS\Settings::i()->automoderation_enabled, FALSE, array(), NULL, NULL, NULL, 'automoderation_enabled' ) );
$form->add( new \IPS\Helpers\Form\Number( 'automoderation_report_again_mins', \IPS\Settings::i()->automoderation_report_again_mins, FALSE, array(), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('automoderation_report_again_mins_suffix'), 'automoderation_report_again_mins' ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => (int) $values['automoderation_enabled'] ), array( '`key`=?', 'automaticmoderation' ) );
\IPS\Session::i()->log( 'acplog__automoderation_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=reportedContent' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reportedContent_settings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'reportedContent_settings', $form, FALSE );
}
}
@@ -0,0 +1,41 @@
<?php
/**
* @brief reportedContentTypes
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 14 Dec 2017
*/
namespace IPS\core\modules\admin\moderation;
/* 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;
}
/**
* reportedContentTypes
*/
class _reportedContentTypes extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\core\Reports\Types';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'reportedContentTypes_manage' );
parent::execute();
}
}
@@ -8,7 +8,7 @@
* @since 18 Apr 2013
*/
namespace IPS\core\modules\admin\membersettings;
namespace IPS\core\modules\admin\moderation;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
@@ -44,7 +44,7 @@ class _spam extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Work out output */
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
/* If this is an AJAX request, just return it */
if( \IPS\Request::i()->isAjax() )
@@ -59,24 +59,44 @@ class _spam extends \IPS\Dispatcher\Controller
$tabs['flagging'] = 'spamprevention_flagging';
$tabs['service'] = 'enhancements__core_SpamMonitoring';
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'qanda_manage' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_manage' ) and in_array( \IPS\Login::registrationType(), array( 'normal', 'full' ) ) )
{
$tabs['qanda'] = 'qanda_settings';
}
/* Add a button for logs */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'spam_service_log' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_service_log' ) )
{
\IPS\Output::i()->sidebar['actions']['errorLog'] = array(
'title' => 'spamlogs',
'icon' => 'exclamation-triangle',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=serviceLogs' ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=serviceLogs' ),
);
}
/* Add a button for whitelist */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_whitelist_manage' ) )
{
\IPS\Output::i()->sidebar['actions']['whitelist'] = array(
'title' => 'spam_whitelist',
'icon' => 'shield',
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelist' ),
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_delete' ) )
{
\IPS\Output::i()->sidebar['actions']['delete_guest_content'] = array(
'title' => 'member_delete_guest_content',
'icon' => 'trash-o',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=deleteGuestContent' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('member_delete_guest_content') )
);
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_membersettings_spam');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $this->activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=membersettings&controller=spam" ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_moderation_spam');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $this->activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=moderation&controller=spam" ) );
}
/**
@@ -90,14 +110,14 @@ class _spam extends \IPS\Dispatcher\Controller
switch( $type )
{
case 'options':
return array( 'none' => 'captcha_type_none', 'recaptcha2' => 'captcha_type_recaptcha2', 'recaptcha' => 'captcha_type_recaptcha', 'keycaptcha' => 'captcha_type_keycaptcha' );
return array( 'none' => 'captcha_type_none', 'invisible' => 'captcha_type_invisible', 'recaptcha2' => 'captcha_type_recaptcha2', 'keycaptcha' => 'captcha_type_keycaptcha' );
break;
case 'toggles':
return array(
'none' => array( 'bot_antispam_type_warning' ),
'recaptcha2' => array( 'guest_captcha', 'recaptcha2_public_key', 'recaptcha2_private_key' ),
'recaptcha' => array( 'guest_captcha', 'recaptcha_public_key', 'recaptcha_private_key' ),
'invisible' => array( 'guest_captcha', 'recaptcha2_public_key', 'recaptcha2_private_key' ),
'keycaptcha' => array( 'guest_captcha', 'keycaptcha_privatekey' )
);
break;
@@ -121,10 +141,8 @@ class _spam extends \IPS\Dispatcher\Controller
), NULL, NULL, NULL, 'bot_antispam_type' ) );
$form->add( new \IPS\Helpers\Form\Text( 'recaptcha2_public_key', \IPS\Settings::i()->recaptcha2_public_key, FALSE, array(), NULL, NULL, NULL, 'recaptcha2_public_key' ) );
$form->add( new \IPS\Helpers\Form\Text( 'recaptcha2_private_key', \IPS\Settings::i()->recaptcha2_private_key, FALSE, array(), NULL, NULL, NULL, 'recaptcha2_private_key' ) );
$form->add( new \IPS\Helpers\Form\Text( 'recaptcha_public_key', \IPS\Settings::i()->recaptcha_public_key, FALSE, array(), NULL, NULL, NULL, 'recaptcha_public_key' ) );
$form->add( new \IPS\Helpers\Form\Text( 'recaptcha_private_key', \IPS\Settings::i()->recaptcha_private_key, FALSE, array(), NULL, NULL, NULL, 'recaptcha_private_key' ) );
$form->add( new \IPS\Helpers\Form\Text( 'keycaptcha_privatekey', \IPS\Settings::i()->keycaptcha_privatekey, FALSE, array(), NULL, NULL, NULL, 'keycaptcha_privatekey' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'guest_captcha', \IPS\Settings::i()->guest_captcha, FALSE, array(), NULL, NULL, \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'membertools_delete' ) ? ( "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=deleteGuestContent' ) . "' data-ipsDialog data-ipsDialog-title='" . \IPS\Member::loggedIn()->language()->addToStack('member_delete_guest_content'). "'>" . \IPS\Member::loggedIn()->language()->addToStack('member_delete_guest_content') . "</a>" ) : '', 'guest_captcha' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'guest_captcha', \IPS\Settings::i()->guest_captcha, FALSE, array(), NULL, NULL, NULL, 'guest_captcha' ) );
/* Save values */
if ( $form->values() )
@@ -179,7 +197,7 @@ class _spam extends \IPS\Dispatcher\Controller
$form->addHeader( 'enhancements__core_SpamMonitoring' );
$disabled = FALSE;
if( !$licenseData or !isset( $licenseData['products']['spam'] ) or !$licenseData['products']['spam'] or strtotime( $licenseData['expires'] ) < time() )
if( !$licenseData or !isset( $licenseData['products']['spam'] ) or !$licenseData['products']['spam'] or ( !$licenseData['cloud'] AND strtotime( $licenseData['expires'] ) < time() ) )
{
$disabled = TRUE;
if( !\IPS\Settings::i()->ipb_reg_number )
@@ -218,7 +236,7 @@ class _spam extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'qanda_manage' );
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_question_and_answer', \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&tab=qanda' ) );
$table = new \IPS\Helpers\Table\Db( 'core_question_and_answer', \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&tab=qanda' ) );
$table->include = array( 'qa_question' );
$table->joins = array(
array( 'select' => 'w.word_custom', 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'core_question_and_answer_', core_question_and_answer.qa_id ) AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
@@ -234,13 +252,13 @@ class _spam extends \IPS\Dispatcher\Controller
$table->quickSearch = array( 'word_custom', 'qa_question' );
$table->sortDirection = $table->sortDirection ?: 'asc';
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'qanda_add' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_add' ) )
{
$table->rootButtons = array(
'add' => array(
'icon' => 'plus',
'title' => 'qanda_add_question',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=question' ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=question' ),
)
);
}
@@ -249,21 +267,21 @@ class _spam extends \IPS\Dispatcher\Controller
{
$return = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'qanda_edit' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_edit' ) )
{
$return['edit'] = array(
'icon' => 'pencil',
'title' => 'edit',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=question&id=' ) . $row['qa_id'],
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=question&id=' ) . $row['qa_id'],
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'qanda_delete' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_delete' ) )
{
$return['delete'] = array(
'icon' => 'times-circle',
'title' => 'delete',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=delete&id=' ) . $row['qa_id'],
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=delete&id=' ) . $row['qa_id'],
'data' => array( 'delete' => '' ),
);
}
@@ -326,7 +344,7 @@ class _spam extends \IPS\Dispatcher\Controller
\IPS\Lang::saveCustom( 'core', "core_question_and_answer_{$id}", $values['qa_question'] );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&tab=qanda' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&tab=qanda' ), 'saved' );
}
/* Display */
@@ -354,7 +372,7 @@ class _spam extends \IPS\Dispatcher\Controller
\IPS\Lang::deleteCustom( 'core', "core_question_and_answer_{$id}" );
/* And redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=membersettings&controller=spam&tab=qanda" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=moderation&controller=spam&tab=qanda" ) );
}
/**
@@ -367,7 +385,7 @@ class _spam extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'spam_service_log' );
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_spam_service_log', \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=serviceLogs' ) );
$table = new \IPS\Helpers\Table\Db( 'core_spam_service_log', \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=serviceLogs' ) );
$table->langPrefix = 'spamlogs_';
@@ -399,14 +417,14 @@ class _spam extends \IPS\Dispatcher\Controller
'settings' => array(
'title' => 'prunesettings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=serviceLogSettings' ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=serviceLogSettings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
),
);
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('spamlogs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'spamlogs', $table );
\IPS\Output::i()->output = (string) $table;
}
/**
@@ -426,10 +444,200 @@ class _spam extends \IPS\Dispatcher\Controller
{
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplog__spamlog_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=spam&do=serviceLogs' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=serviceLogs' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('spamlogssettings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'spamlogssettings', $form, FALSE );
}
/**
* Spam defense whitelist
*
* @return void
*/
protected function whitelist()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'spam_whitelist_manage' );
$table = new \IPS\Helpers\Table\Db( 'core_spam_whitelist', \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelist' ) );
$table->filters = array(
'spam_whitelist_ip' => 'whitelist_type=\'ip\'',
'spam_whitelist_domain' => 'whitelist_type=\'domain\''
);
$table->include = array( 'whitelist_type', 'whitelist_content', 'whitelist_reason', 'whitelist_date' );
$table->mainColumn = 'whiteist_content';
$table->rowClasses = array( 'whitelist_reason' => array( 'ipsTable_wrap' ) );
$table->sortBy = $table->sortBy ?: 'whitelist_date';
$table->sortDirection = $table->sortDirection ?: 'asc';
$table->quickSearch = 'whitelist_content';
$table->advancedSearch = array(
'whitelist_reason' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'whitelist_date' => \IPS\Helpers\Table\SEARCH_DATE_RANGE
);
/* Custom parsers */
$table->parsers = array(
'whitelist_date' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->localeDate();
},
'whitelist_type' => function( $val, $row )
{
switch( $val )
{
default:
case 'ip':
return \IPS\Member::loggedIn()->language()->addToStack('spam_whitelist_ip_select');
break;
case 'domain':
return \IPS\Member::loggedIn()->language()->addToStack('spam_whitelist_domain_select');
break;
}
}
);
/* Row buttons */
$table->rowButtons = function( $row )
{
$return = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_whitelist_edit' ) )
{
$return['edit'] = array(
'icon' => 'pencil',
'title' => 'edit',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit') ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelistForm&id=' ) . $row['whitelist_id'],
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_whitelist_delete' ) )
{
$return['delete'] = array(
'icon' => 'times-circle',
'title' => 'delete',
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelistDelete&id=' ) . $row['whitelist_id'],
'data' => array( 'delete' => '' ),
);
}
return $return;
};
/* Add an add button for whitelist */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_whitelist_add' ) )
{
\IPS\Output::i()->sidebar['actions'] = array(
'add' => array(
'primary' => TRUE,
'icon' => 'plus',
'title' => 'spam_whitelist_add',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('spam_whitelist_add') ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelistForm' )
)
);
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('spam_whitelist');
\IPS\Output::i()->output = (string) $table;
}
/**
* Whitelist add/edit form
*
* @return void
*/
protected function whitelistForm()
{
$current = NULL;
if ( \IPS\Request::i()->id )
{
$current = \IPS\Db::i()->select( '*', 'core_spam_whitelist', array( 'whitelist_id=?', \IPS\Request::i()->id ) )->first();
\IPS\Dispatcher::i()->checkAcpPermission( 'spam_whitelist_edit' );
}
else
{
\IPS\Dispatcher::i()->checkAcpPermission( 'spam_whitelist_add' );
}
/* Build form */
$form = new \IPS\Helpers\Form();
$form->add( new \IPS\Helpers\Form\Select( 'whitelist_type', $current['whitelist_type'], TRUE,
array(
'options' => array(
'ip' => 'spam_whitelist_ip_select',
'domain' => 'spam_whitelist_domain_select'
),
'toggles' => array(
'ip' => array( 'whitelist_ip_content' ),
'domain' => array( 'whitelist_domain_content' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_ip_content', $current['whitelist_content'], TRUE, array(), NULL, NULL, NULL, 'whitelist_ip_content' ) );
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_domain_content', $current['whitelist_content'], TRUE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
if( isset( $value ) AND mb_stripos( $value, '@' ) )
{
throw new \DomainException( 'whitelist_domain_email_detected' );
}
}, NULL, NULL, 'whitelist_domain_content' ) );
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_reason', $current['whitelist_reason'] ) );
/* Handle submissions */
if ( $values = $form->values() )
{
$whitelistContent = $values['whitelist_type'] == 'ip' ? $values['whitelist_ip_content'] : $values['whitelist_domain_content'];
$save = array(
'whitelist_type' => $values['whitelist_type'],
'whitelist_content' => $whitelistContent,
'whitelist_reason' => $values['whitelist_reason'],
'whitelist_date' => time()
);
if ( $current )
{
unset( $save['whitelist_date'] );
\IPS\Db::i()->update( 'core_spam_whitelist', $save, array( 'whitelist_id=?', $current['whitelist_id'] ) );
\IPS\Session::i()->log( 'acplog__spam_whitelist_edited', array( 'spam_whitelist_' . $save['whitelist_type'] . '_select' => TRUE, $save['whitelist_content'] => FALSE ) );
}
else
{
\IPS\Db::i()->insert( 'core_spam_whitelist', $save );
\IPS\Session::i()->log( 'acplog__spam_whitelist_created', array( 'spam_whitelist_' . $save['whitelist_type'] . '_select' => TRUE, $save['whitelist_content'] => FALSE ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelist' ), 'saved' );
}
/* Display */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( $current ? $current['whitelist_content'] : 'add', $form, FALSE );
}
/**
* Delete whitelist entry
*
* return @void
*/
protected function whitelistDelete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'spam_whitelist_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$current = \IPS\Db::i()->select( '*', 'core_spam_whitelist', array( 'whitelist_id=?', \IPS\Request::i()->id ) )->first();
\IPS\Session::i()->log( 'acplog__spam_whitelist_deleted', array( 'whitelist_filter_' . $current['whitelist_type'] . '_select' => TRUE, $current['whitelist_content'] => FALSE ) );
\IPS\Db::i()->delete( 'core_spam_whitelist', array( 'whitelist_id=?', \IPS\Request::i()->id ) );
}
catch ( \UnderflowException $e ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelist' ) );
}
}
@@ -8,7 +8,7 @@
* @since 23 Apr 2013
*/
namespace IPS\core\modules\admin\membersettings;
namespace IPS\core\modules\admin\moderation;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
@@ -51,7 +51,7 @@ class _warnings extends \IPS\Node\Controller
$tabs = array();
/* Reasons */
if ( \IPS\Settings::i()->warn_on and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'reasons_view' ) )
if ( \IPS\Settings::i()->warn_on and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'reasons_view' ) )
{
$tabs['reasons'] = 'warn_reasons';
if ( $activeTab == 'reasons' )
@@ -62,13 +62,13 @@ class _warnings extends \IPS\Node\Controller
}
/* Actions */
if ( \IPS\Settings::i()->warn_on and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'actions_view' ) )
if ( \IPS\Settings::i()->warn_on and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'actions_view' ) )
{
$tabs['actions'] = 'warn_actions';
if ( $activeTab == 'actions' )
{
/* Init */
$table = new \IPS\Helpers\Table\Db( 'core_members_warn_actions', \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings' ) );
$table = new \IPS\Helpers\Table\Db( 'core_members_warn_actions', \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings' ) );
$table->include = array( 'wa_points', 'wa_mq', 'wa_rpa', 'wa_suspend' );
$table->sortBy = $table->sortBy ?: 'wa_points';
$table->sortDirection = $table->sortDirection ?: 'asc';
@@ -78,21 +78,21 @@ class _warnings extends \IPS\Node\Controller
{
$return = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'actions_edit' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'actions_edit' ) )
{
$return['edit'] = array(
'icon' => 'pencil',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&do=actionForm&id=' ) . $row['wa_id'],
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&do=actionForm&id=' ) . $row['wa_id'],
'title' => 'edit',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add') )
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'actions_delete' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'actions_delete' ) )
{
$return['delete'] = array(
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&do=actionDelete&id=' ) . $row['wa_id'],
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&do=actionDelete&id=' ) . $row['wa_id'],
'title' => 'delete',
'data' => array( 'delete' => '' )
);
@@ -118,12 +118,12 @@ class _warnings extends \IPS\Node\Controller
);
/* Add button */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'actions_add' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'actions_add' ) )
{
$table->rootButtons = array(
'add' => array(
'icon' => 'plus',
'link' => \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&do=actionForm' ),
'link' => \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&do=actionForm' ),
'title' => 'add',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('add') )
)
@@ -154,7 +154,7 @@ class _warnings extends \IPS\Node\Controller
{
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplog__warn_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&tab=settings' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&tab=settings' ), 'saved' );
}
$activeTabContents = (string) $form;
@@ -174,7 +174,7 @@ class _warnings extends \IPS\Node\Controller
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=membersettings&controller=warnings" ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=moderation&controller=warnings" ) );
}
}
@@ -241,7 +241,7 @@ class _warnings extends \IPS\Node\Controller
\IPS\Session::i()->log( 'acplog__wa_created', array( $save['wa_points'] => FALSE ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&tab=actions' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&tab=actions' ), 'saved' );
}
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'warn_action', $form, FALSE );
@@ -268,6 +268,6 @@ class _warnings extends \IPS\Node\Controller
}
catch ( \UnderflowException $e ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=warnings&tab=actions' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=warnings&tab=actions' ), 'saved' );
}
}
@@ -109,15 +109,52 @@ class _dashboard extends \IPS\Dispatcher\Controller
/* Warnings */
$warnings = array();
$dir = @dir( '/' );
if ( $dir instanceof \Directory )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_desc'),
);
}
$functionsToDisable = array( 'exec', 'system', 'passhtru', 'pcntl_exec', 'popen', 'proc_open', 'shell_exec' );
$showingFunctionWarning = FALSE;
foreach ( $functionsToDisable as $k => $function )
{
if ( function_exists( $function ) )
{
$showingFunctionWarning = TRUE;
}
else
{
unset( $functionsToDisable[ $k ] );
}
}
if ( $showingFunctionWarning )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_desc', FALSE, array( 'sprintf' => array( implode( ', ', $functionsToDisable ) ) ) ),
);
}
if ( !\IPS\IN_DEV and ini_get( 'display_errors' ) )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_desc'),
'risk' => "medium",
);
}
$tasks = \IPS\Db::i()->select( '*', 'core_tasks', 'lock_count >= 3' );
$keys = array();
foreach( $tasks as $task )
{
$keys[] = $task['key'];
}
if ( !empty( $keys ) )
{
$warnings[] = array(
@@ -143,6 +180,50 @@ class _dashboard extends \IPS\Dispatcher\Controller
);
}
if( !\IPS\Settings::i()->orig_tables_checked )
{
/* Check if we have any orig_* tables */
$tables = \IPS\Db::i()->getTables( 'orig_' . \IPS\Db::i()->prefix );
/* If we don't have any, we're good. Set a flag so we don't check this every dashboard load. */
if( !count( $tables ) )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 1 ), array( 'conf_key=?', 'orig_tables_checked' ) );
unset( \IPS\Data\Store::i()->settings );
}
else
{
/* Determine if the background queue task has already been launched */
try
{
\IPS\Db::i()->select( '*', 'core_queue', array( "`key`=?", 'CleanupOrigTables' ) )->first();
$inProgress = TRUE;
}
catch( \UnderflowException $e )
{
$inProgress = FALSE;
}
/* Launch the task if we clicked to do so */
if( !$inProgress AND isset( \IPS\Request::i()->cleanupOrigTables ) AND \IPS\Request::i()->cleanupOrigTables )
{
\IPS\Task::queue( 'core', 'CleanupOrigTables', array( 'originalCount' => count( $tables ) ), 5 );
$inProgress = TRUE;
\IPS\Output::i()->inlineMessage = \IPS\Member::loggedIn()->language()->addToStack('orig_tables_rebuilding');
}
if( !$inProgress )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('block_core_OrigTables'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('orig_cleanup_suggested')
);
}
}
}
/* Check Tasks */
try
{
@@ -155,21 +236,21 @@ class _dashboard extends \IPS\Dispatcher\Controller
if( \IPS\Settings::i()->task_use_cron == 'cron' )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_cron_broken_desc' )
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( \IPS\CIC ? 'dashboard_tasks_cron_broken_desc_cic' : 'dashboard_tasks_cron_broken_desc' )
);
}
elseif( \IPS\Settings::i()->task_use_cron == 'web' )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_web_broken_desc' )
);
}
else
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_not_enough_desc' )
);
}
@@ -184,8 +265,10 @@ class _dashboard extends \IPS\Dispatcher\Controller
'description' => \IPS\Member::loggedIn()->language()->addToStack('dasbhoard_tasks_site_offline_desc')
);
}
/* If there have been more than 10 datastore failurs in the last hour, or if an instant test fails, show a message */
/* If there have been more than 10 datastore failures in the last hour, or if an instant test fails, show a message */
if( !\IPS\Data\Store::i()->test() OR \IPS\Db::i()->select( 'COUNT(*)', 'core_log', array( '`category`=? AND `time`>?', 'datastore', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) )->first() >= 10 )
{
/* Have we just recently updated the configuration? If so, ignore this warning for 24 hours */
@@ -197,13 +280,92 @@ class _dashboard extends \IPS\Dispatcher\Controller
);
}
}
if ( \IPS\CIC )
{
try
{
$cicEmails = \IPS\Data\Cache::i()->getWithExpire( 'cicEmailUsage', TRUE );
}
catch( \OutOfRangeException $e )
{
preg_match( '/^\/var\/www\/html\/(.+?)(?:\/|$)/i', \IPS\ROOT_PATH, $matches );
try
{
$cicEmails = \IPS\Http\Url::external( "http://ips-cic-email.invisioncic.com/blocked.php?account={$matches[1]}" )->request()->get()->decodeJson();
}
catch( \Exception $e )
{
/* Request failed, so assume okay and try again in an hour */
$cicEmails = array( 'status' => 'OKAY', 'time' => time() );
}
\IPS\Data\Cache::i()->storeWithExpire( 'cicEmailUsage', $cicEmails, \IPS\DateTime::create()->add( new \DateInterval( 'PT1H' ) ), true );
}
if ( isset( $cicEmails['status'] ) AND $cicEmails['status'] == 'BLOCKED' )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_cic_email_quota' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_cic_email_quota_desc' )
);
}
}
/* Cache Check */
if ( \IPS\CACHE_METHOD AND \IPS\CACHE_METHOD != 'None' AND \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_invalid_cachesetup' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_invalid_cachesetup_desc' )
);
}
/* Get new core update available data */
$update = \IPS\Application::load( 'core' )->availableUpgrade( TRUE );
$update = \IPS\Application::load( 'core' )->availableUpgrade( TRUE );
/* Determine if there are any new features to show */
$latestFeatureId = \IPS\Application::load( 'core' )->newFeature();
$features = array();
try
{
$latestSeenFeature = \IPS\Db::i()->select( 'feature_id', 'core_members_feature_seen', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ) )->first();
}
catch( \UnderflowException $e )
{
$latestSeenFeature = 0;
}
if( $latestFeatureId AND ( !$latestSeenFeature OR $latestSeenFeature < $latestFeatureId ) )
{
try
{
$features = json_encode( \IPS\Http\Url::ips('newFeatures')->setQueryString( array( 'since' => (int) $latestSeenFeature ) )->request()->get()->decodeJson() );
/* Reset our last feature ID information so this doesn't show on subsequent page loads */
\IPS\Db::i()->replace( 'core_members_feature_seen', array( 'member_id' => \IPS\Member::loggedIn()->member_id, 'feature_id' => $latestFeatureId ) );
}
catch( \RuntimeException $e ){}
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('dashboard');
\IPS\Output::i()->customHeader = \IPS\Theme::i()->getTemplate( 'dashboard' )->dashboardHeader( $info, $blocks );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'dashboard' )->dashboard( $update, $toShow, $blocks, $info, $bulletins, $warnings );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'dashboard' )->dashboard( $update, $features, $toShow, $blocks, $info, $bulletins, $warnings );
}
/**
* Reset the latest features we've seen so that we can see them again
*
* @return void
*/
public function whatsNew()
{
\IPS\Db::i()->delete( 'core_members_feature_seen', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=dashboard" ) );
}
/**
@@ -234,9 +396,12 @@ class _dashboard extends \IPS\Dispatcher\Controller
$blocks[ \IPS\Member::loggedIn()->member_id ] = $toShow;
\IPS\Settings::i()->acp_dashboard_blocks = json_encode( $blocks );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Settings::i()->acp_dashboard_blocks ), array( 'conf_key=?', 'acp_dashboard_blocks' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'acp_dashboard_blocks' => json_encode( $blocks ) ) );
}
/* Upon initial upgrade to 4.3 the key won't exist, so apply to bg queue by default */
elseif( !array_key_exists( 'collapsed', $toShow ) )
{
$toShow['collapsed'] = array( 'core_BackgroundQueue' );
}
if( $return === TRUE )
@@ -292,20 +457,17 @@ class _dashboard extends \IPS\Dispatcher\Controller
$saveBlocks = \IPS\Request::i()->blocks;
if( !isset( $saveBlocks['main'] ) )
foreach( array( 'main', 'side', 'collapsed' ) as $saveKey )
{
$saveBlocks['main'] = array();
}
if( !isset( $saveBlocks['side'] ) )
{
$saveBlocks['side'] = array();
if( !isset( $saveBlocks[ $saveKey ] ) )
{
$saveBlocks[ $saveKey ] = array();
}
}
$blocks[ \IPS\Member::loggedIn()->member_id ] = $saveBlocks;
\IPS\Settings::i()->acp_dashboard_blocks = json_encode( $blocks );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Settings::i()->acp_dashboard_blocks ), array( 'conf_key=?', 'acp_dashboard_blocks' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'acp_dashboard_blocks' => json_encode( $blocks ) ) );
if( \IPS\Request::i()->isAjax() )
{
@@ -72,16 +72,21 @@ class _files extends \IPS\Dispatcher\Controller
}*/
$table = new \IPS\Helpers\Table\Db( 'core_attachments', \IPS\Http\Url::internal( 'app=core&module=overview&controller=files' ) );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'dashboard' ), 'fileTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'dashboard' ), 'fileTableRows' );
$table->filters = array(
'images' => "attach_is_image=1",
'files' => "attach_is_image=0",
);
$table->include = array( 'attach_file', 'attach_filesize', 'attach_date', 'attach_member_id' );
$table->include = array( 'attach_id', 'attach_file', 'attach_filesize', 'attach_date', 'attach_member_id' );
$table->rowClasses = array( 'attach_file' => array( 'ipsTable_wrap' ) );
if ( $table->filter !== 'images' )
{
$table->include[] = 'attach_hits';
}
$table->noSort = array( 'attach_type' );
$table->noSort = array( 'attach_type', 'attach_id' );
$table->quickSearch = 'attach_file';
$table->parsers = array(
'attach_file' => function( $val, $row ) use ( $table )
@@ -94,7 +99,7 @@ class _files extends \IPS\Dispatcher\Controller
else
{
$url = \IPS\Http\Url::external( \IPS\Settings::i()->base_url . "applications/core/interface/file/attachment.php" )->setQueryString( 'id', $row['attach_id'] )->makeSafeForAcp( FALSE );
$val = htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$val = htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE );
return "<a href='{$url}' target='_blank'>{$val}</a>";
}
},
@@ -133,7 +138,7 @@ class _files extends \IPS\Dispatcher\Controller
}
else
{
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' . $val ) . "'>" . htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . '</a>';
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' . $val ) . "'>" . htmlentities( \IPS\Member::load( $val )->name, ENT_DISALLOWED, 'UTF-8', FALSE ) . '</a>';
}
}
@@ -168,7 +173,9 @@ class _files extends \IPS\Dispatcher\Controller
return $buttons;
};
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'dashboard/files.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_files.js', 'core', 'admin' ) );
\IPS\Output::i()->output = (string) $table;
}
@@ -393,8 +400,7 @@ class _files extends \IPS\Dispatcher\Controller
\IPS\Task::queue( 'core', 'DeleteMovedFiles', array( 'delete' => true ), 5, array( 'delete' ) ); /* We use a key in the data array just to trigger the code that deletes duplicate tasks */
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $values ) ), array( 'conf_key=?', 'upload_settings' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'upload_settings' => json_encode( $values ) ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -558,7 +564,7 @@ class _files extends \IPS\Dispatcher\Controller
$toggles = array();
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/system/File' ) as $f )
{
if ( !$f->isDot() and mb_substr( $f, -4 ) === '.php' and $f != 'File.php' and $f != 'Iterator.php' )
if ( !$f->isDot() and mb_substr( $f, -4 ) === '.php' and $f != 'File.php' and $f != 'Iterator.php' and $f != 'Exception.php' )
{
$key = mb_substr( $f, 0, -4 );
@@ -566,6 +572,12 @@ class _files extends \IPS\Dispatcher\Controller
{
continue;
}
/* Hide FTP option from form unless it's already in use */
if ( ( $key === 'Ftp' AND isset( $current['method'] ) AND $current['method'] !== 'Ftp' ) OR ( $key === 'Ftp' AND !isset( $current['method'] ) ) )
{
continue;
}
$handlers[ $key ] = 'filehandler__' . $key;
@@ -713,8 +725,7 @@ class _files extends \IPS\Dispatcher\Controller
}
}
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $settings ) ), array( 'conf_key=?', 'upload_settings' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'upload_settings' => json_encode( $settings ) ) );
if ( $values['filestorage_move'] )
{
@@ -853,4 +864,37 @@ class _files extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=files" ), 'orphaned_files_tasks_added' );
}
/**
* Multimod
*
* @return void
*/
protected function multimod()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'files_delete' );
\IPS\Session::i()->csrfCheck();
if( !isset( \IPS\Request::i()->multimod ) OR !is_array( \IPS\Request::i()->multimod ) OR !count( \IPS\Request::i()->multimod ) )
{
\IPS\Output::i()->error( 'nothing_mm_selected', '2C158/6', 403, '' );
}
foreach ( \IPS\Db::i()->select( '*', 'core_attachments', \IPS\Db::i()->in( 'attach_id', array_keys( \IPS\Request::i()->multimod ) ) ) as $attachment )
{
\IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
if( $attachment['attach_thumb_location'] )
{
\IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
}
\IPS\Session::i()->log( 'acplogs__file_deleted', array( $attachment['attach_file'] => FALSE ) );
}
\IPS\Db::i()->delete( 'core_attachments', \IPS\Db::i()->in( 'attach_id', array_keys( \IPS\Request::i()->multimod ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=files" ), 'deleted' );
}
}
@@ -1,403 +0,0 @@
<?php
/**
* @brief Security Settings
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 11 Jun 2013
*/
namespace IPS\core\modules\admin\overview;
/* 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;
}
/**
* Security Settings
*/
class _security extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'security_manage' );
parent::execute();
}
/**
* Security Center
*
* @return void
*/
protected function manage()
{
/* Init */
$content = array();
\IPS\Output::i()->sidebar['actions'] = array(
'settings' => array(
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=overview&controller=security&do=settings' ),
'title' => 'security_settings',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('security_settings') )
),
'list_admins' => array(
'icon' => 'key',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&filter=members_filter_administrators' ),
'title' => 'security_list_admins',
),
);
/* open_basedir */
$dir = @dir( '/' );
if ( $dir instanceof Directory )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_desc'),
'risk' => "high",
);
}
/* Htaccess Protection */
$needUploads = FALSE;
foreach( \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', 'FileSystem' ) ) as $uploads )
{
$uploads = json_decode( $uploads['configuration'], TRUE );
if( isset( $uploads['dir'] ) )
{
$uploads['dir'] = str_replace( '{root}', \IPS\ROOT_PATH, $uploads['dir'] );
if( !is_file( $uploads['dir'] . '/.htaccess' ) )
{
$needUploads = TRUE;
}
}
}
$storeSettings = json_decode( \IPS\STORE_CONFIG, TRUE );
if ( ( $needUploads OR
( \IPS\STORE_METHOD == 'FileSystem' AND !is_file( str_replace( '{root}', \IPS\ROOT_PATH, $storeSettings['path'] ) . '/.htaccess' ) ) ) AND !\IPS\NO_WRITES )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('htaccess_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('htaccess_desc'),
'risk' => "high",
'button' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('security_run_tool'), 'action' => "app=core&module=overview&controller=security&do=htaccess" ),
);
}
/* Configuration File */
if ( is_writable( \IPS\ROOT_PATH . '/conf_global.php' ) AND !\IPS\NO_WRITES )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('conf_writeable_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('conf_writeable_desc'),
'risk' => "high",
'button' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('security_run_tool'), 'action' => "app=core&module=overview&controller=security&do=conf" ),
);
}
/* Disabled PHP Functions */
$functionsToDisable = array( 'exec', 'system', 'passhtru', 'pcntl_exec', 'popen', 'proc_open', 'shell_exec' );
$showingFunctionWarning = FALSE;
foreach ( $functionsToDisable as $k => $function )
{
if ( function_exists( $function ) )
{
$showingFunctionWarning = TRUE;
}
else
{
unset( $functionsToDisable[ $k ] );
}
}
if ( $showingFunctionWarning )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_desc', FALSE, array( 'sprintf' => array( implode( ', ', $functionsToDisable ) ) ) ),
'risk' => "high",
);
}
/* Display Errors */
if ( ini_get( 'display_errors' ) )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_desc'),
'risk' => "medium",
);
}
/* ACP Directory Name */
if ( \IPS\CP_DIRECTORY == 'admin' and !\IPS\CIC )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('rename_admin_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('rename_admin_desc'),
'risk' => "low",
'button' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('security_learn_more'), 'action' => "app=core&module=overview&controller=security&do=renameAdmin" ),
);
}
/* ACP Password Protection */
if ( ! is_file( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . '/.htaccess' ) AND !\IPS\NO_WRITES AND !\IPS\CIC )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('admin_pass_title'),
'description' => \IPS\Member::loggedIn()->language()->addToStack('admin_pass_desc'),
'risk' => "low",
'button' => array( 'title' => \IPS\Member::loggedIn()->language()->addToStack('security_run_tool'), 'action' => "app=core&module=overview&controller=security&do=acpHtaccess" ),
);
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('security_center');
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/security.css', 'core', 'admin' ) );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'overview' )->security( $content );
}
/**
* Security Settings
*
* @return void
*/
protected function settings()
{
$form = new \IPS\Helpers\Form;
/* IP Addresses */
$form->addHeader( 'security_header_ips' );
if ( !\IPS\CIC )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'xforward_matching', \IPS\Settings::i()->xforward_matching, FALSE ) );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'match_ipaddress', \IPS\Settings::i()->match_ipaddress, FALSE ) );
if( \IPS\BYPASS_ACP_IP_CHECK === TRUE )
{
\IPS\Member::loggedIn()->language()->words['match_ipaddress_warning'] = \IPS\Member::loggedIn()->language()->addToStack('ip_override_warn');
}
/* Account Security */
$form->addHeader( 'security_header_accounts' );
$form->add( new \IPS\Helpers\Form\YesNo( 'device_management', \IPS\Settings::i()->device_management, FALSE ) );
/* Password Strength */
$form->addHeader( 'security_header_passwords' );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter', \IPS\Settings::i()->password_strength_meter, FALSE, array( 'togglesOn' => array( 'password_strength_meter_enforce' ) ), NULL, NULL, NULL, 'password_strength_meter' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter_enforce', \IPS\Settings::i()->password_strength_meter_enforce, FALSE, array( 'togglesOn' => array( 'password_strength_option' ) ), NULL, NULL, NULL, 'password_strength_meter_enforce' ) );
$strengthOptions = array(
'3' => 'strength_3',
'4' => 'strength_4',
'5' => 'strength_5',
);
$form->add( new \IPS\Helpers\Form\Radio( 'password_strength_option', \IPS\Settings::i()->password_strength_option, FALSE, array( 'options' => $strengthOptions ), NULL, NULL, NULL, 'password_strength_option' ) );
/* ACP Link */
$form->addHeader( 'security_header_admincp' );
$form->add( new \IPS\Helpers\Form\YesNo( 'security_remove_acp_link', !\IPS\Settings::i()->security_remove_acp_link, FALSE ) );
/* Handle Submissions */
if ( $values = $form->values() )
{
$values['security_remove_acp_link'] = $values['security_remove_acp_link'] ? FALSE : TRUE;
/* Disabling the password strength meter should also disable enforcing a strength */
$values['password_strength_meter_enforce'] = $values['password_strength_meter'] ? $values['password_strength_meter_enforce'] : FALSE;
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__security_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=security" ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('security_settings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'storage_settings', $form );
}
/**
* Change conf global permissions
*
* @return void
*/
protected function conf()
{
/* INIT */
$done = FALSE;
/* Try... */
if ( \IPS\NO_WRITES or !@chmod( \IPS\ROOT_PATH . '/conf_global.php', 0444 ) )
{
\IPS\Output::i()->error( 'conf_not_altered', '2C258/2', 500, '' );
}
/* All Done */
\IPS\Session::i()->log( 'acplogs__security_conf' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=security" ), 'conf_altered' );
}
/**
* Add htaccess files to writeable directory
*
* @return void
*/
protected function htaccess()
{
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C258/7', 403, '' );
}
/* INIT */
$errors = array();
$deny = <<<EOF
#<ipb-protection>
<Files ~ "^.*\.(php|cgi|pl|php3|php4|php5|php6|phtml|shtml|([a-z0-9]{32}))$">
Order allow,deny
Deny from all
</Files>
#</ipb-protection>
EOF;
foreach( \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', 'FileSystem' ) ) as $uploads )
{
$uploads = json_decode( $uploads['configuration'], TRUE );
if( isset( $uploads['dir'] ) )
{
$uploads['dir'] = str_replace( '{root}', \IPS\ROOT_PATH, $uploads['dir'] );
if( !is_file( $uploads['dir'] . '/.htaccess' ) )
{
if ( !@\file_put_contents( $uploads['dir'] . '/.htaccess', $deny ) )
{
$errors[] = $uploads['dir'];
}
}
}
}
if ( isset( $uploadSettings['FileSystem']['dir'] ) )
{
$directory = $uploadSettings['FileSystem']['dir'];
if ( !@\file_put_contents( $directory . '/.htaccess', $deny ) )
{
$errors[] = $directory;
}
}
$storeSettings = json_decode( \IPS\STORE_CONFIG, TRUE );
if ( \IPS\STORE_METHOD == 'FileSystem' )
{
$directory = str_replace( '{root}', \IPS\ROOT_PATH, $storeSettings['path'] );
if ( !@\file_put_contents( $directory . '/.htaccess', $deny ) )
{
$errors[] = $directory;
}
}
if( count( $errors ) )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'htaccess_not_written', FALSE, array( 'sprintf' => \IPS\Member::loggedIn()->language()->formatList( $errors ) ) ), '2C258/1', 403, '', array(), $deny );
}
/* All Done */
\IPS\Session::i()->log( 'acplogs__security_htaccess_writeable' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=security" ), 'htaccess_written' );
}
/**
* Rename ACP directory
*
* @return void
*/
protected function renameAdmin()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('rename_admin_title');
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Output::i()->title );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'overview' )->securityRenameAdmin();
}
/**
* ACP Htaccess Protection
*
* @return void
*/
protected function acpHtaccess()
{
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C258/6', 403, '' );
}
if ( !is_writable( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY ) )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'err_not_writable', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY ) ) ), '1C258/5', 403, '' );
}
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'htaccess_username', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Password( 'htaccess_password', NULL, TRUE ) );
if ( $values = $form->values() )
{
$done = FALSE;
/* See this for an explanation why ErrorDocument is needed: http://www.myriadinteractive.com/blog/view/id/29/conflict-between-apache-url-rewriting-and-basic-authentication */
$htaccess_auth = "ErrorDocument 401 \"Unauthorized Access\"\n"
. "AuthType Basic\n"
. "AuthName \"Invision Community AdminCP\"\n"
. 'AuthUserFile "' . \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . "/.htpasswd\"\n"
. "Require valid-user\n";
$htaccess_pw = $values['htaccess_username'] . ":" .
( ( mb_strtoupper( mb_substr( PHP_OS, 0, 3 ) ) === 'WIN' ) ? $values['htaccess_password'] : crypt( $values['htaccess_password'], base64_encode( $values['htaccess_password'] ) ) );
if ( $FH = @\fopen( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . '/.htpasswd', 'w' ) )
{
\fwrite( $FH, $htaccess_pw );
\fclose( $FH );
$FF = @\fopen( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . '/.htaccess', 'w' );
\fwrite( $FF, $htaccess_auth );
\fclose( $FF );
$done = TRUE;
\IPS\Session::i()->log( 'acplogs__security_acp_password' );
\IPS\IPS::resyncIPSCloud('Added htaccess protection to ACP');
}
/* All Done */
if ( $done )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=security" ), 'admin_pass_written' );
}
else
{
\IPS\Output::i()->error( 'admin_pass_not_written', '1C258/3', 403, '' );
}
}
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'admin_pass_warning', 'warning' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('admin_pass_title');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( \IPS\Output::i()->title, $form );
}
}
@@ -190,6 +190,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Select( 'ads_circulation', \IPS\Settings::i()->ads_circulation, TRUE, array( 'options' => array( 'random' => 'ad_circ_random', 'newest' => 'ad_circ_newest', 'oldest' => 'ad_circ_oldest', 'least' => 'ad_circ_leasti' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ads_force_sidebar', \IPS\Settings::i()->ads_force_sidebar, TRUE ) );
if ( $values = $form->values() )
{
@@ -268,8 +269,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
$adsExist = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_advertisements', 'ad_active=1' )->first();
if ( $adsExist != \IPS\Settings::i()->ads_exist )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $adsExist ), array( 'conf_key=?', 'ads_exist' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ads_exist' => $adsExist ) );
}
/* Clear guest page caches */
@@ -537,8 +537,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
$adsExist = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_advertisements', 'ad_active=1' )->first();
if ( $adsExist != \IPS\Settings::i()->ads_exist )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $adsExist ), array( 'conf_key=?', 'ads_exist' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ads_exist' => $adsExist ) );
}
/* Clear guest page caches */
@@ -50,7 +50,7 @@ class _promote extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Work out output */
$activeTabContents = call_user_func( array( $this, '_manage' . ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
/* If this is an AJAX request, just return it */
if( \IPS\Request::i()->isAjax() )
@@ -232,11 +232,11 @@ class _promote extends \IPS\Dispatcher\Controller
*/
protected function _manageTwitter()
{
$twitter = \IPS\Login::getHandler('Twitter');
$twitter = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth1\Twitter');
$account = \IPS\core\Promote::getPromoter('Twitter')->setMember( \IPS\Member::loggedIn() );
/* Have we set up Facebook yet? */
if ( ! $twitter->settings['consumer_key'] )
/* Have we set up Twitter yet? */
if ( !$twitter OR !$twitter->settings['consumer_key'] )
{
/* Nope, so lets do that first... */
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoTwitterApp();
@@ -249,11 +249,28 @@ class _promote extends \IPS\Dispatcher\Controller
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoTwitterUser();
}
/* Do we have post to page permissions? */
$response = $account->canPostToPage();
if ( $response !== TRUE )
{
/* Token stores permissions, so wipe it */
$account->enabled = FALSE;
$account->saveSettings( array(
'token' => NULL,
'secret' => NULL,
'owner' => NULL,
'name' => NULL
) );
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoTwitterPostToPagePermission( $response );
}
$form = new \IPS\Helpers\Form;
if ( isset( \IPS\Request::i()->clear ) and \IPS\Request::i()->clear === 'true' )
{
/* We want to clear settings */
$account->enabled = FALSE;
$account->saveSettings( array(
'token' => NULL,
'secret' => NULL,
@@ -276,6 +293,7 @@ class _promote extends \IPS\Dispatcher\Controller
catch( \OutOfRangeException $e )
{
/* Member no longer exists, so clear settings */
$account->enabled = FALSE;
$account->saveSettings( array(
'token' => NULL,
'secret' => NULL,
@@ -328,21 +346,21 @@ class _promote extends \IPS\Dispatcher\Controller
*/
protected function _manageFacebook()
{
$facebook = \IPS\Login::getHandler('Facebook');
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
$account = \IPS\core\Promote::getPromoter('Facebook')->setMember( \IPS\Member::loggedIn() );
/* Have we set up Facebook yet? */
if ( ! $facebook->settings['app_id'] )
if ( !$facebook OR ! $facebook->settings['client_id'] )
{
/* Nope, so lets do that first... */
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookApp();
}
/* Have we synchronized our user account with Facebook? */
if ( ! $account->connected() )
if ( ! $facebook->canProcess( \IPS\Member::loggedIn() ) )
{
/* Nope, so lets do that now... */
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookUser();
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookUser( $facebook );
}
/* Do we have post to page permissions? */
@@ -350,7 +368,7 @@ class _promote extends \IPS\Dispatcher\Controller
if ( $response !== TRUE )
{
/* Nope, so lets do that now... */
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookPostToPagePermission( $response );
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookPostToPagePermission( $response, $facebook );
}
$form = new \IPS\Helpers\Form;
@@ -358,30 +376,58 @@ class _promote extends \IPS\Dispatcher\Controller
if ( isset( \IPS\Request::i()->clear ) and \IPS\Request::i()->clear === 'true' )
{
/* We want to clear settings */
$account->enabled = FALSE;
$account->saveSettings( array(
'token' => NULL,
'owner' => NULL,
'page_name' => NULL,
'enabled' => NULL,
'page' => NULL
'page' => NULL,
'group' => NULL
) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=promotion&controller=promote&tab=facebook" ) );
}
/* We're all set, so show the form! */
$pages = $account->getPages();
$pages = $facebook->getPages( \IPS\Member::loggedIn() );
$options = array();
$shareable = array();
foreach( $pages as $id => $data )
{
$options[ $id ] = $data[0];
$options[ 'p_' . $id ] = \IPS\Member::loggedIn()->language()->addToStack( 'promote_facebook_page_prefix', NULL, array( 'sprintf' => array( $data[0] ) ) );
}
$groups = $facebook->getGroups( \IPS\Member::loggedIn() );
foreach( $groups as $id => $data )
{
$options[ 'g_' . $id ] = \IPS\Member::loggedIn()->language()->addToStack( 'promote_facebook_group_prefix', NULL, array( 'sprintf' => array( $data[0] ) ) );
}
$output = '';
$owner = \IPS\Member::load( $account->settings['owner'] );
if ( isset( $account->settings['shareable'] ) )
{
if( isset( $account->settings['shareable']['pages'] ) )
{
foreach( $account->settings['shareable']['pages'] as $id => $data )
{
$shareable[] = 'p_' . $id;
}
}
if( isset( $account->settings['shareable']['groups'] ) )
{
foreach( $account->settings['shareable']['groups'] as $id => $data )
{
$shareable[] = 'g_' . $id;
}
}
}
if ( $account->settings['owner'] and $account->settings['page_name'] )
if ( $account->settings['owner'] )
{
try
{
@@ -390,6 +436,7 @@ class _promote extends \IPS\Dispatcher\Controller
catch( \OutOfRangeException $e )
{
/* Member no longer exists, so clear settings */
$account->enabled = FALSE;
$account->saveSettings( array(
'token' => NULL,
'owner' => NULL,
@@ -400,11 +447,11 @@ class _promote extends \IPS\Dispatcher\Controller
}
}
$form->add( new \IPS\Helpers\Form\YesNo( 'promote_facebook_enabled', $account->enabled, FALSE, array( 'togglesOn' => array( 'promote_facebook_page', 'promote_facebook_groups', 'promote_facebook_members', 'promote_facebook_tags' ) ), NULL, NULL, NULL, 'promote_facebook_enabled' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'promote_facebook_enabled', $account->enabled, FALSE, array( 'togglesOn' => array( 'promote_facebook_shareable', 'promote_facebook_members', 'promote_facebook_tags' ) ), NULL, NULL, NULL, 'promote_facebook_enabled' ) );
if ( ! $account->settings['owner'] or ( \IPS\Member::loggedIn()->member_id == $account->settings['owner'] ) )
{
$form->add( new \IPS\Helpers\Form\Select( 'promote_facebook_page', $account->settings['page'], FALSE, array( 'options' => $options ), NULL, NULL, NULL, 'promote_facebook_page' ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'promote_facebook_shareable', $shareable, FALSE, array( 'options' => $options ), NULL, NULL, NULL, 'promote_facebook_shareable' ) );
}
$form->add( new \IPS\Helpers\Form\Stack( 'promote_facebook_tags', $account->settings['tags'], FALSE, array( 'stackFieldType' => 'Text' ), NULL, NULL, NULL, 'promote_facebook_tags' ) );
@@ -423,13 +470,40 @@ class _promote extends \IPS\Dispatcher\Controller
$account->enabled = $values['promote_facebook_enabled'];
/* If we have page data, then we are the page owner and can have extra special things */
if ( $values['promote_facebook_page'] )
if ( isset( $values['promote_facebook_shareable'] ) )
{
/* Get a non-expiring page token */
$save['token'] = $facebook->exchangeToken( $pages[ $values['promote_facebook_page'] ][1] );
$shareable = array( 'pages' => array(), 'groups' => array() );
foreach( $values['promote_facebook_shareable'] as $id )
{
$realId = mb_substr( $id, 2 );
/* Page or group? */
if ( mb_substr( $id, 0, 2 ) == 'p_' )
{
$shareable['pages'][ $realId ] = array(
'token' => $facebook->exchangeToken( $pages[ $realId ][1] ),
'name' => $pages[ $realId ][0]
);
}
else
{
$shareable['groups'][ $realId ] = array(
'name' => $groups[ $realId ][0]
);
}
}
$save['shareable'] = $shareable;
$save['owner'] = \IPS\Member::loggedIn()->member_id;
$save['page_name'] = $pages[ $values['promote_facebook_page'] ][0];
$save['page'] = $values['promote_facebook_page'];
try
{
$save['token'] = \IPS\Db::i()->select( 'token_access_token', 'core_login_links', array( 'token_login_method=? and token_member=?', $facebook->id, \IPS\Member::loggedIn()->member_id ) )->first();
}
catch( \UnderflowException $e )
{
$save['token'] = NULL;
}
$save['tags'] = $values['promote_facebook_tags'];
}
@@ -39,6 +39,12 @@ class _seo extends \IPS\Dispatcher\Controller
/* Get tab content */
$this->activeTab = \IPS\Request::i()->tab ?: 'urls';
\IPS\Output::i()->sidebar['actions']['rebuildsitemap'] = array(
'link' => \IPS\Http\Url::internal( 'app=core&module=promotion&controller=seo&do=rebuildSitemap' ),
'title' => 'rebuild_sitemap',
'icon' => 'history'
);
parent::execute();
}
@@ -50,7 +56,7 @@ class _seo extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Work out output */
$activeTabContents = call_user_func( array( $this, '_manage' . ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
/* If this is an AJAX request, just return it */
if( \IPS\Request::i()->isAjax() )
@@ -142,6 +148,7 @@ class _seo extends \IPS\Dispatcher\Controller
{
/* Init */
$form = new \IPS\Helpers\Form;
$form->addMessage( 'sitemap_blurb', 'ipsMessage ipsMessage_info' );
$form->add( new \IPS\Helpers\Form\Url( 'sitemap_url', \IPS\Settings::i()->sitemap_url ?: \IPS\Settings::i()->base_url . 'sitemap.php', FALSE ) );
/* Get extension settings */
@@ -206,6 +213,7 @@ class _seo extends \IPS\Dispatcher\Controller
if( !$form->error )
{
$values['sitemap_url'] = (string) $values['sitemap_url'];
$form->saveAsSettings( $values );
foreach( \IPS\Application::allExtensions( 'core', 'Sitemap', FALSE, 'core' ) as $extKey => $extension )
@@ -223,7 +231,7 @@ class _seo extends \IPS\Dispatcher\Controller
}
}
return \IPS\Theme::i()->getTemplate( 'forms' )->blurb( 'sitemap_blurb' ) . $form;
return $form;
}
/**
@@ -390,7 +398,7 @@ class _seo extends \IPS\Dispatcher\Controller
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->class = 'ipsForm_vertical ipsPad';
$form->add( new \IPS\Helpers\Form\Text( 'metatag_url', $url, FALSE, array( 'placeholder' => 'profile/*' ), NULL, \IPS\Settings::i()->base_url ) );
$form->hiddenValues['original_url'] = $url;
@@ -502,4 +510,21 @@ FILE;
\IPS\Output::i()->sendOutput( $htaccess, 200, 'application/x-htaccess', array( 'Content-Disposition' => 'attachment; filename=.htaccess' ) );
}
/**
* Trigger the sitemap rebuild
*/
protected function rebuildSitemap()
{
/* truncate sitemap */
\IPS\Db::i()->delete( 'core_sitemap' );
$extensions = \IPS\Application::allExtensions( 'core', 'Sitemap', new \IPS\Member, 'core' );
foreach ( $extensions as $k => $extension )
{
\IPS\Task::queue( 'core', 'RebuildSitemap', array( 'extensionKey' => $k ), 5 );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=promotion&controller=seo" ), 'rebuild_sitemap_initialized' );
}
}
@@ -45,11 +45,11 @@ class _advanced extends \IPS\Dispatcher\Controller
\IPS\Request::i()->tab = isset( \IPS\Request::i()->tab ) ? \IPS\Request::i()->tab : 'settings';
if ( $pos = mb_strpos( \IPS\Request::i()->tab, '-' ) )
{
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( mb_substr( \IPS\Request::i()->tab, 0, $pos ) ) ), mb_substr( \IPS\Request::i()->tab, $pos + 1 ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( mb_substr( \IPS\Request::i()->tab, 0, $pos ) ) ), mb_substr( \IPS\Request::i()->tab, $pos + 1 ) );
}
else
{
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( \IPS\Request::i()->tab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( \IPS\Request::i()->tab ) ) );
}
/* If this is an AJAX request, just return it */
@@ -99,10 +99,7 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Clear it */
\IPS\Data\Cache::i()->clearAll();
\IPS\Data\Store::i()->clearAll();
/* Enable/disable the clearcaches task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => intval( \IPS\CACHE_METHOD === 'None' and \IPS\CACHE_PAGE_TIMEOUT ) ), "`key`='clearcache'" );
/* Log and redirect */
\IPS\Session::i()->log( 'acplogs__datastore_settings_updated' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&tab=datastore' ), 'saved' );
@@ -149,7 +146,7 @@ class _advanced extends \IPS\Dispatcher\Controller
{
if ( !$input->htmlId )
{
$input->htmlId = md5( uniqid() );
$input->htmlId = md5( mt_rand() );
}
$extra[] = $input;
@@ -170,7 +167,7 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Cache */
$extra = array();
$toggles = array();
$toggles = array( 'Redis' => array( 'redis_enabled' ) );
$disabled = array();
$cacheConfigurationFields = array();
$options = array(
@@ -200,7 +197,7 @@ class _advanced extends \IPS\Dispatcher\Controller
{
if ( !$input->htmlId )
{
$input->htmlId = md5( uniqid() );
$input->htmlId = md5( mt_rand() );
}
$extra[] = $input;
@@ -218,6 +215,9 @@ class _advanced extends \IPS\Dispatcher\Controller
{
$form->add( $input );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'redis_enabled', \IPS\REDIS_ENABLED, FALSE, array(), NULL, NULL, NULL, 'redis_enabled' ) );
$form->add( new \IPS\Helpers\Form\Number( 'cache_guest_page', \IPS\CACHE_PAGE_TIMEOUT, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'disable' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('for'), \IPS\Member::loggedIn()->language()->addToStack('seconds'), 'cache_guest_page' ) );
/* Handle submissions */
@@ -242,7 +242,7 @@ class _advanced extends \IPS\Dispatcher\Controller
}
/* If we've changed anything, explain to the admin they have to update */
if ( $values['datastore_method'] !== \IPS\STORE_METHOD or str_replace( '\\/', '/', json_encode( $storeConfiguration ) ) !== \IPS\STORE_CONFIG or $values['cache_method'] !== \IPS\CACHE_METHOD or json_encode( $cacheConfiguration ) !== \IPS\CACHE_CONFIG or $values['cache_guest_page'] !== \IPS\CACHE_PAGE_TIMEOUT )
if ( $values['datastore_method'] !== \IPS\STORE_METHOD or str_replace( '\\/', '/', json_encode( $storeConfiguration ) ) !== \IPS\STORE_CONFIG or $values['cache_method'] !== \IPS\CACHE_METHOD or json_encode( $cacheConfiguration ) !== \IPS\CACHE_CONFIG or $values['cache_guest_page'] !== \IPS\CACHE_PAGE_TIMEOUT or \IPS\REDIS_ENABLED != (boolean) $values['redis_enabled'] )
{
/* Connect to cache engine if we can and invalidate any existing caches */
try
@@ -256,17 +256,22 @@ class _advanced extends \IPS\Dispatcher\Controller
}
}
catch( \Exception $e ){}
/* Enable/disable the clearcaches task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => intval( $values['cache_method'] === 'None' and $values['cache_guest_page'] ) ), "`key`='clearcache'" );
/* Invalidate any existing datastore records */
try
{
$classname = 'IPS\Data\Store\\' . $values['datastore_method'];
$instance = new $classname( $storeConfiguration );
$instance->clearAll();
}
catch( \Exception $e ){}
/* Reset the last update flag for data store */
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => time() ), array( 'conf_key=?', 'last_data_store_update' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'last_data_store_update' => time() ) );
/* Display */
$downloadUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=downloadDatastoreConstants' )->setQueryString( array( 'store_method' => $values['datastore_method'], 'store_config' => str_replace( '\\/', '/', json_encode( $storeConfiguration ) ), 'cache_method' => $values['cache_method'], 'cache_config' => json_encode( $cacheConfiguration ), 'cache_guest_page' => $values['cache_guest_page'] ) );
$checkUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&tab=datastore&checkConstants=1' )->setQueryString( array( 'store_method' => $values['datastore_method'], 'store_config' => str_replace( '\\/', '/', json_encode( $storeConfiguration ) ), 'cache_method' => $values['cache_method'], 'cache_config' => json_encode( $cacheConfiguration ), 'cache_guest_page' => $values['cache_guest_page'] ) );
$downloadUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=downloadDatastoreConstants' )->setQueryString( array( 'store_method' => $values['datastore_method'], 'store_config' => str_replace( '\\/', '/', json_encode( $storeConfiguration ) ), 'cache_method' => $values['cache_method'], 'cache_config' => json_encode( $cacheConfiguration ), 'cache_guest_page' => $values['cache_guest_page'], 'redis_enabled' => $values['redis_enabled'] ) );
$checkUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&tab=datastore&checkConstants=1' )->setQueryString( array( 'store_method' => $values['datastore_method'], 'store_config' => str_replace( '\\/', '/', json_encode( $storeConfiguration ) ), 'cache_method' => $values['cache_method'], 'cache_config' => json_encode( $cacheConfiguration ), 'cache_guest_page' => $values['cache_guest_page'], 'redis_enabled' => $values['redis_enabled'] ) );
return \IPS\Theme::i()->getTemplate( 'settings' )->dataStoreChange( $downloadUrl, $checkUrl );
}
/* Otherwise just log and redirect */
@@ -293,19 +298,38 @@ class _advanced extends \IPS\Dispatcher\Controller
foreach ( \IPS\IPS::defaultConstants() as $k => $v )
{
$val = constant( 'IPS\\' . $k );
if ( $val !== $v and !in_array( $k, array( 'STORE_METHOD', 'STORE_CONFIG', 'CACHE_METHOD', 'CACHE_CONFIG', 'CACHE_PAGE_TIMEOUT', 'SUITE_UNIQUE_KEY' ) ) )
if ( $val !== $v and !in_array( $k, array( 'STORE_METHOD', 'STORE_CONFIG', 'CACHE_METHOD', 'CACHE_CONFIG', 'CACHE_PAGE_TIMEOUT', 'SUITE_UNIQUE_KEY', 'READ_WRITE_SEPARATION', 'REDIS_ENABLED' ) ) )
{
$output .= "define( '{$k}', " . var_export( $val, TRUE ) . " );\n";
}
}
/* We have to treat READ_WRITE_SEPARATION special because admin/index.php always disables it */
if( \file_exists( \IPS\ROOT_PATH . '/constants.php' ) )
{
$constants = \file_get_contents( \IPS\ROOT_PATH . '/constants.php' );
/* Did we sniff the constant out with a quick check? */
if( mb_strpos( $constants, 'READ_WRITE_SEPARATION' ) )
{
preg_match( "/define\(\s*?['\"]READ_WRITE_SEPARATION[\"']\s*?,\s*?(.+?)\);/i", $constants, $matches );
if( isset( $matches[1] ) )
{
$output .= "define( 'READ_WRITE_SEPARATION', " . $matches[1] . " );\n";
}
}
}
$output .= "\n";
$output .= "define( 'REDIS_ENABLED', " . var_export( (boolean) \IPS\Request::i()->redis_enabled, TRUE ) . " );\n";
$output .= "define( 'STORE_METHOD', " . var_export( \IPS\Request::i()->store_method, TRUE ) . " );\n";
$output .= "define( 'STORE_CONFIG', " . var_export( \IPS\Request::i()->store_config, TRUE ) . " );\n";
$output .= "define( 'CACHE_METHOD', " . var_export( \IPS\Request::i()->cache_method, TRUE ) . " );\n";
$output .= "define( 'CACHE_CONFIG', " . var_export( \IPS\Request::i()->cache_config, TRUE ) . " );\n";
$output .= "define( 'CACHE_PAGE_TIMEOUT', " . var_export( (int) \IPS\Request::i()->cache_guest_page, TRUE ) . " );\n";
$output .= "define( 'SUITE_UNIQUE_KEY', " . var_export( mb_substr( md5( uniqid() ), 10, 10 ), TRUE ) . " );\n"; // Regenerate the unique key so there's no conflicts
$output .= "define( 'SUITE_UNIQUE_KEY', " . var_export( mb_substr( md5( mt_rand() ), 10, 10 ), TRUE ) . " );\n"; // Regenerate the unique key so there's no conflicts
$output .= "\n\n\n";
\IPS\Output::i()->sendOutput( $output, 200, 'text/x-php', array( 'Content-Disposition' => 'attachment; filename=constants.php' ) );
@@ -323,9 +347,7 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Generate a cron key if we don't have one */
if ( !\IPS\Settings::i()->task_cron_key )
{
\IPS\Settings::i()->task_cron_key = md5( uniqid() );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Settings::i()->task_cron_key ), array( 'conf_key=?', 'task_cron_key' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'task_cron_key' => md5( mt_rand() ) ) );
}
/* Sort stuff out for the cron setting */
@@ -372,6 +394,7 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Build and show form */
$form = new \IPS\Helpers\Form;
$form->addHeader('task_manager');
$form->add( new \IPS\Helpers\Form\Radio( 'task_use_cron', \IPS\CIC ? 'ips' : \IPS\Settings::i()->task_use_cron, FALSE, $options, function ( $val )
{
$cronFile = \IPS\ROOT_PATH . '/applications/core/interface/task/task.php';
@@ -380,6 +403,17 @@ class _advanced extends \IPS\Dispatcher\Controller
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('task_use_cron_executable', FALSE, array( 'sprintf' => array( $cronFile ) ) ) );
}
}, NULL, NULL, 'task_use_cron' ) );
$form->addHeader( 'security_header_ips' );
if ( !\IPS\CIC )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'xforward_matching', \IPS\Settings::i()->xforward_matching, FALSE ) );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'match_ipaddress', \IPS\Settings::i()->match_ipaddress, FALSE ) );
if( \IPS\BYPASS_ACP_IP_CHECK === TRUE )
{
\IPS\Member::loggedIn()->language()->words['match_ipaddress_warning'] = \IPS\Member::loggedIn()->language()->addToStack('ip_override_warn');
}
$form->addHeader('performance_settings');
$form->add( new \IPS\Helpers\Form\Number( 'widget_cache_ttl', ( isset( \IPS\Settings::i()->widget_cache_ttl ) ) ? \IPS\Settings::i()->widget_cache_ttl : 60, FALSE, array( 'min' => 60 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('for'), \IPS\Member::loggedIn()->language()->addToStack('seconds') ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'auto_polling_enabled', \IPS\Settings::i()->auto_polling_enabled, FALSE ) );
@@ -417,11 +451,18 @@ class _advanced extends \IPS\Dispatcher\Controller
{
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_tasks' );
$table = new \IPS\Helpers\Table\Db( 'core_tasks', \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=tasks' ) );
$table = new \IPS\Helpers\Table\Db( 'core_tasks', \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=tasks' ), array( array( 'a.app_enabled=1' ) ) );
$table->joins = array(
array( 'select' => 'a.app_enabled', 'from' => array( 'core_applications', 'a' ), 'where' => "a.app_directory=app" )
);
$table->langPrefix = 'task_manager_';
$table->include = array( 'app', 'key', 'frequency', 'next_run', 'last_run' );
$table->mainColumn = 'key';
$table->quickSearch = 'key';
$table->primarySortBy = 'enabled';
$table->primarySortDirection = 'DESC';
$table->sortBy = $table->sortBy ?: 'next_run';
$table->sortDirection = $table->sortDirection ?: 'asc';
$table->quickSearch = function( $val )
@@ -429,11 +470,11 @@ class _advanced extends \IPS\Dispatcher\Controller
$matches = \IPS\Member::loggedIn()->language()->searchCustom( 'task__', $val, TRUE );
if ( count( $matches ) )
{
return '(' . \IPS\Db::i()->in( '`key`', array_keys( $matches ) ) . " OR `key` LIKE '%{$val}%')";
return array( '(' . \IPS\Db::i()->in( '`key`', array_keys( $matches ) ) . " OR `key` LIKE '%{$val}%')" );
}
else
{
return "`key` LIKE '%{$val}%'";
return array( "`key` LIKE '%" . \IPS\Db::i()->escape_string( $val ) . "%'" );
}
};
@@ -603,6 +644,10 @@ class _advanced extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'advancedsettings' )->taskResult( TRUE, $output, $task->id );
}
}
catch( \RuntimeException $e )
{
\IPS\Output::i()->error( 'task_class_not_found', '4C124/6', 404, '' );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C124/1', 404, '' );
@@ -803,7 +848,14 @@ class _advanced extends \IPS\Dispatcher\Controller
}
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'furl_friendly', $current ? $current['friendly'] : '', FALSE, array(), NULL, \IPS\Settings::i()->base_url . ( \IPS\Settings::i()->htaccess_mod_rewrite ? '' : 'index.php?/' ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'furl_friendly', $current ? $current['friendly'] : '', FALSE, array( 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('furl_friendly_placeholder') ), function( $val )
{
if( mb_substr( $val, 0, 3 ) == '{?}' )
{
throw new \DomainException( 'furl_too_greedy' );
}
},
\IPS\Settings::i()->base_url . ( \IPS\Settings::i()->htaccess_mod_rewrite ? '' : 'index.php?/' ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'furl_real', $current ? $current['real'] : '', FALSE, array(), NULL, \IPS\Settings::i()->base_url . 'index.php?' ) );
if ( $values = $form->values() )
@@ -853,15 +905,17 @@ class _advanced extends \IPS\Dispatcher\Controller
}
else
{
$key = 'key' . ( count( $furl ) + 1 );
ksort( $furl );
$keys = array_keys( $furl );
$lastKey = str_replace( 'key', '', end( $keys ) );
$key = 'key' . ( $lastKey + 1 );
$furl[ $key ] = $save;
}
\IPS\Session::i()->log( 'acplogs__advanced_furl_edited' );
$newValue = json_encode( $furl );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $newValue ), array( 'conf_key=?', 'furl_configuration' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'furl_configuration' => $newValue ) );
/* Clear Sidebar Caches */
\IPS\Widget::deleteCaches();
@@ -895,8 +949,7 @@ class _advanced extends \IPS\Dispatcher\Controller
{
unset( $furlDefinition[ \IPS\Request::i()->key ] );
$newValue = json_encode( $furlDefinition );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $newValue ), array( 'conf_key=?', 'furl_configuration' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'furl_configuration' => $newValue ) );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -916,8 +969,7 @@ class _advanced extends \IPS\Dispatcher\Controller
{
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_furls' );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => NULL ), array( 'conf_key=?', 'furl_configuration' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'furl_configuration' => NULL ) );
unset( \IPS\Data\Store::i()->furl_configuration );
/* Clear guest page caches */
@@ -42,9 +42,17 @@ class _contactus extends \IPS\Dispatcher\Controller
{
$form = $this->_getConfigForm();
if ( $values = $form->values() )
if ( $values = $form->values( true ) )
{
$form->saveAsSettings();
/* If we unselect 'everyone' and save, an empty string is passed through, so the default value is picked up in Settings::changeValues(),
which is the 'everyone' preference...the end result is that everyone gets rechecked when you uncheck it. To counter that, we'll store an invalid
value here. */
if( $values['contact_access'] === '' )
{
$values['contact_access'] = '-1';
}
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -49,22 +49,18 @@ class _email extends \IPS\Dispatcher\Controller
$settingsForm->add( new \IPS\Helpers\Form\Email( 'email_in', \IPS\Settings::i()->email_in, TRUE ) );
$settingsForm->add( new \IPS\Helpers\Form\Color( 'email_color', \IPS\Settings::i()->email_color, TRUE ) );
$settingsForm->add( new \IPS\Helpers\Form\Upload( 'email_logo', \IPS\Settings::i()->email_logo ? \IPS\File::get( 'core_Theme', \IPS\Settings::i()->email_logo ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Theme' ) ) );
$settingsForm->add( new \IPS\Helpers\Form\YesNo( 'social_links_in_email', \IPS\Settings::i()->social_links_in_email, FALSE, array(), NULL, NULL, NULL, 'social_links_in_email' ) );
if ( \IPS\Settings::i()->promote_community_enabled )
{
$settingsForm->add( new \IPS\Helpers\Form\YesNo( 'our_picks_in_email', \IPS\Settings::i()->our_picks_in_email, FALSE, array(), NULL, NULL, NULL, 'our_picks_in_email' ) );
}
$settingsForm->addHeader( 'advanced_settings' );
$method = \IPS\Settings::i()->mail_method;
$disabled = array();
if ( \IPS\Settings::i()->sparkpost_api_key )
{
if ( \IPS\Settings::i()->sparkpost_use_for == 2 )
{
$method = 'sparkpost';
}
}
else
{
$disabled[] = 'sparkpost';
}
if ( \IPS\Settings::i()->sendgrid_api_key )
{
if ( \IPS\Settings::i()->sendgrid_use_for == 2 )
@@ -76,12 +72,18 @@ class _email extends \IPS\Dispatcher\Controller
{
$disabled[] = 'sendgrid';
}
/* We previously renamed this to 'php' */
if( $method == 'mail' )
{
$method = 'php';
}
$settingsForm->add( new \IPS\Helpers\Form\Radio( 'mail_method', $method, TRUE, array(
'options' => array( 'php' => ( \IPS\CIC ? 'mail_method_cic' : 'mail_method_php' ), 'smtp' => 'mail_method_smtp', 'sendgrid' => 'mail_method_sendgrid', 'sparkpost' => 'mail_method_sparkpost' ),
'options' => array( 'php' => ( \IPS\CIC ? 'mail_method_cic' : 'mail_method_php' ), 'smtp' => 'mail_method_smtp', 'sendgrid' => 'mail_method_sendgrid' ),
'disabled' => $disabled,
'toggles' => array(
'mail' => array( 'php_mail_extra' ),
'php' => array( 'php_mail_extra' ),
'smtp' => array( 'smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_helo', 'smtp_protocol' ),
)
) ) );
@@ -107,15 +109,6 @@ class _email extends \IPS\Dispatcher\Controller
}
}
if ( $values['mail_method'] != 'sparkpost' and \IPS\Settings::i()->sparkpost_use_for == 2 )
{
$values['sparkpost_use_for'] = 1;
}
elseif ( $values['mail_method'] == 'sparkpost' )
{
$values['sparkpost_use_for'] = 2;
}
if ( $values['mail_method'] != 'sendgrid' and \IPS\Settings::i()->sendgrid_use_for == 2 )
{
$values['sendgrid_use_for'] = 1;
@@ -125,6 +118,11 @@ class _email extends \IPS\Dispatcher\Controller
$values['sendgrid_use_for'] = 2;
}
if ( $values['email_logo'] )
{
$values['email_logo'] = (string) $values['email_logo'];
}
$settingsForm->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__email_settings' );
@@ -239,7 +237,7 @@ class _email extends \IPS\Dispatcher\Controller
$val = \IPS\Member::loggedIn()->language()->get('phpmail_not_sent');
}
return \IPS\Theme::i()->getTemplate( 'logs' )->emailErrorLog( nl2br( htmlspecialchars( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) ), $row );
return \IPS\Theme::i()->getTemplate( 'logs' )->emailErrorLog( nl2br( htmlspecialchars( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) ), $row );
},
'mlog_content' => function( $val, $row )
{
@@ -48,9 +48,13 @@ class _general extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\Editor( 'site_offline_message', \IPS\Settings::i()->site_offline_message, FALSE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'onlineoffline', 'attachIds' => array( NULL, NULL, 'site_offline_message' ) ), NULL, NULL, NULL, 'site_offline_message_id' ) );
$form->add( new \IPS\Helpers\Form\Address( 'site_address', \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->site_address ), FALSE ) );
$form->add( new \IPS\Helpers\Form\Stack( 'site_social_profiles', \IPS\Settings::i()->site_social_profiles ? json_decode( \IPS\Settings::i()->site_social_profiles, true ) : array(), FALSE, array( 'stackFieldType' => '\IPS\core\Form\SocialProfiles', 'maxItems' => 50, 'key' => array( 'placeholder' => 'http://example.com', 'size' => 20 ) ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'site_twitter_id', \IPS\Settings::i()->site_twitter_id, FALSE, array( 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('site_twitter_id_placeholder'), 'size' => 20 ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'copyright_line', NULL, FALSE, array( 'app' => 'core', 'key' => 'copyright_line_value', 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('copyright_line_placeholder') ) ) );
$form->add( new \IPS\Helpers\Form\Stack( 'upgrade_email', explode( ',', \IPS\Settings::i()->upgrade_email ), FALSE, array( 'stackFieldType' => 'Email', 'maxItems' => 5 ) ) );
// $form->add( new \IPS\Helpers\Form\YesNo( 'diagnostics_reporting', \IPS\Settings::i()->diagnostics_reporting ) );
/* $form->add( new \IPS\Helpers\Form\CheckboxSet( 'diagnostics_reporting', array( 'usage' => ( (bool) \IPS\Settings::i()->usage_reporting ), 'diagnostics' => ( (bool) \IPS\Settings::i()->diagnostics_reporting ) ), FALSE, array( 'options' => array(
'usage' => 'diagnostics_reporting_usage',
'diagnostics' => 'diagnostics_reporting_diagnostics',
) ) ) ); */
if ( $values = $form->values() )
{
@@ -61,6 +65,12 @@ class _general extends \IPS\Dispatcher\Controller
return (bool) $value['key'];
} ) );
$values['site_address'] = json_encode( $values['site_address'] );
$values['upgrade_email'] = implode( ',', $values['upgrade_email'] );
$values['usage_reporting'] = in_array( 'usage', $values['diagnostics_reporting'] );
$values['diagnostics_reporting'] = in_array( 'diagnostics', $values['diagnostics_reporting'] );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => intval( $values['usage_reporting'] ) ), array( '`key`=?', 'usagereporting' ) );
$form->saveAsSettings( $values );
+410 -190
View File
@@ -1,11 +1,11 @@
<?php
/**
* @brief Login Handlers
* @brief Login Methods
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 15 Mar 2013
* @since 12 May 2017
*/
namespace IPS\core\modules\admin\settings;
@@ -18,14 +18,19 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* Login Handlers
* Login Methods
*/
class _login extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = 'IPS\Login\LoginAbstract';
protected $nodeClass = 'IPS\Login\Handler';
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
/**
* Execute
@@ -34,54 +39,170 @@ class _login extends \IPS\Node\Controller
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_manage' );
\IPS\Dispatcher::i()->checkAcpPermission( 'login_access' );
return parent::execute();
}
/**
* Get Root Buttons
*
* @return array
*/
public function _getRootButtons()
{
$buttons = parent::_getRootButtons();
if ( isset( $buttons['add'] ) )
{
$buttons['add']['link'] = $buttons['add']['link']->setQueryString( '_new', 1 );
}
return $buttons;
}
/**
* Manage
*
* @return void
* @return void
*/
protected function manage()
{
\IPS\Output::i()->sidebar['actions'] = array(
'settings' => array(
'title' => 'login_settings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&do=settings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('login_settings') )
),
'forcelogout' => array(
'title' => 'force_all_logout',
'icon' => 'lock',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&do=forceLogout' ),
'data' => array( 'confirm' => '' ),
),
);
/* Work out tabs */
$tabs = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_manage' ) )
{
$tabs['handlers'] = 'login_handlers';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_settings' ) )
{
$tabs['settings'] = 'login_settings';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'registration_settings' ) )
{
$tabs['registration'] = 'registration_settings';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_account_management' ) )
{
$tabs['accountsettings'] = 'account_management_settings';
}
/* Show IPS Connect "master" information */
$masterUrl = \IPS\Http\Url::internal( 'applications/core/interface/ipsconnect/ipsconnect.php', 'none' );
$masterKey = \IPS\CONNECT_MASTER_KEY ?: md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'login_ipsconnect_info', FALSE, array( 'sprintf' => array( $masterUrl, $masterKey ) ) ), 'info', NULL, FALSE );
return parent::manage();
/* Get active tab */
if ( isset( \IPS\Request::i()->tab ) and isset( $tabs[ \IPS\Request::i()->tab ] ) )
{
$activeTab = \IPS\Request::i()->tab;
}
else
{
$_tabs = array_keys( $tabs ) ;
$activeTab = array_shift( $_tabs );
}
/* Get active tab contents */
$output = '';
switch ( $activeTab )
{
case 'handlers':
\IPS\Dispatcher::i()->checkAcpPermission( 'login_manage' );
parent::manage();
$output = \IPS\Output::i()->output;
break;
case 'settings':
$output = $this->_settings();
break;
case 'registration':
$output = $this->_registration();
break;
case 'accountsettings':
$output = $this->_accountsettings();
break;
}
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_login');
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $output;
}
else
{
\IPS\Output::i()->sidebar['actions'] = array(
'forcelogout' => array(
'title' => 'force_all_logout',
'icon' => 'lock',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&do=forceLogout' ),
'data' => array( 'confirm' => '' ),
),
);
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $output, \IPS\Http\Url::internal( "app=core&module=settings&controller=login" ) );
}
}
/**
* Force all users to be logged out
* Add/Edit Form
*
* @return void
* @return void
*/
protected function forceLogout()
protected function form()
{
\IPS\Db::i()->update( 'core_members_known_devices', array( 'login_key' => NULL ) );
\IPS\Db::i()->delete( 'core_sessions' );
\IPS\Session::i()->log( 'acplogs__logout_force' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login' ), 'logged_out_force' );
if ( \IPS\Request::i()->id )
{
return parent::form();
}
else
{
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( array(
'login_handler' => function( $data )
{
$options = array();
foreach ( \IPS\Login\Handler::handlerClasses() as $class )
{
if ( !$class::$allowMultiple )
{
foreach ( \IPS\Login\Handler::roots() as $handler )
{
if ( $handler instanceof $class )
{
continue 2;
}
}
}
$options[ $class ] = $class::getTitle();
}
$form = new \IPS\Helpers\Form( 'login_handler_1', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'login_handler', TRUE, NULL, array( 'options' => $options ) ) );
if ( $values = $form->values() )
{
return array( 'handler' => $values['login_handler'] );
}
return $form;
},
'login_details' => function( $data )
{
$node = new $data['handler'];
$node->classname = $data['handler'];
$form = $this->_addEditForm( $node );
if ( $values = $form->values() )
{
try
{
$node->settings = array();
$node->order = \IPS\Db::i()->select( 'MAX(login_order)', $node::$databaseTable )->first() + 1;
$node->saveForm( $node->formatFormValues( $values ) );
\IPS\Session::i()->log( 'acplog__node_created', array( $this->title => TRUE, $node->titleForLog() => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=login') );
}
catch ( \LogicException $e )
{
$form->error = $e->getMessage();
}
}
return $form;
}
), \IPS\Http\Url::internal('app=core&module=settings&controller=login&do=form') );
}
}
/**
@@ -92,48 +213,78 @@ class _login extends \IPS\Node\Controller
*/
protected function enableToggle()
{
$node = \IPS\Login\LoginAbstract::load( \IPS\Request::i()->id );
$loginMethod = \IPS\Login\Handler::load( \IPS\Request::i()->id );
if ( \IPS\Request::i()->status )
{
if ( method_exists( $node, 'testSettings' ) )
try
{
try
{
$node->testSettings();
}
catch ( \Exception $e )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=login&do=form&id={$node->key}" ) );
}
$loginMethod->testSettings();
}
catch ( \Exception $e )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=login&do=form&id={$loginMethod->id}" ) );
}
}
else
{
$others = \IPS\Db::i()->select( 'count(*)', 'core_login_handlers', array( 'login_enabled=? and login_key<>?', 1, $node->key ) )->first();
if( !$others )
{
\IPS\Output::i()->error( 'login_atleast_one', '1C166/3', 403, '' );
}
/* Allow the login handler to do stuff on-disable */
$node->onDisable();
$this->_disableCheck( $loginMethod );
}
/* Clear guest page caches */
/* Clear caches */
unset( \IPS\Data\Store::i()->loginMethods );
\IPS\Data\Cache::i()->clearAll();
/* Toggle */
return parent::enableToggle();
}
/**
* Settings
* Delete
*
* @return void
*/
protected function settings()
protected function delete()
{
/* Check it's okay */
$loginMethod = \IPS\Login\Handler::load( \IPS\Request::i()->id );
$this->_disableCheck( $loginMethod );
/* Do it */
parent::delete();
/* Clear caches */
unset( \IPS\Data\Store::i()->loginMethods );
\IPS\Data\Cache::i()->clearAll();
}
/**
* If a particular method is disabled/deleted - will we still be able to log in?
*
* @param \IPS\Login\Handler $methodToRemove Handler to be disabled/deleted
* @return void
*/
protected function _disableCheck( \IPS\Login\Handler $methodToRemove )
{
foreach ( \IPS\Login::methods() as $method )
{
if ( $method != $methodToRemove and $method->canProcess( \IPS\Member::loggedIn() ) and $method->acp )
{
return true;
}
}
\IPS\Output::i()->error( 'login_handler_cannot_disable', '1C166/5', 403, '' );
}
/**
* Login Settings
*
* @return string
*/
protected function _settings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_settings' );
/* Build Form */
$form = new \IPS\Helpers\Form();
$form->addHeader( 'ipb_bruteforce_attempts' );
@@ -142,32 +293,6 @@ class _login extends \IPS\Node\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_bruteforce_unlock', \IPS\Settings::i()->ipb_bruteforce_unlock, FALSE, array(), NULL, NULL, NULL, 'ipb_bruteforce_unlock' ) );
$form->addHeader( 'login_settings' );
$form->add( new \IPS\Helpers\Form\YesNo( 'new_device_email', \IPS\Settings::i()->new_device_email, FALSE ) );
/* Check if the site works over HTTPS before we allow them to change that */
$httpsValue = \IPS\Settings::i()->logins_over_https;
$httpsDisabled = FALSE;
$toggles = array();
if ( mb_substr( \IPS\Settings::i()->base_url, 0, 8 ) === 'https://' )
{
$httpsValue = TRUE;
$httpsDisabled = TRUE;
\IPS\Member::loggedIn()->language()->words['logins_over_https_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'logins_over_https_enabled', FALSE );
}
else
{
try
{
$response = \IPS\Http\Url::external( 'https://' . mb_substr( \IPS\Settings::i()->base_url, 7 ) )->request()->get();
}
catch ( \IPS\Http\Request\Exception $e )
{
$httpsValue = FALSE;
$httpsDisabled = TRUE;
$toggles[] = 'form_logins_over_https_warning';
\IPS\Member::loggedIn()->language()->words['logins_over_https_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'logins_over_https_disabled', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) );
}
}
$form->add( new \IPS\Helpers\Form\YesNo( 'logins_over_https', $httpsValue, FALSE, array( 'disabled' => $httpsDisabled, 'togglesOn' => $toggles ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'disable_anonymous', !\IPS\Settings::i()->disable_anonymous, FALSE, array(), NULL, NULL, NULL, 'disable_anonymous' ) );
/* Save */
@@ -189,125 +314,220 @@ class _login extends \IPS\Node\Controller
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='unlockmembers'" );
}
/* Cache this for the later check */
$currentLoginSetting = \IPS\Settings::i()->logins_over_https;
$form->saveAsSettings( $values );
/* Reset datastore if https setting has changed */
if( $currentLoginSetting != $values['logins_over_https'] )
{
\IPS\Theme::deleteCompiledCss();
\IPS\Data\Store::i()->clearAll();
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__login_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=settings' ), 'saved' );
}
/* Display */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'login_settings', $form, FALSE );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'login_settings' );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'login_settings' ) );
return (string) $form;
}
/**
* Manually reprocess IPS Connect requests that are queued
* HTTPS check
*
* @return null
*/
protected function httpsCheck()
{
try
{
$response = \IPS\Http\Url::external( 'https://' . mb_substr( \IPS\Settings::i()->base_url, 7 ) )->request()->get();
\IPS\Output::i()->output = $response;
}
catch ( \IPS\Http\Request\Exception $e )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->message( $e->getMessage() ?: '500_error_title', 'error' );
}
}
/**
* Registration Settings
*
* @return string
*/
protected function _registration()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'registration_settings' );
/* Build Form */
$form = new \IPS\Helpers\Form();
$form->addHeader('registration_standard_settings');
$form->addMessage('registration_standard_settings_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'allow_reg', \IPS\Login::registrationType(), FALSE, array(
'options' => array(
'normal' => 'allow_reg_normal',
'full' => 'allow_reg_full',
'redirect' => 'allow_reg_redirect',
'disabled' => 'allow_reg_disabled'
),
'toggles' => array(
'full' => array( 'minimum_age', 'use_coppa' ),
'redirect' => array( 'allow_reg_target' )
),
'disabled' => \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\Standard' ) ? array() : array( 'normal', 'full' )
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_reg_target', \IPS\Settings::i()->allow_reg_target, NULL, array(), function( $val )
{
if ( !$val and \IPS\Request::i()->allow_red === 'redirect' )
{
throw new \DomainException('form_required');
}
}, NULL, NULL, 'allow_reg_target' ) );
$form->add( new \IPS\Helpers\Form\Number( 'minimum_age', \IPS\Settings::i()->minimum_age, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'any_age' ), NULL, NULL, NULL, 'minimum_age' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'use_coppa', \IPS\Settings::i()->use_coppa, FALSE, array( 'togglesOn' => array( 'coppa_fax', 'coppa_address' ) ), NULL, NULL, NULL, 'use_coppa' ) );
$form->add( new \IPS\Helpers\Form\Tel( 'coppa_fax', \IPS\Settings::i()->coppa_fax, FALSE, array(), NULL, NULL, NULL, 'coppa_fax' ) );
$form->add( new \IPS\Helpers\Form\Address( 'coppa_address', \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->coppa_address ), FALSE, array(), NULL, NULL, NULL, 'coppa_address' ) );
$form->addHeader('registration_global_settings');
$form->addMessage('registration_global_settings_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'reg_auth_type', \IPS\Settings::i()->reg_auth_type, FALSE, array(
'options' => array( 'user' => 'reg_auth_type_user', 'admin' => 'reg_auth_type_admin', 'admin_user' => 'reg_auth_type_admin_user', 'none' => 'reg_auth_type_none' ),
'toggles' => array( 'user' => array( 'validate_day_prune' ), 'admin_user' => array( 'validate_day_prune' ) )
), NULL, NULL, NULL, 'reg_auth_type' ) );
$form->add( new \IPS\Helpers\Form\Number( 'validate_day_prune', \IPS\Settings::i()->validate_day_prune, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'validate_day_prune' ) );
$form->add( new \IPS\Helpers\Form\Stack( 'allowed_reg_email', explode( ',', \IPS\Settings::i()->allowed_reg_email ), FALSE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
if( isset( $value[0] ) AND mb_stripos( $value[0], '@' ) )
{
throw new \DomainException( 'allowed_reg_email_email_detected' );
}
}, NULL, NULL ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'new_reg_notify', \IPS\Settings::i()->new_reg_notify, FALSE, array(), NULL, NULL, NULL, 'new_reg_notify' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'force_reg_terms', \IPS\Settings::i()->force_reg_terms, FALSE, array( 'options' => array(
'0' => 'force_reg_terms_0',
'1' => 'force_reg_terms_1',
) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'updates_consent_default', \IPS\Settings::i()->updates_consent_default, FALSE, array(
'options' => array( 'enabled' => 'updates_consent_enabled', 'disabled' => 'updates_consent_disabled' ),
), NULL, NULL, NULL, 'updates_consent_default' ) );
/* Save */
if ( $values = $form->values() )
{
/* Save */
if ( isset( $values['allowed_reg_email'] ) and is_array( $values['allowed_reg_email'] ) )
{
$values['allowed_reg_email'] = implode( ',', $values['allowed_reg_email'] );
}
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__registration_settings' );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=registration' ), 'saved' );
}
/* Display */
return (string) $form;
}
/**
* Account Management Settings
*
* @return string
*/
protected function _accountsettings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_account_management' );
/* Build Form */
$form = new \IPS\Helpers\Form();
$form->addHeader( 'security_header_accounts' );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter', \IPS\Settings::i()->password_strength_meter, FALSE, array( 'togglesOn' => array( 'password_strength_meter_enforce' ) ), NULL, NULL, NULL, 'password_strength_meter' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter_enforce', \IPS\Settings::i()->password_strength_meter_enforce, FALSE, array( 'togglesOn' => array( 'password_strength_option' ) ), NULL, NULL, NULL, 'password_strength_meter_enforce' ) );
$strengthOptions = array(
'3' => 'strength_3',
'4' => 'strength_4',
'5' => 'strength_5',
);
$form->add( new \IPS\Helpers\Form\Radio( 'password_strength_option', \IPS\Settings::i()->password_strength_option, FALSE, array( 'options' => $strengthOptions ), NULL, NULL, NULL, 'password_strength_option' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'device_management', \IPS\Settings::i()->device_management, FALSE ) );
$form->addHeader('account_management_email_pass');
$form->addMessage('account_management_email_pass_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'allow_email_changes', \IPS\Settings::i()->allow_email_changes, FALSE, array(
'options' => array(
'normal' => 'allow_email_changes_normal',
'redirect' => 'allow_email_changes_redirect',
'disabled' => 'allow_email_changes_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_email_changes_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_email_changes_target', \IPS\Settings::i()->allow_email_changes_target, NULL, array(), function( $val )
{
if ( !$val and \IPS\Request::i()->allow_email_changes === 'redirect' )
{
throw new \DomainException('form_required');
}
}, NULL, NULL, 'allow_email_changes_target' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'allow_password_changes', \IPS\Settings::i()->allow_password_changes, FALSE, array(
'options' => array(
'normal' => 'allow_password_changes_normal',
'redirect' => 'allow_password_changes_redirect',
'disabled' => 'allow_password_changes_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_password_changes_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_password_changes_target', \IPS\Settings::i()->allow_password_changes_target, NULL, array(), function( $val )
{
if ( !$val and \IPS\Request::i()->allow_password_changes === 'redirect' )
{
throw new \DomainException('form_required');
}
}, NULL, NULL, 'allow_password_changes_target' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'allow_forgot_password', \IPS\Settings::i()->allow_forgot_password, FALSE, array(
'options' => array(
'normal' => 'allow_forgot_password_normal',
'handler' => 'allow_forgot_password_handler',
'redirect' => 'allow_forgot_password_redirect',
'disabled' => 'allow_forgot_password_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_forgot_password_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_forgot_password_target', \IPS\Settings::i()->allow_forgot_password_target, NULL, array(), function( $val )
{
if ( !$val and \IPS\Request::i()->allow_forgot_password === 'redirect' )
{
throw new \DomainException('form_required');
}
}, NULL, NULL, 'allow_forgot_password_target' ) );
/* Save */
if ( $values = $form->values() )
{
$values['password_strength_meter_enforce'] = $values['password_strength_meter'] ? $values['password_strength_meter_enforce'] : FALSE;
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__account_management_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=accountsettings' ), 'saved' );
}
/* Display */
return (string) $form;
}
/**
* Force all users to be logged out
*
* @return void
*/
protected function retryConnect()
protected function forceLogout()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('try_slave_request_again');
\IPS\Db::i()->update( 'core_members_known_devices', array( 'login_key' => NULL ) );
\IPS\Db::i()->delete( 'core_sessions' );
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( "app=core&module=settings&controller=login&do=retryConnect&slave=" . \IPS\Request::i()->slave ),
function( $data )
{
/* On first cycle get data */
if ( !is_array( $data ) )
{
/* Get total number of failures to process for progress bar */
$data = array( 'done' => 0, 'total' => count( \IPS\Db::i()->select( 'id', 'core_ipsconnect_queue', array( 'slave_id=?', intval( \IPS\Request::i()->slave ) ) ) ) );
}
/* Get the next request */
try
{
$request = \IPS\Db::i()->select( 'q.*, s.*', array( 'core_ipsconnect_queue', 'q' ), array( 'q.slave_id=?', intval( \IPS\Request::i()->slave ) ), 'q.id asc', array( 0, 1 ) )
->join( array( 'core_ipsconnect_slaves', 's' ), "s.slave_id=q.slave_id" )
->first();
/* Try to process request again */
try
{
parse_str( $request['request_url'], $variables );
$response = \IPS\Http\Url::external( $request['slave_url'] )
->setQueryString( $variables )
->request()
->get();
if( $response->httpResponseCode !== NULL AND $response->httpResponseCode > 200 )
{
/* Update fail count */
\IPS\Db::i()->update( 'core_ipsconnect_queue', 'fail_count=fail_count+1', array( 'id=?', $request['id'] ) );
/* Show error message */
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'connect_failure_details', FALSE, array( 'sprintf' =>
array( \IPS\Member::loggedIn()->language()->addToStack('connect_slavefail_http', FALSE, array( 'sprintf' => array( $response->httpResponseCode ) ) ) )
) ), '4C166/1', 503, '' );
}
$response = $response->decodeJson();
/* If this is a registered slave but the slave is telling us Connect is disabled, remove it */
if( isset( $response['status'] ) AND $response['status'] == 'DISABLED' )
{
\IPS\Db::i()->update( 'core_ipsconnect_slaves', array( 'slave_enabled' => 0 ), array( 'slave_id=?', $request['slave_id'] ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
unset( \IPS\Data\Store::i()->settings );
}
else if( !isset( $response['status'] ) OR $response['status'] != 'SUCCESS' )
{
throw new \RuntimeException( $response['status'] );
}
/* If we are here, request succeeded - remove from queue */
\IPS\Db::i()->delete( 'core_ipsconnect_queue', array( 'id=?', $request['id'] ) );
}
catch( \RuntimeException $e )
{
/* Update fail count */
\IPS\Db::i()->update( 'core_ipsconnect_queue', 'fail_count=fail_count+1', array( 'id=?', $request['id'] ) );
/* The request failed - show the admin why */
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack('connect_failure_details', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) ), '4C166/2', 503, '' );
}
$data['done']++;
/* Return null to indicate we are done */
return array( $data, 'connect_retry_success', round( $data['done'] / $data['total'] ) );
}
catch( \UnderflowException $e )
{
\IPS\Session::i()->log( 'acplog__connect_queue_cleared' );
/* Disable task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='connect'" );
return NULL;
}
},
function()
{
/* And redirect back to the dashboard */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=overview&controller=dashboard' ), 'connect_queue_cleared' );
}
);
\IPS\Session::i()->log( 'acplogs__logout_force' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login' ), 'logged_out_force' );
}
}
@@ -79,7 +79,7 @@ class _posting extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Work out output */
$activeTabContents = call_user_func( array( $this, '_manage'.ucfirst( $this->activeTab ) ) );
$activeTabContents = call_user_func( array( $this, '_manage' . mb_ucfirst( $this->activeTab ) ) );
/* If this is an AJAX request, just return it */
if( \IPS\Request::i()->isAjax() )
@@ -109,8 +109,8 @@ class _posting extends \IPS\Dispatcher\Controller
$form->hiddenValues['rebuildImageProxy'] = \IPS\Request::i()->rebuildImageProxy ?: 0;
$form->addHeader('posting_attachments');
$form->add( new \IPS\Helpers\Form\Radio( 'attach_allowed_types', \IPS\Settings::i()->attach_allowed_types, FALSE, array(
'options' => array( 'all' => 'attach_allowed_types_all', 'images' => 'attach_allowed_types_images', 'none' => 'attach_allowed_types_none' ),
'toggles' => array( 'all' => array( 'attach_allowed_extensions', 'attachment_resample_size', 'attachment_image_size' ), 'images' => array( 'attachment_resample_size', 'attachment_image_size' ) )
'options' => array( 'all' => 'attach_allowed_types_all', 'media' => 'attach_allowed_types_media', 'images' => 'attach_allowed_types_images', 'none' => 'attach_allowed_types_none' ),
'toggles' => array( 'all' => array( 'attach_allowed_extensions', 'attachment_resample_size', 'attachment_image_size' ), 'media' => array( 'attachment_resample_size', 'attachment_image_size' ), 'images' => array( 'attachment_resample_size', 'attachment_image_size' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'attach_allowed_extensions', \IPS\Settings::i()->attach_allowed_extensions ? explode( ',', \IPS\Settings::i()->attach_allowed_extensions ) : NULL, FALSE, array( 'nullLang' => 'no_restriction', 'autocomplete' => array( 'freeChoice' => TRUE, 'source' => array( 'doc', 'docx', 'log', 'msg', 'odt', 'pages', 'rtf', 'tex', 'txt', 'wpd', 'wps', 'csv', 'dat', 'gbr', 'ged', 'key', 'keychain', 'pps', 'ppt', 'pptx', 'sdf', 'tar', 'tax2012', 'tax2014', 'vcf', 'xml', 'aif', 'iff', 'm3u', 'm4a', 'mid', 'mp3', 'mpa', 'ra', 'wav', 'wma', '3g2', '3gp', 'asf', 'asx', 'avi', 'flv', 'm4v', 'mov', 'mp4', 'mpg', 'rm', 'srt', 'swf', 'vob', 'wmv', '3dm', '3ds', 'max', 'obj', 'bmp', 'dds', 'gif', 'jpg', 'png', 'psd', 'pspimage', 'tga', 'thm', 'tif', 'tiff', 'yuv', 'ai', 'eps', 'ps', 'svg', 'indd', 'pct', 'pdf', 'xlr', 'xls', 'xlsx', 'accdb', 'db', 'dbf', 'mdb', 'pdb', 'sql', 'apk', 'app', 'bat', 'cgi', 'com', 'exe', 'gadget', 'jar', 'pif', 'vb', 'wsf', 'dem', 'gam', 'nes', 'rom', 'sav', 'dwg', 'dxf', 'gpx', 'kml', 'kmz', 'asp', 'aspx', 'cer', 'cfm', 'csr', 'css', 'htm', 'html', 'js', 'jsp', 'php', 'rss', 'xhtml', 'crx', 'plugin', 'fnt', 'fon', 'otf', 'ttf', 'cab', 'cpl', 'cur', 'deskthemepack', 'dll', 'dmp', 'drv', 'icns', 'ico', 'lnk', 'sys', 'cfg', 'ini', 'prf', 'hqx', 'mim', 'uue', '7z', 'cbr', 'deb', 'gz', 'pkg', 'rar', 'rpm', 'sitx', 'tar.gz', 'zip', 'zipx', 'bin', 'cue', 'dmg', 'iso', 'mdf', 'toast', 'vcd', 'c', 'class', 'cpp', 'cs', 'dtd', 'fla', 'h', 'java', 'lua', 'm', 'pl', 'py', 'sh', 'sln', 'swift', 'vcxproj', 'xcodeproj', 'bak', 'tmp', 'crdownload', 'ics', 'msi', 'part', 'torrent' ) ) ), NULL, NULL, NULL, 'attach_allowed_extensions' ) );
$form->addHeader('posting_images');
@@ -170,7 +170,7 @@ class _posting extends \IPS\Dispatcher\Controller
) ) );
}
$form->add( new \IPS\Helpers\Form\Number( 'dellog_retention_period', \IPS\Settings::i()->dellog_retention_period, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'immediately' ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('dellog_days_after_deleted') ) );
$form->add( new \IPS\Helpers\Form\Number( 'dellog_retention_period', \IPS\Settings::i()->dellog_retention_period, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'immediately', 'max' => PHP_INT_MAX ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('dellog_days_after_deleted') ) );
/* Save values */
if ( $values = $form->values() )
@@ -191,7 +191,7 @@ class _posting extends \IPS\Dispatcher\Controller
if( $values['rebuildImageProxy'] )
{
/* Remove any existing rebuilds */
\IPS\Db::i()->delete( 'core_queue', array( '`key`=? OR `key`=?', 'RebuildImageProxy', 'RebuildImageProxyNonContent' ) );
\IPS\Db::i()->delete( 'core_queue', \IPS\Db::i()->in( '`key`', array( 'RebuildImageProxy', 'RebuildImageProxyNonContent', 'DeleteImageProxyFiles' ) ) );
/* Unset task datastore */
unset( \IPS\Data\Store::i()->currentImageProxyRebuild );
@@ -199,21 +199,32 @@ class _posting extends \IPS\Dispatcher\Controller
$enableDisable = $values['remote_image_proxy'] ? TRUE : FALSE;
foreach ( \IPS\Content::routedClasses( FALSE, TRUE ) as $class )
{
try
if( isset( $class::$databaseColumnMap['content'] ) )
{
\IPS\Task::queue( 'core', 'RebuildImageProxy', array( 'class' => $class, 'status' => $enableDisable ), 5 );
try
{
\IPS\Task::queue( 'core', 'RebuildImageProxy', array( 'class' => $class, 'status' => $enableDisable ), 4 );
}
catch( \OutOfRangeException $ex ) { }
}
catch( \OutOfRangeException $ex ) { }
}
foreach( \IPS\Application::allExtensions( 'core', 'EditorLocations', FALSE, NULL, NULL, TRUE, TRUE ) as $_key => $extension )
{
if( method_exists( $extension, 'rebuildImageProxy' ) )
{
\IPS\Task::queue( 'core', 'RebuildImageProxyNonContent', array( 'extension' => $_key, 'status' => $enableDisable ), 5 );
\IPS\Task::queue( 'core', 'RebuildImageProxyNonContent', array( 'extension' => $_key, 'status' => $enableDisable ), 4 );
}
}
/* If we're disabling the image proxy, also delete the files */
if( !$enableDisable )
{
\IPS\Task::queue( 'core', 'DeleteImageProxyFiles', array( 'status' => $enableDisable ), 5 );
}
}
unset( $values['rebuildImageProxy'] );
$form->saveAsSettings( $values );
@@ -417,14 +428,26 @@ class _posting extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\Number( 'max_poll_choices', \IPS\Settings::i()->max_poll_choices ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'poll_allow_public', \IPS\Settings::i()->poll_allow_public ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_poll_only', \IPS\Settings::i()->ipb_poll_only ) );
$form->add( new \IPS\Helpers\Form\Number( 'startpoll_cutoff', \IPS\Settings::i()->startpoll_cutoff, FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'always' ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('hours') ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_poll_creation_after', ( \IPS\Settings::i()->startpoll_cutoff ? TRUE : FALSE ), FALSE, array( 'togglesOn' => array( 'startpoll_cutoff' ) ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'startpoll_cutoff', \IPS\Settings::i()->startpoll_cutoff, FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'always', 'max' => 43800 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('hours'), 'startpoll_cutoff' ) ); #max is roughly 5 years
$form->addHeader('poll_voting');
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_creator_vote', \IPS\Settings::i()->allow_creator_vote ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'poll_allow_vdelete', \IPS\Settings::i()->poll_allow_vdelete, FALSE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_result_view', \IPS\Settings::i()->allow_result_view, FALSE, array(), NULL, NULL, NULL, 'allow_result_view' ) );
if ( $form->saveAsSettings() )
if ( $values = $form->values( TRUE ) )
{
if ( ! $values['allow_poll_creation_after'] )
{
$values['startpoll_cutoff'] = 0;
}
unset( $values['allow_poll_creation_after'] );
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -77,7 +77,7 @@ class _terms extends \IPS\Dispatcher\Controller
$form->addHeader( 'guest_terms_options' );
$form->add( new \IPS\Helpers\Form\YesNo( 'guest_terms_bar', \IPS\Settings::i()->guest_terms_bar, FALSE, array( 'togglesOn' => array( 'guest_terms_bar_text' ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'guest_terms_bar_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'guest_terms_bar_text_value', 'sprintf' => array( '{terms}', '{privacy}', '{guidelines}' ) ), NULL, NULL, NULL, 'guest_terms_bar_text' ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'guest_terms_bar_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'guest_terms_bar_text_value', 'sprintf' => array( '{terms}', '{privacy}', '{guidelines}', '{cookies}' ) ), NULL, NULL, NULL, 'guest_terms_bar_text' ) );
if ( $values = $form->values() )
{
@@ -93,7 +93,7 @@ class _terms extends \IPS\Dispatcher\Controller
{
foreach( $values[ $k ] AS $lang_id => $text )
{
$values[ $k ][ $lang_id ] = str_replace( array( '{terms}', '{privacy}', '{guidelines}' ), array( '%1$s', '%2$s', '%3$s' ), $text );
$values[ $k ][ $lang_id ] = str_replace( array( '{terms}', '{privacy}', '{guidelines}', '{cookies}' ), array( '%1$s', '%2$s', '%3$s', '%4$s' ), $text );
}
}
+65 -59
View File
@@ -46,29 +46,40 @@ class _admin extends \IPS\Dispatcher\Controller
$table = new \IPS\Helpers\Table\Db( 'core_admin_permission_rows', \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin' ) );
/* Columns */
$table->selects = array( 'row_perm_cache', 'row_updated', 'row_id', 'row_id_type' );
$table->langPrefix = 'acprestrictions_';
$table->joins = array(
array( 'select' => "IF(core_admin_permission_rows.row_id_type= 'group', w.word_custom, m.name) as name", 'from' => array( 'core_members', 'm' ), 'where' => "m.member_id=core_admin_permission_rows.row_id AND core_admin_permission_rows.row_id_type='member'" ),
array( 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'core_group_', core_admin_permission_rows.row_id ) AND core_admin_permission_rows.row_id_type='group' AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
);
$table->include = array( 'row_id_type', 'row_id', 'row_updated' );
$table->include = array( 'name', 'row_updated', 'row_perm_cache' );
$table->parsers = array(
'row_id_type' => function( $val, $row )
'name' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'global' )->shortMessage( $val, array( 'ipsBadge', 'ipsBadge_neutral' ) );
},
'row_id' => function( $val, $row )
{
return $row['row_id_type'] === 'group' ? \IPS\Member\Group::load( $row['row_id'] )->formattedName : htmlentities( $row['name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$return = \IPS\Theme::i()->getTemplate( 'global' )->shortMessage( $row['row_id_type'], array( 'ipsBadge', 'ipsBadge_neutral', 'ipsBadge_label' ) );
try
{
$name = empty( $row['name'] ) ? \IPS\Member::loggedIn()->language()->addToStack('deleted_member') : htmlentities( $row['name'], ENT_DISALLOWED, 'UTF-8', FALSE );
$return .= ( $row['row_id_type'] === 'group' ) ? \IPS\Member\Group::load( $row['row_id'] )->formattedName : $name;
}
catch( \OutOfRangeException $e )
{
$return .= \IPS\Member::loggedIn()->language()->addToStack('deleted_group');
}
return $return;
},
'row_updated' => function( $val )
{
return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack('never');
},
'row_perm_cache' => function( $val )
{
return \IPS\Theme::i()->getTemplate( 'members' )->restrictionsLabel( $val );
}
);
$table->mainColumn = 'name';
$table->quickSearch = array( array( 'name', 'word_custom' ), 'row_id' );
$table->classes = array( 'row_id_type' => 'icon' );
$table->quickSearch = array( array( 'name', 'word_custom' ), 'name' );
$table->noSort = array( 'row_perm_cache' );
/* Sorting */
$table->sortBy = $table->sortBy ?: 'row_updated';
@@ -160,11 +171,20 @@ class _admin extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->sidebar['actions']['loginLogs'] = array(
'title' => 'adminloginlogs',
'icon' => 'key',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin&do=loginLogs' ),
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members' ) )
{
\IPS\Output::i()->sidebar['actions']['list_admins'] = array(
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&filter=members_filter_administrators' ),
'title' => 'security_list_admins',
);
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('acprestrictions');
\IPS\Output::i()->output = (string) $table;
@@ -243,7 +263,7 @@ class _admin extends \IPS\Dispatcher\Controller
unset( \IPS\Data\Store::i()->administrators );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=staff&controller=admin&do=edit&id={$current['row_id']}&type={$current['row_id_type']}" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=staff&controller=admin" ) );
}
}
@@ -258,7 +278,8 @@ class _admin extends \IPS\Dispatcher\Controller
*/
protected function edit()
{
try {
try
{
/* Get record */
$current = \IPS\Db::i()->select( '*', 'core_admin_permission_rows', array( "row_id=? AND row_id_type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) )->first();
}
@@ -311,24 +332,7 @@ class _admin extends \IPS\Dispatcher\Controller
}
}
}
/* Warning if they have all permissions */
if ( $current['row_perm_cache'] === '*' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'admin_allperm_warning', 'warning' );
}
/* Or a button to give all */
else
{
\IPS\Output::i()->sidebar['actions'] = array(
'all' => array(
'title' => 'moderators_allperm',
'icon' => 'check-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin&do=allperms&id=' ) . $current['row_id'] . '&type=' . $current['row_id_type'],
),
);
}
/* Display */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_members.js', 'core', 'admin' ) );
\IPS\Output::i()->title = $current['row_id_type'] === 'group' ? \IPS\Member\Group::load( $current['row_id'] )->name : \IPS\Member::load( $current['row_id'] )->name;
@@ -349,8 +353,10 @@ class _admin extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'node_error', '2C113/2', 404, '' );
}
$permissions = ( \IPS\Request::i()->admin_use_restrictions == 'no' ) ? '*' : json_encode( ( is_array( \IPS\Request::i()->r ) ) ? \IPS\Request::i()->r : array() );
/* Save */
\IPS\Db::i()->update( 'core_admin_permission_rows', array( 'row_perm_cache' => json_encode( ( is_array( \IPS\Request::i()->r ) ) ? \IPS\Request::i()->r : array() ), 'row_updated' => time() ), array( "row_id=? AND row_id_type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) );
\IPS\Db::i()->update( 'core_admin_permission_rows', array( 'row_perm_cache' => $permissions, 'row_updated' => time() ), array( "row_id=? AND row_id_type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) );
unset( \IPS\Data\Store::i()->administrators );
@@ -360,32 +366,7 @@ class _admin extends \IPS\Dispatcher\Controller
/* Boink */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin' ), 'saved' );
}
/**
* Give All Permissions
*
* @return void
*/
protected function allperms()
{
/* Load */
$current = \IPS\Db::i()->select( '*', 'core_admin_permission_rows', array( "row_id=? AND row_id_type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) )->first();
if ( !$current )
{
\IPS\Output::i()->error( 'node_error', '2C113/5', 404, '' );
}
/* Set */
\IPS\Db::i()->update( 'core_admin_permission_rows', array( 'row_perm_cache' => '*', 'row_updated' => time() ), array( array( "row_id=? AND row_id_type=?", $current['row_id'], $current['row_id_type'] ) ) );
unset( \IPS\Data\Store::i()->administrators );
\IPS\Session::i()->log( 'acplog__acpr_edited', array( ( $current['row_id_type'] == 'group' ? \IPS\Member\Group::load( $current['row_id'] )->name : \IPS\Member::load( $current['row_id'] )->name ) => FALSE ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin&do=edit&id=' . $current['row_id'] . '&type=' . $current['row_id_type'] ) );
}
/**
* Delete
*
@@ -407,7 +388,32 @@ class _admin extends \IPS\Dispatcher\Controller
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\Session::i()->log( 'acplog__acpr_deleted', array( ( $current['row_id_type'] == 'group' ? \IPS\Member\Group::load( $current['row_id'] )->name : \IPS\Member::load( $current['row_id'] )->name ) => FALSE ) );
if( $current['row_id_type'] == 'group' )
{
try
{
$name = \IPS\Member\Group::load( $current['row_id'] )->name;
}
catch( \OutOfRangeException $e )
{
$name = \IPS\Member::loggedIn()->language()->get('deleted_group');
}
}
else
{
$member = \IPS\Member::load( $current['row_id'] );
if( $member->member_id )
{
$name = $member->name;
}
else
{
$name = \IPS\Member::loggedIn()->language()->get('deleted_member');
}
}
\IPS\Session::i()->log( 'acplog__acpr_deleted', array( $name => FALSE ) );
\IPS\Db::i()->delete( 'core_admin_permission_rows', array( 'row_id=? AND row_id_type=?', intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) );
unset ( \IPS\Data\Store::i()->administrators );
@@ -434,11 +440,11 @@ class _admin extends \IPS\Dispatcher\Controller
$member = \IPS\Member::load( $val );
if ( $member->member_id )
{
return htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlentities( \IPS\Member::load( $val )->name, ENT_DISALLOWED, 'UTF-8', FALSE );
}
else if ( $row['member_name'] != '' )
{
return htmlentities( $row['member_name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlentities( $row['member_name'], ENT_DISALLOWED, 'UTF-8', FALSE );
}
else
{
@@ -30,7 +30,9 @@ class _moderators extends \IPS\Dispatcher\Controller
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'moderators_manage' );
parent::execute();
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'members/restrictions.css', 'core', 'admin' ) );
return parent::execute();
}
/**
@@ -42,31 +44,42 @@ class _moderators extends \IPS\Dispatcher\Controller
{
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_moderators', \IPS\Http\Url::internal( 'app=core&module=staff&controller=moderators' ) );
/* Columns */
$table->langPrefix = 'moderators_';
$table->langPrefix = 'moderators_';
$table->selects = array( 'perms', 'id', 'type', 'updated' );
$table->joins = array(
array( 'select' => "IF(core_moderators.type= 'g', w.word_custom, m.name) as name", 'from' => array( 'core_members', 'm' ), 'where' => "m.member_id=core_moderators.id AND core_moderators.type='m'" ),
array( 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'core_group_', core_moderators.id ) AND core_moderators.type='g' AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
);
$table->include = array( 'type', 'id', 'updated' );
$table->include = array( 'name', 'updated', 'perms' );
$table->parsers = array(
'type' => function( $val, $row )
'name' => function( $val, $row )
{
return "<i class='fa fa-" . ( ( $val === 'm' ) ? 'user' : 'group' ) . "' data-ipstooltip _title=' " . ( ( $val === 'm' ) ? \IPS\Member::loggedIn()->language()->addToStack('acprestrictions_member') : \IPS\Member::loggedIn()->language()->addToStack('acprestrictions_group') ) . "'></i>";
},
'id' => function( $val, $row )
{
return $row['type'] === 'g' ? \IPS\Member\Group::load( $row['id'] )->formattedName : htmlentities( $row['name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$return = \IPS\Theme::i()->getTemplate( 'global' )->shortMessage( $row['type'] === 'g' ? 'group' : 'member', array( 'ipsBadge', 'ipsBadge_neutral', 'ipsBadge_label' ) );
try
{
$name = empty( $row['name'] ) ? \IPS\Member::loggedIn()->language()->addToStack('deleted_member') : htmlentities( $row['name'], ENT_DISALLOWED, 'UTF-8', FALSE );
$return .= ( $row['type'] === 'g' ) ? \IPS\Member\Group::load( $row['id'] )->formattedName : $name;
}
catch( \OutOfRangeException $e )
{
$return .= \IPS\Member::loggedIn()->language()->addToStack('deleted_group');
}
return $return;
},
'updated' => function( $val )
{
return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack('never');
},
'perms' => function( $val )
{
return \IPS\Theme::i()->getTemplate( 'members' )->restrictionsLabel( $val );
}
);
$table->mainColumn = 'name';
$table->quickSearch = array( array( 'name', 'word_custom' ), 'id' );
$table->classes = array( 'type' => 'icon' );
$table->quickSearch = array( array( 'name', 'word_custom' ), 'name' );
$table->noSort = array( 'perms' );
/* Sorting */
$table->sortBy = $table->sortBy ?: 'updated';
@@ -212,7 +225,7 @@ class _moderators extends \IPS\Dispatcher\Controller
unset (\IPS\Data\Store::i()->moderators);
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=staff&controller=moderators&do=edit&id={$current['id']}&type={$current['type']}" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=staff&controller=moderators" ) );
}
}
@@ -285,6 +298,12 @@ class _moderators extends \IPS\Dispatcher\Controller
/* Build */
$form = new \IPS\Helpers\Form;
/* Add the restricted/unrestricted option first */
$form->add(
new \IPS\Helpers\Form\Radio( 'mod_use_restrictions', ( $currentPermissions === '*' ) ? 'no' : 'yes', TRUE, array( 'options' => array( 'no' => 'mod_all_permissions', 'yes' => 'mod_restricted' ), 'toggles' => array( 'yes' => array( 'permission_form_wrapper' ) ) ), NULL, NULL, NULL, 'use_restrictions_id' )
);
$extensions = array();
foreach ( \IPS\Application::allExtensions( 'core', 'ModeratorPermissions', FALSE, 'core' ) as $k => $ext )
{
@@ -373,115 +392,84 @@ class _moderators extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
foreach ( $values as $k => $v )
if( $values['mod_use_restrictions'] == 'no' )
{
/* For node fields, if the value is 0 translate it to -1 so mod permissions can merge properly */
if( in_array( $k, $nodeFields ) )
{
/* If nothing is checked we have '', but if 'all' is checked then the value is 0 */
if( $v === 0 )
{
$v = -1;
$values[ $k ] = $v;
}
}
$permissions = '*';
if ( is_array( $v ) )
{
foreach ( $v as $l => $w )
{
if ( $w instanceof \IPS\Node\Model )
{
$values[ $k ][ $l ] = $w->_id;
}
}
}
}
if ( $currentPermissions == '*' )
{
$changed = $values;
$changed = '*';
}
else
{
$changed = array();
unset( $values['mod_use_restrictions'] );
foreach ( $values as $k => $v )
{
if ( !isset( $currentPermissions[ $k ] ) or $currentPermissions[ $k ] != $v )
/* For node fields, if the value is 0 translate it to -1 so mod permissions can merge properly */
if( in_array( $k, $nodeFields ) )
{
$changed[ $k ] = $v;
/* If nothing is checked we have '', but if 'all' is checked then the value is 0 */
if( $v === 0 )
{
$v = -1;
$values[ $k ] = $v;
}
}
if ( is_array( $v ) )
{
foreach ( $v as $l => $w )
{
if ( $w instanceof \IPS\Node\Model )
{
$values[ $k ][ $l ] = $w->_id;
}
}
}
}
if ( $currentPermissions == '*' )
{
$changed = $values;
}
else
{
$changed = array();
foreach ( $values as $k => $v )
{
if ( !isset( $currentPermissions[ $k ] ) or $currentPermissions[ $k ] != $v )
{
$changed[ $k ] = $v;
}
}
}
$permissions = json_encode( $values );
}
\IPS\Db::i()->update( 'core_moderators', array( 'perms' => json_encode( $values ), 'updated' => time() ), array( array( "id=? AND type=?", $current['id'], $current['type'] ) ) );
foreach ( \IPS\Application::allExtensions( 'core', 'ModeratorPermissions', FALSE ) as $k => $ext )
\IPS\Db::i()->update( 'core_moderators', array( 'perms' => $permissions, 'updated' => time() ), array( array( "id=? AND type=?", $current['id'], $current['type'] ) ) );
if( !( $currentPermissions == '*' AND $changed == '*' ) )
{
$ext->onChange( $current, $changed );
foreach ( \IPS\Application::allExtensions( 'core', 'ModeratorPermissions', FALSE ) as $k => $ext )
{
$ext->onChange( $current, $changed );
}
}
\IPS\Session::i()->log( 'acplog__moderator_edited', array( ( $current['type'] == 'g' ? \IPS\Member::loggedIn()->language()->get( "core_group_{$current['id']}" ) : \IPS\Member::load( $current['id'] )->name ) => FALSE ) );
$currentPermissions = $values;
unset (\IPS\Data\Store::i()->moderators);
unset( \IPS\Data\Store::i()->moderators );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=staff&controller=moderators' ), 'saved' );
}
/* Warning if they have all permissions */
if ( $currentPermissions === '*' )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'moderators_allperm_warning', 'warning' );
}
/* Or a button to give all */
else
{
\IPS\Output::i()->sidebar['actions'] = array(
'all' => array(
'title' => 'moderators_allperm',
'icon' => 'asterisk',
'link' => \IPS\Http\Url::internal( 'app=core&module=staff&controller=moderators&do=allperms&id=' ) . $current['id'] . '&type=' . $current['type'],
'data' => array( 'confirm' => '' )
),
);
}
/* Display */
\IPS\Output::i()->title = $_name;
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_members.js', 'core', 'admin' ) );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'members' )->moderatorPermissions( $_name, $form );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_members.js', 'core', 'admin' ) );
\IPS\Output::i()->output .= $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'members' ) ), 'moderatorPermissions' ) );
}
/**
* Give All Permissions
*
* @return void
*/
protected function allperms()
{
/* Load */
$current = \IPS\Db::i()->select( '*', 'core_moderators', array( "id=? AND type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) )->first();
if ( !$current )
{
\IPS\Output::i()->error( 'node_error', '2C118/3', 404, '' );
}
/* Set */
\IPS\Db::i()->update( 'core_moderators', array( 'perms' => '*', 'updated' => time() ), array( array( "id=? AND type=?", $current['id'], $current['type'] ) ) );
foreach ( \IPS\Application::allExtensions( 'core', 'ModeratorPermissions', FALSE ) as $k => $ext )
{
$ext->onChange( $current, '*' );
}
unset ( \IPS\Data\Store::i()->moderators );
/* Log and redirect */
\IPS\Session::i()->log( 'acplog__moderator_edited', array( ( $current['type'] == 'g' ? \IPS\Member::loggedIn()->language()->get( "core_group_{$current['id']}" ) : \IPS\Member::load( $current['id'] )->name ) => FALSE ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=staff&controller=moderators&do=edit&id=' . $current['id'] . '&type=' . $current['type'] ) );
}
/**
* Delete
*
@@ -546,11 +534,11 @@ class _moderators extends \IPS\Dispatcher\Controller
$member = \IPS\Member::load( $val );
if ( $member->member_id )
{
return htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlentities( \IPS\Member::load( $val )->name, ENT_DISALLOWED, 'UTF-8', FALSE );
}
else if ( $row['member_name'] != '' )
{
return htmlentities( $row['member_name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlentities( $row['member_name'], ENT_DISALLOWED, 'UTF-8', FALSE );
}
else
{
@@ -0,0 +1,118 @@
<?php
/**
* @brief Device usage
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 10 Jan 2018
*/
namespace IPS\core\modules\admin\stats;
/* 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;
}
/**
* Device usage
*/
class _deviceusage extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'deviceusage_manage' );
parent::execute();
}
/**
* Device usage chart
*
* @return void
*/
protected function manage()
{
/* Show button to adjust settings */
\IPS\Output::i()->sidebar['actions']['settings'] = array(
'icon' => 'cog',
'title' => 'prunesettings',
'link' => \IPS\Http\Url::internal( 'app=core&module=stats&controller=deviceusage&do=settings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
);
/* Determine minimum date */
$minimumDate = NULL;
if( \IPS\Settings::i()->stats_device_usage_prune )
{
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_device_usage_prune . 'D' ) );
}
/* We can't retrieve any stats prior to the new tracking being implemented */
try
{
$oldestLog = \IPS\Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'online_users' ) )->first();
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
{
$minimumDate = \IPS\DateTime::ts( $oldestLog );
}
}
catch( \OutOfRangeException $e )
{
/* We have nothing tracked, set minimum date to today */
$minimumDate = \IPS\DateTime::create();
}
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=deviceusage' ), 'core_statistics', 'time', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
), 'AreaChart', 'hourly' );
$chart->where[] = array( 'type=?', 'devices' );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_deviceusage_title');
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
$chart->enableHourly = TRUE;
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_mobiles'), 'number', 'SUM(value_1)', TRUE );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_tablets'), 'number', 'SUM(value_2)', TRUE );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_consoles'), 'number', 'SUM(value_3)', TRUE );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_desktops'), 'number', 'SUM(value_4)', TRUE );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_deviceusage');
\IPS\Output::i()->output = (string) $chart;
}
/**
* Prune Settings
*
* @return void
*/
protected function settings()
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Number( 'stats_device_usage_prune', \IPS\Settings::i()->stats_device_usage_prune, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'prune_log_moderator' ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplog__statsonlineusers_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=stats&controller=deviceusage' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('prunesettings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'prunesettings', $form, FALSE );
}
}
@@ -0,0 +1,171 @@
<?php
/**
* @brief Member Activity
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 10 Jan 2018
*/
namespace IPS\core\modules\admin\stats;
/* 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;
}
/**
* Member Activity
*/
class _membersactivity extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'membersactivity_manage' );
parent::execute();
}
/**
* Member activity statistics
*
* @return void
*/
protected function manage()
{
$count = NULL;
$table = NULL;
$start = NULL;
$end = NULL;
$defaults = array( 'start' => \IPS\DateTime::create()->setDate( date('Y'), date('m'), 1 ), 'end' => new \IPS\DateTime );
if( isset( \IPS\Request::i()->postDateStart ) AND isset( \IPS\Request::i()->postDateEnd ) )
{
$defaults = array( 'start' => \IPS\DateTime::ts( \IPS\Request::i()->postDateStart ), 'end' => \IPS\DateTime::ts( \IPS\Request::i()->postDateEnd ) );
}
$groupOptions = array_combine( array_keys( \IPS\Member\Group::groups( TRUE, FALSE ) ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups( TRUE, FALSE ) ) );
if( isset( \IPS\Request::i()->postGroups ) )
{
$defaultGroups = explode( ',', \IPS\Request::i()->postGroups );
}
else
{
$defaultGroups = array_keys( $groupOptions );
}
$form = new \IPS\Helpers\Form( 'posts', 'continue' );
$form->add( new \IPS\Helpers\Form\DateRange( 'date', $defaults, TRUE ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'groups', $defaultGroups, FALSE, array( 'options' => $groupOptions ), NULL, NULL, NULL, 'group_filters' ) );
if( $values = $form->values() )
{
/* Determine start and end time */
$startTime = $values['date']['start']->getTimestamp();
$endTime = $values['date']['end']->getTimestamp();
$start = $values['date']['start']->html();
$end = $values['date']['end']->html();
$groups = ( count( array_diff( array_keys( $groupOptions ), $values['groups'] ) ) ) ? $values['groups'] : NULL;
}
else
{
/* Determine start and end time */
$startTime = $defaults['start']->getTimestamp();
$endTime = $defaults['end']->getTimestamp();
$start = $defaults['start']->html();
$end = $defaults['end']->html();
$groups = ( count( array_diff( array_keys( $groupOptions ), $defaultGroups ) ) ) ? $defaultGroups : NULL;
}
/* Do we have our date ranges? */
if( $start AND $end )
{
/* Build our where clause */
$where = array( array( 'member_last_post BETWEEN ? AND ?', $startTime, $endTime ) );
if( $groups !== NULL )
{
$where[] = array( '(' . \IPS\Db::i()->in( 'member_group_id', $groups ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $groups ) . ')' );
}
/* Get the count */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where )->first();
/* And now build the table */
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Request::i()->url()->setQueryString( array( 'postDateStart' => $startTime, 'postDateEnd' => $endTime, 'postGroups' => is_array( $groups ) ? implode( ',', $groups ) : NULL ) ), $where );
$table->include = array( 'name', 'email', 'member_posts', 'member_last_post', 'group_name', 'ip_address' );
$table->mainColumn = 'name';
$table->langPrefix = 'activity_';
$table->rowClasses = array( 'email' => array( 'ipsTable_wrap' ), 'group_name' => array( 'ipsTable_wrap' ) );
$table->widths = array( 'group_name' => '25' );
/* Default sort options */
$table->sortBy = $table->sortBy ?: 'member_last_post';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Custom parsers */
$table->parsers = array(
'name' => function( $val, $row )
{
$member = \IPS\Member::constructFromData( $row );
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( $member, 'tiny' ) . ' ' . $member->link();
},
'email' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberEmailCell( htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) );
},
'member_last_post' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->html();
},
'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 "<a href='" . \IPS\Http\Url::internal( "app=core&module=members&controller=ip&ip={$val}" ) . "'>{$val}</a>";
}
return $val;
},
);
$table->extraHtml = \IPS\Theme::i()->getTemplate( 'stats' )->tableheader( $start, $end, $count, "member_activity_results" );
}
$formHtml = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'stats' ) ), 'filtersFormTemplate' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_stats.js', 'core' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_membersactivity');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'stats' )->memberactivity( $formHtml, $count, $table );
}
}
@@ -52,17 +52,31 @@ class _membervisits extends \IPS\Dispatcher\Controller
$defaults = array( 'start' => \IPS\DateTime::ts( \IPS\Request::i()->visitDateStart ), 'end' => \IPS\DateTime::ts( \IPS\Request::i()->visitDateEnd ) );
}
$groupOptions = array_combine( array_keys( \IPS\Member\Group::groups( TRUE, FALSE ) ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups( TRUE, FALSE ) ) );
if( isset( \IPS\Request::i()->visitGroups ) )
{
$defaultGroups = explode( ',', \IPS\Request::i()->visitGroups );
}
else
{
$defaultGroups = array_keys( $groupOptions );
}
$form = new \IPS\Helpers\Form( 'visits', 'continue' );
$form->add( new \IPS\Helpers\Form\DateRange( 'visit_date', $defaults, TRUE ) );
$form->add( new \IPS\Helpers\Form\DateRange( 'date', $defaults, TRUE ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'groups', $defaultGroups, FALSE, array( 'options' => $groupOptions ), NULL, NULL, NULL, 'group_filters' ) );
if( $values = $form->values() )
{
/* Determine start and end time */
$startTime = $values['visit_date']['start']->getTimestamp();
$endTime = $values['visit_date']['end']->getTimestamp();
$startTime = $values['date']['start']->getTimestamp();
$endTime = $values['date']['end']->getTimestamp();
$start = $values['visit_date']['start']->html();
$end = $values['visit_date']['end']->html();
$start = $values['date']['start']->html();
$end = $values['date']['end']->html();
$groups = ( count( array_diff( array_keys( $groupOptions ), $values['groups'] ) ) ) ? $values['groups'] : NULL;
}
else
{
@@ -72,20 +86,31 @@ class _membervisits extends \IPS\Dispatcher\Controller
$start = $defaults['start']->html();
$end = $defaults['end']->html();
$groups = ( count( array_diff( array_keys( $groupOptions ), $defaultGroups ) ) ) ? $defaultGroups : NULL;
}
/* Do we have our date ranges? */
if( $start AND $end )
{
/* Build our where clause */
$where = array( array( 'last_visit BETWEEN ? AND ?', $startTime, $endTime ) );
if( $groups !== NULL )
{
$where[] = array( '(' . \IPS\Db::i()->in( 'member_group_id', $groups ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $groups ) . ')' );
}
/* Get the count */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'last_visit BETWEEN ? AND ?', $startTime, $endTime ) )->first();
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where )->first();
/* And now build the table */
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Request::i()->url()->setQueryString( array( 'visitDateStart' => $startTime, 'visitDateEnd' => $endTime ) ), array( array( 'last_visit BETWEEN ? AND ?', $startTime, $endTime ) ) );
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Request::i()->url()->setQueryString( array( 'visitDateStart' => $startTime, 'visitDateEnd' => $endTime, 'visitGroups' => is_array( $groups ) ? implode( ',', $groups ) : NULL ) ), $where );
$table->include = array( 'name', 'last_visit' );
$table->include = array( 'name', 'email', 'last_visit', 'group_name', 'ip_address' );
$table->mainColumn = 'name';
$table->langPrefix = 'visits_';
$table->rowClasses = array( 'email' => array( 'ipsTable_wrap' ), 'group_name' => array( 'ipsTable_wrap' ) );
/* Default sort options */
$table->sortBy = $table->sortBy ?: 'last_visit';
@@ -98,17 +123,47 @@ class _membervisits extends \IPS\Dispatcher\Controller
$member = \IPS\Member::constructFromData( $row );
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( $member, 'tiny' ) . ' ' . $member->link();
},
'email' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberEmailCell( htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) );
},
'last_visit' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->html();
},
'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 "<a href='" . \IPS\Http\Url::internal( "app=core&module=members&controller=ip&ip={$val}" ) . "'>{$val}</a>";
}
return $val;
},
);
$table->extraHtml = \IPS\Theme::i()->getTemplate( 'stats' )->tableheader( $start, $end, $count );
$table->extraHtml = \IPS\Theme::i()->getTemplate( 'stats' )->tableheader( $start, $end, $count, "member_visits_results" );
}
$formHtml = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'stats' ) ), 'visitsFormTemplate' ) );
$formHtml = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'stats' ) ), 'filtersFormTemplate' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_stats.js', 'core' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_membervisits');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'stats' )->membervisits( $formHtml, $count, $table );
}
@@ -50,11 +50,13 @@ class _errorLogs extends \IPS\Dispatcher\Controller
$table->parsers = array(
'log_member' => function( $val )
{
try
$member = \IPS\Member::load( $val );
if( $member->member_id )
{
return htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlentities( $member->name, ENT_DISALLOWED, 'UTF-8', FALSE );
}
catch ( \OutOfBoundsException $e )
else
{
return '';
}
@@ -62,7 +62,7 @@ class _hookedFiles extends \IPS\Dispatcher\Controller
{
try
{
return \IPS\Plugin::load($row['plugin'])->name;
return htmlspecialchars( \IPS\Plugin::load($row['plugin'])->name, ENT_DISALLOWED, 'UTF-8', FALSE );
}
catch ( \OutOfRangeException $e )
{
@@ -109,27 +109,7 @@ class _recovery extends \IPS\Dispatcher\Controller
return array( 3, \IPS\Member::loggedIn()->language()->addToStack( 'reset_theme_to_default' ), 75 );
break;
case 3: # Login Handlers
$handlersDisabled = array();
/* Disable all login handlers other than Internal */
foreach( \IPS\Login::handlers( TRUE ) AS $key => $handler )
{
if ( $key != 'Internal' )
{
$handler->_enabled = FALSE;
$handler->save();
$handlersDisabled[] = $key;
}
}
$_SESSION['recoveryLogins'] = $handlersDisabled;
return array( 4, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_login_handlers' ), 100 );
break;
case 4: # Done
return NULL;
break;
@@ -165,14 +145,7 @@ class _recovery extends \IPS\Dispatcher\Controller
/* Did we reset the theme? */
$theme = $_SESSION['recoveryTheme'];
/* Did we disable any login handlers? */
$logins = array();
foreach( $_SESSION['recoveryLogins'] AS $handler )
{
$logins[] = \IPS\Login\LoginAbstract::constructFromData( \IPS\Db::i()->select( '*', 'core_login_handlers', array( "login_key=?", $handler ) )->first() );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'recovery_mode' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->recovery( $apps, $plugins, $theme, $logins );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->recovery( $apps, $plugins, $theme );
}
}
@@ -175,6 +175,9 @@ class _support extends \IPS\Dispatcher\Controller
/* Reset theme maps to make sure bad data hasn't been cached by visits mid-setup */
foreach( \IPS\Theme::themes() as $id => $set )
{
/* Invalidate template disk cache */
$set->cache_key = md5( microtime() . mt_rand( 0, 1000 ) );
/* Update mappings */
$set->css_map = array();
$set->save();
@@ -536,9 +539,7 @@ class _support extends \IPS\Dispatcher\Controller
'toolbars' => \IPS\Settings::i()->ckeditor_toolbars,
);
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => '' ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => '', 'ckeditor_toolbars' => '' ) );
$restoredEditor = TRUE;
}
@@ -632,9 +633,7 @@ class _support extends \IPS\Dispatcher\Controller
{
$editorConfigutation = \IPS\Data\Store::i()->editorConfiguationToRestore;
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $editorConfigutation['extraPlugins'] ), array( 'conf_key=?', 'ckeditor_extraPlugins' ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $editorConfigutation['toolbars'] ), array( 'conf_key=?', 'ckeditor_toolbars' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ckeditor_extraPlugins' => $editorConfigutation['extraPlugins'], 'ckeditor_toolbars' => $editorConfigutation['toolbars'] ) );
unset( \IPS\Data\Store::i()->editorConfiguationToRestore );
}
@@ -84,7 +84,8 @@ class _systemLogs extends \IPS\Dispatcher\Controller
$table->langPrefix = 'log_';
$table->include = array( 'time', 'category', 'message' );
$table->parsers = array(
'message' => function( $val, $row ) {
'message' => function( $val, $row )
{
if ( mb_strlen( $val ) > 100 )
{
$val = mb_substr( $val, 0, 100 ) . '...';
@@ -94,15 +95,17 @@ class _systemLogs extends \IPS\Dispatcher\Controller
$val = "{$row['exception_class']} ({$row['exception_code']})\n{$val}";
}
$val = htmlspecialchars( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$val = htmlspecialchars( $val, ENT_DISALLOWED, 'UTF-8', FALSE );
return $val;
},
'time' => function( $val ) {
'time' => function( $val )
{
return \IPS\DateTime::ts( $val );
},
'member_id' => function ( $val ){
return \IPS\Member::load( $val )->name;
'member_id' => function ( $val )
{
return htmlspecialchars( \IPS\Member::load( $val )->name, ENT_DISALLOWED, 'UTF-8', FALSE );
}
);
$table->sortBy = $table->sortBy ?: 'time';
@@ -234,7 +237,8 @@ class _systemLogs extends \IPS\Dispatcher\Controller
$table = new \IPS\Helpers\Table\Custom( $source, \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ) );
$table->langPrefix = 'log_';
$table->parsers = array(
'time' => function( $val ) {
'time' => function( $val )
{
return \IPS\DateTime::ts( $val );
}
);
@@ -43,7 +43,7 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter');
/* Check it isn't utf8mb4 already */
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') )
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') === TRUE)
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global', 'core')->message( 'utf8mb4_converter_finished', 'success' );
return;
@@ -74,7 +74,7 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
{
$form = new \IPS\Helpers\Form( 'utf8mb4_converter_intro', 'continue' );
$form->hiddenValues['continue'] = 1;
$form->addMessage( 'utf8mb4_converter_explain' );
$form->addMessage( \IPS\CIC ? 'utf8mb4_converter_cic_explain' : 'utf8mb4_converter_explain' );
if ( $form->values() )
{
@@ -233,7 +233,7 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
}
/* If this is the search index table, initiate rebuild now. */
if( $table == 'core_search_index' )
if( $table == 'core_search_index' and \IPS\Settings::i()->search_method == 'mysql' )
{
\IPS\Content\Search\Index::i()->rebuild();
}
@@ -89,6 +89,12 @@ class _ajax extends \IPS\core\modules\front\system\ajax
$keywords[ $word['url'] ]['keywords'][] = $word['keyword'];
}
/* Make sure the keywords are unique */
foreach( $keywords as $url => $entry )
{
$keywords[ $url ]['keywords'] = array_unique( $entry['keywords'] );
}
\file_put_contents( \IPS\ROOT_PATH . "/applications/{$qs['app']}/data/acpsearch.json", json_encode( $keywords, version_compare( PHP_VERSION, '5.4.0' ) >= 0 ? JSON_PRETTY_PRINT : 0 ) );
}
@@ -28,40 +28,49 @@ class _login extends \IPS\Dispatcher\Controller
* @return void
*/
protected function manage()
{
{
/* Init login class */
$url = \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'admin', NULL, array(), \IPS\Settings::i()->logins_over_https );
$url = \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'admin' );
if ( isset( \IPS\Request::i()->ref ) )
{
$url = $url->setQueryString( 'ref', \IPS\Request::i()->ref );
}
$login = new \IPS\Login( $url );
$login->flagOptions = FALSE;
$login = new \IPS\Login( $url, \IPS\Login::LOGIN_ACP );
/* Set the default tab */
$forms = $login->forms( TRUE, ( \IPS\Request::i()->ref ?: TRUE ) );
$this->activeTab = \IPS\Request::i()->tab ?: key($forms);
/* Process */
/* Authenticate */
$error = NULL;
try
{
/* Authenticate */
$member = $login->authenticate();
if ( $member !== NULL and $member->member_id )
/* If we were successful... */
if ( $success = $login->authenticate() )
{
/* Success */
if ( $member->isAdmin() )
/* Check we can actually access the ACP */
if ( $success->member->isAdmin() )
{
$this->_doLogin( $member );
/* If we need to do two-factor authentication, do that */
if ( $success->mfa( 'AuthenticateAdmin' ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id );
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=mfa', 'admin', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
{
$url = $url->setQueryString( 'ref', \IPS\Request::i()->ref );
}
if ( isset( \IPS\Request::i()->auth ) )
{
$url = $url->setQueryString( 'auth', \IPS\Request::i()->auth );
}
\IPS\Output::i()->redirect( $url );
}
/* Otherwise go ahead */
$this->_doLogin( $success->member );
}
/* Error */
/* ... otherwise show an error */
else
{
$error = 'no_access_cp';
/* Log */
$this->log( 'fail' );
}
}
@@ -69,11 +78,10 @@ class _login extends \IPS\Dispatcher\Controller
catch ( \IPS\Login\Exception $e )
{
$error = $e->getMessage();
/* Log */
$this->log( 'fail' );
}
/* Have we been sent here because of an IP address mismatch? */
if ( is_null( $error ) AND isset( \IPS\Request::i()->error ) )
{
switch( \IPS\Request::i()->error )
@@ -87,16 +95,8 @@ class _login extends \IPS\Dispatcher\Controller
break;
}
}
/* Get icons */
$icons = array();
$haveStandard = FALSE;
foreach ( \IPS\Login::handlers() as $key => $handler )
{
$icons[ $key ] = $handler::$icon;
}
/* Do we need an error? */
/* Do we need to show a message about an unfinished upgrade? */
$upgradeError = FALSE;
if ( !\IPS\IN_DEV and !isset( \IPS\Request::i()->noWarning ) )
{
@@ -109,7 +109,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Display Login Form */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_system.js', 'core', 'admin' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/login.css', 'core', 'admin' ) );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->login( $forms, $this->activeTab, $error, $icons, $upgradeError ) );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->login( $login, $error, $upgradeError ) );
}
/**
@@ -203,6 +203,9 @@ class _login extends \IPS\Dispatcher\Controller
}
}
/* Set the cookie */
\IPS\Request::i()->setCookie( 'acp_login_key', \IPS\Session::i()->cookieKey );
/* Boink - if we're in recovery mode, go there */
if ( \IPS\RECOVERY_MODE === TRUE )
{
@@ -252,4 +255,5 @@ class _login extends \IPS\Dispatcher\Controller
\IPS\Db::i()->insert( 'core_admin_login_logs', $save );
}
}
@@ -21,7 +21,12 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
* upgrade
*/
class _upgrade extends \IPS\Dispatcher\Controller
{
{
/**
* @brief IPS clientArea Password
*/
protected $_clientAreaPassword;
/**
* Manage
*
@@ -29,10 +34,8 @@ class _upgrade extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
protected function manage()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'upgrade_manage' );
\IPS\Dispatcher::i()->checkAcpPermission( 'upgrade_manage', 'core', 'overview' );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( "http://ipbmafia.ru/files/file/1560-ips-community-suite-41-nulled/" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( "http://ipbmafia.ru/files/file/2134-invision-community-42-nulled/" ) );
}
}
@@ -60,6 +60,10 @@ class _directory extends \IPS\Dispatcher\Controller
protected function manage()
{
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' );
if ( isset( \IPS\Request::i()->view ) and in_array( \IPS\Request::i()->view, array( 'grid', 'list' ) ) )
{
$baseUrl = $baseUrl->setQueryString( 'view', \IPS\Request::i()->view );
}
/* All Clubs: Sort */
$sortOption = \IPS\Settings::i()->clubs_default_sort;
@@ -71,11 +75,25 @@ class _directory extends \IPS\Dispatcher\Controller
/* All Clubs: Filters */
$filters = array();
$mineOnly = FALSE;
$extraWhere = NULL;
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter === 'mine' )
{
$mineOnly = TRUE;
$baseUrl = $baseUrl->setQueryString( 'filter', 'mine' );
}
if ( isset( \IPS\Request::i()->type ) and in_array( \IPS\Request::i()->type, array( 'free', 'paid' ) ) )
{
$baseUrl = $baseUrl->setQueryString( 'type', \IPS\Request::i()->type );
if ( \IPS\Request::i()->type === 'free' )
{
$extraWhere[] = array( 'fee IS NULL' );
}
else
{
$extraWhere[] = array( 'fee IS NOT NULL' );
}
}
foreach ( \IPS\Member\Club\CustomField::fields() as $field )
{
$k = "f{$field->id}";
@@ -100,7 +118,14 @@ class _directory extends \IPS\Dispatcher\Controller
{
if ( isset( $options[ $id ] ) )
{
$filters[ $field->id ][ $id ] = $options[ $id ];
if( $field->type == 'CheckboxSet' )
{
$filters[ $field->id ][ $id ] = $id;
}
else
{
$filters[ $field->id ][ $id ] = $options[ $id ];
}
}
}
$baseUrl = $baseUrl->setQueryString( 'f' . $field->id, array_keys( $filters[ $field->id ] ) );
@@ -116,8 +141,8 @@ class _directory extends \IPS\Dispatcher\Controller
/* Get All Clubs */
$perPage = 24;
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), $sortOption, $mineOnly, $filters );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $allClubs->count( TRUE ) / $perPage ), $page, $perPage );
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), $sortOption, $mineOnly, $filters, $extraWhere );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( ( is_object( $allClubs ) ? $allClubs->count( TRUE ) : 0 ) / $perPage ), $page, $perPage );
/* Get my clubs */
$myClubsActivity = NULL;
@@ -128,7 +153,7 @@ class _directory extends \IPS\Dispatcher\Controller
/* Build Map */
$mapMarkers = NULL;
if ( \IPS\Settings::i()->googlemaps and \IPS\Settings::i()->google_maps_api_key )
if ( \IPS\GeoLocation::enabled() )
{
$mapMarkers = array();
@@ -139,7 +164,7 @@ class _directory extends \IPS\Dispatcher\Controller
}
elseif ( !\IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$where[] = array( "( type<>? OR status IN('" . \IPS\Member\Club::STATUS_MEMBER . "','" . \IPS\Member\Club::STATUS_MODERATOR . "','" . \IPS\Member\Club::STATUS_LEADER . "') )", \IPS\Member\Club::TYPE_PRIVATE );
$where[] = array( "( type<>? OR status IN('" . \IPS\Member\Club::STATUS_MEMBER . "','" . \IPS\Member\Club::STATUS_MODERATOR . "','" . \IPS\Member\Club::STATUS_LEADER . "','" . \IPS\Member\Club::STATUS_EXPIRED . "','" . \IPS\Member\Club::STATUS_EXPIRED_MODERATOR . "') )", \IPS\Member\Club::TYPE_PRIVATE );
}
$select = \IPS\Db::i()->select( array( 'id', 'name', 'location_lat', 'location_long' ), 'core_clubs', $where );
@@ -164,8 +189,21 @@ class _directory extends \IPS\Dispatcher\Controller
}
/* Display */
$view = \IPS\Settings::i()->clubs_default_view;
if ( \IPS\Settings::i()->clubs_allow_view_change )
{
if ( isset( \IPS\Request::i()->view ) and in_array( \IPS\Request::i()->view, array( 'grid', 'list' ) ) )
{
\IPS\Request::i()->setCookie( 'clubs_view', \IPS\Request::i()->view, \IPS\DateTime::create()->add( new \DateInterval('P1Y' ) ) );
$view = \IPS\Request::i()->view;
}
elseif ( isset( \IPS\Request::i()->cookie['clubs_view'] ) and in_array( \IPS\Request::i()->cookie['clubs_view'], array( 'grid', 'list' ) ) )
{
$view = \IPS\Request::i()->cookie['clubs_view'];
}
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->directory( $featuredClubs, $allClubs, $pagination, $baseUrl, $sortOption, $myClubsActivity, $mapMarkers );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->directory( $featuredClubs, $allClubs, $pagination, $baseUrl, $sortOption, $myClubsActivity, $mapMarkers, $view );
}
/**
@@ -187,6 +225,15 @@ class _directory extends \IPS\Dispatcher\Controller
) ) ) );
}
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on )
{
$form->add( new \IPS\Helpers\Form\Radio( 'club_membership_fee', isset( \IPS\Request::i()->type ) ? \IPS\Request::i()->type : 'all', TRUE, array( 'options' => array(
'all' => 'all_clubs',
'free' => 'club_membership_free',
'paid' => 'club_membership_paid'
) ) ) );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
@@ -225,6 +272,11 @@ class _directory extends \IPS\Dispatcher\Controller
$url = $url->setQueryString( 'filter', 'mine' );
}
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on and $values['club_membership_fee'] !== 'all' )
{
$url = $url->setQueryString( 'type', $values['club_membership_fee'] );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
@@ -273,11 +325,14 @@ class _directory extends \IPS\Dispatcher\Controller
protected function create()
{
$availableTypes = array();
foreach ( explode( ',', \IPS\Member::loggedIn()->group['g_create_clubs'] ) as $type )
if ( \IPS\Member::loggedIn()->member_id ) // Guests can't create any type of clubs
{
if ( $type !== '' )
foreach ( explode( ',', \IPS\Member::loggedIn()->group['g_create_clubs'] ) as $type )
{
$availableTypes[ $type ] = 'club_type_' . $type;
if ( $type !== '' )
{
$availableTypes[ $type ] = 'club_type_' . $type;
}
}
}
if ( !$availableTypes )
@@ -285,6 +340,14 @@ class _directory extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( \IPS\Member::loggedIn()->member_id ? 'no_module_permission' : 'no_module_permission_guest', '2C349/1', 403, '' );
}
if ( \IPS\Member::loggedIn()->group['g_club_limit'] )
{
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', array( 'owner=?', \IPS\Member::loggedIn()->member_id ) )->first() >= \IPS\Member::loggedIn()->group['g_club_limit'] )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'too_many_clubs', FALSE, array( 'pluralize' => array( \IPS\Member::loggedIn()->group['g_club_limit'] ) ) ), '2C349/3', 403, '' );
}
}
$club = new \IPS\Member\Club;
if ( $form = $club->form( FALSE, TRUE, $availableTypes ) )
{
+473 -36
View File
@@ -105,6 +105,12 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*/
protected function manage()
{
/* Club info in sidebar */
if ( \IPS\Settings::i()->clubs_header == 'sidebar' )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'clubs', 'core' )->header( $this->club, NULL, 'sidebar' );
}
/* If this is a closed club, and we don't have permission to read it, show the member page instead */
if ( $this->club->type == \IPS\Member\Club::TYPE_CLOSED && !$this->club->canRead() )
{
@@ -113,7 +119,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get the activity stream */
$activity = \IPS\Content\Search\Query::init()->filterByClub( $this->club )->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_UPDATED )->search();
$activity = \IPS\Content\Search\Query::init()->filterByClub( $this->club )->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_CREATED )->search();
/* Get who joined the club in between those results */
if ( $this->club->type != \IPS\Member\Club::TYPE_PUBLIC )
@@ -121,7 +127,14 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$lastTime = NULL;
foreach ( $activity as $key => $result )
{
$lastTime = $result->createdDate->getTimestamp();
if ( $result !== NULL )
{
$lastTime = $result->createdDate->getTimestamp();
}
else
{
unset( $activity[ $key ] );
}
}
$joins = array();
$joinWhere = array( array( 'club_id=?', $this->club->id ), array( \IPS\Db::i()->in( 'status', array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) ) );
@@ -132,7 +145,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$select = 'core_clubs_memberships.joined' . ',' . implode( ',', array_map( function( $column ) {
return 'core_members.' . $column;
}, \IPS\Member::columnsForPhoto() ) );
foreach ( \IPS\Db::i()->select( $select, 'core_clubs_memberships', $joinWhere, 'joined DESC', NULL, NULL, NULL, \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS )->join( 'core_members', 'core_members.member_id=core_clubs_memberships.member_id' ) as $join )
foreach ( \IPS\Db::i()->select( $select, 'core_clubs_memberships', $joinWhere, 'joined DESC', array( 0, 50 ), NULL, NULL, \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS )->join( 'core_members', 'core_members.member_id=core_clubs_memberships.member_id' ) as $join )
{
$joins[] = new \IPS\Content\Search\Result\Custom(
\IPS\DateTime::ts( $join['core_clubs_memberships']['joined'] ),
@@ -144,7 +157,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Merge them in */
if ( !empty( $joins ) )
{
$activity = array_merge( iterator_to_array( $activity ), $joins );
$activity = array_filter( array_merge( iterator_to_array( $activity ), $joins ) );
uasort( $activity, function( $a, $b )
{
if ( $a->createdDate->getTimestamp() == $b->createdDate->getTimestamp() )
@@ -163,7 +176,8 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
}
/* Display */
/* Display */
\IPS\Output::i()->linkTags['canonical'] = (string) $this->club->url();
\IPS\Output::i()->title = $this->club->name;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->view( $this->club, $activity, $this->club->fieldValues() );
}
@@ -215,7 +229,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*/
protected function editPhoto()
{
if ( !( $this->club->owner and $this->club->owner == \IPS\Member::loggedIn() ) and !\IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
if ( !$this->club->isLeader() )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/R', 403, '' );
}
@@ -301,7 +315,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$form->add( new \IPS\Helpers\Form\Custom('photo_crop', array( 0, 0, $suggestedWidth, $suggestedHeight ), FALSE, array(
'getHtml' => function( $field ) use ( $original )
{
return \IPS\Theme::i()->getTemplate('profile')->photoCrop( $field->name, $field->value, $this->club->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
return \IPS\Theme::i()->getTemplate('members', 'core', 'global')->photoCrop( $field->name, $field->value, $this->club->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
}
) ) );
@@ -323,7 +337,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Save it */
$croppedFilename = mb_substr( $original->originalFilename, 0, mb_strrpos( $original->originalFilename, '.' ) ) . '.cropped' . mb_substr( $original->originalFilename, mb_strrpos( $original->originalFilename, '.' ) );
$cropped = \IPS\File::create( 'core_Profile', $original->originalFilename, (string) $image );
$cropped = \IPS\File::create( 'core_Clubs', $croppedFilename, (string) $image );
$this->club->profile_photo = (string) $cropped;
$this->club->save();
@@ -389,12 +403,21 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
break;
case \IPS\Member\Club::STATUS_WAITING_PAYMENT:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_WAITING_PAYMENT;
$statuses = array( \IPS\Member\Club::STATUS_WAITING_PAYMENT );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_WAITING_PAYMENT );
}
break;
case \IPS\Member\Club::STATUS_BANNED:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_BANNED;
$statuses = array( \IPS\Member\Club::STATUS_DECLINED, \IPS\Member\Club::STATUS_BANNED );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_REQUESTED );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_BANNED );
}
break;
@@ -402,10 +425,19 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_INVITED;
$statuses = array( \IPS\Member\Club::STATUS_INVITED );
$statuses = array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_INVITED );
}
break;
case \IPS\Member\Club::STATUS_EXPIRED:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_EXPIRED;
$statuses = array( \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_EXPIRED );
}
break;
}
}
@@ -420,11 +452,18 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Sort out the offset */
$perPage = 28;
$activePage = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
if( $activePage < 1 )
{
$activePage = 1;
}
$offset = ( $activePage - 1 ) * $perPage;
/* Fetch them */
$members = $this->club->members( $statuses, array( $offset, $perPage ), $orderByClause, $this->club->isLeader() ? 3 : 1 );
$members = $this->club->members( $statuses, array( $offset, $perPage ), $orderByClause, $this->club->isLeader() ? 5 : 1 );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $members->count(TRUE) / $perPage ), $activePage, $perPage );
/* Display */
@@ -434,9 +473,16 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
$staffStatuses = array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR );
if ( $this->club->isLeader( \IPS\Member::loggedIn() ) )
{
$staffStatuses[] = \IPS\Member\Club::STATUS_EXPIRED_MODERATOR;
}
$clubStaff = $this->club->members( $staffStatuses, NULL, "IF(core_clubs_memberships.status='leader',0,1), core_clubs_memberships.joined ASC", $this->club->isLeader( \IPS\Member::loggedIn() ) ? 5 : 3 );
\IPS\Output::i()->title = $this->club->name;
\IPS\Output::i()->breadcrumb[] = array( $this->club->url()->setQueryString( 'do', 'members' ), \IPS\Member::loggedIn()->language()->addToStack('club_members') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'clubs' )->members( $this->club, $members, $pagination, $sortBy, $filter );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'clubs' )->members( $this->club, $members, $pagination, $sortBy, $filter, $clubStaff );
}
}
@@ -464,7 +510,12 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Add them */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE, \IPS\Member::loggedIn(), NULL, TRUE );
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( $this->club->isPaid() and !isset( \IPS\Request::i()->waiveFee ) )
{
$status = \IPS\Member\Club::STATUS_WAITING_PAYMENT;
}
$this->club->addMember( $member, $status, TRUE, \IPS\Member::loggedIn(), NULL, TRUE );
$this->club->recountMembers();
/* Notify the member */
@@ -574,7 +625,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR ) ) )
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/7', 403, '' );
}
@@ -603,14 +654,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( $this->club->memberStatus( $member ) != \IPS\Member\Club::STATUS_LEADER )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -633,14 +697,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_LEADER ) ) )
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_LEADER ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/L', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MODERATOR;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED_MODERATOR;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MODERATOR, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -663,14 +740,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( $this->club->memberStatus( $member ) != \IPS\Member\Club::STATUS_MODERATOR )
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/N', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -695,17 +785,218 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
$status = $this->club->memberStatus( $member );
if ( !in_array( $status, array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) )
/* If this was just an invite, then just remove that */
if ( in_array( $status, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
if ( $this->club->owner and $this->club->owner->member_id === $member->member_id )
{
\IPS\Output::i()->error( 'club_cannot_remove_owner', '2C350/E', 403, '' );
$this->club->removeMember( $member );
\IPS\Db::i()->delete( 'core_notifications', array( 'member=? AND notification_app=? AND notification_key=? and item_id=?', $member->member_id, 'core', 'club_invitation', $this->club->id ) );
$member->recountNotifications();
}
/* Remove */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_BANNED, TRUE, \IPS\Member::loggedIn() );
/* If they were previously accepted and waiting for payment, treat it as a decline */
elseif ( in_array( $status, array( \IPS\Member\Club::STATUS_WAITING_PAYMENT ) ) )
{
/* Decline them */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_DECLINED, TRUE, \IPS\Member::loggedIn() );
/* Notify the member */
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_response', $this->club, array( $this->club, FALSE ) );
$notification->recipients->attach( $member );
$notification->send();
}
/* Otherwise check they are actually a member that can be removed */
else
{
if ( !in_array( $status, array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
if ( $this->club->owner and $this->club->owner->member_id === $member->member_id )
{
\IPS\Output::i()->error( 'club_cannot_remove_owner', '2C350/E', 403, '' );
}
/* Cancel purchase */
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::load( \IPS\Request::i()->member ), $this->club->id ) as $purchase )
{
$purchase->cancelled = TRUE;
$purchase->member->log( 'purchase', array( 'type' => 'cancel', 'id' => $purchase->id, 'name' => $purchase->name ) );
$purchase->can_reactivate = FALSE;
$purchase->save();
}
}
/* Remove */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_BANNED, TRUE, \IPS\Member::loggedIn() );
}
/* Recount */
$this->club->recountMembers();
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
}
/**
* Waive membership fee
*
* @return void
*/
protected function bypassPayment()
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() or !\IPS\Application::appIsEnabled('nexus') or !\IPS\Settings::i()->clubs_paid_on )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/W', 403, '' );
}
/* Get member */
$member = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
/* Do it */
switch ( $this->club->memberStatus( $member ) )
{
/* If they were waiting for payment, just go ahead and promote them to a member */
case \IPS\Member\Club::STATUS_WAITING_PAYMENT:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
break;
/* If they were already in the club, find their purchase and remove the expiry date */
case \IPS\Member\Club::STATUS_MEMBER:
case \IPS\Member\Club::STATUS_EXPIRED:
case \IPS\Member\Club::STATUS_MODERATOR:
case \IPS\Member\Club::STATUS_EXPIRED_MODERATOR:
case \IPS\Member\Club::STATUS_LEADER:
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
$extra = $purchase->extra;
$extra['originalExpire'] = $purchase->expire ? $purchase->expire->getTimestamp() : NULL;
$purchase->extra = $extra;
$purchase->expire = NULL;
$purchase->save();
$member->log( 'purchase', array( 'type' => 'info', 'info' => 'never_expire', 'id' => $purchase->id, 'name' => $purchase->name ) );
}
break;
/* If they have been invited, just change their status to invited bypassing payment */
case \IPS\Member\Club::STATUS_INVITED:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT, TRUE );
break;
/* For anything else, we can't do this... */
default:
\IPS\Output::i()->error( 'node_error', '2C350/X', 403, '' );
}
$this->club->recountMembers();
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
}
/**
* Restore Payment
*
* @return void
*/
protected function restorePayment()
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() or !\IPS\Application::appIsEnabled('nexus') or !\IPS\Settings::i()->clubs_paid_on )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/W', 403, '' );
}
/* Get member */
$member = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
/* Do it */
$status = $this->club->memberStatus( $member );
switch ( $status )
{
/* If they were already in the club, find their purchase and restore the expiry date */
case \IPS\Member\Club::STATUS_MEMBER:
case \IPS\Member\Club::STATUS_EXPIRED:
case \IPS\Member\Club::STATUS_MODERATOR:
case \IPS\Member\Club::STATUS_EXPIRED_MODERATOR:
case \IPS\Member\Club::STATUS_LEADER:
$foundPurchase = FALSE;
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
$foundPurchase = TRUE;
if ( !$purchase->renewals or !$purchase->renewals->cost->amount->isZero() )
{
$purchase->renewals = $this->club->renewalTerm( $purchase->renewal_currency ?: $member->defaultCurrency() );
}
if ( isset( $purchase->extra['originalExpire'] ) )
{
$newExpiry = \IPS\DateTime::ts( $purchase->extra['originalExpire'] );
}
else
{
$newExpiry = \IPS\DateTime::create()->add( $purchase->renewals->interval );
}
$purchase->expire = $newExpiry;
$purchase->save();
$member->log( 'purchase', array( 'type' => 'info', 'info' => 'restored_expire', 'id' => $purchase->id, 'name' => $purchase->name ) );
if ( $newExpiry->getTimestamp() < time() )
{
if ( $status === \IPS\Member\Club::STATUS_MEMBER )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_EXPIRED, TRUE );
}
elseif ( $status === \IPS\Member\Club::STATUS_MODERATOR )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR, TRUE );
}
}
else
{
if ( $status === \IPS\Member\Club::STATUS_EXPIRED )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
}
elseif ( $status === \IPS\Member\Club::STATUS_EXPIRED_MODERATOR )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MODERATOR, TRUE );
}
}
}
/* If we couldn't find a purchase, we'll have to remove them and re-invite them */
if ( !$foundPurchase )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_invitation', $this->club, array( $this->club, \IPS\Member::loggedIn() ), array( 'invitedBy' => \IPS\Member::loggedIn()->member_id ) );
$notification->recipients->attach( $member );
$notification->send();
}
break;
/* If they have been invited, just change their status to invited NOT bypassing payment */
case \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE );
break;
/* For anything else, we can't do this... */
default:
\IPS\Output::i()->error( 'node_error', '2C350/X', 403, '' );
}
$this->club->recountMembers();
/* Redirect */
@@ -729,11 +1020,55 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Session::i()->csrfCheck();
/* If this is an open club, or the member was invited, or they have mod access anyway go ahead and add them */
if ( $this->memberStatus === \IPS\Member\Club::STATUS_INVITED or $this->club->type === \IPS\Member\Club::TYPE_OPEN or \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
if ( in_array( $this->memberStatus, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT, \IPS\Member\Club::STATUS_WAITING_PAYMENT ) ) or $this->club->type === \IPS\Member\Club::TYPE_OPEN or \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$this->club->addMember( \IPS\Member::loggedIn(), \IPS\Member\Club::STATUS_MEMBER, TRUE, NULL, NULL, TRUE );
$this->club->recountMembers();
$notificationKey = 'club_join';
/* Unless they have to pay */
if ( $this->club->isPaid() and $this->memberStatus !== \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT )
{
if ( $fee = $this->club->joiningFee() )
{
/* Create the item */
$item = new \IPS\core\extensions\nexus\Item\ClubMembership( $this->club->name, $fee );
$item->id = $this->club->id;
try
{
$item->tax = \IPS\Settings::i()->clubs_paid_tax ? \IPS\nexus\Tax::load( \IPS\Settings::i()->clubs_paid_tax ) : NULL;
}
catch ( \OutOfRangeException $e ) { }
if ( \IPS\Settings::i()->clubs_paid_gateways )
{
$item->paymentMethodIds = explode( ',', \IPS\Settings::i()->clubs_paid_gateways );
}
$item->renewalTerm = $this->club->renewalTerm( $fee->currency );
$item->payTo = $this->club->owner;
$item->commission = \IPS\Settings::i()->clubs_paid_commission;
if ( $fees = \IPS\Settings::i()->clubs_paid_transfee and isset( $fees[ $fee->currency ] ) )
{
$item->fee = new \IPS\nexus\Money( $fees[ $fee->currency ]['amount'], $fee->currency );
}
/* Generate the invoice */
$invoice = new \IPS\nexus\Invoice;
$invoice->currency = $fee->currency;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice->addItem( $item );
$invoice->return_uri = "app=core&module=clubs&controller=view&id={$this->club->id}";
$invoice->save();
/* Take them to it */
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
}
else
{
\IPS\Output::i()->error( 'club_paid_unavailable', '1C350/N', 403, '' );
}
}
else
{
$this->club->addMember( \IPS\Member::loggedIn(), \IPS\Member\Club::STATUS_MEMBER, TRUE, NULL, NULL, TRUE );
$this->club->recountMembers();
$notificationKey = 'club_join';
}
}
/* Otherwise, add the request */
else
@@ -762,7 +1097,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
protected function leave()
{
/* Can we leave? */
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) or ( $this->club->owner and $this->club->owner->member_id == \IPS\Member::loggedIn()->member_id ) )
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR, \IPS\Member\Club::STATUS_WAITING_PAYMENT, \IPS\Member\Club::STATUS_INVITED ) ) or ( $this->club->owner and $this->club->owner->member_id == \IPS\Member::loggedIn()->member_id ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/S', 403, '' );
}
@@ -770,15 +1105,57 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Cancel purchase */
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::loggedIn(), $this->club->id ) as $purchase )
{
$purchase->cancelled = TRUE;
$purchase->member->log( 'purchase', array( 'type' => 'cancel', 'id' => $purchase->id, 'name' => $purchase->name ) );
$purchase->can_reactivate = FALSE;
$purchase->save();
}
}
/* Leave */
$this->club->removeMember( \IPS\Member::loggedIn() );
$this->club->recountMembers();
$this->club->save();
/* Delete the invitation */
\IPS\Db::i()->delete( 'core_notifications', array( 'member=? AND notification_app=? AND notification_key=? and item_id=?', \IPS\Member::loggedIn()->member_id, 'core', 'club_invitation', $this->club->id ) );
\IPS\Member::loggedIn()->recountNotifications();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ) );
}
/**
* Renew
*
* @return void
*/
protected function renew()
{
/* Can we renew? */
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/Y', 403, '' );
}
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Find the purchase */
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::loggedIn(), $this->club->id ) as $purchase )
{
\IPS\Output::i()->redirect( $purchase->url()->setQueryString( array( 'do' => 'renew', 'cycles' => 1 ) )->csrf() );
}
/* Couldn't find it? */
\IPS\Output::i()->error( 'no_module_permission', '2C350/Z', 500, '' );
}
/**
* Invite Members
*
@@ -794,9 +1171,23 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$form = new \IPS\Helpers\Form( 'form', 'club_send_invitations' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Member( 'members', NULL, TRUE, array( 'multiple' => NULL ) ) );
if ( $this->club->isPaid() and $this->club->isLeader() )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'club_invite_waive_fee', FALSE ) );
if ( $this->club->renewal_price )
{
\IPS\Member::loggedIn()->language()->words['club_invite_waive_fee_desc'] = \IPS\Member::loggedIn()->language()->addToStack('club_invite_waive_fee_renewal');
}
}
if ( $values = $form->values() )
{
$status = \IPS\Member\Club::STATUS_INVITED;
if ( $this->club->isPaid() and $this->club->isLeader() and $values['club_invite_waive_fee'] )
{
$status = \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT;
}
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_invitation', $this->club, array( $this->club, \IPS\Member::loggedIn() ), array( 'invitedBy' => \IPS\Member::loggedIn()->member_id ) );
foreach ( $values['members'] as $member )
{
@@ -805,7 +1196,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$memberStatus = $this->club->memberStatus( $member );
if ( !$memberStatus or in_array( $memberStatus, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_REQUESTED, \IPS\Member\Club::STATUS_DECLINED, \IPS\Member\Club::STATUS_BANNED ) ) )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$this->club->addMember( $member, $status, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$notification->recipients->attach( $member );
}
}
@@ -999,6 +1390,52 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->output = \IPS\Request::i()->isAjax() ? $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) ) : $form;
}
/**
* Delete a node
*
* @return void
*/
protected function nodeDelete()
{
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/AA', 403, '' );
}
/* Load */
$class = \IPS\Request::i()->type;
try
{
$node = $class::load( \IPS\Request::i()->node );
$club = $node->club();
if ( !$club or $club->id !== $this->club->id )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2C350/AB', 404, '' );
}
/* Permission check */
$itemClass = $node::$contentItemClass;
if ( !$node->modPermission( 'delete', \IPS\Member::loggedIn() ) and $itemClass::contentCount( $node, TRUE, TRUE, TRUE, 1 ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/AC', 403, '' );
}
/* Delete */
\IPS\Db::i()->delete( 'core_clubs_node_map', array( 'club_id=? AND node_class=? AND node_id=?', $club->id, $class, $node->_id ) );
$node->deleteOrMoveFormSubmit( array() );
/* Redirect */
\IPS\Output::i()->redirect( $club->url() );
}
/* !Cover Photo */
/**
@@ -31,7 +31,7 @@ class _contact extends \IPS\Dispatcher\Controller
{
if ( !\IPS\Member::loggedIn()->canUseContactUs() )
{
\IPS\Output::i()->error( 'no_permission', '2S333/1', 403, '' );
\IPS\Output::i()->error( 'no_module_permission', '2S333/1', 403, '' );
}
/* Execute */
@@ -100,15 +100,4 @@ class _contact extends \IPS\Dispatcher\Controller
}
}
/**
* Can Use Contact Us
*
* @return bool
* @deprecated 4.3
*/
public static function canUseContactUs()
{
return \IPS\Member::loggedIn()->canUseContactUs();
}
}
@@ -145,7 +145,7 @@ class _popular extends \IPS\Dispatcher\Controller
$table->sortDirection = $table->sortDirection ?: 'DESC';
/* Like or what? */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
if ( \IPS\Content\Reaction::isLikeMode() )
{
\IPS\Member::loggedIn()->language()->words['leader_rep_total'] = \IPS\Member::loggedIn()->language()->addToStack( 'leader_rep_total_likes' );
\IPS\Member::loggedIn()->language()->words['leaderboard_history__desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_desc', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_likes') ) ) );
@@ -202,7 +202,7 @@ class _popular extends \IPS\Dispatcher\Controller
$endDate = \IPS\DateTime::ts( time() )->setTimezone( $timezone );
$firstRepDate = \IPS\Db::i()->select( 'MIN(rep_date)', 'core_reputation_index' )->first();
$firstIndexDate = \IPS\Db::i()->select( 'MIN(index_date_updated)', 'core_search_index' )->first();
$firstIndexDate = \IPS\Content\Search\Index::i()->firstIndexDate();
$appWhere = null;
$descApp = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_in_all_apps' );
@@ -320,13 +320,14 @@ class _popular extends \IPS\Dispatcher\Controller
}
}
/* Got an app? */
$appWhere = '';
/* Do we want results for a specific app */
$customApp = FALSE;
if ( isset( \IPS\Request::i()->in ) and isset( $areas[ \IPS\Request::i()->in ] ) )
{
$appWhere = " AND rep_class='" . \IPS\Db::i()->escape_string( $areas[ \IPS\Request::i()->in ][ 0 ] ) . "'";
$descApp = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_in_app', NULL, array( 'sprintf' => array( $areas[ \IPS\Request::i()->in ][ 1 ] ) ) );
$customApp = TRUE;
}
else
{
@@ -341,7 +342,7 @@ class _popular extends \IPS\Dispatcher\Controller
$storeKey = NULL;
$hashes = NULL;
if ( ! $customStart and ! $customEnd AND ! $appWhere )
if ( ! $customStart and ! $customEnd AND ! $customApp )
{
$storeKey = 'leaderHashes_' . \IPS\Request::i()->time . '-' . md5( implode( ',', \IPS\Member::loggedIn()->groups ) );
@@ -368,9 +369,9 @@ class _popular extends \IPS\Dispatcher\Controller
/* Get rep hashes */
$inner = \IPS\Db::i()->select( 'class_type_id_hash, SUM(rep_rating) as total_rep', array( 'core_reputation_index', 'x' ), array( 'rep_date BETWEEN ' . $date->getTimeStamp() . ' AND ' . $endDate->getTimeStamp() . $appWhere ), NULL, NULL, 'class_type_id_hash' );
$repHashes = iterator_to_array( \IPS\Db::i()->select( 'class_type_id_hash, total_rep', $inner, NULL, 'x.total_rep desc', array( 0, 500 ) )->setKeyField('class_type_id_hash') );
/* Now filter through permissions */
$searchHashes = iterator_to_array( \IPS\Db::i()->select( 'index_class_type_id_hash', array( 'core_search_index', 'si' ), array( array( "( si.index_permissions = '*' OR " . \IPS\Db::i()->findInSet( 'si.index_permissions', \IPS\Member::loggedIn()->groups ) . ' AND si.index_hidden=0 )' ), array( \IPS\Db::i()->in( 'si.index_class_type_id_hash', array_keys( $repHashes ) ) ) ) )->setKeyField('index_class_type_id_hash') );
$searchHashes = \IPS\Content\Search\Index::i()->hashesWithPermission( array_keys( $repHashes ), \IPS\Member::loggedIn() );
/* Filter out rep hashes not in search results */
$hashes = array_slice( array_intersect_key( $repHashes, $searchHashes ), 0, 50 );
@@ -386,7 +387,7 @@ class _popular extends \IPS\Dispatcher\Controller
$or = array();
$results = array();
$preLoadMembers = array();
if ( count( $hashes ) )
{
/* Now get the reputation data */
@@ -395,25 +396,15 @@ class _popular extends \IPS\Dispatcher\Controller
$data['total_rep'] = $hashes[ $data['class_type_id_hash'] ]['total_rep'];
$repData[ $data['rep_class'] . '-' . $data['type_id'] ] = $data;
$classes[ $data['rep_class'] ][] = $data['type_id'];
if ( ! empty( $data['member_id'] ) )
{
$preLoadMembers[] = $data['member_id'];
}
}
foreach( $classes as $class => $ids )
{
$or[] = '( index_class=\'' . \IPS\Db::i()->escape_string( $class ) . '\' AND ' . \IPS\Db::i()->in( 'index_object_id', $ids ) . ')';
$or[] = \IPS\Content\Search\ContentFilter::init( $class )->onlyInIds( $ids );
}
/* Construct the query */
$query = \IPS\Db::i()->select( '*', array( 'core_search_index', 'main' ), array( implode( ' OR ', $or ) ), NULL, NULL, NULL, NULL );
$array = iterator_to_array( $query );
$sorted = array();
/* Manually sort */
/* Query and manually sort */
$array = \IPS\Content\Search\Query::init()->filterByContent( $or )->search()->getArrayCopy();
foreach( $array as $index => $data )
{
if ( isset( $repData[ $data['index_class'] . '-' . $data['index_object_id'] ] ) )
@@ -433,8 +424,13 @@ class _popular extends \IPS\Dispatcher\Controller
/* Get top rated contributors */
$topContributors = array();
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', array( 'member_received>0 ' . $appWhere . ' and rep_date BETWEEN ' . intval( $date->getTimeStamp() ) . ' AND ' . intval( $endDate->getTimeStamp() ) ), NULL, NULL, 'member' );
$innerQueryWhere = array();
$innerQueryWhere[] = array( 'member_received>0 ' . $appWhere . ' and rep_date BETWEEN ' . intval( $date->getTimeStamp() ) . ' AND ' . intval( $endDate->getTimeStamp() ) );
$innerQueryWhere[] = \IPS\Db::i()->in( 'member_group_id', \IPS\Settings::i()->leaderboard_excluded_groups, TRUE );
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', $innerQueryWhere, NULL, NULL, 'member' )->join( 'core_members', array( 'core_reputation_index.member_received = core_members.member_id' ) );
foreach( \IPS\Db::i()->select( 'member, rep', array( $innerQuery, 'in' ), NULL, 'rep DESC', 4 )->setKeyField('member')->setValueField('rep') as $member => $rep )
{
$topContributors[ $member ] = $rep;
@@ -455,7 +451,7 @@ class _popular extends \IPS\Dispatcher\Controller
}
/* Work out the description for popular content */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
if ( \IPS\Content\Reaction::isLikeMode() )
{
$popularResultsSingle = 'popular_results_single_desc';
$popularResultsMany = 'popular_results_desc';
@@ -481,6 +477,12 @@ class _popular extends \IPS\Dispatcher\Controller
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=leaderboard", 'front', 'leaderboard_leaderboard' );
/* If there are no results tell search engines not to index the page */
if( !count( $results ) )
{
\IPS\Output::i()->metaTags['robots'] = 'noindex';
}
/* Display */
return \IPS\Theme::i()->getTemplate('popular')->popularWrapper( $results, $areas, $topContributors, $dates, $description, $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) ), $tzOffsetDifference );
}
@@ -5,7 +5,6 @@
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 13 Oct 2016
*/
@@ -39,7 +39,8 @@ class _streams extends \IPS\Dispatcher\Controller
/* Necessary CSS/JS */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_streams.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_statuses.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
@@ -121,7 +122,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( array(
'url' => $defaultStream->url(),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ),
'tooltip' => $defaultStream->_title, // We need to pass this individually for the tooltip that shows, but the JS itself will escape any entities
'id' => $defaultStream->_id
) );
@@ -166,7 +167,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( array(
'url' => \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ),
'id' => $defaultStream->_id
) );
}
@@ -187,7 +188,13 @@ class _streams extends \IPS\Dispatcher\Controller
/* but only if we haven't submitted the form on this request */
if( !\IPS\Request::i()->stream_submitted )
{
$streamFields = array( 'include_comments', 'classes', 'clubs', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' );
$streamFields = array( 'include_comments', 'classes', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' );
/* Clubs enabled? */
if( \IPS\Settings::i()->clubs )
{
$streamFields[] = 'clubs';
}
/* Build and format field values */
$_values = array();
@@ -379,7 +386,7 @@ class _streams extends \IPS\Dispatcher\Controller
$output = \IPS\Theme::i()->getTemplate('streams')->streamItems( $results, TRUE, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
$return = array(
'title' => htmlspecialchars( $stream->_title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $stream->_title, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'blurb' => $stream->blurb(),
'config' => json_encode( $stream->config() ),
'count' => count( $results ),
@@ -484,7 +491,7 @@ class _streams extends \IPS\Dispatcher\Controller
if ( $stream->member != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_permission', '2C280/8', 403, '' );
\IPS\Output::i()->error( 'no_module_permission', '2C280/8', 403, '' );
}
$form = new \IPS\Helpers\Form;
@@ -599,7 +606,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
$url = $stream ? $stream->baseUrl->setQueryString( 'className', $class ) : \IPS\Request::i()->url()->setQueryString( 'className', $class );
$containerClass = $class::$containerNodeClass;
$field = new \IPS\Helpers\Form\Node( 'stream_containers_' . $class::$title, isset( $currentContainers[ $class ] ) ? $currentContainers[ $class ] : array(), NULL, array( 'url' => $url, 'class' => $class::$containerNodeClass, 'multiple' => TRUE, 'permissionCheck' => $containerClass::searchableNodesPermission(), 'clubs' => \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) ), NULL, NULL, NULL, 'stream_containers_' . $class::$title );
$field = new \IPS\Helpers\Form\Node( 'stream_containers_' . $class::$title, isset( $currentContainers[ $class ] ) ? $currentContainers[ $class ] : array(), NULL, array( 'url' => $url, 'class' => $class::$containerNodeClass, 'multiple' => TRUE, 'permissionCheck' => $containerClass::searchableNodesPermission(), 'clubs' => ( \IPS\Settings::i()->clubs AND \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) ) ), NULL, NULL, NULL, 'stream_containers_' . $class::$title );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( 'stream_narrow_by_container_label', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $containerClass::$nodeTitle ) ) ) );
return \IPS\Output::i()->json( array( 'node' => \IPS\Theme::i()->getTemplate('streams')->filterFormContentTypeContent( $field, $class, \IPS\Request::i()->key ) ) );
@@ -616,6 +623,11 @@ class _streams extends \IPS\Dispatcher\Controller
*/
protected function getClubElement()
{
if( !\IPS\Settings::i()->clubs )
{
return \IPS\Output::i()->json( array( 'field' => '' ) );
}
$clubOptions = array();
foreach ( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE ) as $club )
{
@@ -681,25 +693,48 @@ class _streams extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* As the node container form elements are not in the actual form, we need to work some magic. And by magic, I do mean a sort of hacky thing. */
foreach ( \IPS\Request::i() as $k => $v )
/* As the node container form elements are not in the actual form, we need to work some magic.
And by magic, I do mean a sort of hacky thing. First, if we are editing a stream, we need to get our existing stream filters
and put these into an array. Then we loop over the input and overwrite the existing filters with what was submitted. If the user
never loaded the container filters we'll retain what we had (expected) but if they did and adjusted or removed container filters
then we'll update with what they submitted (expected).
*/
if( $stream->id )
{
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' and $v )
$currentContainers = $stream->containers ? json_decode( $stream->containers, TRUE ) : array();
foreach( $currentContainers as $class => $containers )
{
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
$values['stream_containers_' . $class::$title ] = array_combine( $containers, $containers );
}
}
foreach ( \IPS\Request::i() as $k => $v )
{
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' )
{
if( $v )
{
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
}
elseif( isset( $values[ $k ] ) )
{
$values[ $k ] = NULL;
}
}
}
/* Update only */
if ( isset( \IPS\Request::i()->updateOnly ) )
{
$formattedValues = $stream->formatFormValues( $values );
foreach ( array( 'include_comments', 'classes', 'containers', 'clubs', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' ) as $k )
{
$requestKey = 'stream_' . $k;
if ( isset( $formattedValues[ $k ] ) AND $stream->$k != $formattedValues[ $k ] )
if ( array_key_exists( $k, $formattedValues ) AND $stream->$k != $formattedValues[ $k ] )
{
$stream->$k = $formattedValues[ $k ];
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_' . $k, \IPS\Request::i()->$requestKey );
@@ -50,6 +50,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_profile.js', 'core' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_statuses.js', 'core' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_core.js', 'core', 'global' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/profiles.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/leaderboard.css' ) );
@@ -57,7 +58,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/profiles_responsive.css' ) );
}
}
}
/* Go */
@@ -103,9 +104,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$canAccessStatuses = $canAccessSingleStatuses and ( $this->member->pp_setting_count_comments or \IPS\Member::loggedIn()->member_id == $this->member->member_id );
/* Are we loading a different page of comments? */
if ( \IPS\Request::i()->status && \IPS\Request::i()->isAjax() && \IPS\Request::i()->page && $canAccessStatuses )
if ( \IPS\Request::i()->status && \IPS\Request::i()->isAjax() && \IPS\Request::i()->page && $canAccessStatuses && !isset( \IPS\Request::i()->getUploader ) )
{
$status = \IPS\core\Statuses\Status::loadAndCheckPerms( \IPS\Request::i()->status );
try
{
$status = \IPS\core\Statuses\Status::loadAndCheckPerms( \IPS\Request::i()->status );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C138/M', 404, '' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'statuses' )->statusReplies( $status );
return;
}
@@ -167,11 +176,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
/* What tabs are available? */
$tabs = array( 'activity' => 'users_activity_feed' );
if ( \IPS\Settings::i()->clubs )
if ( \IPS\Settings::i()->clubs and count( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'created', $this->member ) ) )
{
$tabs['clubs'] = 'users_clubs';
}
@@ -279,7 +287,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$perPage = 24;
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), 'last_activity', $this->member );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $allClubs->count( TRUE ) / $perPage ), $page, $perPage );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ( ceil( is_object( $allClubs ) ? $allClubs->count( TRUE ) : 0 ) / $perPage ), $page, $perPage );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/clubs.css', 'core', 'front' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
@@ -376,7 +384,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
'@context' => "http://schema.org",
'@type' => "ProfilePage",
'url' => (string) $this->member->url(),
'name' => htmlspecialchars( $this->member->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'name' => $this->member->name,
'primaryImageOfPage' => array(
'@type' => "ImageObject",
'contentUrl' => (string) $this->member->get_photo(),
@@ -403,7 +411,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
),
),
);
\IPS\Output::i()->linkTags['canonical'] = (string) $this->member->url();
/* Output */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_profile.js', 'core' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->profile( $this->member, $mainContent, $visitors, $sidebarFields, $followers, $addWarningUrl );
@@ -439,15 +449,13 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
foreach( $router->classes as $class )
{
if( !isset( $class::$includeInUserProfiles ) OR !$class::$includeInUserProfiles )
{
continue;
}
/* Add CSS for this app */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'profile.css', $class::$application ) );
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class;
if ( isset( $class::$databaseColumnMap['author'] ) )
{
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class;
}
$supportsComments = ( in_array( 'IPS\Content\Item', class_parents( $class ) ) and $class::supportsComments( \IPS\Member::loggedIn() ) );
if ( $supportsComments )
@@ -516,8 +524,16 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->setQueryString( 'page', $highestPage ?: 1 ), NULL, 303 );
}
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $this->member->url()->setQueryString( array( 'do' => 'content' ) ), ceil( $results->count( TRUE ) / $query->resultsToGet ), $page, $query->resultsToGet ) );
$output = \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination );
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $this->member->url()->setQueryString( array( 'do' => 'content', 'all_activity' => 1 ) ), ceil( $results->count( TRUE ) / $query->resultsToGet ), $page, $query->resultsToGet ) );
if ( \IPS\Request::i()->isAjax() AND \IPS\Request::i()->all_activity )
{
\IPS\Output::i()->json( array( 'rows' => \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination ) ) );
return;
}
else
{
$output = \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination );
}
}
else
{
@@ -667,9 +683,35 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
/* Get the reputation summary */
$reactions = array( 'given' => array(), 'received' => array() );
foreach( \IPS\Db::i()->select( 'reaction, COUNT(*) as count', 'core_reputation_index', array( 'member_id=?', $this->member->member_id ), NULL, NULL, 'reaction' ) as $reaction )
{
try
{
$object = \IPS\Content\Reaction::load( $reaction['reaction'] );
$reactions['given'][] = array( 'count' => $reaction['count'], 'reaction' => $object );
}
catch( \UnderflowException $e ){}
}
foreach( \IPS\Db::i()->select( 'reaction, COUNT(*) as count', 'core_reputation_index', array( 'member_received=?', $this->member->member_id ), NULL, NULL, 'reaction' ) as $reaction )
{
try
{
$object = \IPS\Content\Reaction::load( $reaction['reaction'] );
$reactions['received'][] = array( 'count' => $reaction['count'], 'reaction' => $object );
}
catch( \UnderflowException $e ){}
}
\IPS\Output::i()->title = ( $table->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'member_reputation_from', FALSE, array('sprintf' => $this->member->name ) ), $table->page ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'member_reputation_from', FALSE, array('sprintf' => $this->member->name ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userReputation( $this->member, $types, $currentAppModule, $currentType, (string) $table );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userReputation( $this->member, $types, $currentAppModule, $currentType, (string) $table, $reactions );
}
}
@@ -741,7 +783,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
$form = new \IPS\Helpers\Form( 'form', 'status_save' );
$form->class = 'ipsForm_vertical';
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$formElements = \IPS\core\Statuses\Status::formElements( $status );
$form->add( $formElements['status_content'] );
@@ -755,7 +797,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->redirect( $status->url() );
}
\IPS\Output::i()->output = $form;
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
catch ( \Exception $e )
{
@@ -763,6 +805,54 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
}
/**
* Edit Status Reply
*
* @return void
*/
protected function editStatusReply()
{
try
{
$reply = \IPS\core\Statuses\Reply::loadAndCheckPerms( \IPS\Request::i()->reply );
if ( !$reply->canEdit() )
{
throw new \DomainException;
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Editor( 'comment_value', $reply->content, TRUE, array(
'app' => 'core',
'key' => 'Members',
'autoSaveKey' => 'editComment-core/members-' . $reply->id,
'attachIds' => $reply->attachmentIds()
) ) );
if ( $values = $form->values() )
{
$reply->editContents( $values['comment_value'] );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $reply->html();
return;
}
else
{
\IPS\Output::i()->redirect( $reply->url() );
}
}
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
catch( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2C138/K', 404, '' );
}
}
/**
* Edit Profile
*
@@ -931,24 +1021,27 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->member_title = $values['member_title'];
}
if( $values['bday'] and ( ( $values['bday']['day'] and !$values['bday']['month'] ) or ( $values['bday']['month'] and !$values['bday']['day'] ) ) )
if( isset( $values['bday'] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'bday_month_and_day_required' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editContentForm( \IPS\Member::loggedIn()->language()->addToStack( 'profile_edit' ), $form );
return;
}
if( $values['bday'] and ( ( $values['bday']['day'] and !$values['bday']['month'] ) or ( $values['bday']['month'] and !$values['bday']['day'] ) ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'bday_month_and_day_required' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editContentForm( \IPS\Member::loggedIn()->language()->addToStack( 'profile_edit' ), $form );
return;
}
if ( $values['bday'] and $values['bday']['day'] and $values['bday']['month'] )
{
$this->member->bday_day = $values['bday']['day'];
$this->member->bday_month = $values['bday']['month'];
$this->member->bday_year = $values['bday']['year'];
}
else
{
$this->member->bday_day = NULL;
$this->member->bday_month = NULL;
$this->member->bday_year = NULL;
if ( $values['bday'] and $values['bday']['day'] and $values['bday']['month'] )
{
$this->member->bday_day = $values['bday']['day'];
$this->member->bday_month = $values['bday']['month'];
$this->member->bday_year = $values['bday']['year'];
}
else
{
$this->member->bday_day = NULL;
$this->member->bday_month = NULL;
$this->member->bday_year = NULL;
}
}
if ( isset( $values['enable_status_updates'] ) )
@@ -980,14 +1073,21 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
$profileFields = array();
}
$profileFields['member_id'] = $this->member->member_id;
foreach ( \IPS\core\ProfileFields\Field::fields( $profileFields, \IPS\core\ProfileFields\Field::PROFILE ) as $group => $fields )
{
foreach ( $fields as $id => $field )
{
$profileFields[ "field_{$id}" ] = $field::stringValue( $values[ $field->name ] );
if ( $field instanceof \IPS\Helpers\Form\Upload )
{
$profileFields[ "field_{$id}" ] = (string) $values[ $field->name ];
}
else
{
$profileFields[ "field_{$id}" ] = $field::stringValue( $values[ $field->name ] );
}
if ( $field instanceof \IPS\Helpers\Form\Editor )
{
@@ -1076,17 +1176,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
}
/* ProfileSync (Facebook, etc.) */
foreach ( \IPS\core\ProfileSync\ProfileSyncAbstract::services() as $key => $class )
{
$obj = new $class( $this->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 ) ) ) );
}
}
/* And of course we can always not have a photo... except when we can't */
$photoRequired = FALSE;
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
@@ -1097,7 +1186,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
break;
}
}
if ( $photoRequired === FALSE )
{
$options['none'] = 'member_photo_none';
@@ -1116,7 +1204,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( $photoVars[0] )
{
$form->add( new \IPS\Helpers\Form\Upload( 'member_photo_upload', NULL, FALSE, array( 'image' => array( 'maxWidth' => $photoVars[1], 'maxHeight' => $photoVars[2] ), 'storageExtension' => 'core_Profile', 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL ), function( $val ) {
if ( $val instanceof \IPS\File )
{
$image = \IPS\Image::create( $val->contents() );
@@ -1128,7 +1215,16 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}, NULL, NULL, 'member_photo_upload' ) );
/* Create the URL */
$form->add( new \IPS\Helpers\Form\Url( 'member_photo_url', NULL, FALSE, array( 'file' => 'core_Profile', 'image' => TRUE, 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL, 'maxDimensions' => array( 'width' => $photoVars[1], 'height' => $photoVars[2] ) ), NULL, NULL, NULL, 'member_photo_url' ) );
$form->add( new \IPS\Helpers\Form\Url( 'member_photo_url', NULL, FALSE, array( 'file' => 'core_Profile', 'image' => TRUE, 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL, 'maxDimensions' => array( 'width' => $photoVars[1], 'height' => $photoVars[2] ) ), function( $val ) {
if ( $val instanceof \IPS\Http\Url )
{
$image = \IPS\Image::create( (string) $val->request()->get() );
if( $image->isAnimatedGif and !$this->member->group['g_upload_animated_photos'] )
{
throw new \DomainException('member_photo_upload_no_animated');
}
}
}, NULL, NULL, 'member_photo_url' ) );
}
/* Add additional elements */
@@ -1142,16 +1238,12 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
$this->member->pp_photo_type = $values['pp_photo_type'];
/* If we are changing our photo, it is safe to assume that any services currently set to sync should no longer do so */
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
if ( !empty( $services ) )
/* Disable syncing */
$profileSync = $this->member->profilesync;
if ( isset( $profileSync['photo'] ) )
{
foreach( $services AS $class )
{
$obj = new $class( $this->member );
$obj->save( array( 'profilesync_photo' => FALSE ) );
}
unset( $profileSync['photo'] );
$this->member->profilesync = $profileSync;
}
switch ( $values['pp_photo_type'] )
@@ -1197,14 +1289,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
case 'gravatar':
$this->member->pp_gravatar = ( !isset( $values['photo_gravatar_email_public'] ) or $values['photo_gravatar_email_public'] === $this->member->email ) ? NULL : $values['photo_gravatar_email_public'];
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( $this->member );
$obj->save( array( 'profilesync_photo' => TRUE ) );
}
}
/* Reset Profile Complete flag in case this was an optional step */
@@ -1212,6 +1296,15 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->save();
if ( $this->member->pp_photo_type )
{
$this->member->logHistory( 'core', 'photo', array( 'action' => 'new', 'type' => $this->member->pp_photo_type ) );
}
else
{
$this->member->logHistory( 'core', 'photo', array( 'action' => 'remove' ) );
}
if ( $this->member->pp_photo_type == 'custom' )
{
if ( \IPS\Request::i()->isAjax() )
@@ -1270,8 +1363,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get the photo */
$original = \IPS\File::get( 'core_Profile', $this->member->pp_main_photo );
$image = \IPS\Image::create( $original->contents() );
try
{
$original = \IPS\File::get( 'core_Profile', $this->member->pp_main_photo );
$image = \IPS\Image::create( $original->contents() );
}
catch( \Exception $e )
{
\IPS\Log::log( $e, 'crop_error' );
\IPS\Output::i()->error( 'no_photo_to_crop', '3C138/N', 404, '' );
}
/* Work out which dimensions to suggest */
if ( $image->width < $image->height )
@@ -1290,7 +1392,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$form->add( new \IPS\Helpers\Form\Custom('photo_crop', array( 0, 0, $suggestedWidth, $suggestedHeight ), FALSE, array(
'getHtml' => function( $field ) use ( $original, $member )
{
return \IPS\Theme::i()->getTemplate('profile')->photoCrop( $field->name, $field->value, $member->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
return \IPS\Theme::i()->getTemplate('members', 'core', 'global')->photoCrop( $field->name, $field->value, $member->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
}
) ) );
@@ -1328,7 +1430,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
catch ( \Exception $e )
{
$form->error = 'photo_crop_bad';
$form->error = \IPS\Member::loggedIn()->language()->addToStack('photo_crop_bad');
}
}
@@ -1485,7 +1587,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$tabs['all'] = \IPS\Member::loggedIn()->language()->addToStack('all');
foreach( \IPS\Content\Reaction::roots() AS $reaction )
{
$tabs[ $reaction->id ] = $reaction->_title;
if ($reaction->_enabled !== FALSE)
{
$tabs[$reaction->id] = $reaction->_title;
}
}
$activeTab = 'all';
@@ -1537,7 +1642,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( $canReport !== TRUE )
{
\IPS\Output::i()->error( 'generic_error', '1C138/6', 403, '' );
\IPS\Output::i()->error( $canReport, '1C138/6', 403, '' );
}
$form = new \IPS\Helpers\Form( NULL, 'report_submit' );
@@ -1613,23 +1718,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
* Set Cover Photo
*
* @param \IPS\Helpers\CoverPhoto $photo New Photo
* @param string $type 'new', 'remove', 'reposition'
* @return void
*/
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo )
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo, $type=NULL )
{
/* If we are changing our cover photo, it is safe to assume that any services currently set to sync should no longer do so */
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
if ( !empty( $services ) )
/* Disable syncing */
$profileSync = $this->member->profilesync;
if ( isset( $profileSync['cover'] ) )
{
foreach( $services AS $class )
{
$obj = new $class( $this->member );
if ( $obj->connected() )
{
$obj->save( array( 'profilesync_cover' => FALSE ) );
}
}
unset( $profileSync['cover'] );
$this->member->profilesync = $profileSync;
}
$this->member->pp_cover_photo = (string) $photo->file;
@@ -1639,6 +1738,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->members_bitoptions['profile_completed'] = FALSE;
$this->member->save();
if ( $type != 'reposition' )
{
$this->member->logHistory( 'core', 'coverphoto', array( 'action' => $type ) );
}
}
/**
@@ -232,9 +232,9 @@ class _messenger extends \IPS\Content\Controller
{
$where[] = array( 'core_message_topic_user_map.map_has_unread=1' );
}
/* Add a folder filter */
if ( isset( \IPS\Request::i()->folder ) or !is_null( $folder ) )
/* Add a folder filter, if we are not coming from the Messages menu */
if ( !isset( \IPS\Request::i()->_fromMenu ) )
{
if ( !is_null( $folder ) AND isset( $folders[ $folder ] ) )
{
@@ -252,6 +252,9 @@ class _messenger extends \IPS\Content\Controller
if ( \IPS\Request::i()->q )
{
/* Limit result set to prevent time outs */
$where[] = array( 'core_message_topic_user_map.map_last_topic_reply > ?', \IPS\DateTime::ts( time() )->sub( new \DateInterval( 'P1Y' ) )->getTimeStamp() );
$subQuery = \IPS\Db::i()->select( 'map_topic_id', array( 'core_message_topic_user_map', 'core_message_topic_user_map' ), $where );
$where = array( array( 'core_message_posts.msg_topic_id IN (?)', $subQuery ) );
$query = array();
@@ -283,7 +286,7 @@ class _messenger extends \IPS\Content\Controller
/* Get a count */
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_posts', $where, NULL, NULL, 'msg_topic_id' )
$count = \IPS\Db::i()->select( 'COUNT( DISTINCT(msg_topic_id) )', 'core_message_posts', array_merge( $where, array( array( 'core_message_topic_user_map.map_last_topic_reply > ?', \IPS\DateTime::ts( time() )->sub( new \DateInterval( 'P1Y' ) )->getTimeStamp() ) ) ) )
->join(
'core_message_topics',
'core_message_posts.msg_topic_id=core_message_topics.mt_id'
@@ -416,10 +419,17 @@ class _messenger extends \IPS\Content\Controller
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->conversation( $conversation, $folders );
}
elseif( \IPS\Request::i()->q )
{
\IPS\Output::i()->json( array(
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, FALSE, $folders ),
'pagination' => $pagination
) );
}
elseif( \IPS\Request::i()->overview )
{
\IPS\Output::i()->json( array(
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, TRUE, $folders ),
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, \IPS\Request::i()->_fromMenu ? FALSE : TRUE, $folders ),
'pagination' => $pagination,
'listBaseUrl' => $listUrl->setQueryString( array( 'sortBy' => \IPS\Request::i()->sortBy, 'filter' => \IPS\Request::i()->filter ) )->stripQueryString( 'id' )
) );
@@ -431,7 +441,7 @@ class _messenger extends \IPS\Content\Controller
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->template( $folder, $folders, $folderCounts, $conversations, $pagination, $conversation, $baseUrl, ( $conversation ? 'messenger_convo' : 'messenger' ), ( \IPS\Request::i()->sortBy ? htmlspecialchars( \IPS\Request::i()->sortBy, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ): 'mt_last_post_time' ), ( \IPS\Request::i()->filter ? htmlspecialchars( \IPS\Request::i()->filter, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : '' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->template( $folder, $folders, $folderCounts, $conversations, $pagination, $conversation, $baseUrl, ( $conversation ? 'messenger_convo' : 'messenger' ), ( \IPS\Request::i()->sortBy ? htmlspecialchars( \IPS\Request::i()->sortBy, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ): 'mt_last_post_time' ), ( \IPS\Request::i()->filter ? htmlspecialchars( \IPS\Request::i()->filter, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ) : '' ) );
}
}
@@ -459,8 +469,13 @@ class _messenger extends \IPS\Content\Controller
\IPS\Session::i()->csrfCheck();
$folders = json_decode( \IPS\Member::loggedIn()->pconversation_filters, TRUE );
array_walk( $folders, function( &$val )
{
$val = htmlspecialchars( $val, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8' );
} );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Select( 'move_message_to', NULL, FALSE, array( 'options' => array_merge( array( 'myconvo' => 'inbox' ), $folders ) ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'move_message_to', NULL, FALSE, array( 'options' => array_merge( array( 'myconvo' => \IPS\Member::loggedIn()->language()->addToStack('inbox') ), $folders ), 'parse' => 'normal' ) ) );
if ( $values = $form->values() )
{
@@ -742,6 +757,7 @@ class _messenger extends \IPS\Content\Controller
$ids[] = $member->member_id;
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'private_message_added', $conversation, array( $conversation, \IPS\Member::loggedIn() ) );
$notification->recipients->attach( $member );
$notification->send();
}
+38 -16
View File
@@ -22,6 +22,35 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _modcp extends \IPS\Dispatcher\Controller
{
/**
* Dispatcher looks for methods to match do param, which may exist in the extension files, so this method
* prevents dispatcher throwing a 2S106/1 and allows the extensions to use the values
*
* @param string $method Desired method
* @param array $args Arguments
* @return void
*/
public function __call( $method, $args )
{
if ( isset( \IPS\Request::i()->do ) )
{
$activeTab = \IPS\Request::i()->tab ?: 'overview';
foreach ( \IPS\Application::allExtensions( 'core', 'ModCp', TRUE ) as $key => $extension )
{
if( method_exists( $extension, 'getTab' ) and mb_strtolower( $extension->getTab() ) == mb_strtolower( $activeTab ) )
{
if ( method_exists( $extension, \IPS\Request::i()->do ) )
{
return $this->manage();
}
}
}
}
/* Still here? */
\IPS\Output::i()->error( 'page_not_found', '2C139/5', 404, '' );
}
/**
* Moderator Control Panel
*
@@ -45,6 +74,9 @@ class _modcp extends \IPS\Dispatcher\Controller
$activeTab = \IPS\Request::i()->tab ?: 'overview';
$tabs = array( 'reports' => array(), 'approval' => array() );
$content = '';
$approvalQueueCount = 0;
foreach ( \IPS\Application::allExtensions( 'core', 'ModCp', TRUE ) as $key => $extension )
{
if( method_exists( $extension, 'getTab' ) )
@@ -55,6 +87,12 @@ class _modcp extends \IPS\Dispatcher\Controller
{
$tabs[ $tab ][] = $key;
}
/* Get the count for the approval queue from the extension */
if( $tab == 'approval' )
{
$approvalQueueCount = $extension->getApprovalQueueCount( false );
}
}
if( mb_strtolower( $extension->getTab() ) == mb_strtolower( $activeTab ) )
@@ -113,22 +151,6 @@ class _modcp extends \IPS\Dispatcher\Controller
}
}
/* Get the count for the approval queue. If the community has a lot of data in the search index, thid can take a long
time, so we cache for a short while */
try
{
$approvalQueueCount = \IPS\Data\Cache::i()->getWithExpire( 'modCpApprovalQueueCount_' . \IPS\Member::loggedIn()->member_id, TRUE );
}
catch ( \OutOfRangeException $e )
{
$approvalQueueCount = \IPS\Content\Search\Query::init()->setHiddenFilter( \IPS\Content\Search\Query::HIDDEN_UNAPPROVED )->count();
if ( \IPS\Settings::i()->clubs and \IPS\Settings::i()->clubs_require_approval and \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$approvalQueueCount += \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', 'approved=0' )->first();
}
\IPS\Data\Cache::i()->storeWithExpire( 'modCpApprovalQueueCount_' . \IPS\Member::loggedIn()->member_id, $approvalQueueCount, \IPS\DateTime::create()->add( new \DateInterval( 'PT15M' ) ), TRUE );
}
/* Display */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp_responsive.css' ) );
@@ -36,76 +36,43 @@ class _online extends \IPS\Dispatcher\Controller
\IPS\Session\Front::i()->setTheme( \IPS\Member::loggedIn()->skin ?: 0 );
session_write_close();
$notInMyName = array();
foreach( \IPS\Member\Group::groups() as $group )
{
if ( $group->g_hide_online_list )
{
$notInMyName[] = $group->g_id;
}
}
/* Initial filters */
$subWhere = array(
array( "s.running_time>?", \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ),
array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_SPIDER )
);
if ( !\IPS\Member::loggedIn()->isAdmin() )
{
$subWhere[] = array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_ANONYMOUS );
}
if ( count( $notInMyName ) )
{
$subWhere[] = array( \IPS\Db::i()->in( 's.member_group', $notInMyName, TRUE ) );
}
/* Ok, this looks odd, but the ONLY_FULL_GROUP_BY bites us here, so selecting max(id) allows us to return a session ID even though we're grouping on member_id */
$where = array( array( "( core_sessions.id IN(?) OR ( core_sessions.member_id IS NULL AND core_sessions.login_type != ? AND core_sessions.running_time > ?) )", \IPS\Db::i()->select( 'MAX(id)', array( 'core_sessions', 's' ), $subWhere, NULL, NULL, 'member_id' ), \IPS\Session\Front::LOGIN_TYPE_SPIDER, \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ) );
if ( count( $notInMyName ) )
{
$where[] = array( \IPS\Db::i()->in( 'core_sessions.member_group', $notInMyName, TRUE ) );
}
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_sessions', \IPS\Http\Url::internal( 'app=core&module=online&controller=online', 'front', 'online' ), $where );
$table = new \IPS\core\Online\Table( \IPS\Http\Url::internal( 'app=core&module=online&controller=online', 'front', 'online' ) );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' ), 'onlineUsersTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' ), 'onlineUsersRow' );
$table->langPrefix = 'online_users_';
$table->include = array( 'photo', 'member_name', 'location_lang', 'running_time', 'ip_address', 'login_type' );
$table->limit = 30;
$table->noSort = array( 'photo', 'location_lang' );
/* Custom parsers */
$table->parsers = array(
'location_lang' => function( $val, $row )
'location_lang' => function( $val, $row )
{
return \IPS\Session\Front::getLocation( $row );
},
'photo' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::load( $row['member_id'] ), 'mini' );
},
'running_time' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->relative();
},
'member_name' => function( $val, $row )
{
if( $row['member_id'] )
{
return \IPS\Session\Front::getLocation( $row );
},
'photo' => function( $val, $row )
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $row['member_id'] ) );
}
else
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::load( $row['member_id'] ), 'mini' );
},
'running_time' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->relative();
},
'member_name' => function( $val, $row )
{
if( $row['member_id'] )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $row['member_id'] ) );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( 'guest' );
}
},
return \IPS\Member::loggedIn()->language()->addToStack( 'guest' );
}
},
);
$table->filters = array(
'filter_loggedin' => 'core_sessions.member_id <> 0',
'filter_loggedin' => 'filter_loggedin',
);
foreach ( \IPS\Member\Group::groups( TRUE, TRUE, TRUE ) as $group )
@@ -123,29 +90,18 @@ class _online extends \IPS\Dispatcher\Controller
if( $group->g_id == \IPS\Settings::i()->guest_group )
{
$table->filters[ 'group_' . $group->g_id ] = 'core_sessions.member_id IS NULL';
$table->filters[ 'group_' . $group->g_id ] = $group->g_id;
}
else
{
$table->filters[ 'group_' . $group->g_id ] = 'core_sessions.member_group=' . $group->g_id;
$table->filters[ 'group_' . $group->g_id ] = $group->g_id;
}
}
$table->sortBy = $table->sortBy ?: 'running_time';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Get the count */
$counter = \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', $where );
foreach( $table->joins as $join )
{
$counter = $counter->join( $join['from'], $join['where'] );
}
$totalCount = $counter->first();
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('online_users');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' )->onlineUsersList( (string) $table, $totalCount );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' )->onlineUsersList( (string) $table, $table->count );
}
}
@@ -42,6 +42,11 @@ class _promote extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'page_not_found', '2C356/5', 404, '' );
}
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) and $promote->added_by != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2C366/2', 403, '' );
}
try
{
$object = $class::load( $id );
@@ -57,13 +62,87 @@ class _promote extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'page_not_found', '2C356/7', 404, '' );
}
$title = NULL;
$settings = $promote->form_data;
if ( ! empty( $settings['internal']['title'] ) )
{
$title = $settings['internal']['title'];
}
$form = new \IPS\Helpers\Form( 'form', 'save' );
$form->class = 'ipsForm_vertical cPromoteDialog';
$form->attributes = array( 'data-controller' => 'core.front.system.promote' );
$form->add( new \IPS\Helpers\Form\Text( 'promote_social_title_internal', $title, FALSE ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'promote_internal_text', $promote->getText('internal'), FALSE, array( 'rows' => 10 ) ) );
/* Existing media */
try
{
if ( $images = $object->contentImages( 20 ) )
{
$form->addHtml( \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialogImages( $images, $promote ) );
}
}
catch( \BadMethodCallException $e ) { }
/* Upload box */
$existingMedia = array();
if ( $promote )
{
foreach( $promote->media as $file )
{
try
{
$existingMedia[] = \IPS\File::get( 'core_Promote', $file );
}
catch ( \OutOfRangeException $e ) { }
}
}
$uploader = new \IPS\Helpers\Form\Upload( 'promote_media', $existingMedia, FALSE, array(
'multiple' => TRUE,
'storageExtension' => 'core_Promote',
'maxFiles' => 10,
'image' => TRUE,
'maxFileSize' => 3,
) );
$form->add( $uploader );
/* Saving? */
if ( $values = $form->values() )
{
/* Content images */
$saveImages = array();
if ( $images )
{
foreach( $images as $image )
{
foreach( $image as $extension => $path )
{
if ( \IPS\Request::i()->attach_files and in_array( $path, array_keys( \IPS\Request::i()->attach_files ) ) )
{
$saveImages[] = array( $extension => $path );
}
}
}
}
$media = array();
if ( is_array( $values['promote_media'] ) )
{
foreach( $values['promote_media'] as $key => $file )
{
$media[] = (string) $file;
}
}
$settings['internal']['title'] = $values['promote_social_title_internal'];
$promote->images = $saveImages;
$promote->media = $media;
$promote->form_data = $settings;
$promote->setText( 'internal', $values['promote_internal_text'] );
$promote->save();
@@ -129,6 +208,11 @@ class _promote extends \IPS\Dispatcher\Controller
/* Create the table */
$table = new \IPS\core\Promote\Table( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ) );
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) )
{
$table->setMember( \IPS\Member::loggedIn() );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_promote.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote.css' ) );
@@ -160,6 +244,12 @@ class _promote extends \IPS\Dispatcher\Controller
try
{
$item = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) and $item->added_by != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2C366/1', 403, '' );
}
$item->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ), 'promote_item_deleted' );
@@ -228,6 +318,11 @@ class _promote extends \IPS\Dispatcher\Controller
try
{
if( !$class OR !class_exists( $class ) )
{
throw new \InvalidArgumentException;
}
$object = $class::load( $id );
}
catch ( \Exception $ex )
@@ -405,6 +500,8 @@ class _promote extends \IPS\Dispatcher\Controller
{
$text = array();
$shareTo = array();
$processedForms = array();
foreach( $services as $service )
{
$key = mb_strtolower( $service->key );
@@ -413,9 +510,10 @@ class _promote extends \IPS\Dispatcher\Controller
$text[ $key ] = $values[ 'promote_social_content_' . $key ];
$shareTo[] = $key;
}
$processedForms[ $key ] = $service->processPromoteForm( $values );
}
$media = array();
if ( is_array( $values['promote_media'] ) )
{
@@ -481,6 +579,7 @@ class _promote extends \IPS\Dispatcher\Controller
$promote->share_to = $shareTo;
$promote->failed = 0; # Reset the failed flag if we're re-promoting
$promote->sent = 0;
$promote->form_data = $processedForms;
$promote->save();
if ( isset( \IPS\Request::i()->promote_id ) )
@@ -496,7 +595,7 @@ class _promote extends \IPS\Dispatcher\Controller
}
else
{
$output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialog( \IPS\Member::loggedIn()->language()->addToStack('promote_social_title'), $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'promote', 'core' ) ), 'promoteDialogTemplate' ) ), $existing, $object );
$output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialog( \IPS\Member::loggedIn()->language()->addToStack('promote_social_title'), $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'promote', 'core' ) ), 'promoteDialogTemplate' ), $existing, $object ) );
}
+114 -29
View File
@@ -114,7 +114,7 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'tags', \IPS\Request::i()->tags );
}
$types = $this->_contentTypes();
$types = static::contentTypes();
/* Flood control */
\IPS\Request::floodCheck();
@@ -199,8 +199,16 @@ class _search extends \IPS\Dispatcher\Controller
foreach( $groups as $_idx => $groupId )
{
if( \IPS\Member\Group::load( $groupId )->g_bitoptions['gbw_hide_group'] )
try
{
if( \IPS\Member\Group::load( $groupId )->g_bitoptions['gbw_hide_group'] )
{
unset( $groups[ $_idx ] );
}
}
catch( \OutOfRangeException $e )
{
/* Group didn't exist, so let's ignore it */
unset( $groups[ $_idx ] );
}
}
@@ -339,9 +347,10 @@ class _search extends \IPS\Dispatcher\Controller
/* Set content type */
if ( isset( \IPS\Request::i()->type ) and array_key_exists( \IPS\Request::i()->type, $types ) )
{
$class = $types[ \IPS\Request::i()->type ];
if ( isset( \IPS\Request::i()->item ) )
{
$class = $types[ \IPS\Request::i()->type ];
try
{
$item = $class::loadAndCheckPerms( \IPS\Request::i()->item );
@@ -392,19 +401,19 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'search_min_comments', \IPS\Request::i()->search_min_comments );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_comments', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_comments ) ) );
}
if ( isset( \IPS\Request::i()->search_min_replies ) )
if ( isset( \IPS\Request::i()->search_min_replies ) AND isset( $class::$commentClass ) )
{
$filter->minimumComments( \IPS\Request::i()->search_min_replies + 1 );
$baseUrl = $baseUrl->setQueryString( 'search_min_replies', \IPS\Request::i()->search_min_replies );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_replies', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_replies ) ) );
}
if ( isset( \IPS\Request::i()->search_min_reviews ) )
if ( isset( \IPS\Request::i()->search_min_reviews ) AND isset( $class::$reviewClass ) )
{
$filter->minimumReviews( \IPS\Request::i()->search_min_reviews );
$baseUrl = $baseUrl->setQueryString( 'search_min_reviews', \IPS\Request::i()->search_min_reviews );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_reviews', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_reviews ) ) );
}
if ( isset( \IPS\Request::i()->search_min_views ) )
if ( isset( \IPS\Request::i()->search_min_views ) AND isset( $class::$databaseColumnMap['views'] ) )
{
$filter->minimumViews( \IPS\Request::i()->search_min_views );
$baseUrl = $baseUrl->setQueryString( 'search_min_views', \IPS\Request::i()->search_min_views );
@@ -429,7 +438,7 @@ class _search extends \IPS\Dispatcher\Controller
}
/* Filter by club */
if ( isset( \IPS\Request::i()->club ) )
if ( isset( \IPS\Request::i()->club ) AND \IPS\Settings::i()->clubs )
{
$clubIds = array();
$clubNames = array();
@@ -521,12 +530,16 @@ class _search extends \IPS\Dispatcher\Controller
$tagList = array_map( function( $val )
{
return '\'' . htmlentities( $val, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . '\'';
return '\'' . htmlentities( $val, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . '\'';
}, explode( ',', \IPS\Request::i()->tags ) );
}
$title = '';
if ( \IPS\Request::i()->q )
{
\IPS\core\Facebook\Pixel::i()->Search = array(
'search_string' => \IPS\Request::i()->q
);
if ( \IPS\Request::i()->tags )
{
if ( isset( \IPS\Request::i()->eitherTermsOrTags ) and \IPS\Request::i()->eitherTermsOrTags === 'and' )
@@ -588,10 +601,11 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'sortby', \IPS\Request::i()->sortby );
$flags = ( isset( \IPS\Request::i()->eitherTermsOrTags ) and \IPS\Request::i()->eitherTermsOrTags === 'and' ) ? \IPS\Content\Search\Query::TERM_AND_TAGS : \IPS\Content\Search\Query::TERM_OR_TAGS;
if ( isset( \IPS\Request::i()->search_and_or ) and \IPS\Request::i()->search_and_or === 'or' )
$operator = NULL;
if ( isset( \IPS\Request::i()->search_and_or ) and in_array( \IPS\Request::i()->search_and_or, array( \IPS\Content\Search\Query::OPERATOR_OR, \IPS\Content\Search\Query::OPERATOR_AND ) ) )
{
$flags = $flags | \IPS\Content\Search\Query::TERM_OR_MODE;
$operator = \IPS\Request::i()->search_and_or;
$baseUrl = $baseUrl->setQueryString( 'search_and_or', \IPS\Request::i()->search_and_or );
}
@@ -605,7 +619,8 @@ class _search extends \IPS\Dispatcher\Controller
$results = $query->search(
isset( \IPS\Request::i()->q ) ? ( \IPS\Request::i()->q ) : NULL,
isset( \IPS\Request::i()->tags ) ? explode( ',', \IPS\Request::i()->tags ) : NULL,
$flags + \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY
$flags + \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY,
$operator
);
/* Get pagination */
@@ -622,7 +637,7 @@ class _search extends \IPS\Dispatcher\Controller
{
/* There's no point resetting the page at this point as the search query has been run and no results have been found */
$_SESSION['lastSearch'] = 0;
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'page', 1 ) );
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'page', 1 ), NULL, 303 );
}
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, $pages, $page, $query->resultsToGet ) );
@@ -690,7 +705,7 @@ class _search extends \IPS\Dispatcher\Controller
/* Types */
$types = array( '' => 'search_everything' );
$contentTypes = $this->_contentTypes();
$contentTypes = static::contentTypes();
$contentToggles = array();
$typeFields = array();
$typeFieldToggles = array('' => array( 'club' ) );
@@ -742,7 +757,13 @@ class _search extends \IPS\Dispatcher\Controller
$types[ $k ] = $k . '_pl';
if ( $k !== 'core_members' )
{
$typeFieldToggles[ $k ] = array_merge( $contentToggles, array( $k . '_node', 'search_min_views' ) );
$typeFieldToggles[ $k ][] = $k . '_node';
if( isset( $class::$databaseColumnMap['views'] ) )
{
$typeFieldToggles[ $k ][] = 'search_min_views';
}
if ( isset( $class::$commentClass ) )
{
if ( $class::$firstCommentRequired )
@@ -768,23 +789,26 @@ class _search extends \IPS\Dispatcher\Controller
/* Term */
$form->add( new \IPS\Helpers\Form\Text( 'q' ), NULL, 'search_tab_all' );
$form->add( new \IPS\Helpers\Form\Text( 'tags', \IPS\Request::i()->tags, FALSE, array( 'autocomplete' => TRUE ), NULL, NULL, NULL, 'tags' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Text( 'tags', \IPS\Request::i()->tags, FALSE, array( 'autocomplete' => array( 'minimized' => FALSE ) ), NULL, NULL, NULL, 'tags' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'eitherTermsOrTags', \IPS\Request::i()->eitherTermsOrTags, FALSE, array( 'options' => array( 'or' => 'termsortags_or_desc', 'and' => 'termsortags_and_desc' ) ), NULL, NULL, NULL, 'eitherTermsOrTags' ), NULL, 'search_tab_content' );
/* Author */
$form->add( new \IPS\Helpers\Form\Member( 'author', NULL, FALSE, array(), NULL, NULL, NULL, 'author' ), NULL, 'search_tab_content' );
/* Club */
$clubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE );
if ( count( $clubs ) )
if( \IPS\Settings::i()->clubs )
{
$clubOptions = array();
foreach ( $clubs as $club )
$clubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE );
if ( is_object( $clubs ) AND $clubs->count( TRUE ) )
{
$clubOptions[ "c{$club->id}" ] = $club->name;
$clubOptions = array();
foreach ( $clubs as $club )
{
$clubOptions[ "c{$club->id}" ] = $club->name;
}
$form->add( new \IPS\Helpers\Form\Select( 'club', NULL, FALSE, array( 'options' => $clubOptions, 'parse' => 'normal', 'multiple' => TRUE, 'noDefault' => TRUE, 'class' => 'ipsField_fullWidth' ), NULL, NULL, NULL, 'club' ), NULL, 'search_tab_content' );
}
$form->add( new \IPS\Helpers\Form\Select( 'club', NULL, FALSE, array( 'options' => $clubOptions, 'parse' => 'normal', 'multiple' => TRUE, 'noDefault' => TRUE, 'class' => 'ipsContained' ), NULL, NULL, NULL, 'club' ), NULL, 'search_tab_content' );
}
/* Dates */
@@ -795,15 +819,29 @@ class _search extends \IPS\Dispatcher\Controller
/* Other filters */
$form->add( new \IPS\Helpers\Form\Radio( 'search_in', \IPS\Request::i()->search_in, FALSE, array( 'options' => array( 'all' => 'titles_and_body', 'titles' => 'titles_only' ) ), NULL, NULL, NULL, 'searchIn' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'search_and_or', \IPS\Request::i()->search_and_or, FALSE, array( 'options' => array( 'and' => 'search_and', 'or' => 'search_or' ) ), NULL, NULL, NULL, 'andOr' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'search_and_or', isset( \IPS\Request::i()->search_and_or ) ? \IPS\Request::i()->search_and_or : \IPS\Settings::i()->search_default_operator, FALSE, array( 'options' => array( 'and' => 'search_and', 'or' => 'search_or' ) ), NULL, NULL, NULL, 'andOr' ), NULL, 'search_tab_content' );
/* Nodes */
foreach ( $contentTypes as $k => $class )
{
if ( isset( $class::$containerNodeClass ) )
{
$nodes = NULL;
/* If we have a node type, we should only select nodes for that type */
if( isset( \IPS\Request::i()->type ) AND !empty( \IPS\Request::i()->type ) )
{
$typeInfo = explode( '_', \IPS\Request::i()->type );
$typeClass = 'IPS\\' . $typeInfo[0] . '\\' . mb_ucfirst( $typeInfo[1] );
if( $typeClass == $class )
{
$nodes = ( isset( \IPS\Request::i()->nodes ) ) ? \IPS\Request::i()->nodes : NULL;
}
}
$nodeClass = $class::$containerNodeClass;
$field = new \IPS\Helpers\Form\Node( $k . '_node', ( isset( \IPS\Request::i()->nodes ) ) ? \IPS\Request::i()->nodes : NULL, FALSE, array( 'class' => $nodeClass, 'multiple' => TRUE, 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE, 'clubs' => \IPS\IPS::classUsesTrait( $nodeClass, 'IPS\Content\ClubContainer' ) ), NULL, NULL, NULL, $k . '_node' );
$field = new \IPS\Helpers\Form\Node( $k . '_node', $nodes, FALSE, array( 'class' => $nodeClass, 'subnodes' => FALSE, 'multiple' => TRUE, 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE, 'clubs' => ( \IPS\Settings::i()->clubs AND \IPS\IPS::classUsesTrait( $nodeClass, 'IPS\Content\ClubContainer' ) ) ), NULL, NULL, NULL, $k . '_node' );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle );
$form->add( $field, NULL, 'search_tab_nodes' );
}
@@ -1018,12 +1056,57 @@ class _search extends \IPS\Dispatcher\Controller
return $form;
}
/**
* Handle quicksearch and redirect to correct results page
*
* @return array
*/
public static function quicksearch()
{
$query = array();
if ( \IPS\Request::i()->q )
{
$query['q'] = \IPS\Request::i()->q;
if ( \IPS\Request::i()->type != 'all' )
{
if ( mb_substr( \IPS\Request::i()->type, 0, 11 ) === 'contextual_' )
{
if ( $json = json_decode( mb_substr( \IPS\Request::i()->type, 11 ), TRUE ) )
{
foreach ( $json as $k => $v )
{
$query[ $k ] = $v;
}
}
}
else
{
$query['type'] = \IPS\Request::i()->type;
}
}
if ( \IPS\Request::i()->search_and_or != \IPS\Settings::i()->search_default_operator )
{
$query['search_and_or'] = \IPS\Request::i()->search_and_or;
}
if ( \IPS\Request::i()->search_in == 'titles' )
{
$query['search_in'] = 'titles';
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=search&controller=search', 'front', 'search' )->setQueryString( $query ) );
}
/**
* Get the different content type extensions
*
* @return array
*/
protected function _contentTypes()
public static function contentTypes()
{
$types = array();
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
@@ -1039,7 +1122,7 @@ class _search extends \IPS\Dispatcher\Controller
/**
* Splits the search term into distinct matches
* e.g. one "two three" beccomes ['one', 'two three']
* e.g. one "two three" becomes ['one', 'two three']
*
* @return string
*/
@@ -1050,10 +1133,12 @@ class _search extends \IPS\Dispatcher\Controller
}
$words = preg_split("/[\s]*\\\"([^\\\"]+)\\\"[\s]*|[\s]*'([^']+)'[\s]*|[\s]+/", \IPS\Request::i()->q, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$words = \IPS\Content\Search\Index::i()->stemmedTerms( $words );
foreach( $words as $idx => $word )
{
$words[ $idx ] = htmlentities( $word, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ); // ENT_QUOTES is because this will go in a HTML attribute (data-term="$value") so if you include a single quote in your search query, it can break
$words[ $idx ] = htmlentities( $word, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ); // ENT_QUOTES is because this will go in a HTML attribute (data-term="$value") so if you include a single quote in your search query, it can break
}
return json_encode( $words );
@@ -1066,6 +1151,6 @@ class _search extends \IPS\Dispatcher\Controller
*/
protected function globalFilterOptions()
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'search' )->globalSearchMenuOptions( \IPS\Request::i()->checked ) );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'search' )->globalSearchMenuOptions( explode( ',', \IPS\Request::i()->exclude ) ) );
}
}
+22 -15
View File
@@ -56,8 +56,8 @@ class _ajax extends \IPS\Dispatcher\Controller
$results[] = array(
'id' => $member->member_id,
'value' => $member->name,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName,
'photo' => (string) $member->photo,
);
}
@@ -342,9 +342,9 @@ class _ajax extends \IPS\Dispatcher\Controller
$return['notifications']['data'][] = array(
'id' => $notification->id,
'title' => htmlspecialchars( $data['title'], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $data['title'], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $data['url'],
'content' => isset( $data['content'] ) ? htmlspecialchars( $data['content'], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : NULL,
'content' => isset( $data['content'] ) ? htmlspecialchars( $data['content'], ENT_DISALLOWED, 'UTF-8', FALSE ) : NULL,
'date' => $notification->updated_time->getTimestamp(),
'author_photo' => $data['author'] ? $data['author']->photo : NULL
);
@@ -360,17 +360,24 @@ class _ajax extends \IPS\Dispatcher\Controller
foreach ( \IPS\Db::i()->select( 'map_topic_id', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1 AND map_has_unread=1 AND map_ignore_notification=0', \IPS\Member::loggedIn()->member_id ), 'map_last_topic_reply DESC', $messagesDifference ) as $conversationId )
{
$conversation = \IPS\core\Messenger\Conversation::load( $conversationId );
$message = $conversation->comments( 1, 0, 'date', 'desc' );
$return['messages']['data'][] = array(
'id' => $conversation->id,
'title' => htmlspecialchars( $conversation->title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $conversation->url()->setQueryString( 'latest', 1 ),
'message' => $message->truncated(),
'date' => $message->mapped('date'),
'author_photo' => (string) $message->author()->photo
);
$conversation = \IPS\core\Messenger\Conversation::load( $conversationId );
$message = $conversation->comments( 1, 0, 'date', 'desc' );
if( $message )
{
$return['messages']['data'][] = array(
'id' => $conversation->id,
'title' => htmlspecialchars( $conversation->title, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $conversation->url()->setQueryString( 'latest', 1 ),
'message' => $message->truncated(),
'date' => $message->mapped('date'),
'author_photo' => (string) $message->author()->photo
);
}
else
{
\IPS\Log::log( "Private conversation {$conversation->id} titled {$conversation->title} has no messages", 'orphaned_data' );
}
}
}
}
@@ -0,0 +1,41 @@
<?php
/**
* @brief Cookie Policy
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 12 Dec 2017
*/
namespace IPS\core\modules\front\system;
/* 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;
}
/**
* Cookie Policy
*/
class _cookies extends \IPS\Dispatcher\Controller
{
/**
* Privacy Policy
*
* @return void
*/
protected function manage()
{
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=cookies', NULL, 'cookies' ), array(), 'loc_viewing_cookie_policy' );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('cookies_about') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cookies_about');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->cookies();
}
}
@@ -29,6 +29,6 @@ class _designermode extends \IPS\Dispatcher\Controller
*/
protected function missing()
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'theme_designers_mode_error_missing', FALSE, array( 'sprintf' => array( \IPS\Request::i()->id ) ) ), "DESMODE", 500 );
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'theme_designers_mode_error_missing', FALSE, array( 'sprintf' => array( intval( \IPS\Request::i()->id ) ) ) ), "4C370/1", 500 );
}
}
@@ -51,7 +51,7 @@ class _editor extends \IPS\Dispatcher\Controller
protected function code()
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( uniqid() ), \IPS\Request::i()->lang ?: '' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( mt_rand() ), \IPS\Request::i()->lang ?: '' );
}
/**
@@ -155,7 +155,7 @@ class _editor extends \IPS\Dispatcher\Controller
}
else
{
$title = \IPS\Request::i()->title ?: $url;
$title = \IPS\Request::i()->title ?: (string) $url;
$insert = "<a href='{$url}' ipsNoEmbed='true'>{$title}</a>";
}
@@ -178,41 +178,42 @@ class _editor extends \IPS\Dispatcher\Controller
}
/**
* Get Emoticons Configuration
* Get Emoji
*
* @return void
*/
protected function emoticons()
protected function emoji()
{
$emoticons = array();
$emoji = ( \IPS\Settings::i()->emoji_style == 'disabled' or !\IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') ) ? array() : json_decode( file_get_contents( \IPS\ROOT_PATH . '/applications/core/data/emoji.json' ), TRUE );
foreach ( \IPS\Db::i()->select( '*', 'core_emoticons', NULL, 'emo_set_position,emo_position' ) as $row )
{
if ( !isset( $emoticons[ $row['emo_set'] ] ) )
$shortcode = ( \IPS\Settings::i()->emoji_shortcodes and preg_match( '/^:.*:$/', $row['typed'] ) );
try
{
$setLang = 'core_emoticon_group_' . $row['emo_set'];
$emoticons[ $row['emo_set'] ] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( $setLang ),
'total' => 0,
'emoticons' => array(),
);
$categoryName = \IPS\Member::loggedIn()->language()->get( 'core_emoticon_group_' . $row['emo_set'] );
}
catch( \UnderflowException $e )
{
$categoryName = '_default';
}
$emoticons[ $row['emo_set'] ]['emoticons'][] = array(
'src' => \IPS\File::get( 'core_Emoticons', $row['image'] )->url,
'srcset' => $row['image_2x'] ? \IPS\File::get( 'core_Emoticons', $row['image_2x'] )->url . ' 2x' : FALSE,
'height' => $row['height'] ?: FALSE,
'width' => $row['width'] ?: FALSE,
'text' => $row['typed']
$emoji[ $row['emo_set'] ][] = array(
'code' => 'custom-' . $row['emo_set'] . '-' . $row['id'],
'name' => $row['typed'],
'skinTone' => false,
'shortNames' => $shortcode ? array( trim( $row['typed'], ':' ) ) : array(),
'ascii' => $shortcode ? array() : array( $row['typed'] ),
'categoryName' => $categoryName,
'image' => \IPS\File::get( 'core_Emoticons', $row['image'] )->url,
'image2x' => $row['image_2x'] ? \IPS\File::get( 'core_Emoticons', $row['image_2x'] )->url : FALSE,
'width' => $row['width'],
'height' => $row['height'],
);
}
}
foreach ( $emoticons as $set => $data )
{
$emoticons[ $set ]['total'] = count( $data['emoticons'] );
}
\IPS\Output::i()->json( $emoticons );
\IPS\Output::i()->json( $emoji );
}
/**
@@ -37,9 +37,6 @@ class _followed extends \IPS\Dispatcher\Controller
/* Get the different types */
$types = array();
/* Don't forget Members */
$types['core'] = array( 'core_member' => "\IPS\Member" );
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
{
@@ -61,6 +58,9 @@ class _followed extends \IPS\Dispatcher\Controller
}
}
}
/* Don't forget Members - add this on to the end so it never defaults UNLESS we only have apps that do not have followable content */
$types['core'] = array( 'core_member' => "\IPS\Member" );
/* What type are we looking at? */
$currentAppModule = NULL;
@@ -84,11 +84,6 @@ class _followed extends \IPS\Dispatcher\Controller
{
foreach ( $_types as $key => $class )
{
if ( $key == 'core_member' )
{
continue;
}
$currentAppModule = $appModule;
$currentType = $key;
break 2;
@@ -31,11 +31,14 @@ class _guidelines extends \IPS\Dispatcher\Controller
{
if ( \IPS\Settings::i()->gl_type == "none" )
{
\IPS\Output::i()->error( 'node_error', '', 404 ); /* @todo Error code */
\IPS\Output::i()->error( 'node_error', '2C380/1', 404, 'guidelines_set_to_none_admin' );
}
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=guidelines', NULL, 'guidelines' ), array(), 'loc_viewing_guidelines' );
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('guidelines') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('guidelines');
+81 -115
View File
@@ -34,24 +34,47 @@ class _login extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
}
/* Force HTTPs? */
if ( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' and \IPS\Settings::i()->logins_over_https and \IPS\Request::i()->url()->data['scheme'] !== 'https' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
}
/* Init login class */
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
/* Init login class */
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' ) );
/* What's our referrer? */
$ref = \IPS\Request::i()->ref;
/* Process */
$error = isset( \IPS\Request::i()->_err ) && \IPS\Member::loggedIn()->language()->checkKeyExists( \IPS\Request::i()->_err ) ? \IPS\Request::i()->_err : NULL;
$error = NULL;
try
{
$member = $login->authenticate();
if ( $member !== NULL )
if ( $success = $login->authenticate() )
{
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'], \IPS\Login::getDestination(), FALSE, $login->usedHandler );
if ( $ref and $ref = @base64_decode( $ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
if ( $success->mfa() )
{
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id, 'anonymous' => $success->anonymous, 'remember' => $success->rememberMe, 'destination' => (string) $ref, 'handler' => $success->handler->id );
\IPS\Output::i()->redirect( $ref->setQueryString( '_mfaLogin', 1 ) );
}
$success->process();
\IPS\Output::i()->redirect( $ref->setQueryString( '_fromLogin', 1 ) );
}
}
catch ( \IPS\Login\Exception $e )
@@ -59,91 +82,33 @@ class _login extends \IPS\Dispatcher\Controller
if ( $e->getCode() === \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT )
{
$e->member = $e->member->member_id;
$e->handler = $e->handler->id;
$_SESSION['linkAccounts'] = json_encode( $e );
$linkUrl = \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
{
$linkUrl = $linkUrl->setQueryString( 'ref', \IPS\Request::i()->ref );
}
\IPS\Output::i()->redirect( $linkUrl );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', $ref ), '', 303 );
}
$error = $e->getMessage();
}
if ( \IPS\Request::i()->isAjax() && $error )
{
\IPS\Output::i()->json( array( 'status' => 'error', 'error' => $error ), 401 );
}
else
{
/* Display Login Form */
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->login( $login->forms(), $error );
}
/* Display Login Form */
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->login( $login, $ref, $error );
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', NULL, 'login' ), array(), 'loc_logging_in' );
}
/**
* Process the login
*
* @param \IPS\Member $member The member
* @param bool $anonymous If the login is anonymous
* @param bool $rememberMe If the "remember me" checkbox was checked
* @param \IPS\Http\Url $destination Where to redirect to
* @param bool $bypass2FA If true, will not perform 2FA check
* @param string $loginHandler Which login handler processed the login
* @return void
*/
protected function _doLogin( $member, $anonymous=FALSE, $rememberMe=TRUE, $destination=NULL, $bypass2FA=FALSE, $loginHandler=NULL )
{
/* Get destination */
if ( !$destination )
{
$destination = \IPS\Http\Url::internal( '' );
}
/* Is this a known device? */
$device = \IPS\Member\Device::loadOrCreate( $member );
/* Do we need to do 2FA? */
if ( !$bypass2FA and $output = \IPS\MFA\MFAHandler::accessToArea( 'core', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Http\Url::internal( '' ), $member ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $member->member_id, 'anonymous' => $anonymous, 'remember' => $rememberMe, 'destination' => (string) $destination, 'handler' => $loginHandler );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
/* Log in */
\IPS\Session::i()->setMember( $member );
if ( $anonymous and !\IPS\Settings::i()->disable_anonymous )
{
\IPS\Session::i()->setAnon();
}
/* Log device */
$device->anonymous = $anonymous and !\IPS\Settings::i()->disable_anonymous;
$device->updateAfterAuthentication( $rememberMe, $loginHandler );
/* Member sync */
$member->memberSync( 'onLogin', array( \IPS\Login::getDestination() ) );
/* Redirect */
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ), '', 303 );
}
/**
* MFA
*
* @return void
*/
protected function mfa()
{
{
/* Have we logged in? */
$member = NULL;
if ( isset( $_SESSION['processing2FA'] ) )
@@ -156,7 +121,7 @@ class _login extends \IPS\Dispatcher\Controller
}
/* Where do we want to go? */
$destination = NULL;
$destination = \IPS\Http\Url::internal( '' );
try
{
$destination = \IPS\Http\Url::createFromString( $_SESSION['processing2FA']['destination'] );
@@ -167,8 +132,9 @@ class _login extends \IPS\Dispatcher\Controller
$device = \IPS\Member\Device::loadOrCreate( $member );
$output = \IPS\MFA\MFAHandler::accessToArea( 'core', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=mfa', 'front', 'login' ), $member );
if ( !$output )
{
$this->_doLogin( $member, $_SESSION['processing2FA']['anonymous'], $_SESSION['processing2FA']['remember'], $destination, TRUE, $_SESSION['processing2FA']['handler'] );
{
( new \IPS\Login\Success( $member, \IPS\Login\Handler::load( $_SESSION['processing2FA']['handler'] ), $_SESSION['processing2FA']['remember'], $_SESSION['processing2FA']['anonymous'] ) )->process();
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ), '', 303 );
}
/* Nope, just send us where we want to go not logged in */
@@ -199,35 +165,36 @@ class _login extends \IPS\Dispatcher\Controller
*/
protected function link()
{
/* Get the member we're linking with */
if ( !isset( $_SESSION['linkAccounts'] ) )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
$details = json_decode( $_SESSION['linkAccounts'], TRUE );
$member = \IPS\Member::load( $details['member'] );
if ( !$member->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
$form = new \IPS\Helpers\Form( 'link_accounts', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
/* And then handler to link with */
$handler = \IPS\Login\Handler::load( $details['handler'] );
/* Init reauthentication */
$login = new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', isset( \IPS\Request::i()->ref ) ? \IPS\Request::i()->ref : NULL ), \IPS\Login::LOGIN_REAUTHENTICATE );
$login->reauthenticateAs = $member;
$error = NULL;
/* If successful (or if there's no way to reauthenticate which would only happen if a login handler has been deleted)) complete the link... */
try
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->addDummy( 'email_address', htmlspecialchars( isset( $details['email'] ) ? $details['email'] : $member->email, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'validateFor' => $member ) ) );
if ( $values = $form->values() )
{
try
{
$class = 'IPS\Login\\' . ucfirst( $details['handler'] );
$class::link( $member, $details['details'] );
if ( $success = $login->authenticate() or ( !count( $login->usernamePasswordMethods() ) and !count( $login->buttonMethods() ) ) )
{
$handler->completeLink( $member, $details['details'] );
unset( $_SESSION['linkAccounts'] );
$destination = NULL;
$destination = \IPS\Http\Url::internal( '' );
if ( isset( \IPS\Request::i()->ref ) )
{
try
@@ -240,18 +207,27 @@ class _login extends \IPS\Dispatcher\Controller
}
catch ( \Exception $e ) { }
}
$this->_doLogin( $member, FALSE, TRUE, $destination, FALSE, $details['handler'] );
$success = new \IPS\Login\Success( $member, $handler );
if ( $success->mfa() )
{
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id, 'anonymous' => $success->anonymous, 'remember' => $success->rememberMe, 'destination' => (string) $destination, 'handler' => $success->handler->id );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
$success->process();
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ) );
}
catch ( \IPS\Login\Exception $e )
{
$form->error = $e->getMessage();
}
}
catch ( \IPS\Login\Exception $e )
{
$error = $e->getMessage();
}
/* Otherwise show the reauthenticate form */
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->mergeSocialAccount( $details['handler'], $member, $form );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->mergeSocialAccount( $handler, $member, $login, $error );
}
/**
@@ -309,16 +285,6 @@ class _login extends \IPS\Dispatcher\Controller
setcookie( session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );
session_destroy();
/* Login handler callback */
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
try
{
$handler->logoutAccount( $member, $redirectUrl );
}
catch( \BadMethodCallException $e ) {}
}
/* Member sync callback */
$member->memberSync( 'onLogout', array( $redirectUrl ) );
@@ -345,7 +311,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Not logged in as admin? */
if ( $admin->member_id != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https )->setQueryString( array( 'ref' => base64_encode( \IPS\Request::i()->url() ), '_err' => 'login_as_user_login' ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( array( 'ref' => base64_encode( \IPS\Request::i()->url() ), '_err' => 'login_as_user_login' ) ) );
}
/* Do it */
@@ -22,6 +22,26 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _lostpass extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
if ( \IPS\Settings::i()->allow_forgot_password == 'disabled' )
{
\IPS\Output::i()->error( 'page_doesnt_exist', '2S151/2', 404, '' );
}
if ( \IPS\Settings::i()->allow_forgot_password == 'redirect' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Settings::i()->allow_forgot_password_target ) );
}
return parent::execute();
}
/**
* Manage
*
@@ -32,11 +52,7 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form( "lostpass", 'request_password' );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'bypassProfanity' => TRUE ), function( $val ){
/* Check email exists */
$member = \IPS\Member::load( $val, 'email' );
if( !$member->member_id )
if( !\IPS\Login::emailIsInUse( $val ) )
{
throw new \LogicException( 'lost_pass_no_email' );
}
@@ -47,62 +63,107 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Handle the reset */
if ( $values = $form->values() )
{
/* Load the member */
/* If using "normal" method and we have an account, and at least one login handler we can process a password change for, we're good */
$member = \IPS\Member::load( $values['email_address'], 'email' );
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
if ( $member->member_id and \IPS\Settings::i()->allow_forgot_password == 'normal' )
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) )->first();
$vid = $existing['vid'];
/* If we sent a lost password email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
foreach ( \IPS\Login::methods() as $method )
{
$sendEmail = FALSE;
if ( $method->canChangePassword( $member ) )
{
return $this->_sendForgotPasswordEmail( $member );
}
}
else
{
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
'email_sent' => time(),
) );
}
/* Send email */
if ( $sendEmail )
/* If not, send them to the handler if we can */
foreach( \IPS\Login::methods() as $method )
{
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "lost_pass_confirm";
if( $method->emailIsInUse( $values['email_address'] ) === TRUE )
{
if ( $url = $method->forgotPasswordUrl() )
{
\IPS\Output::i()->redirect( $url );
}
}
}
/* If we have no way to reset the password, can we allow creating a local password as a last attempt? */
if ( $member->member_id )
{
foreach( \IPS\Login::methods() as $method )
{
if ( $method instanceof \IPS\Login\Handler\Standard )
{
return $this->_sendForgotPasswordEmail( $member );
}
}
}
/* Otherwise, sorry, we can't do this */
\IPS\Output::i()->error( 'lost_pass_not_possible', '1S151/3', 403, '' );
}
/* Show form */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPass( $form );
}
/**
* Send forgot password email
*
* @param \IPS\Member $member The member
* @return void
*/
protected function _sendForgotPasswordEmail( \IPS\Member $member )
{
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) )->first();
$vid = $existing['vid'];
/* If we sent a lost password email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
{
$sendEmail = FALSE;
}
else
{
$message = "lost_pass_too_soon";
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( $message );
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
'email_sent' => time(),
) );
}
/* Send email */
if ( $sendEmail )
{
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "lost_pass_confirm";
}
else
{
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPass( $form );
$message = "lost_pass_too_soon";
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( $message );
}
/**
@@ -135,21 +196,17 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Reset the failed logins storage - we don't need to save because the login handler will do that for us later */
$member->failed_logins = array();
/* Now reset the member's password */
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
/* Now reset the member's password. If no handlers accept the change, create a local password */
if ( !$member->changePassword( $values['password'], 'lost' ) )
{
/* We cannot update our password in some login handlers, that's ok */
try
{
$handler->changePassword( $member, $values['password'] );
}
catch( \BadMethodCallException $e ){}
$member->setLocalPassword( $values['password'] );
$member->save();
}
/* Log in, and invalidate all other sessions */
\IPS\Session::i()->setMember( $member );
$member->invalidateSessionsAndLogins( \IPS\Session::i()->id );
\IPS\Member\Device::loadOrCreate( $member )->updateAfterAuthentication( isset( \IPS\Request::i()->cookie['login_key'] ), '' );
\IPS\Member\Device::loadOrCreate( $member )->updateAfterAuthentication( isset( \IPS\Request::i()->cookie['login_key'] ) );
/* Delete validating record and log in */
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) );
@@ -93,6 +93,8 @@ class _metatags extends \IPS\Dispatcher\Controller
*/
protected function end()
{
\IPS\Session::i()->csrfCheck();
$_SESSION['live_meta_tags'] = FALSE;
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( \IPS\Request::i()->url ) );
@@ -113,6 +113,12 @@ class _notifications extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* Log if admin mail setting is changed */
if ( \IPS\Member::loggedIn()->allow_admin_mails !== $values['allow_admin_mails'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'admin_mails', array( 'enabled' => $values['allow_admin_mails'] ) );
}
\IPS\Member::loggedIn()->allow_admin_mails = $values['allow_admin_mails'];
\IPS\Member::loggedIn()->auto_track = json_encode( array(
'content' => ( is_array( $values['auto_track'] ) AND in_array( 'content', $values['auto_track'] ) ) ? 1 : 0,
@@ -168,12 +174,12 @@ class _notifications extends \IPS\Dispatcher\Controller
{
foreach ( $ext->classes as $classname )
{
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
@@ -182,7 +188,7 @@ class _notifications extends \IPS\Dispatcher\Controller
{
foreach( $classname::$containerFollowClasses as $followClass )
{
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $followClass;
break;
@@ -216,6 +222,11 @@ class _notifications extends \IPS\Dispatcher\Controller
$class = 'IPS\\Member';
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\Member\Club';
}
if ( !$class )
{
\IPS\Output::i()->error( 'node_error', '2C154/3', 404, '' );
@@ -223,7 +234,6 @@ class _notifications extends \IPS\Dispatcher\Controller
/* Get thing */
$thing = NULL;
$indexId = NULL;
try
{
if ( in_array( 'IPS\Node\Model', class_parents( $class ) ) )
@@ -242,17 +252,19 @@ class _notifications extends \IPS\Dispatcher\Controller
}
catch ( \Exception $e ) { }
}
else if ( $class != "IPS\Member" )
elseif ( $class == 'IPS\Member\Club' )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->_title ) ) );
\IPS\Output::i()->breadcrumb = array(
array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') ),
array( $thing->url(), $thing->name )
);
}
elseif ( $class != "IPS\Member" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->mapped('title') ) ) );
/* Work out the index ID */
try
{
$indexId = \IPS\Content\Search\Index::i()->getIndexId( $thing );
}
catch ( \UnderflowException $e ) { }
/* Set navigation */
$container = NULL;
@@ -300,7 +312,7 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$type = 'follower_content';
}
elseif ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
elseif ( $class == 'IPS\Member\Club' or in_array( 'IPS\Content\Item', class_parents( $class ) ) )
{
$type = 'new_comment';
}
@@ -348,8 +360,11 @@ class _notifications extends \IPS\Dispatcher\Controller
if ( $class != "IPS\Member" )
{
$options['daily'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_daily');
$options['weekly'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly');
if ( $class != "IPS\Member\Club" )
{
$options['daily'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_daily');
$options['weekly'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly');
}
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_no_notification');
}
@@ -361,7 +376,7 @@ class _notifications extends \IPS\Dispatcher\Controller
) ) );
}
else
{
{
foreach ( $options as $k => $v )
{
$form->hiddenValues[ $k ] = $v;
@@ -401,7 +416,6 @@ class _notifications extends \IPS\Dispatcher\Controller
'follow_notify_freq' => ( $class == "IPS\Member" ) ? 'immediate' : $values['follow_type'],
'follow_notify_sent' => 0,
'follow_visible' => 1,
'follow_index_id' => $indexId,
);
if ( $current )
{
@@ -412,6 +426,33 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->insert( 'core_follow', $save );
}
/* Also follow all nodes if following club */
if( $class == "IPS\Member\Club" )
{
foreach ( $thing->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
$save = array(
'follow_id' => md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ),
'follow_app' => $followApp,
'follow_area' => $followArea,
'follow_rel_id' => $node['node_id'],
'follow_member_id' => \IPS\Member::loggedIn()->member_id,
'follow_is_anon' => !$values['follow_public'],
'follow_added' => time(),
'follow_notify_do' => ( isset( $values['follow_type'] ) AND $values['follow_type'] == 'none' ) ? 0 : 1,
'follow_notify_meta' => '',
'follow_notify_freq' => $values['follow_type'],
'follow_notify_sent' => 0,
'follow_visible' => 1,
);
\IPS\Db::i()->insert( 'core_follow', $save, TRUE );
}
}
/* Send notification if following member */
if( $class == "IPS\Member" )
{
@@ -463,40 +504,46 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', \IPS\Request::i()->id, \IPS\Member::loggedIn()->member_id ) );
/* Get class */
$class = NULL;
foreach ( \IPS\Application::load( \IPS\Request::i()->follow_app )->extensions( 'core', 'ContentRouter' ) as $ext )
/* Get class */
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'member' )
{
foreach ( $ext->classes as $classname )
$class = 'IPS\\Member';
}
elseif( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = NULL;
foreach ( \IPS\Application::load( \IPS\Request::i()->follow_app )->extensions( 'core', 'ContentRouter' ) as $ext )
{
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
foreach ( $ext->classes as $classname )
{
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
}
if( isset( $classname::$containerFollowClasses ) )
{
foreach( $classname::$containerFollowClasses as $followClass )
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
}
if( isset( $classname::$containerFollowClasses ) )
{
foreach( $classname::$containerFollowClasses as $followClass )
{
$class = $followClass;
break;
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $followClass;
break;
}
}
}
}
}
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'member' )
{
$class = 'IPS\\Member';
}
/* Get thing */
$thing = NULL;
@@ -515,6 +562,19 @@ class _notifications extends \IPS\Dispatcher\Controller
catch ( \OutOfRangeException $e )
{
}
/* Unfollow club areas */
if( $class == "IPS\Member\Club" )
{
foreach ( $thing->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ), \IPS\Member::loggedIn()->member_id ) );
}
}
if ( \IPS\Request::i()->isAjax() )
{
@@ -542,9 +602,13 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$class = 'IPS\\Member';
}
else if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area );
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
}
if ( !class_exists( $class ) )
@@ -566,6 +630,13 @@ class _notifications extends \IPS\Dispatcher\Controller
$anonymous = $classname::containerFollowers( $thing, $classname::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->_title;
}
else if ( $class == "IPS\Member\Club" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
$anonymous = $thing->followers( $class::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->_title;
}
else if ( $class != "IPS\Member" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
@@ -617,9 +688,13 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$class = 'IPS\\Member';
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area );
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
}
if ( !class_exists( $class ) )
{
@@ -693,6 +768,23 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id ) );
if( \IPS\Request::i()->follow_area == 'club' )
{
try
{
$club = \IPS\Member\Club::load( \IPS\Request::i()->follow_id );
foreach ( $club->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', $followApp, $followArea, $node['node_id'] ) );
}
}
catch ( \OutOfRangeException $e ) { }
}
\IPS\Output::i()->redirect( ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ), 'followers_removed' );
}
}
@@ -31,7 +31,7 @@ class _privacy extends \IPS\Dispatcher\Controller
{
if ( \IPS\Settings::i()->privacy_type == "none" )
{
\IPS\Output::i()->error( 'node_error', '', 404 ); /* @todo Error code */
\IPS\Output::i()->error( 'node_error', '2C381/1', 404, 'privacy_set_to_none_acp' );
}
/* Set Session Location */
@@ -34,11 +34,19 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Settings::i()->base_url );
}
if( !\IPS\Settings::i()->allow_reg and \IPS\Request::i()->do !== 'complete'
if( \IPS\Request::i()->do !== 'complete'
and \IPS\Request::i()->do !== 'changeEmail' and \IPS\Request::i()->do !== 'validate'
and \IPS\Request::i()->do !== 'validating' and \IPS\Request::i()->do !== 'reconfirm' )
and \IPS\Request::i()->do !== 'validating' and \IPS\Request::i()->do !== 'reconfirm'
and \IPS\Request::i()->do !== 'finish' )
{
\IPS\Output::i()->error( 'reg_disabled', '2S129/5', 403, '' );
if ( \IPS\Login::registrationType() == 'redirect' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Settings::i()->allow_reg_target ) );
}
elseif ( \IPS\Login::registrationType() == 'disabled' )
{
\IPS\Output::i()->error( 'reg_disabled', '2S129/5', 403, '' );
}
}
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
@@ -62,20 +70,20 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->allowDefaultWidgets = FALSE;
/* Quick registration does not work with COPPA */
if ( \IPS\Settings::i()->quick_register )
if ( \IPS\Login::registrationType() == 'normal' )
{
$form = $this->_registrationForm();
$form->class = 'ipsForm_fullWidth';
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('registration');
if( (string) \IPS\Request::i()->url() == (string) \IPS\Http\Url::internal( 'app=core&module=system&controller=register', NULL, 'register' ) )
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) );
}
else
{
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) ) );
}
return;
@@ -137,7 +145,7 @@ class _register extends \IPS\Dispatcher\Controller
{
$form = $this->_registrationForm();
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form, new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form, new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) );
};
/* Output */
@@ -209,18 +217,36 @@ class _register extends \IPS\Dispatcher\Controller
/* Log them in */
\IPS\Session::i()->setMember( $member );
\IPS\Member\Device::loadOrCreate( $member, FALSE )->updateAfterAuthentication( TRUE, '' );
\IPS\Member\Device::loadOrCreate( $member, FALSE )->updateAfterAuthentication( TRUE, NULL );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
if ( isset( \IPS\Request::i()->ref ) and $ref = @base64_decode( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
\IPS\Output::i()->json( array( 'redirect' => (string) $ref ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
\IPS\Output::i()->redirect( $ref );
}
}
}
@@ -241,7 +267,7 @@ class _register extends \IPS\Dispatcher\Controller
$haveRequired = FALSE;
foreach( $steps AS $id => $step )
{
if ( $step->required )
if ( $step->required AND !$step->completed( \IPS\Member::loggedIn() ) )
{
$haveRequired = TRUE;
break;
@@ -253,8 +279,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Nope, forward */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
$wizardSteps = array();
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=finish', 'front', 'register' );
foreach( \IPS\Application::allExtensions( 'core', 'ProfileSteps' ) AS $extension )
@@ -265,6 +290,8 @@ class _register extends \IPS\Dispatcher\Controller
}
}
$wizardSteps = \IPS\Member\ProfileStep::setOrder( $wizardSteps );
$wizardSteps = array_merge( $wizardSteps, array( 'profile_done' => function( $data ) {
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'saved' );
} ) );
@@ -288,11 +315,11 @@ class _register extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form( 'form', 'register_button', NULL, array( 'data-controller' => 'core.front.system.register') );
$form->add( new \IPS\Helpers\Form\Text( 'username', NULL, TRUE, array( 'accountUsername' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE, 'maxLength' => 150, 'bypassProfanity' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'checkStrength' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password' ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'checkStrength' => TRUE, 'bypassProfanity' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password', 'bypassProfanity' => TRUE ) ) );
/* Profile fields */
if ( ! \IPS\Settings::i()->quick_register )
if ( \IPS\Login::registrationType() == 'full' )
{
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
@@ -330,7 +357,15 @@ class _register extends \IPS\Dispatcher\Controller
if( $qanda )
{
$question = \IPS\Db::i()->select( '*', 'core_question_and_answer', array( 'qa_id=?', $qanda ) )->first();
try
{
$question = \IPS\Db::i()->select( '*', 'core_question_and_answer', array( 'qa_id=?', $qanda ) )->first();
}
catch( \UnderflowException $e )
{
throw new \DomainException( 'q_and_a_incorrect' );
}
$answers = json_decode( $question['qa_answers'] );
if( $answers )
@@ -380,14 +415,14 @@ class _register extends \IPS\Dispatcher\Controller
$form->addSeparator();
}
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_admin_mails', TRUE, FALSE ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_admin_mails', \IPS\Settings::i()->updates_consent_default == 'enabled' ? TRUE : FALSE, FALSE ) );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms' ) );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms', array(), \IPS\Http\Url::PROTOCOL_RELATIVE ) );
/* Build the appropriate links for registration terms & privacy policy */
if ( \IPS\Settings::i()->privacy_type == "internal" )
{
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] .= sprintf( \IPS\Member::loggedIn()->language()->get("reg_privacy_link"), \IPS\Http\Url::internal( 'app=core&module=system&controller=privacy', 'front', 'privacy' ), 'data-ipsDialog data-ipsDialog-size="wide" data-ipsDialog-title="' . \IPS\Member::loggedIn()->language()->get("privacy") . '"' );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] .= sprintf( \IPS\Member::loggedIn()->language()->get("reg_privacy_link"), \IPS\Http\Url::internal( 'app=core&module=system&controller=privacy', 'front', 'privacy', array(), \IPS\Http\Url::PROTOCOL_RELATIVE ), 'data-ipsDialog data-ipsDialog-size="wide" data-ipsDialog-title="' . \IPS\Member::loggedIn()->language()->get("privacy") . '"' );
}
else if ( \IPS\Settings::i()->privacy_type == "external" )
{
@@ -478,33 +513,40 @@ class _register extends \IPS\Dispatcher\Controller
$member = new \IPS\Member;
$member->name = $values['username'];
$member->email = $values['email_address'];
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $values['password'] );
$member->setLocalPassword( $values['password'] );
$member->allow_admin_mails = $values['reg_admin_mails'];
$member->member_group_id = \IPS\Settings::i()->member_group;
$member->members_bitoptions['view_sigs'] = TRUE;
$member->last_visit = time();
/* Query spam service */
$spamCode = NULL;
$spamAction = NULL;
if( \IPS\Settings::i()->spam_service_enabled )
{
if( $member->spamService() == 4 )
$spamAction = $member->spamService( 'register', NULL, $spamCode );
if( $spamAction == 4 )
{
\IPS\Output::i()->error( 'spam_denied_account', '2S129/1', 403, '' );
}
}
/* Initial Save */
$member->save();
/* This looks a bit weird, but the extensions expect an account to exist at this point, so we'll let the system save it now, then do what we need to do, then save again */
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
if ( \IPS\Settings::i()->quick_register )
{
$extension = $step->extension;
$extension::formatFormValues( $values, $member, $form );
/* Initial Save */
$member->save();
/* This looks a bit weird, but the extensions expect an account to exist at this point, so we'll let the system save it now, then do what we need to do, then save again */
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
{
$extension = $step->extension;
$extension::formatFormValues( $values, $member, $form );
}
}
/* Save anything the profile extensions did */
$member->save();
$member->logHistory( 'core', 'account', array( 'type' => 'register', 'spamCode' => $spamCode, 'spamAction' => $spamAction ), FALSE );
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
@@ -550,7 +592,18 @@ class _register extends \IPS\Dispatcher\Controller
{
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
}
/* Log that we gave consent for admin emails */
$member->logHistory( 'core', 'admin_mails', array( 'enabled' => (boolean) $member->allow_admin_mails ) );
/* Log that we gave consent for terms and privacy */
if ( \IPS\Settings::i()->privacy_type != 'none' )
{
$member->logHistory( 'core', 'terms_acceptance', array( 'type' => 'privacy' ) );
}
$member->logHistory( 'core', 'terms_acceptance', array( 'type' => 'terms' ) );
/* Handle validation */
$member->postRegistration();
@@ -593,7 +646,13 @@ class _register extends \IPS\Dispatcher\Controller
}
/* They're not validated but in what way? */
if( $validating['user_verified'] )
if ( $validating['reg_cancelled'] )
{
/* They are cancelled and will be deleted, haha, etc */
\IPS\Output::i()->error( 'reg_is_cancelled', '2C223/9', 403, '' );
}
else if ( $validating['user_verified'] )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->notAdminValidated();
}
@@ -690,7 +749,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Check we are an incomplete member */
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
elseif ( \IPS\Member::loggedIn()->real_name and \IPS\Member::loggedIn()->email )
{
@@ -711,6 +770,17 @@ class _register extends \IPS\Dispatcher\Controller
{
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE ) ) );
}
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] )
{
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms' ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_agreed_terms', NULL, TRUE, array(), function( $val )
{
if ( !$val )
{
throw new \InvalidArgumentException('reg_not_agreed_terms');
}
} ) );
}
$form->addButton( 'cancel', 'link', \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=cancel', 'front', 'register' )->csrf() );
/* Handle the submission */
@@ -720,13 +790,16 @@ class _register extends \IPS\Dispatcher\Controller
{
\IPS\Member::loggedIn()->name = $values['username'];
}
$spamCode = NULL;
$spamAction = NULL;
if( isset( $values['email_address'] ) )
{
\IPS\Member::loggedIn()->email = $values['email_address'];
if( \IPS\Settings::i()->spam_service_enabled )
{
if( \IPS\Member::loggedIn()->spamService() == 4 )
$spamAction = \IPS\Member::loggedIn()->spamService( 'register', NULL, $spamCode );
if( $spamAction == 4 )
{
$action = \IPS\Settings::i()->spam_service_action_4;
@@ -740,9 +813,11 @@ class _register extends \IPS\Dispatcher\Controller
}
}
}
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] = FALSE;
/* Save */
\IPS\Member::loggedIn()->save();
\IPS\Member::loggedIn()->logHistory( 'core', 'account', array( 'type' => 'complete' ), FALSE );
/* Handle validation */
\IPS\Member::loggedIn()->postRegistration( ( isset( $values['email_address'] ) ) ? FALSE : TRUE );
@@ -751,7 +826,26 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Session::i()->setType( \IPS\Session\Front::LOGIN_TYPE_MEMBER );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Login::getRegistrationDestination( \IPS\Member::loggedIn() ) );
if ( isset( \IPS\Request::i()->ref ) and $ref = @base64_decode( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
\IPS\Output::i()->redirect( $ref );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_details');
@@ -784,7 +878,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => \IPS\Member::loggedIn() ) ) );
$captcha = new \IPS\Helpers\Form\Captcha;
if ( (string) $captcha !== '' )
{
@@ -794,17 +888,33 @@ class _register extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* Check spam defense whitelist */
if( \IPS\Settings::i()->spam_service_enabled AND ( isset( $pending['new_reg'] ) AND $pending['new_reg'] ) AND \IPS\Member::loggedIn()->spamDefenseWhitelist() )
{
/* We specifically say it's 'register' so that actions are still performed on the account */
$newEmailScore = \IPS\Member::loggedIn()->spamService( 'register', $values['new_email'] );
/* Is it a ban response? */
if( $newEmailScore == 4 )
{
\IPS\Output::i()->error( 'spam_denied_account', '2C223/A', 403, '' );
}
}
/* Change the email */
$oldEmail = \IPS\Member::loggedIn()->email;
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
\IPS\Member::loggedIn()->email = $values['new_email'];
\IPS\Member::loggedIn()->save();
foreach ( \IPS\Login::methods() as $method )
{
try
{
$handler->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
$method->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
}
catch( \BadMethodCallException $e ) {}
}
\IPS\Member::loggedIn()->save();
\IPS\Member::loggedIn()->memberSync( 'onEmailChange', array( $values['new_email'], $oldEmail ) );
\IPS\Member::loggedIn()->logHistory( 'core', 'email_change', array( 'old' => $oldEmail, 'new' => $values['new_email'], 'by' => 'manual' ) );
/* Invalidate sessions except this one */
\IPS\Member::loggedIn()->invalidateSessionsAndLogins( \IPS\Session::i()->id );
@@ -879,16 +989,9 @@ class _register extends \IPS\Dispatcher\Controller
/* Member sync callback */
\IPS\Member::loggedIn()->memberSync( 'onLogout', array( \IPS\Http\Url::internal( '' ) ) );
/* Login handler callback */
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
try
{
$handler->logoutAccount( \IPS\Member::loggedIn(), \IPS\Http\Url::internal( '' ) );
}
catch( \BadMethodCallException $e ) {}
}
/* Flag user as having cancelled their registration */
\IPS\Db::i()->update( 'core_validating', array( 'reg_cancelled' => time() ), array( 'member_id=? AND new_reg=1', \IPS\Member::loggedIn()->member_id ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'reg_canceled' );
@@ -902,23 +1005,27 @@ class _register extends \IPS\Dispatcher\Controller
protected function reconfirm()
{
/* Generate form */
$form = new \IPS\Helpers\Form;
$form = new \IPS\Helpers\Form( 'reconfirm_checkbox', 'reconfirm_checkbox' );
if ( isset( \IPS\Request::i()->ref ) )
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Checkbox( 'reconfirm_checkbox', NULL, FALSE, array(), function( $val )
{
if ( !$val )
{
throw new \InvalidArgumentException('reg_not_agreed_terms');
}
} ) );
/* Handle submissions */
if ( $values = $form->values() )
{
/* Log that we gave consent */
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_privacy'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'terms_acceptance', array( 'type' => 'privacy' ) );
}
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'terms_acceptance', array( 'type' => 'terms' ) );
}
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_privacy'] = FALSE;
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] = FALSE;
\IPS\Member::loggedIn()->save();
File diff suppressed because it is too large. Load diff
@@ -31,10 +31,10 @@ class _twitter extends \IPS\Dispatcher\Controller
{
if ( ! \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https )->setQueryString( 'ref', base64_encode( \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' ) ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( 'ref', base64_encode( \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' ) ) ) );
}
$twitter = \IPS\Login::getHandler('Twitter');
$twitter = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth1\Twitter');
$promote = \IPS\core\Promote::getPromoter( 'Twitter' );
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' );
@@ -43,8 +43,7 @@ class _twitter extends \IPS\Dispatcher\Controller
/* Get a request token */
if ( !isset( \IPS\Request::i()->oauth_token ) )
{
$callback = $url->setQueryString( 'csrf', \IPS\Session::i()->csrfKey );
$response = $twitter->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) $callback ) )->decodeQueryString('oauth_token');
$response = $twitter->requestToken( $url->setQueryString( 'csrf', \IPS\Session::i()->csrfKey ) );
\IPS\Output::i()->redirect( "https://api.twitter.com/oauth/authorize?force_login=1&oauth_token={$response['oauth_token']}" );
}
@@ -55,9 +54,7 @@ class _twitter extends \IPS\Dispatcher\Controller
}
/* Authenticate */
$response = $twitter->sendRequest( 'post', 'https://api.twitter.com/oauth/access_token', array( 'oauth_verifier' => \IPS\Request::i()->oauth_verifier ), \IPS\Request::i()->oauth_token )->decodeQueryString('user_id');
$user = $twitter->sendRequest( 'get', 'https://api.twitter.com/1.1/account/verify_credentials.json', array(), $response['oauth_token'], $response['oauth_token_secret'] )->decodeJson();
$response = $twitter->exchangeToken( \IPS\Request::i()->oauth_verifier, \IPS\Request::i()->oauth_token );
/* Store the settings */
$promote->saveSettings( array(
@@ -65,17 +62,19 @@ class _twitter extends \IPS\Dispatcher\Controller
'owner' => \IPS\Member::loggedIn()->member_id,
'secret' => $response['oauth_token_secret'],
'token' => $response['oauth_token'],
'name' => $user['screen_name']
'name' => $response['screen_name']
) );
/* Show a done page */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_twitter_sorted');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteTwitterComplete( $user );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteTwitterComplete( $response );
}
catch ( \Exception $e )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
\IPS\Log::log( $e, 'twitter_promote' );
\IPS\Output::i()->error( 'generic_error', '4C375/1', 403, $e->getMessage() );
}
}
}
@@ -49,6 +49,9 @@ class _unsubscribe extends \IPS\Dispatcher\Controller
$member->allow_admin_mails = 0;
$member->save();
/* Log it */
$member->logHistory( 'core', 'admin_mails', array( 'enabled' => FALSE ) );
/* And then show them a confirmation screen */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('unsubscribed');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->unsubscribed();
+12 -6
View File
@@ -81,7 +81,7 @@ class _vse extends \IPS\Dispatcher\Controller
/* VSE CSS */
if ( isset( $css['core']['front']['custom']['vse.css'] ) )
{
$functionName = "css_" . uniqid();
$functionName = "css_" . mt_rand();
\IPS\Theme::makeProcessFunction( \IPS\Theme::fixResourceTags( $css['core']['front']['custom']['vse.css']['css_content'], 'front' ), $functionName, '', FALSE, TRUE );
$vseCss = call_user_func( 'IPS\\Theme\\'. $functionName );
}
@@ -89,7 +89,7 @@ class _vse extends \IPS\Dispatcher\Controller
if ( isset( $css['core']['front']['custom']['custom.css'] ) )
{
/* Custom CSS */
$functionName = "css_" . uniqid();
$functionName = "css_" . mt_rand();
\IPS\Theme::makeProcessFunction( \IPS\Theme::fixResourceTags( $css['core']['front']['custom']['custom.css']['css_content'], 'front' ), $functionName, '', FALSE, TRUE );
$customCss = call_user_func( 'IPS\\Theme\\'. $functionName );
}
@@ -133,10 +133,16 @@ class _vse extends \IPS\Dispatcher\Controller
$options['options'] = $options;
break;
}
$field = new $class( "core_theme_setting_title_{$data['sc_id']}", $value, false, $options );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $data['sc_title'], FALSE, array( 'escape' => true ) );
$form->add( $field );
if ( class_exists( $class ) )
{
$field = new $class( "core_theme_setting_title_{$data['sc_id']}", $value, false, $options );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $data['sc_title'], FALSE, array( 'escape' => true ) );
$form->add( $field );
}
else
{
\IPS\Log::log( 'VSE tried to load ' . $class . ' for theme setting ' . $key, 'vse_error' );
}
}
}
@@ -135,7 +135,7 @@ class _warnings extends \IPS\Content\Controller
{
\IPS\Output::i()->error( 'no_module_permission', '2C184/6', 403, '' );
}
/* Build the form */
$form = \IPS\core\Warnings\Warning::create();
$form->class = 'ipsForm_vertical';
@@ -165,7 +165,7 @@ class _warnings extends \IPS\Content\Controller
}
/**
* Axknowledge Warning
* Acknowledge Warning
*
* @return void
*/
@@ -262,7 +262,13 @@ class _warnings extends \IPS\Content\Controller
* @return void
*/
protected function reasonAjax()
{
{
/* Check permission */
if ( ! ( \IPS\Settings::i()->warn_on AND \IPS\Member::loggedIn()->modPermission('mod_see_warn') ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C135/9', 403, '' );
}
$remove = array(
'date' => NULL,
'time' => NULL,
@@ -351,6 +357,13 @@ class _warnings extends \IPS\Content\Controller
);
$member = \IPS\Member::load( \IPS\Request::i()->member );
/* Check permission */
if ( !( \IPS\Settings::i()->warn_on AND ( \IPS\Member::loggedIn()->modPermission('mod_see_warn') or ( \IPS\Settings::i()->warn_show_own and \IPS\Member::loggedIn()->member_id == $member->member_id ) ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C135/9', 403, '' );
}
try
{
$action = \IPS\Db::i()->select( '*', 'core_members_warn_actions', array( 'wa_points<=?', ( $member->warn_level + \IPS\Request::i()->points ) ), 'wa_points DESC', 1 )->first();
@@ -68,7 +68,7 @@ class _widgets extends \IPS\Dispatcher\Controller
}
}
$block = \IPS\Widget::load( $appOrPlugin, $widget['key'], uniqid(), array(), $widget['restrict'], null );
$block = \IPS\Widget::load( $appOrPlugin, $widget['key'], mt_rand(), array(), $widget['restrict'], null );
$block->allowReuse = (boolean) $widget['allow_reuse'];
$block->menuStyle = $widget['menu_style'];
@@ -131,12 +131,20 @@ class _widgets extends \IPS\Dispatcher\Controller
}
}
}
catch ( \OutOfRangeException $e ) { }
catch ( \UnderflowException $e ) { }
}
if ( !isset( $widget ) )
{
$widget = \IPS\Widget::load( ( $key[0] == 'plugin' ) ? \IPS\Plugin::load( $key[1] ) : \IPS\Application::load( $key[1] ), $key[2], $key[3], array(), null, \IPS\Request::i()->orientation );
try
{
$widget = \IPS\Widget::load( ( $key[0] == 'plugin' ) ? \IPS\Plugin::load( $key[1] ) : \IPS\Application::load( $key[1] ), $key[2], $key[3], array(), null, \IPS\Request::i()->orientation );
}
catch( \OutOfRangeException $e )
{
$widget = '';
}
}
\IPS\Output::i()->sendOutput( (string) $widget );
@@ -217,6 +225,7 @@ class _widgets extends \IPS\Dispatcher\Controller
$blocks[ $k ]['configuration'] = $values;
\IPS\Db::i()->insert( 'core_widget_areas', array( 'app' => \IPS\Request::i()->pageApp, 'module' => \IPS\Request::i()->pageModule, 'controller' => \IPS\Request::i()->pageController, 'area' => \IPS\Request::i()->pageArea, 'widgets' => json_encode( $blocks ) ), TRUE );
\IPS\Widget::deleteCaches( $block['key'], ( isset( $block['app'] ) ) ? $block['app'] : NULL, ( isset( $block['plugin'] ) ) ? $block['plugin'] : NULL );
\IPS\Output::i()->json( 'OK' );
}
\IPS\Output::i()->output = $widget->configuration()->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'widgets', 'core' ) ), 'formTemplate' ), $widget );
@@ -30,7 +30,7 @@ class _admin extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form( 'admin', 'continue' );
$form->add( new \IPS\Helpers\Form\Text( 'admin_user', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Password( 'admin_pass1', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Password( 'admin_pass1', NULL, TRUE, array() ) );
$form->add( new \IPS\Helpers\Form\Password( 'admin_pass2', NULL, TRUE, array( 'confirm' => 'admin_pass1' ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'admin_email', NULL, TRUE ) );
@@ -119,6 +119,9 @@ class _applications extends \IPS\Dispatcher\Controller
'getHtml' => function( $element ) use ( $apps )
{
$options = array_combine( array_keys( $apps ), array_map( function( $value ){ return $value['name']; }, $apps ) );
/* But put system app at end of list to ensure it's not selected by default over something else */
unset( $options['core'] );
$options['core'] = $apps['core']['name'];
return \IPS\Theme::i()->getTemplate( 'forms' )->select( 'default_app', $element->value, TRUE, $options );
},
'validate' => function( $element ) use ( $apps )
@@ -42,11 +42,7 @@ class _done extends \IPS\Dispatcher\Controller
require \IPS\ROOT_PATH . '/conf_global.php';
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => $INFO['lkey'] ), array( 'conf_key=?', 'ipb_reg_number' ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => md5( $INFO['sql_pass'] . $INFO['base_url'] . $INFO['sql_database'] ) ), array( 'conf_key=?', 'site_secret_key' ) );
\IPS\Settings::i()->ipb_reg_number = $INFO['lkey'];
\IPS\Settings::i()->site_secret_key = md5( $INFO['sql_pass'] . $INFO['base_url'] . $INFO['sql_database'] );
unset( \IPS\Data\Store::i()->settings );
\IPS\Settings::i()->changeValues( array( 'ipb_reg_number' => $INFO['lkey'], 'site_secret_key' => md5( $INFO['sql_pass'] . $INFO['base_url'] . $INFO['sql_database'] ) ) );
\file_put_contents( \IPS\ROOT_PATH . '/conf_global.php', "<?php\n\n" . '$INFO = ' . var_export( array(
'sql_host' => $INFO['sql_host'],
@@ -30,7 +30,7 @@ class _license extends \IPS\Dispatcher\Controller
public function manage()
{
$form = new \IPS\Helpers\Form( 'license', 'continue', \IPS\Http\Url::external( ( \IPS\Request::i()->isSecure() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?controller=license' ) );
$form->add( new \IPS\Helpers\Form\Text( 'lkey', 'Nulled by IPBMafia.ru | 25.07.2017', TRUE, array( 'size' => 50 ), function( $val )
$form->add( new \IPS\Helpers\Form\Text( 'lkey', 'Nulled by IPBMafia.ru | 18.04.2018', TRUE, array( 'size' => 50 ), function( $val )
{
\IPS\IPS::checkLicenseKey( $val, ( \IPS\Request::i()->isSecure() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . mb_substr( $_SERVER['SCRIPT_NAME'], 0, -mb_strlen( \IPS\CP_DIRECTORY . '/install/index.php' ) ) );
}, NULL, '<a href="' . \IPS\Http\Url::ips( 'docs/find_lkey' ) . '" target="_blank">' . \IPS\Member::loggedIn()->language()->addToStack('lkey_help') . '</a>' ) );
@@ -57,8 +57,16 @@ class _done extends \IPS\Dispatcher\Controller
unset( $_SESSION['sqlFinished'] );
}
if( isset( $_SESSION['uniqueKey'] ) )
{
unset( $_SESSION['uniqueKey'] );
}
unset( $_SESSION['key'] );
/* Unset settings datastore to prevent any upgrade settings that were overridden becoming persistent */
\IPS\Settings::i()->clearCache();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud('Upgraded community');
Loaded 100 of 1349 files, more files were not shown because too many files have changed in this diff. Show more