Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

@@ -0,0 +1,155 @@
<?php
/**
* @brief API Splash Page
* @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 03 Dec 2015
* @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;
}
/**
* API Splash Page
*/
class _api extends \IPS\Dispatcher\Controller
{
/**
* Call
*
* @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 )
{
$url = \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->base_url, '/' ) . '/api/core/hello' );
}
else
{
$url = \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->base_url, '/' ) . '/api/index.php?/core/hello' );
}
try
{
if ( \IPS\Request::i()->isCgi() )
{
$response = $url->setQueryString( 'key', 'test' )->request()->get()->decodeJson();
}
else
{
$response = $url->request()->login( 'test', '' )->get()->decodeJson();
}
if ( $response['errorMessage'] != 'INVALID_API_KEY' and $response['errorMessage'] != 'TOO_MANY_REQUESTS_WITH_BAD_KEY' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_applications_api');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'api' )->htaccess( isset( \IPS\Request::i()->recheck ), $url );
return;
}
/* Work out tabs */
$tabs = array();
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_manage' ) )
{
$tabs['apiKeys'] = 'api_keys';
}
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_logs' ) )
{
$tabs['apiLogs'] = 'api_logs';
}
if( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_reference' ) )
{
$tabs['apiReference'] = 'api_reference';
}
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 );
}
/* Route */
$classname = 'IPS\core\modules\admin\applications\\' . $activeTab;
$class = new $classname;
$class->url = \IPS\Http\Url::internal("app=core&module=applications&controller=api&tab={$activeTab}");
$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( 'global', 'core' )->tabs( $tabs, $activeTab, $output, \IPS\Http\Url::internal( "app=core&module=applications&controller=api" ) );
}
/**
* Download .htaccess file
*
* @return void
*/
protected function htaccess()
{
$dir = rtrim( str_replace( \IPS\CP_DIRECTORY . '/index.php', '', $_SERVER['PHP_SELF'] ), '/' ) . '/api/';
$path = $dir . 'index.php';
if( \strpos( $dir, ' ' ) !== FALSE )
{
$dir = '"' . $dir . '"';
$path = '"' . $path . '"';
}
$htaccess = <<<FILE
<IfModule mod_setenvif.c>
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
</IfModule>
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase {$dir}
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
</IfModule>
FILE;
\IPS\Output::i()->sendOutput( $htaccess, 200, 'application/x-htaccess', array( 'Content-Disposition' => 'attachment; filename=.htaccess' ) );
}
}
@@ -0,0 +1,47 @@
<?php
/**
* @brief API Keys
* @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 03 Dec 2015
* @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;
}
/**
* api
*/
class _apiKeys extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = 'IPS\Api\Key';
/**
* Description can contain HTML?
*/
public $_descriptionHtml = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'api_manage' );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/api.css', 'core', 'admin' ) );
parent::execute();
}
}
@@ -0,0 +1,218 @@
<?php
/**
* @brief API Logs
* @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 04 Dec 2015
* @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;
}
/**
* apiReference
*/
class _apiLogs extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'api_logs' );
parent::execute();
}
/**
* View Logs
*
* @return void
*/
protected function manage()
{
/* Init table */
$table = new \IPS\Helpers\Table\Db( 'core_api_logs', \IPS\Http\Url::internal('app=core&module=applications&controller=api&tab=apiLogs') );
$table->langPrefix = 'api_log_';
/* Columns */
$table->include = array( 'date', 'endpoint', 'api_key', 'ip_address', 'response_code' );
$table->parsers = array(
'date' => function( $val )
{
return \IPS\DateTime::ts( $val );
},
'endpoint' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate('api')->apiKey( $row['method'] . ' ' . $val );
},
'api_key' => function( $val, $row )
{
try
{
return \IPS\Api\Key::load( $val )->_title;
}
catch ( \OutOfRangeException $e )
{
return \IPS\Theme::i()->getTemplate('api')->apiKey( $val );
}
},
'response_code' => function( $val )
{
return $val . ' ' . \IPS\Output::$httpStatuses[ $val ];
}
);
/* Default sort */
$table->sortBy = $table->sortBy ?: 'date';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Filters */
$table->filters = array(
'api_log_success' => array( 'response_code LIKE ?', '2%' ),
'api_log_fail' => array( 'response_code NOT LIKE ?', '2%' ),
);
/* Search */
$endpoints = array();
foreach ( \IPS\Api\Controller::getAllEndpoints() as $k => $data )
{
$endpoints[ $data['title'] ] = $data['title'];
}
$statuses = array();
foreach ( \IPS\Output::$httpStatuses as $code => $name )
{
$statuses[ $code ] = "{$code} {$name}";
}
$table->advancedSearch = array(
'date' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'endpoint' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $endpoints ), function( $val )
{
$exploded = explode( ' ', $val );
return array( 'method=? AND endpoint=?', $exploded[0], trim( $exploded[1], '/' ) );
} ),
'api_key' => array( \IPS\Helpers\Table\SEARCH_NODE, array( 'class' => 'IPS\Api\Key' ) ),
'ip_address' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'response_code' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $statuses ) ),
);
/* Buttons */
$table->rowButtons = function( $row )
{
$return = array(
'view' => array(
'icon' => 'search',
'title' => 'view',
'link' => \IPS\Http\Url::internal('app=core&module=applications&controller=apiLogs&do=view')->setQueryString( 'id', $row['id'] ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => $row['method'] . ' ' . $row['endpoint'] )
)
);
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_logs_delete' ) )
{
$return['delete'] = array(
'icon' => 'times-circle',
'title' => 'delete',
'link' => \IPS\Http\Url::internal('app=core&module=applications&controller=apiLogs&do=delete')->setQueryString( 'id', $row['id'] ),
'data' => array( 'delete' => '' )
);
}
return $return;
};
/* Display */
if ( !isset( \IPS\Request::i()->advancedSearchForm ) )
{
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'applications', 'api_logs_settings' ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms' )->blurb( \IPS\Member::loggedIn()->language()->addToStack( 'api_log_blurb_change', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->api_log_prune ) ) ), TRUE, TRUE ) . $table;
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms' )->blurb( \IPS\Member::loggedIn()->language()->addToStack( 'api_log_blurb', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->api_log_prune ) ) ), TRUE, TRUE ) . $table;
}
}
else
{
\IPS\Output::i()->output = $table;
}
}
/**
* View Log
*
* @return void
*/
protected function view()
{
try
{
$log = \IPS\Db::i()->select( '*', 'core_api_logs', array( 'id=?', \IPS\Request::i()->id ) )->first();
}
catch ( \UnderflowException $e )
{
\IPS\Output::i()->error( 'node_error', '2C293/1', 404, '' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('api')->viewLog( $log['request_data'], $log['response_output'] );
}
/**
* Delete Log
*
* @return void
*/
protected function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'api_logs_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$log = \IPS\Db::i()->select( '*', 'core_api_logs', array( 'id=?', \IPS\Request::i()->id ) )->first();
}
catch ( \UnderflowException $e )
{
\IPS\Output::i()->error( 'node_error', '2C293/2', 404, '' );
}
\IPS\Db::i()->delete( 'core_api_logs', array( 'id=?', $log['id'] ) );
\IPS\Session::i()->log( 'acplog__api_log_deleted', array( $log['id'] => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=applications&controller=api&tab=apiLogs') );
}
/**
* Prune Settings
*
* @return void
*/
protected function settings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'api_logs_settings' );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Number( 'api_log_prune', \IPS\Settings::i()->api_log_prune, FALSE, array(), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days') ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplogs__api_log_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=applications&controller=api&tab=apiLogs') );
}
\IPS\Output::i()->output = $form;
}
}
@@ -0,0 +1,181 @@
<?php
/**
* @brief API Reference
* @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 03 Dec 2015
* @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;
}
/**
* apiReference
*/
class _apiReference extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'api_reference' );
parent::execute();
}
/**
* View Reference
*
* @return void
*/
protected function manage()
{
/* If Opcache is enabled but opcache.save_comments is disabled, the API reference won't work */
if( extension_loaded( 'opcache' ) AND !ini_get( 'opcache.save_comments' ) )
{
\IPS\Output::i()->error( 'api_opcache_disable', '4C331/1', 403, '' );
}
/* Get endpoint details */
$endpoints = \IPS\Api\Controller::getAllEndpoints();
$selected = NULL;
$content = '';
/* If we're viewing a specific one, get information about it */
if ( isset( \IPS\Request::i()->endpoint ) and array_key_exists( \IPS\Request::i()->endpoint, $endpoints ) )
{
$selected = \IPS\Request::i()->endpoint;
$additionalClassesToReference = array();
$params = array();
if ( isset( $endpoints[ $selected ]['details']['reqapiparam'] ) )
{
$params = array_map( function( $v ) {
$v[4] = TRUE;
return $v;
}, $endpoints[ $selected ]['details']['reqapiparam'] );
}
if ( isset( $endpoints[ $selected ]['details']['apiparam'] ) )
{
$params = array_merge( $params, $endpoints[ $selected ]['details']['apiparam'] );
}
$exceptions = isset( $endpoints[ $selected ]['details']['throws'] ) ? $endpoints[ $selected ]['details']['throws'] : NULL;
$response = NULL;
$return = array_filter( $endpoints[ $selected ]['details']['return'][0] );
$return = array_pop( $return );
if ( $return == 'array' )
{
if ( isset( $endpoints[ $selected ]['details']['apiresponse'] ) )
{
foreach ( $endpoints[ $selected ]['details']['apiresponse'] as $data )
{
if ( !in_array( $data[0], array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
{
if ( mb_substr( $data[0], 0, 1 ) == '[' )
{
if ( !in_array( mb_substr( $data[0], 1, -1 ), array( 'int', 'string', 'float', 'datetime', 'bool', 'object' ) ) )
{
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( mb_substr( $data[0], 1, -1 ) ) );
}
}
else
{
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $data[0] ) );
}
}
}
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( $endpoints[ $selected ]['details']['apiresponse'] );
}
}
elseif ( mb_substr( $return, 0, mb_strlen( '\IPS\Api\PaginatedResponse' ) ) == '\IPS\Api\PaginatedResponse' )
{
$class = mb_substr( trim( $return ), mb_strlen( '\IPS\Api\PaginatedResponse' ) + 1, -1 );
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $class ) );
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( array(
array( 'int', 'page', 'api_int_page' ),
array( 'int', 'perPage', 'api_int_perpage' ),
array( 'int', 'totalResults', 'api_int_totalresults' ),
array( 'int', 'totalPages', 'api_int_totalpages' ),
array( "[{$class}]", 'results', 'api_results_thispage' ),
) );
}
elseif ( $return = trim( $return ) and class_exists( $return ) and method_exists( $return, 'apiOutput' ) )
{
$additionalClassesToReference = array_merge( $additionalClassesToReference, $this->_getAdditionalClasses( $return, TRUE ) );
$reflection = new \ReflectionMethod( $return, 'apiOutput' );
$decoded = \IPS\Api\Controller::decodeDocblock( $reflection->getDocComment() );
$response = \IPS\Theme::i()->getTemplate('api')->referenceTable( $decoded['details']['apiresponse'] );
}
$additionalClasses = array();
foreach ( $additionalClassesToReference as $class )
{
$reflection = new \ReflectionMethod( $class, 'apiOutput' );
$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 );
}
$endpointTree = array();
foreach ( $endpoints as $key => $endpoint )
{
$pieces = explode('/', $key);
$endpointTree[ $pieces[0] ][ $pieces[1] ][ $key ] = $endpoint;
}
if ( \IPS\Request::i()->endpoint and \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $content, 200, 'text/html' );
}
/* Output */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('api')->referenceTemplate( $endpoints, $endpointTree, $selected, $content );
}
/**
* Get any additional classes referenced in the return types of this class
*
* @param string $class The classname
* @param bool $exclude If FALSE, will include this class itself in the return array
* @return array
*/
protected function _getAdditionalClasses( $class, $exclude=FALSE )
{
$return = $exclude ? array() : array( $class => $class );
$reflection = new \ReflectionMethod( $class, 'apiOutput' );
$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_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' ) ) )
{
$return = array_merge( $return, $this->_getAdditionalClasses( mb_substr( $response[0], 1, -1 ) ) );
}
}
elseif ( !in_array( $response[0], $return ) )
{
$return = array_merge( $return, $this->_getAdditionalClasses( $response[0] ) );
}
}
}
return $return;
}
}
@@ -2,9 +2,9 @@
/**
* @brief Application & Module Management Controller
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Feb 2013
* @version SVN_VERSION_NUMBER
*/
@@ -27,6 +27,17 @@ class _applications extends \IPS\Node\Controller
* Node Class
*/
protected $nodeClass = 'IPS\Application';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'app_manage' );
parent::execute();
}
/**
* Manage
@@ -213,6 +224,7 @@ class _applications extends \IPS\Node\Controller
'icon' => 'cogs',
'link' => \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications&do=buildAll' ),
'title' => 'build_all_apps',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('build_all_apps') )
);
}
}
@@ -446,6 +458,68 @@ class _applications extends \IPS\Node\Controller
\IPS\Output::i()->output = $form;
}
/**
* Build form
*
* @param string $appKey The application key
* @param bool $includeDownloadOption If a "just download" option should be included
* @return \IPS\Helpers\Form
*/
protected function _buildForm( $appKey, $includeDownloadOption=FALSE )
{
$json = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$appKey}/data/versions.json" ), TRUE );
ksort( $json );
$defaults = array( 'human' => '1.0.0', 'long' => '10000' );
$long = NULL;
$human = NULL;
foreach ( array_reverse( $json, TRUE ) as $long => $human )
{
$exploded = explode( '.', $human );
$defaults['human'] = "{$exploded[0]}.{$exploded[1]}." . ( intval( $exploded[2] ) + 1 );
$defaults['long'] = $long + 1;
break;
}
$options = array(
'options' => array(),
'toggles' => array( 'new' => array( 'versions_human', 'versions_long' ) )
);
if ( $human !== NULL )
{
$options['options']['rebuild'] = 'developer_build_type_rebuild';
\IPS\Member::loggedIn()->language()->words['developer_build_type_rebuild'] = sprintf( \IPS\Member::loggedIn()->language()->get('developer_build_type_rebuild'), $human );
}
$options['options']['new'] = 'developer_build_new';
if ( $includeDownloadOption )
{
$options['options']['download'] = 'developer_build_download';
}
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Radio( 'developer_build_type', 'rebuild', TRUE, $options ) );
$form->add( new \IPS\Helpers\Form\Text( 'versions_human', $defaults['human'], NULL, array(), function( $val )
{
if ( !preg_match( '/^\d*\.\d*\.\d*(( (Alpha|Beta|RC)\s?[a-zA-Z0-9]*)|(\.\d*))?$/', $val ) )
{
throw new \DomainException( 'versions_human_error' );
}
}, NULL, NULL, 'versions_human' ) );
$form->add( new \IPS\Helpers\Form\Text( 'versions_long', $defaults['long'], NULL, array(), function( $val ) use ( $json )
{
if ( !preg_match( '/^\d*$/', $val ) )
{
throw new \DomainException( 'form_number_bad' );
}
if( isset( $json[ $val ] ) )
{
throw new \DomainException( 'versions_long_exists' );
}
}, NULL, NULL, 'versions_long' ) );
return $form;
}
/**
* Build all applications
*
@@ -457,20 +531,32 @@ class _applications extends \IPS\Node\Controller
{
\IPS\Output::i()->error( 'not_in_dev', '2C133/M', 403, '' );
}
foreach ( \IPS\Application::applications() as $application )
$form = $this->_buildForm( 'core' );
if ( $values = $form->values() )
{
try
foreach ( \IPS\Application::applications() as $application )
{
$application->build();
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
if ( $values['developer_build_type'] === 'new' )
{
$application->assignNewVersion( $values['versions_long'], $values['versions_human'] );
}
try
{
$application->build();
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_built' );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_built' );
\IPS\Output::i()->output = $form;
}
/**
@@ -487,17 +573,28 @@ class _applications extends \IPS\Node\Controller
$application = \IPS\Application::load( \IPS\Request::i()->appKey );
try
{
$application->build();
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
}
$form = $this->_buildForm( $application->directory );
/* And redirect back to the overview screen */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_built' );
if ( $values = $form->values() )
{
if ( $values['developer_build_type'] === 'new' )
{
$application->assignNewVersion( $values['versions_long'], $values['versions_human'] );
}
try
{
$application->build();
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_built' );
}
\IPS\Output::i()->output = $form;
}
/**
@@ -508,50 +605,49 @@ class _applications extends \IPS\Node\Controller
*/
public function download()
{
if( empty( \IPS\Request::i()->type ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'applications' )->downloadDialog( \IPS\Request::i()->appKey );
return;
}
$application = \IPS\Application::load( \IPS\Request::i()->appKey );
if( \IPS\Request::i()->type == 'build' )
$form = $this->_buildForm( $application->directory, TRUE );
if ( $values = $form->values() )
{
if ( $values['developer_build_type'] !== 'download' )
{
if ( $values['developer_build_type'] === 'new' )
{
$application->assignNewVersion( $values['versions_long'], $values['versions_human'] );
}
try
{
$application->build();
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
}
}
try
{
$application->build();
$pharPath = str_replace( '\\', '/', rtrim( \IPS\TEMP_DIRECTORY, '/' ) ) . '/' . $application->directory . ".tar";
$download = new \PharData( $pharPath, 0, $application->directory . ".tar", \Phar::TAR );
$download->buildFromIterator( new \IPS\Application\BuilderIterator( $application ) );
}
catch ( \Exception $e )
catch( \PharException $e )
{
\IPS\Output::i()->error( $e->getMessage(), '' );
\IPS\Output::i()->error( 'app_no_phar', '4C133/7', 403, '' );
}
$output = \file_get_contents( rtrim( \IPS\TEMP_DIRECTORY, '/' ) . '/' . $application->directory . ".tar" );
/* Cleanup */
unset($download);
\Phar::unlinkArchive($pharPath);
\IPS\Output::i()->sendOutput( $output, 200, 'application/tar', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', $application->directory . '.tar' ) ), FALSE, FALSE, FALSE );
}
if ( !extension_loaded('phar') )
{
\IPS\Output::i()->error( 'app_no_phar', '1C133/Q', 403, '' );
}
try
{
$pharPath = str_replace( '\\', '/', rtrim( \IPS\TEMP_DIRECTORY, '/' ) ) . '/' . $application->directory . ".tar";
$download = new \PharData( $pharPath, 0, $application->directory . ".tar", \Phar::TAR );
$download->buildFromIterator( new \IPS\Application\BuilderIterator( $application ) );
}
catch( \PharException $e )
{
\IPS\Output::i()->error( 'app_no_phar', '4C133/7', 403, '' );
}
$output = \file_get_contents( rtrim( \IPS\TEMP_DIRECTORY, '/' ) . '/' . $application->directory . ".tar" );
/* Cleanup */
unset($download);
\Phar::unlinkArchive($pharPath);
\IPS\Output::i()->sendOutput( $output, 200, 'application/tar', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', $application->directory . '.tar' ) ), FALSE, FALSE, FALSE );
\IPS\Output::i()->output = $form;
}
/**
@@ -562,7 +658,7 @@ class _applications extends \IPS\Node\Controller
*/
public function upgrade()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('installing_application');
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('upgrading_application');
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( "app=core&module=applications&controller=applications&do=upgrade&appKey=" . \IPS\Request::i()->appKey ),
@@ -771,7 +867,7 @@ class _applications extends \IPS\Node\Controller
/* Return null to indicate we are done */
if( $laststep === NULL )
{
\IPS\Session::i()->log( 'acplog__application_updated', array( \IPS\Application::load( $data['key'] )->_title => TRUE, \IPS\Application::load( $data['key'] )->version => TRUE ) );
\IPS\Session::i()->log( 'acplog__application_updated', array( \IPS\Application::load( $data['key'] )->titleForLog() => FALSE, \IPS\Application::load( $data['key'] )->version => TRUE ) );
return NULL;
}
@@ -782,6 +878,9 @@ class _applications extends \IPS\Node\Controller
},
function()
{
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* And redirect back to the overview screen */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_updated' );
}
@@ -827,7 +926,7 @@ class _applications extends \IPS\Node\Controller
\IPS\Output::i()->error( 'app_invalid_data', '4C133/5', 403, '' );
}
$application['app_position'] = \IPS\DB::i()->select( 'MAX(app_position)', 'core_applications' )->first() + 1;
$application['app_position'] = \IPS\Db::i()->select( 'MAX(app_position)', 'core_applications' )->first() + 1;
$application['app_added'] = time();
$application['app_protected'] = 0;
$application['app_enabled'] = 0; /* We will reset this post-installation */
@@ -835,7 +934,7 @@ class _applications extends \IPS\Node\Controller
//\IPS\Lang::saveCustom( $application['app_directory'], "__app_{$application['app_directory']}", $application['application_title'] );
unset($application['application_title']);
\IPS\DB::i()->insert( 'core_applications', $application );
\IPS\Db::i()->insert( 'core_applications', $application );
}
else
{
@@ -984,6 +1083,7 @@ class _applications extends \IPS\Node\Controller
/* Clear caches so templates can rebuild and so on */
\IPS\Data\Store::i()->clearAll();
\IPS\Data\Cache::i()->clearAll();
\IPS\IPS::resyncIPSCloud();
/* And redirect back to the overview screen */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), 'application_now_installed' );
@@ -1008,7 +1108,23 @@ class _applications extends \IPS\Node\Controller
try
{
$node = call_user_func( "{$nodeClass}::load", \IPS\Request::i()->id );
/* Load the application - we don't use \IPS\Application::load() because this could be a legacy out of date application
and if no Application.php an exception will be thrown. We don't need to stop just based on that, we want to proceed with delete. */
$node = NULL;
foreach( \IPS\Data\Store::i()->applications as $application )
{
if( $application['app_directory'] == \IPS\Request::i()->id )
{
$node = \IPS\Application::constructFromData( $application );
break;
}
}
if( $node === NULL )
{
throw new \UnexpectedValueException;
}
/* Permission check */
if( !$node->canDelete() )
@@ -1020,6 +1136,11 @@ class _applications extends \IPS\Node\Controller
{
return $this->setNewDefaultApplication($node);
}
else
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
}
/* Delete it */
\IPS\Session::i()->log( 'acplog__application_uninstalled', array( $node->directory => TRUE ) );
@@ -1065,10 +1186,11 @@ class _applications extends \IPS\Node\Controller
protected function setNewDefaultApplication($node)
{
$form = new \IPS\Helpers\Form();
$form->hiddenValues['wasConfirmed'] = 1;
$form->add( new \IPS\Helpers\Form\Node( 'new_default_app', NULL, false, array(
'class' => 'IPS\Application',
'subnodes' => false,
'permissionCheck' => function( $app )
'permissionCheck' => function( $app ) use ( $node )
{
if ( $app->directory == 'core')
{
@@ -1076,7 +1198,7 @@ class _applications extends \IPS\Node\Controller
}
else
{
return true;
return !($node->directory == $app->directory);
}
}
@@ -1086,7 +1208,7 @@ class _applications extends \IPS\Node\Controller
{
$values['new_default_app']->setAsDefault();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=applications&do=delete&id={$node->_id}" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=applications&do=delete&id={$node->_id}&wasConfirmed=1" ) );
}
else
{
@@ -1133,6 +1255,7 @@ class _applications extends \IPS\Node\Controller
$tabs = array();
$tabs['details'] = 'app_details_details';
$tabs['upgrades'] = 'app_details_upgrades';
$tabs['hooks'] = 'app_details_hooks';
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $tabs[ $tab ] );
@@ -1173,7 +1296,21 @@ class _applications extends \IPS\Node\Controller
{
try
{
$app = \IPS\Application::load( \IPS\Request::i()->appKey );
$app = NULL;
foreach( \IPS\Data\Store::i()->applications as $application )
{
if( $application['app_directory'] == \IPS\Request::i()->appKey )
{
$app = \IPS\Application::constructFromData( $application );
break;
}
}
if( $app === NULL )
{
throw new \OutOfRangeException;
}
}
catch ( \UnexpectedValueException $e )
{
@@ -1224,8 +1361,11 @@ class _applications extends \IPS\Node\Controller
/* Get app directory */
$appdata = json_decode( file_get_contents( "phar://" . $values['application_file'] . '/data/application.json' ), TRUE );
$appDirectory = $appdata['app_directory'];
/* Extract */
$application->extractTo( \IPS\ROOT_PATH . "/applications/" . $appDirectory, NULL, TRUE );
$this->_checkChmod( \IPS\ROOT_PATH . '/applications/' . $appDirectory );
\IPS\IPS::resyncIPSCloud();
}
catch( \PharException $e )
{
@@ -1242,6 +1382,34 @@ class _applications extends \IPS\Node\Controller
/* Display */
\IPS\Output::i()->output = $form;
}
/**
* Recursively check and adjust CHMOD permissions after uploading an application
*
* @param string $directory Directory to check
* @return void
* @see Ticket 956849
*/
protected function _checkChmod( $directory )
{
if ( !is_dir( $directory ) )
{
throw new \UnexpectedValueException;
}
$it = new \RecursiveDirectoryIterator( $directory, \FilesystemIterator::SKIP_DOTS );
foreach( new \RecursiveIteratorIterator( $it ) AS $f )
{
if ( $f->isDir() )
{
@chmod( $f->getPathname(), \IPS\IPS_FOLDER_PERMISSION );
}
else
{
@chmod( $f->getPathname(), \IPS\IPS_FILE_PERMISSION );
}
}
}
/**
* Import JS from /dev folders and compile into file objects
@@ -1318,7 +1486,7 @@ class _applications extends \IPS\Node\Controller
{
try
{
$history = \IPS\DB::i()->select( 'upgrade_date', 'core_upgrade_history', array( 'upgrade_app=?', $application->directory ), 'upgrade_version_id DESC', array( 0, 1 ) )->first();
$history = \IPS\Db::i()->select( 'upgrade_date', 'core_upgrade_history', array( 'upgrade_app=?', $application->directory ), 'upgrade_version_id DESC', array( 0, 1 ) )->first();
}
catch( \UnderflowException $ex )
{
@@ -1345,6 +1513,32 @@ class _applications extends \IPS\Node\Controller
return ( count( $upgrades ) ) ? \IPS\Theme::i()->getTemplate( 'global' )->definitionTable( $list ) : \IPS\Member::loggedIn()->language()->addToStack('app_no_upgrade_history');
}
/**
* Show the application hooks
*
* @param \IPS\Application $application Application
* @return string
*/
protected function _showHooks( $application )
{
$table = new \IPS\Helpers\Table\Db( 'core_hooks', \IPS\Http\Url::internal( "app=core&module=applications&controller=applications&do=details&id={$application->directory}&tab=hooks" ), array( 'app=?', $application->directory ) );
$table->include = array( 'filename', 'class' );
$table->langPrefix = 'plugin_hook_';
if ( !$table->sortBy )
{
$table->sortBy = 'class';
$table->sortDirection = 'asc';
}
$table->parsers = array(
'filename' => function( $val, $row )
{
return $val . '.php';
}
);
return $table;
}
/**
* Toggle Enabled/Disable
@@ -2,9 +2,9 @@
/**
* @brief Developer Center Controller
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Feb 2013
* @version SVN_VERSION_NUMBER
*/
@@ -436,6 +436,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function deleteModule()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Load the module */
try
{
@@ -671,6 +674,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function menuDelete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Get Menu */
$menu = $this->_getJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/acpmenu.json" );
@@ -942,6 +948,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
public function restrictionGroupDelete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$restrictions = $this->_getJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/acprestrictions.json" );
$module = $this->_loadModule();
@@ -983,6 +992,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
public function restrictionRowDelete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$restrictions = $this->_getJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/acprestrictions.json" );
$module = $this->_loadModule();
$group = \IPS\Request::i()->group;
@@ -1072,7 +1084,7 @@ class _developer extends \IPS\Dispatcher\Controller
$contents = str_replace(
array(
'{controller}',
"{subpackage}\n",
"{subpackage}",
'{date}',
'{app}',
'{module}',
@@ -1083,7 +1095,7 @@ class _developer extends \IPS\Dispatcher\Controller
),
array(
$values['filename'],
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) . "\n" ) : '',
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) ) : '',
date( 'd M Y' ),
$this->application->directory,
\IPS\Request::i()->module_key,
@@ -1114,7 +1126,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'],
'tab' => $values['acpmenu_tab'][0],
'controller' => $values['filename'],
'do' => '',
'restriction' => $restriction
@@ -1139,11 +1151,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
/* Create the file if it doesn't exist */
$json = $this->_getSchema();
/* Get out latest version */
$latestVersion = $this->_getLatestVersion();
$human = $latestVersion['human'];
/* Build list table */
$table = new \IPS\Helpers\Table\Custom( $json, \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=schema" ) );
$table->langPrefix = 'database_table_';
@@ -1167,7 +1175,7 @@ class _developer extends \IPS\Dispatcher\Controller
/* Add the buttons for each row */
$appKey = $this->application->directory;
$table->rowButtons = function( $row ) use ( $human, $appKey )
$table->rowButtons = function( $row ) use ( $appKey )
{
return array(
'edit' => array(
@@ -1180,7 +1188,7 @@ class _developer extends \IPS\Dispatcher\Controller
'icon' => 'times-circle',
'title' => 'database_table_delete',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$appKey}&do=deleteTable&name={$row['name']}" ),
'data' => array( 'delete' => '', 'delete-warning' => \IPS\Member::loggedIn()->language()->addToStack( 'database_droptable_info', FALSE, array( 'sprintf' => array( $human ) ) ) )
'data' => array( 'delete' => '', 'delete-warning' => \IPS\Member::loggedIn()->language()->addToStack( 'database_droptable_info' ) )
)
);
};
@@ -1196,9 +1204,8 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function addTable()
{
/* Get out latest version */
$latestVersion = $this->_getLatestVersion();
$queriesJson = $this->_getQueries( $latestVersion['long'] );
/* Get our current working version queries */
$queriesJson = $this->_getQueries( 'working' );
/* Get form */
$message = NULL;
@@ -1224,7 +1231,7 @@ class _developer extends \IPS\Dispatcher\Controller
},
"{$this->application->directory}_"
) );
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_newtable_info', FALSE, array( 'sprintf' => array( $latestVersion['human'] ) ) ), 'information' );
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_newtable_info'), 'information' );
break;
/* Import */
@@ -1248,7 +1255,7 @@ class _developer extends \IPS\Dispatcher\Controller
) );
/* Warn the user we may rename the table */
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_renametable_info', FALSE, array( 'sprintf' => array( "{$this->application->directory}_", $latestVersion['human'] ) ) ), 'information' );
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_renametable_info', FALSE, array( 'sprintf' => array( "{$this->application->directory}_" ) ) ), 'information' );
break;
@@ -1289,7 +1296,7 @@ class _developer extends \IPS\Dispatcher\Controller
}
}
) );
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_newtable_info', FALSE, array( 'sprintf' => array( $latestVersion['human'] ) ) ), 'information' );
$message = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_newtable_info'), 'information' );
break;
}
@@ -1333,7 +1340,7 @@ class _developer extends \IPS\Dispatcher\Controller
/* Add to the queries.json file */
$queriesJson = $this->_addQueryToJson( $queriesJson, array( 'method' => 'createTable', 'params' => array( $definition ) ) );
$this->_writeQueries( $latestVersion['long'], $queriesJson );
$this->_writeQueries( 'working', $queriesJson );
break;
@@ -1354,7 +1361,7 @@ class _developer extends \IPS\Dispatcher\Controller
/* Add to the queries.json file */
$queriesJson = $this->_addQueryToJson( $queriesJson, array( 'method' => 'renameTable', 'params' => array( $definition['name'], "{$this->application->directory}_{$definition['name']}" ) ) );
$this->_writeQueries( $latestVersion['long'], $queriesJson );
$this->_writeQueries( 'working', $queriesJson );
/* Set the name for later */
$definition['name'] = "{$this->application->directory}_{$definition['name']}";
@@ -1369,18 +1376,25 @@ class _developer extends \IPS\Dispatcher\Controller
/* Put the app key in if it's not already */
$appKey = $this->application->directory;
$contents = preg_replace_callback( '/CREATE (TEMPORARY )?TABLE (IF NOT EXISTS )?`?(.+?)`?\s+?/', function( $matches ) use ( $appKey )
$contents = preg_replace_callback( '/CREATE (TEMPORARY )?TABLE (IF NOT EXISTS )?`?(.+?)`?\s+?/i', function( $matches ) use ( $appKey )
{
$prefix = '';
if ( \IPS\Db::i()->prefix AND mb_substr( $matches[3], 0, mb_strlen( \IPS\Db::i()->prefix ) ) !== \IPS\Db::i()->prefix )
{
$prefix = \IPS\Db::i()->prefix;
}
if ( mb_substr( $matches[3], 0, mb_strlen( $appKey ) + 1 ) !== "{$appKey}_" )
{
return str_replace( $matches[3], "{$appKey}_{$matches[3]}", $matches[0] );
return str_replace( $matches[3], "{$prefix}{$appKey}_{$matches[3]}", $matches[0] );
}
return $matches[0];
}, $contents );
/* Work out the name */
preg_match( '/CREATE (TEMPORARY )?TABLE (IF NOT EXISTS )?`?(.+?)`?\s+?\(/i', $contents, $matches );
$prefix = \IPS\Db::i()->prefix;
preg_match( "/CREATE (TEMPORARY )?TABLE (IF NOT EXISTS )?`?{$prefix}(.+?)`?\s+?\(/i", $contents, $matches );
$name = $matches[3];
/* Run the query */
@@ -1388,10 +1402,10 @@ class _developer extends \IPS\Dispatcher\Controller
/* Now get the definition */
$definition = \IPS\Db::i()->getTableDefinition( $name );
/* Add to the queries.json file */
$queriesJson = $this->_addQueryToJson( $queriesJson, array( 'method' => 'createTable', 'params' => array( $definition ) ) );
$this->_writeQueries( $latestVersion['long'], $queriesJson );
$this->_writeQueries( 'working', $queriesJson );
/* Delete the file */
unlink( $values['upload'] );
@@ -1471,14 +1485,11 @@ class _developer extends \IPS\Dispatcher\Controller
ksort( $definition['columns'][ $k ] );
}
/* Get out latest version */
$latestVersion = $this->_getLatestVersion();
/* Init Output */
\IPS\Output::i()->title = $definition['name'];
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=schema" ), \IPS\Member::loggedIn()->language()->addToStack( 'database_tables' ) );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_changes_info', FALSE, array( 'sprintf' => array( $latestVersion['human'] ) ) ), 'information' );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_changes_info'), 'information' );
/* Does it match the database? */
$_definition = $definition;
@@ -1516,7 +1527,7 @@ class _developer extends \IPS\Dispatcher\Controller
$_schemaJson = $schemaJson;
/* We'll probably also need the queries.json file */
$queriesJson = $this->_getQueries( $latestVersion['long'] );
$queriesJson = $this->_getQueries( 'working' );
$_queriesJson = $queriesJson;
$queries = array();
@@ -1655,7 +1666,7 @@ class _developer extends \IPS\Dispatcher\Controller
}
if ( $_queriesJson !== $queriesJson )
{
$this->_writeQueries( $latestVersion['long'], $queriesJson );
$this->_writeQueries( 'working', $queriesJson );
}
/* Redirect */
@@ -1893,7 +1904,6 @@ class _developer extends \IPS\Dispatcher\Controller
{
$column = $definition['columns'][ \IPS\Request::i()->column ];
}
$latestVersion = $this->_getLatestVersion();
/* Build form */
$form = new \IPS\Helpers\Form();
@@ -1958,6 +1968,14 @@ class _developer extends \IPS\Dispatcher\Controller
$save = array();
foreach ( $values as $k => $v )
{
/* If this is a new column and we have set the auto_increment flag, or if this is an existing column and the auto_increment
flag was not previously set but we have toggled it on, then we need to add the primary key flag as well because MySQL
requires any auto_increment column to also be a primary key */
if( $k == 'database_column_auto_increment' AND $v AND ( !$column OR ( !$column['auto_increment'] ) ) )
{
$save['primary'] = true;
}
$save[ str_replace( 'database_column_', '', $k ) ] = $v;
}
@@ -1973,12 +1991,12 @@ class _developer extends \IPS\Dispatcher\Controller
if ( !$column )
{
\IPS\Db::i()->addColumn( $definition['name'], $save );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'addColumn', 'params' => array( $definition['name'], $save ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'addColumn', 'params' => array( $definition['name'], $save ) ) ) );
}
else
{
\IPS\Db::i()->changeColumn( $definition['name'], $column['name'], $save );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'changeColumn', 'params' => array( $definition['name'], $column['name'], $save ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'changeColumn', 'params' => array( $definition['name'], $column['name'], $save ) ) ) );
if ( $column['name'] != $save['name'] )
{
@@ -1986,7 +2004,24 @@ class _developer extends \IPS\Dispatcher\Controller
}
}
$schema[ $definition['name'] ]['columns'][ $save['name'] ] = $save;
/* If we added the 'primary' flag, remove it before saving schema.json because it should not be reflected there...BUT we
need to add primary key index definition to the schema.json instead in this case */
if( isset( $save['primary'] ) )
{
unset( $save['primary'] );
$schema[ $definition['name'] ]['columns'][ $save['name'] ] = $save;
$schema[ $definition['name'] ]['indexes']['PRIMARY'] = array(
'type' => 'primary',
'name' => 'PRIMARY',
'length' => array( 0 => NULL ),
'columns' => array( 0 => $save['name'] )
);
}
else
{
$schema[ $definition['name'] ]['columns'][ $save['name'] ] = $save;
}
if( $column AND $save['name'] !== $column['name'] AND isset( $schema[ $definition['name'] ]['indexes'] ) )
{
@@ -2031,9 +2066,8 @@ class _developer extends \IPS\Dispatcher\Controller
throw new \Exception('dev_could_not_write_schema_data');
}
$latestVersion = $this->_getLatestVersion();
\IPS\Db::i()->dropColumn( \IPS\Request::i()->_name, \IPS\Request::i()->column );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'dropColumn', 'params' => array( \IPS\Request::i()->_name, \IPS\Request::i()->column ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'dropColumn', 'params' => array( \IPS\Request::i()->_name, \IPS\Request::i()->column ) ) ) );
$schema = $this->_getSchema();
unset( $schema[ \IPS\Request::i()->_name ]['columns'][ \IPS\Request::i()->column ] );
@@ -2069,7 +2103,7 @@ class _developer extends \IPS\Dispatcher\Controller
$schema[ \IPS\Request::i()->_name ]['indexes'][ $name ] = $definition;
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'changeIndex', 'params' => array( $name, $name, $definition ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'changeIndex', 'params' => array( $name, $name, $definition ) ) ) );
}
}
}
@@ -2106,7 +2140,6 @@ class _developer extends \IPS\Dispatcher\Controller
{
$index = $definition['indexes'][ \IPS\Request::i()->index ];
}
$latestVersion = $this->_getLatestVersion();
/* Build form */
$form = new \IPS\Helpers\Form();
@@ -2161,7 +2194,7 @@ class _developer extends \IPS\Dispatcher\Controller
if ( !$index )
{
\IPS\Db::i()->addIndex( $definition['name'], $save );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'addIndex', 'params' => array( $definition['name'], $save ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'addIndex', 'params' => array( $definition['name'], $save ) ) ) );
if ( $index['name'] != $save['name'] )
{
@@ -2171,7 +2204,7 @@ class _developer extends \IPS\Dispatcher\Controller
else
{
\IPS\Db::i()->changeIndex( $definition['name'], $index['name'], $save );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'changeIndex', 'params' => array( $definition['name'], $index['name'], $save ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'changeIndex', 'params' => array( $definition['name'], $index['name'], $save ) ) ) );
}
$schema[ $definition['name'] ]['indexes'][ $save['name'] ] = $save;
@@ -2210,9 +2243,8 @@ class _developer extends \IPS\Dispatcher\Controller
throw new \Exception('dev_could_not_write_schema_data');
}
$latestVersion = $this->_getLatestVersion();
\IPS\Db::i()->dropIndex( \IPS\Request::i()->_name, \IPS\Request::i()->index );
$this->_writeQueries( $latestVersion['long'], $this->_addQueryToJson( $this->_getQueries( $latestVersion['long'] ), array( 'method' => 'dropIndex', 'params' => array( \IPS\Request::i()->_name, \IPS\Request::i()->index ) ) ) );
$this->_writeQueries( 'working', $this->_addQueryToJson( $this->_getQueries( 'working' ), array( 'method' => 'dropIndex', 'params' => array( \IPS\Request::i()->_name, \IPS\Request::i()->index ) ) ) );
$schema = $this->_getSchema();
unset( $schema[ \IPS\Request::i()->_name ]['indexes'][ \IPS\Request::i()->index ] );
@@ -2243,7 +2275,6 @@ class _developer extends \IPS\Dispatcher\Controller
$index = \IPS\Request::i()->row;
$data = $definition['inserts'][ \IPS\Request::i()->row ];
}
$latestVersion = $this->_getLatestVersion();
/* Build form */
$form = new \IPS\Helpers\Form();
@@ -2400,7 +2431,7 @@ class _developer extends \IPS\Dispatcher\Controller
unset( $schema[ \IPS\Request::i()->_name ]['inserts'][ \IPS\Request::i()->row ] );
$this->_writeSchema( $schema );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=editSchema&_name={$definition['name']}&tab=inserts" ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=editSchema&_name=" . \IPS\Request::i()->_name . "&tab=inserts" ) );
}
catch ( \Exception $e )
{
@@ -2417,7 +2448,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block(
\IPS\Request::i()->_name,
str_replace( '&lt;?php', '', highlight_string( "<?php " . var_export(\IPS\DB::i()->getTableDefinition( \IPS\Request::i()->_name ), TRUE ), TRUE ) ),
str_replace( '&lt;?php', '', highlight_string( "<?php " . var_export(\IPS\Db::i()->getTableDefinition( \IPS\Request::i()->_name ), TRUE ), TRUE ) ),
FALSE
);
}
@@ -2498,6 +2529,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function deleteTable()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$table = \IPS\Request::i()->name;
/* Drop the table */
@@ -2505,10 +2539,9 @@ class _developer extends \IPS\Dispatcher\Controller
call_user_func_array( array( \IPS\Db::i(), $query['method'] ), $query['params'] );
/* Add the drop to the queries.json file */
$latestVersion = $this->_getLatestVersion();
$queries = $this->_getQueries( $latestVersion['long'] );
$queries = $this->_getQueries( 'working' );
$queries = $this->_addQueryToJson( $queries, $query );
$this->_writeQueries( $latestVersion['long'], $queries );
$this->_writeQueries( 'working', $queries );
/* Remove from schema.json */
$schemaJson = $this->_getSchema();
@@ -2659,19 +2692,19 @@ class _developer extends \IPS\Dispatcher\Controller
{
$form = new \IPS\Helpers\Form();
$form->hiddenFields['type'] = \IPS\Request::i()->type;
$form->add( new \IPS\Helpers\Form\Text( 'dev_extensions_classname', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Text( 'dev_extensions_classname', NULL, TRUE, array( 'regex' => '/^[A-Z0-9]+$/i' ) ) );
if ( $values = $form->values() )
{
$contents = str_replace(
array(
"{subpackage}\n",
"{subpackage}",
'{date}',
'{app}',
'{class}',
),
array(
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) . "\n" ) : '',
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) ) : '',
date( 'd M Y' ),
$this->application->directory,
$values['dev_extensions_classname']
@@ -2709,9 +2742,39 @@ class _developer extends \IPS\Dispatcher\Controller
'default' => array( 'Text' )
);
$form->rows = $settings;
if ( $values = $form->values() )
if ( $form->values() !== FALSE )
{
$values = $form->values();
if ( !empty( $form->addedRows ) )
{
$insert = array();
foreach ( $form->addedRows as $key )
{
$insert[] = array( 'conf_key' => $values[ $key ]['key'], 'conf_value' => $values[ $key ]['default'], 'conf_default' => $values[ $key ]['default'], 'conf_app' => $this->application->directory );
}
\IPS\Db::i()->insert( 'core_sys_conf_settings', $insert );
}
if ( !empty( $form->changedRows ) )
{
foreach ( $form->changedRows as $key )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_key' => $values[ $key ]['key'], 'conf_default' => $values[ $key ]['default'] ), array( 'conf_key=?', $form->rows[ $key ]['key'] ) );
}
}
if ( !empty( $form->removedRows ) )
{
$delete = array();
foreach ( $form->removedRows as $key )
{
$delete[] = $form->rows[ $key ]['key'];
}
\IPS\Db::i()->delete( 'core_sys_conf_settings', \IPS\Db::i()->in( 'conf_key', $delete ) );
}
$save = array();
foreach ( $values as $data )
{
@@ -2847,6 +2910,7 @@ class _developer extends \IPS\Dispatcher\Controller
{
array_unshift( $rows, $this->_getVersionRow( $long ) );
}
array_unshift( $rows, $this->_getVersionRow( 'working' ) );
return $rows;
}
@@ -2885,21 +2949,37 @@ class _developer extends \IPS\Dispatcher\Controller
);
}
$buttons = array_merge( $buttons, array(
'add' => array(
'icon' => 'plus-circle',
'title' => 'versions_query',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=addVersionQuery&id={$long}" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('versions_query') )
),
'delete' => array(
$buttons['add'] = array(
'icon' => 'plus-circle',
'title' => 'versions_query',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=addVersionQuery&id={$long}" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('versions_query'), 'ipsDialog-remoteVerify' => "false" )
);
if( $long != 'install' and $long !== 'working' )
{
$buttons['delete'] = array(
'icon' => 'times-circle',
'title' => 'delete',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&do=deleteVersion&id={$long}" ),
'data' => array( 'delete' => '' )
) ) );
);
}
if ( $long === 'install' )
{
$nameToDisplay = \IPS\Member::loggedIn()->language()->addToStack('versions_install');
}
elseif ( $long === 'working' )
{
$nameToDisplay = \IPS\Member::loggedIn()->language()->addToStack('versions_working');
}
else
{
$nameToDisplay = isset( $this->json[ $long ] ) ? $this->json[ $long ] : $long;
}
return \IPS\Theme::i()->getTemplate( 'trees', 'core' )->row( $this->url, $long, isset( $this->json[ $long ] ) ? $this->json[ $long ] : $long, $hasChildren, $buttons, $long, NULL, NULL, $root );
return \IPS\Theme::i()->getTemplate( 'trees', 'core' )->row( $this->url, $long, $nameToDisplay, $hasChildren, $buttons, $long, NULL, NULL, $root );
}
/**
@@ -2956,22 +3036,15 @@ class _developer extends \IPS\Dispatcher\Controller
{
/* Create New */
case 'new':
$defaults = array( 'human' => '1.0.0', 'long' => '10000' );
foreach ( array_reverse( $json, TRUE ) as $long => $human )
{
$exploded = explode( '.', $human );
$defaults['human'] = "{$exploded[0]}.{$exploded[1]}." . ( $exploded[2] + 1 );
$defaults['long'] = $long + 1;
break;
}
$form->add( new \IPS\Helpers\Form\Text( 'versions_human', $defaults['human'], TRUE, array(), function( $val )
$form->addMessage( 'versions_add_information' );
$form->add( new \IPS\Helpers\Form\Text( 'versions_human', NULL, TRUE, array( 'placeholder' => '1.0.0' ), function( $val )
{
if ( !preg_match( '/^\d*\.\d*\.\d*(( (Alpha|Beta|RC)\s?[a-zA-Z0-9]*)|(\.\d*))?$/', $val ) )
{
throw new \DomainException( 'versions_human_error' );
}
} ) );
$form->add( new \IPS\Helpers\Form\Text( 'versions_long', $defaults['long'], TRUE, array(), function( $val ) use ( $json )
$form->add( new \IPS\Helpers\Form\Text( 'versions_long', NULL, TRUE, array( 'placeholder' => '10000' ), function( $val ) use ( $json )
{
if ( !preg_match( '/^\d*$/', $val ) )
{
@@ -3091,6 +3164,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function deleteVersion()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$versionsFile = \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/versions.json";
$json = $this->_getVersions();
if ( isset( $json[ intval( \IPS\Request::i()->id ) ] ) )
@@ -3108,11 +3184,9 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function addVersionQuery()
{
$latestVersion = $this->_getLatestVersion();
/* Build Form */
$form = new \IPS\Helpers\Form( 'add_version_query' );
$form->add( new \IPS\Helpers\Form\Text( 'versions_query_code', '\IPS\Db::i()->', TRUE, array( 'size' => 45 ), function( $val ) use ( $latestVersion )
$form->add( new \IPS\Helpers\Form\TextArea( 'versions_query_code', '\IPS\Db::i()->', TRUE, array( 'size' => 45 ), function( $val )
{
/* Check it starts with \IPS\Db::i()-> */
$val = trim( $val );
@@ -3138,12 +3212,19 @@ class _developer extends \IPS\Dispatcher\Controller
throw new \DomainException( 'versions_query_format' );
}
/* Run it, but only if we are editing the latest version */
if( \IPS\Request::i()->id == $latestVersion )
/* Run it if we're adding it to the current working version */
if( \IPS\Request::i()->id == 'working' )
{
try
{
if ( @eval( $val ) === FALSE )
try
{
if ( @eval( $val ) === FALSE )
{
throw new \DomainException( 'versions_query_phperror' );
}
}
catch ( \ParseError $e )
{
throw new \DomainException( 'versions_query_phperror' );
}
@@ -3194,7 +3275,10 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function deleteVersionQuery()
{
$version = ( \IPS\Request::i()->version == 'install' ? 'install' : intval( \IPS\Request::i()->version ) );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$version = ( \IPS\Request::i()->version == 'install' ? 'install' : \IPS\Request::i()->version );
$json = $this->_getQueries( $version );
unset( $json[ intval( \IPS\Request::i()->query ) ] );
@@ -3210,16 +3294,24 @@ class _developer extends \IPS\Dispatcher\Controller
protected function versionCode()
{
/* Get version */
$long = intval( \IPS\Request::i()->id );
$json = $this->_getVersions();
if ( !isset( $json[ $long ] ) )
if ( \IPS\Request::i()->id !== 'working' )
{
\IPS\Output::i()->error( 'node_error', '2C103/8', 404, '' );
$long = intval( \IPS\Request::i()->id );
$json = $this->_getVersions();
if ( !isset( $json[ $long ] ) )
{
\IPS\Output::i()->error( 'node_error', '2C103/8', 404, '' );
}
$human = $json[ $long ];
}
else
{
$long = 'working';
$human = '{version_human}';
}
$human = $json[ $long ];
/* Write the file if we don't already have one */
$phpFilePath = \IPS\ROOT_PATH . "/applications/{$this->application->directory}/setup/" . ( $long === 'install' ? $long : "upg_{$long}" );
$phpFilePath = \IPS\ROOT_PATH . "/applications/{$this->application->directory}/setup/upg_{$long}";
$phpFile = $phpFilePath . '/upgrade.php';
if ( !file_exists( $phpFile ) )
{
@@ -3227,18 +3319,17 @@ class _developer extends \IPS\Dispatcher\Controller
$contents = str_replace(
array(
'{version_human}',
"{subpackage}\n",
"{subpackage}",
'{date}',
'{app}',
'{version_long}',
),
array(
$human,
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) . "\n" ) : '',
( $this->application->directory != 'core' ) ? ( " * @subpackage\t" . \IPS\Member::loggedIn()->language()->get( "__app_{$this->application->directory}" ) ) : '',
date( 'd M Y' ),
$this->application->directory,
$long,
),
file_get_contents( \IPS\ROOT_PATH . "/applications/core/data/defaults/Upgrade.txt" )
);
@@ -3272,14 +3363,12 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function _manageTasks()
{
$latestVersion = $this->_getLatestVersion();
return \IPS\Task::devTable(
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/tasks.json",
\IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=tasks" ),
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/tasks",
$this->application->directory,
$this->application->directory . '\tasks',
$latestVersion['long'],
$this->application->directory
);
}
@@ -3290,17 +3379,14 @@ class _developer extends \IPS\Dispatcher\Controller
* @return string
*/
protected function _manageWidgets()
{
$latestVersion = $this->_getLatestVersion();
{
return \IPS\Widget::devTable(
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/widgets.json",
\IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=widgets" ),
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/widgets",
$this->application->directory,
$this->application->directory,
$latestVersion['long'],
$this->application->directory
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/widgets.json",
\IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=widgets" ),
\IPS\ROOT_PATH . "/applications/{$this->application->directory}/widgets",
$this->application->directory,
$this->application->directory,
$this->application->directory
);
}
/**
@@ -3326,7 +3412,16 @@ class _developer extends \IPS\Dispatcher\Controller
{
try
{
\IPS\Plugin\Hook::load( \IPS\Request::i()->hook )->editForm( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=hooks" ) );
if ( \IPS\Request::i()->hookApp and \IPS\Request::i()->hookFilename )
{
$hook = \IPS\Plugin\Hook::constructFromData( \IPS\Db::i()->select( '*', 'core_hooks', array( 'app=? AND filename=?', \IPS\Request::i()->hookApp, \IPS\Request::i()->hookFilename ) )->first() );
}
else
{
$hook = \IPS\Plugin\Hook::load( \IPS\Request::i()->hook );
}
$hook->editForm( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=hooks" ) );
}
catch ( \Exception $e )
{
@@ -3488,15 +3583,13 @@ class _developer extends \IPS\Dispatcher\Controller
*/
protected function _schemaJsonIsWritable()
{
if ( ! is_writable( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/schema.json" ) )
if ( !is_writable( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/schema.json" ) )
{
return false;
}
$latestVersion = $this->_getLatestVersion();
$file = \IPS\ROOT_PATH . "/applications/{$this->application->directory}/setup/" . ( $latestVersion['long'] === 'install' ? $latestVersion['long'] : "upg_{$latestVersion['long']}" ) . '/queries.json';
if ( file_exists( $file ) and ! is_writable( $file ) )
$file = \IPS\ROOT_PATH . "/applications/{$this->application->directory}/setup/upg_working/queries.json";
if ( file_exists( $file ) and !is_writable( $file ) )
{
return false;
}
@@ -3516,27 +3609,7 @@ class _developer extends \IPS\Dispatcher\Controller
return $result;
}
/**
* Get latest version
*
* @return array array( 'human' => '1.0.0', 'long' => 10000 )
*/
protected function _getLatestVersion()
{
$versions = $this->_getVersions();
if ( empty( $versions ) )
{
\IPS\Output::i()->error( 'database_schema_needs_version', '1C103/C', 403, '' );
}
foreach ( array_reverse( $versions, TRUE ) as $long => $human )
{
break;
}
return array( 'human' => $human, 'long' => $long );
}
/**
* Write versions.json file
*
@@ -3664,12 +3737,22 @@ class _developer extends \IPS\Dispatcher\Controller
chmod( $path, \IPS\IPS_FOLDER_PERMISSION );
}
/* We need to make sure the array is 1-indexed otherwise the upgrader gets confused */
$write = array();
$i = 0;
foreach ( $json as $query )
/* We need to make sure the array is 1-indexed otherwise the upgrader gets confused - unless this is the "working" version
since that causes conflicts if two branches try to add queries - for the "working" version, this same thing is done
by \IPS\Application::assignNewVersion() */
if ( $long === 'working' )
{
$write[ ++$i ] = $query;
$write = array_values( $json );
}
else
{
$write = array();
$i = 0;
foreach ( $json as $query )
{
$write[ ++$i ] = $query;
}
}
/* Write */
@@ -2,9 +2,9 @@
/**
* @brief Community Enhancements
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 17 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -79,7 +79,15 @@ class _enhancements extends \IPS\Dispatcher\Controller
{
$langKey = 'enhancements__' . \IPS\Request::i()->id;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $langKey );
$this->enhancements[ \IPS\Request::i()->id ]->edit();
try
{
$this->enhancements[ \IPS\Request::i()->id ]->edit();
}
catch ( \DomainException $e )
{
\IPS\Output::i()->error( $e->getMessage(), $e->getCode() );
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -2,9 +2,9 @@
/**
* @brief Menu Manager
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 29 Jun 2015
* @version SVN_VERSION_NUMBER
*/
@@ -66,18 +66,27 @@ class _menu extends \IPS\Dispatcher\Controller
/* Get items from the database */
$items = array( 0 => array(), 1 => array() );
$menus = array();
foreach ( \IPS\Db::i()->select( '*', 'core_menu', NULL, 'position' ) as $item )
{
if ( \IPS\Application::appIsEnabled( $item['app'] ) )
{
$class = 'IPS\\' . $item['app'] . '\extensions\core\FrontNavigation\\' . $item['extension'];
$items[ intval( $item['parent'] ) ][ $item['id'] ] = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'] );
if ( !$item['is_menu_child'] )
{
$class = 'IPS\\' . $item['app'] . '\extensions\core\FrontNavigation\\' . $item['extension'];
$items[ intval( $item['parent'] ) ][ $item['id'] ] = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'] );
}
if ( $item['app'] == 'core' and $item['extension'] == 'Menu' )
{
$class = 'IPS\\' . $item['app'] . '\extensions\core\FrontNavigation\\' . $item['extension'];
$menus[ $item['id'] ] = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'] );
}
}
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_applications_menu');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'applications' )->menuManager( $items );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'applications' )->menuManager( $items, $menus );
}
/**
@@ -87,7 +96,18 @@ class _menu extends \IPS\Dispatcher\Controller
*/
protected function publish()
{
unset( \IPS\Data\Store::i()->frontNavigation );
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_menu' )->first() )
{
unset( \IPS\Data\Store::i()->frontNavigation );
}
else
{
\IPS\Data\Store::i()->frontNavigation = array( 0 => array(), 1 => array() );
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplog__menu_published' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=applications&controller=menu'), 'menu_manager_published' );
}
@@ -123,6 +143,7 @@ class _menu extends \IPS\Dispatcher\Controller
/* What options are available? */
$options = array();
$disabled = array();
$toggles = array();
$fieldNames = array();
$extraFields = array();
@@ -157,13 +178,17 @@ class _menu extends \IPS\Dispatcher\Controller
$toggles[ $key ][] = 'menu_manager_access';
}
}
if ( !$class::isEnabled() )
{
$disabled[] = $key;
}
}
}
/* Create the form */
$form = new \IPS\Helpers\Form( 'menu_item', 'save_menu_item' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Radio( 'menu_manager_extension', $existing ? "{$existing['app']}_{$existing['extension']}" : NULL, TRUE, array( 'options' => $options, 'toggles' => $toggles ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'menu_manager_extension', $existing ? "{$existing['app']}_{$existing['extension']}" : NULL, TRUE, array( 'options' => $options, 'toggles' => $toggles, 'disabled' => $disabled ) ) );
foreach ( $extraFields as $field )
{
$form->add( $field );
@@ -173,7 +198,7 @@ class _menu extends \IPS\Dispatcher\Controller
{
$groups[ $group->g_id ] = $group->name;
}
$form->add( new \IPS\Helpers\Form\Radio( 'menu_manager_access_type', ( $existing and $existing['permissions'] ) ? 1 : 0, TRUE, array(
$form->add( new \IPS\Helpers\Form\Radio( 'menu_manager_access_type', ( $existing and $existing['permissions'] !== NULL ) ? 1 : 0, TRUE, array(
'options' => array( 0 => 'menu_manager_access_type_inherit', 1 => 'menu_manager_access_type_override' ),
'toggles' => array( 1 => array( 'menu_manager_access' ) )
), NULL, NULL, NULL, 'menu_manager_access_type' ) );
@@ -206,23 +231,34 @@ class _menu extends \IPS\Dispatcher\Controller
'extension' => $exploded[1],
'config' => json_encode( $config ),
'parent' => $existing ? $existing['parent'] : ( \IPS\Request::i()->parent ?: NULL ),
'is_menu_child' => FALSE
);
if ( $class::permissionsCanInherit() )
if ( $save['parent'] )
{
if ( $values['menu_manager_access_type'] )
try
{
$save['permissions'] = $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] );
}
else
{
$save['permissions'] = '';
$parent = \IPS\Db::i()->select( '*', 'core_menu', array( 'id=?', $save['parent'] ) )->first();
if ( ( $parent['app'] === 'core' ) and ( $parent['extension'] === 'Menu' ) )
{
$save['is_menu_child'] = TRUE;
}
}
catch ( \UnderflowException $e ) { }
}
/* First we need to determine if the access type option was even shown */
$hasAccessType = ( in_array( 'menu_manager_access_type', $toggles[ $values['menu_manager_extension'] ] ) ) ? TRUE : FALSE;
/* If we didn't have the access type field, then we should just check the permissions that were specified */
if ( $values['menu_manager_access_type'] OR !$hasAccessType )
{
$save['permissions'] = $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] );
}
else
{
$save['permissions'] = $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] );
}
$save['permissions'] = $class::permissionsCanInherit() ? NULL : '';
}
if ( $existing )
{
$id = $existing['id'];
@@ -256,14 +292,25 @@ class _menu extends \IPS\Dispatcher\Controller
\IPS\Db::i()->update( 'core_menu', array( 'config' => json_encode( $_config ) ), array( 'id=?', $id ) );
}
}
/**
* If this entry used to be a drop-down and we change the link type without deleting the child links, we
* should convert the child links to sub-menu entries (and vice-versa)
*/
\IPS\Db::i()->update(
'core_menu',
array( 'is_menu_child' => ( ( $save['app'] === 'core' ) and ( $save['extension'] === 'Menu' ) ) ),
array( 'parent=?', $id )
);
if( \IPS\Request::i()->isAjax() )
{
$item = new $class( $_config, $id, $save['permissions'] );
$output = array(
'menu_item' => \IPS\Theme::i()->getTemplate( 'applications' )->menuItem( $item, $id )
'menu_item' => \IPS\Theme::i()->getTemplate( 'applications' )->menuItem( $item, $id ),
'id' => $id
);
/* If the item has a parent and it's a dropdown menu, then the menu_item
we need to return needs to be the one used for dropdown menus */
if ( $save['parent'] )
@@ -298,6 +345,10 @@ class _menu extends \IPS\Dispatcher\Controller
/* Display */
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'applications', 'core' ) ), 'menuManagerForm' ) );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Output::i()->output );
}
}
/**
@@ -324,6 +375,9 @@ class _menu extends \IPS\Dispatcher\Controller
static::_remove( $child );
}
\IPS\Db::i()->delete( 'core_menu', array( 'id=?', $id ) );
/* remove the title language strings */
\IPS\Lang::deleteCustom( 'core', "menu_item_{$id}" );
}
/**
@@ -334,13 +388,34 @@ class _menu extends \IPS\Dispatcher\Controller
protected function reorder()
{
$positions = array();
foreach ( \IPS\Request::i()->menu_order as $id => $parent )
foreach ( \IPS\Request::i()->menu_order as $id => $parentId )
{
if ( !isset( $positions[ $parent ] ) )
if ( !isset( $positions[ $parentId ] ) )
{
$positions[ $parent ] = 1;
$positions[ $parentId ] = 1;
}
\IPS\Db::i()->update( 'core_menu', array( 'position' => $positions[ $parent ]++, 'parent' => $parent == 'null' ? NULL : $parent ), array( 'id=?', $id ) );
$save = array(
'position' => $positions[ $parentId ]++,
'parent' => NULL
);
if ( $parentId != 'null' )
{
try
{
$parent = \IPS\Db::i()->select( '*', 'core_menu', array( 'id=?', $parentId ) )->first();
$save['parent'] = $parent['id'];
if ( $parent['app'] === 'core' and $parent['extension'] === 'Menu' )
{
$save['is_menu_child'] = TRUE;
}
}
catch ( \UnderflowException $e ) {}
}
\IPS\Db::i()->update( 'core_menu', $save, array( 'id=?', $id ) );
}
\IPS\Output::i()->json('OK');
}
@@ -2,9 +2,9 @@
/**
* @brief Plugins
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 25 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -189,7 +189,7 @@ class _plugins extends \IPS\Node\Controller
if ( $values = $form->values() )
{
/* Already installed? */
$xml = new \XMLReader;
$xml = new \IPS\Xml\XMLReader;
$xml->open( $values['plugin_upload'] );
if ( !@$xml->read() )
{
@@ -211,7 +211,12 @@ class _plugins extends \IPS\Node\Controller
move_uploaded_file( $values['plugin_upload'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins&do=doInstall&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) . ( isset( \IPS\Request::i()->id ) ? '&id=' . \IPS\Request::i()->id : '' ) ) );
$url = \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins&do=doInstall' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) );
if ( isset( \IPS\Request::i()->id ) )
{
$url = $url->setQueryString( 'id', \IPS\Request::i()->id );
}
\IPS\Output::i()->redirect( $url );
}
/* Display */
@@ -233,11 +238,11 @@ class _plugins extends \IPS\Node\Controller
}
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins&do=doInstall&file=' . urlencode( \IPS\Request::i()->file ) . '&key=' . \IPS\Request::i()->key . '&id=' . \IPS\Request::i()->id ),
\IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins&do=doInstall' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key, 'id' => \IPS\Request::i()->id ) ),
function( $data )
{
/* Open XML file */
$xml = new \XMLReader;
$xml = new \IPS\Xml\XMLReader;
$xml->open( \IPS\Request::i()->file );
$new = FALSE;
@@ -249,6 +254,8 @@ class _plugins extends \IPS\Node\Controller
{
if( !$xml->getAttribute('name') )
{
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->error( 'xml_upload_invalid', '2C145/E', 403, '' );
}
@@ -257,6 +264,11 @@ class _plugins extends \IPS\Node\Controller
try
{
$plugin = \IPS\Plugin::load( \IPS\Request::i()->id );
/* Disable the plugin to prevent errors if core classes are extended */
$plugin->enabled = FALSE;
$plugin->save();
/* If we're upgrading, remove current HTML, CSS, etc. We'll insert again in a moment */
\IPS\Theme::removeTemplates( 'core', 'global', 'plugins', $plugin->id );
\IPS\Theme::removeCss( 'core', 'front', 'custom', $plugin->id );
@@ -296,7 +308,20 @@ class _plugins extends \IPS\Node\Controller
\mkdir( \IPS\ROOT_PATH . "/plugins/{$plugin->location}" );
chmod( \IPS\ROOT_PATH . "/plugins/{$plugin->location}", \IPS\IPS_FOLDER_PERMISSION );
}
/* Check to make sure that worked */
if( !\is_dir( \IPS\ROOT_PATH . "/plugins/{$plugin->location}" ) )
{
\IPS\Output::i()->error( 'plugin_mkdir_perm', '4C145/H', 403, '' );
}
\file_put_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/index.html", '' );
/* Check to make sure that worked */
if( !\file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/index.html" ) )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'plugin_fpc_perm', FALSE, array( 'sprintf' => array( $plugin->location ) ) ), '4C145/J', 403, '' );
}
return array( array(
'id' => $plugin->id,
@@ -356,7 +381,7 @@ class _plugins extends \IPS\Node\Controller
while ( $xml->read() and $xml->name == 'hook' )
{
/* Make up a filename */
$filename = md5( uniqid() . mt_rand() );
$filename = $xml->getAttribute( 'filename' ) ?: md5( uniqid() . 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 ) );
@@ -509,11 +534,11 @@ class _plugins extends \IPS\Node\Controller
try
{
$js = \IPS\Output\Javascript::find( 'core', 'plugins', '/', $name );
$js->delete();
}
catch ( \OutOfRangeException $e )
{
$js = new \IPS\Output\Javascript;
}
catch ( \OutOfRangeException $e ) {}
$js = new \IPS\Output\Javascript;
$js->plugin = $plugin->id;
$js->name = $name;
$js->content = base64_decode( $xml->readString() );
@@ -542,41 +567,80 @@ class _plugins extends \IPS\Node\Controller
/* Lang */
case 'lang':
\IPS\Db::i()->delete( 'core_sys_lang_words', array( 'word_plugin=?', $plugin->id ) );
/* Fetch existing language keys */
$existingLanguageKeys = iterator_to_array( \IPS\Db::i()->select( 'word_key', 'core_sys_lang_words', array( 'word_plugin=? and lang_id=?', $plugin->id, \IPS\Lang::defaultLanguage() ) ) );
$keysToDelete = $existingLanguageKeys;
$inserts = array();
$batchSize = 25;
$i = 0;
while ( $xml->read() and $xml->name == 'word' )
{
$key = $xml->getAttribute('key');
$js = $xml->getAttribute('js');
$value = $xml->readString();
$i++;
foreach ( \IPS\Lang::languages() as $lang )
{
$inserts[] = array(
'lang_id' => $lang->id,
'word_app' => NULL,
'word_plugin' => $plugin->id,
'word_key' => $key,
'word_default' => $value,
'word_custom' => NULL,
'word_default_version' => $plugin->version_long,
'word_custom_version' => NULL,
'word_js' => $js,
'word_export' => 1,
);
if ( count( $existingLanguageKeys ) and in_array( $key, $existingLanguageKeys ) )
{
/* Exists so do not delete */
$keysToDelete = array_diff( $keysToDelete, array( $key ) );
\IPS\Db::i()->update( 'core_sys_lang_words', array(
'word_default' => $value,
'word_default_version' => $plugin->version_long,
'word_js' => $js
),
array( 'lang_id=? and word_plugin=? and word_key=?', $lang->id, $plugin->id, $key )
);
}
else
{
$inserts[] = array(
'lang_id' => $lang->id,
'word_app' => NULL,
'word_plugin' => $plugin->id,
'word_key' => $key,
'word_default' => $value,
'word_custom' => NULL,
'word_default_version' => $plugin->version_long,
'word_custom_version' => NULL,
'word_js' => $js,
'word_export' => 1,
);
}
}
if ( $i % $batchSize === 0 )
{
if ( count( $inserts ) )
{
\IPS\Db::i()->replace( 'core_sys_lang_words', $inserts );
$inserts = array();
}
}
if ( !$xml->isEmptyElement )
{
$xml->read();
$xml->next();
}
$xml->read();
$xml->next();
}
/* Anything left that doesn't quite match up with a batch size? */
if( count( $inserts ) )
{
\IPS\Db::i()->replace( 'core_sys_lang_words', $inserts );
}
if ( count( $keysToDelete ) )
{
\IPS\Db::i()->delete( 'core_sys_lang_words', array( 'word_plugin=? AND ' . \IPS\Db::i()->in( 'word_key', $keysToDelete ), $plugin->id ) );
}
break;
/* Versions */
@@ -640,18 +704,20 @@ class _plugins extends \IPS\Node\Controller
/* Insert into DB */
try
{
$widget = \IPS\Widget::load( $plugin, 'key', array( 'plugin=?', $plugin->id ) );
$widget->plugin = $plugin->id;
$widget->key = $key;
$widget->class = $xml->getAttribute('class');
$widget->default_area = $xml->getAttribute('default_area');
$widget->allow_reuse = intval( $xml->getAttribute('allow_reuse') );
$widget->menu_style = $xml->getAttribute('menu_style');
$widget->embeddable = intval( $xml->getAttribute('embeddable') );
$widget->restrict = explode( ",", $xml->getAttribute('restrict') );
$widget->save();
$widget = \IPS\Db::i()->select( '*', 'core_widgets', array( '`key`=? and plugin=?', $key, $plugin->id ) )->first();
\IPS\Db::i()->update( 'core_widgets', array(
'plugin' => $plugin->id,
'key' => $key,
'class' => $xml->getAttribute('class'),
'restrict' => json_encode( explode( ",", $xml->getAttribute('restrict') ) ),
'default_area' => $xml->getAttribute('default_area'),
'allow_reuse' => intval( $xml->getAttribute('allow_reuse') ),
'menu_style' => $xml->getAttribute('menu_style'),
'embeddable' => intval( $xml->getAttribute('embeddable') )
), array( '`id`=?', $widget['id'] ) );
}
catch ( \OutOfRangeException $e )
catch ( \UnderflowException $e )
{
$inserts[] = array(
'plugin' => $plugin->id,
@@ -661,7 +727,7 @@ class _plugins extends \IPS\Node\Controller
'default_area' => $xml->getAttribute('default_area'),
'allow_reuse' => intval( $xml->getAttribute('allow_reuse') ),
'menu_style' => $xml->getAttribute('menu_style'),
'embeddable' => intval( $xml->getAttribute('embeddable') ),
'embeddable' => intval( $xml->getAttribute('embeddable') )
);
\IPS\Db::i()->insert( 'core_widgets', $inserts, TRUE );
}
@@ -693,26 +759,26 @@ class _plugins extends \IPS\Node\Controller
/* Do upgrade classes */
if ( count( $data['setUpClasses'] ) )
{
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: found " . count( $data['setUpClasses'] ). " set up classes to run ", 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: found " . count( $data['setUpClasses'] ). " set up classes to run ", 'plugin_setup' );
/* Grab class and run it, step by step */
$versionToRun = current( $data['setUpClasses'] );
$key = 'plugin_' . $plugin->id . '_setup_' . $versionToRun . '_class';
$class = ( $versionToRun === 'install' ) ? 'ips_plugins_setup_install' : 'ips_plugins_setup_upg_' . $versionToRun;
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: looking for class key " . $key, 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: looking for class key " . $key, 'plugin_setup' );
if ( isset( \IPS\Data\Store::i()->$key ) )
{
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: found class key " . $key . " class " . $class, 'plugin_setup' );
\IPS\Log::i( LOG_DEBUG )->write( \IPS\Data\Store::i()->$key, 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: found class key " . $key . " class " . $class, 'plugin_setup' );
\IPS\Log::debug( \IPS\Data\Store::i()->$key, 'plugin_setup' );
/* As this is to be evaled, make sure PHP tags aren't there */
\IPS\Data\Store::i()->$key = preg_replace( '/^<' . '?php(\n)/', '', \IPS\Data\Store::i()->$key );
eval( \IPS\Data\Store::i()->$key );
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: looking for class " . $class, 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: looking for class " . $class, 'plugin_setup' );
if ( class_exists( $class ) )
{
@@ -722,11 +788,11 @@ class _plugins extends \IPS\Node\Controller
$method = 'step' . $stepToRun;
$more = FALSE;
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: looking for class key " . $key . ", " . $method, 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: looking for class key " . $key . ", " . $method, 'plugin_setup' );
if ( method_exists( $upgrader, $method ) )
{
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: Running " . $key . ", " . $method, 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: Running " . $key . ", " . $method, 'plugin_setup' );
$result = $upgrader->$method();
@@ -736,7 +802,7 @@ class _plugins extends \IPS\Node\Controller
if ( method_exists( $upgrader, $method ) )
{
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: Running " . $key . ", next method " . $method . " found", 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: Running " . $key . ", next method " . $method . " found", 'plugin_setup' );
/* Hit it on the next redirect */
$data['step']++;
@@ -763,19 +829,19 @@ class _plugins extends \IPS\Node\Controller
}
}
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: Class " . $versionToRun . " completed", 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: Class " . $versionToRun . " completed", 'plugin_setup' );
/* Done this class completely */
$data['step'] = 0;
unset( $data['setUpClasses'][ $versionToRun ] );
\IPS\Log::i( LOG_DEBUG )->write( json_encode( $data ), 'plugin_setup' );
\IPS\Log::debug( json_encode( $data ), 'plugin_setup' );
/* Go for another hit on multiredirector */
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('plugins_install_setup_method', FALSE, array( 'sprintf' => array( $versionToRun ) ) ) );
}
\IPS\Log::i( LOG_DEBUG )->write( "Plugin setup: All set up classes run", 'plugin_setup' );
\IPS\Log::debug( "Plugin setup: All set up classes run", 'plugin_setup' );
/* All set up classes are done, so delete stored data so far */
if ( count( $data['storeKeys'] ) )
@@ -816,12 +882,21 @@ class _plugins extends \IPS\Node\Controller
/* Log */
\IPS\Session::i()->log( 'acplog__plugin_installed', array( $plugin->name => FALSE ) );
/* Re-enable the plugin */
$plugin->enabled = TRUE;
$plugin->save();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* All done */
return NULL;
},
function()
{
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins' ) );
}
);
@@ -964,7 +1039,7 @@ class _plugins extends \IPS\Node\Controller
{
$plugin = \IPS\Plugin::load( \IPS\Request::i()->id );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=developer&id={$plugin->id}&tab=hooks" ), $plugin->_title );
\IPS\Plugin\Hook::load( \IPS\Request::i()->hook )->editForm( \IPS\Request::i()->url() );
\IPS\Plugin\Hook::load( \IPS\Request::i()->hook )->editForm( \IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=developer&id=" . $plugin->id . "&tab=hooks" ) );
}
catch ( \OutOfRangeException $e )
{
@@ -982,9 +1057,8 @@ class _plugins extends \IPS\Node\Controller
$exploded = explode( '_', \IPS\Request::i()->class );
$bits = \IPS\Theme::load( \IPS\Theme::defaultTheme() )->getRawTemplates( $exploded[1], $exploded[2], $exploded[3], \IPS\Theme::RETURN_ALL );
$document = new \DOMDocument();
$document = new \IPS\Xml\DOMDocument();
$document->strictErrorChecking = FALSE;
libxml_use_internal_errors(TRUE);
/* Get the template content */
$code = $bits[ $exploded[1] ][ $exploded[2] ][ $exploded[3] ][ \IPS\Request::i()->template ]['template_content'];
@@ -1023,13 +1097,19 @@ class _plugins extends \IPS\Node\Controller
}
/* Fix embedded single quotes */
$code = preg_replace_callback( '/=\'([^\']*?){.+?}([^\']*?)\'/', function( $matches )
$code = preg_replace_callback( '/=\'([^\']+?){.+?}([^\']+?)\'/', function( $matches )
{
return "=''";
}, $code );
/* 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];
}, $code );
/* Now load the HTML - doctype necessary sometimes */
$document->loadHTML( '<!DOCTYPE html><ipscontent id="ipscontent">' . $code . '</ipscontent>' );
$document->loadHTML( \IPS\Xml\DOMDocument::wrapHtml( '<ipscontent id="ipscontent">' . $code . '</ipscontent>' ) );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'applications' )->themeHookEditorTreeRoot( $document->getElementById('ipscontent') );
}
@@ -1117,9 +1197,11 @@ class _plugins extends \IPS\Node\Controller
'default' => array( 'Text' )
);
$matrix->rows = file_exists( $file ) ? json_decode( file_get_contents( $file ), TRUE ) : array();
if ( $values = $matrix->values() )
if ( $matrix->values() !== FALSE )
{
$values = $matrix->values();
if ( !empty( $matrix->addedRows ) )
{
$insert = array();
@@ -1149,7 +1231,7 @@ class _plugins extends \IPS\Node\Controller
}
unset( \IPS\Data\Store::i()->settings );
\file_put_contents( $file, json_encode( array_filter( array_values( $values ), function ( $v )
{
return (bool) $v['key'];
@@ -1178,7 +1260,6 @@ class _plugins extends \IPS\Node\Controller
\IPS\ROOT_PATH . "/plugins/{$plugin->location}/tasks",
$plugin->location,
'pluginTasks',
$plugin->version_long,
$plugin->id
);
}
@@ -1192,13 +1273,12 @@ class _plugins extends \IPS\Node\Controller
protected function _manageWidgets( $plugin )
{
return \IPS\Widget::devTable(
\IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/widgets.json",
\IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=developer&id={$plugin->id}&tab=widgets" ),
\IPS\ROOT_PATH . "/plugins/{$plugin->location}/widgets",
$plugin->location,
"plugins\\" . $plugin->location,
$plugin->version_long,
$plugin->id
\IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/widgets.json",
\IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=developer&id={$plugin->id}&tab=widgets" ),
\IPS\ROOT_PATH . "/plugins/{$plugin->location}/widgets",
$plugin->location,
"plugins\\" . $plugin->location,
$plugin->id
);
}
@@ -1212,7 +1292,7 @@ class _plugins extends \IPS\Node\Controller
{
if ( !file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/versions.json" ) )
{
\file_put_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/versions.json", json_encode( array( '10000' => '1.0.0' ) ) );
\file_put_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/versions.json", json_encode( array() ) );
}
$versions = array();
foreach ( json_decode( file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/versions.json" ) ) as $long => $human )
@@ -1347,6 +1427,9 @@ class _plugins extends \IPS\Node\Controller
*/
protected function deleteVersion()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Load Plugin */
try
{
@@ -1410,24 +1493,58 @@ class _plugins extends \IPS\Node\Controller
$hookNode = $hooks->addChild( 'hook', \IPS\Plugin::addExceptionHandlingToHookFile( \IPS\ROOT_PATH . '/plugins/' . $plugin->location . '/hooks/' . $hook['filename'] . '.php' ) );
$hookNode->addAttribute( 'type', $hook['type'] );
$hookNode->addAttribute( 'class', $hook['class'] );
$hookNode->addAttribute( 'filename', $hook['filename'] );
}
/* Get Settings */
if ( file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/settings.json" ) )
{
$settings = json_decode( file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/settings.json" ), TRUE );
$settings = json_decode( file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/settings.json" ), TRUE );
if ( !empty( $settings ) )
{
$inserts = array();
$xml->addChild( 'settings', $settings );
foreach( $settings as $setting )
{
$key = $setting['key'];
if( isset( \IPS\Settings::i()->$key ) )
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array(
'conf_default' => $setting['default'],
'conf_plugin' => $plugin->id
), array( 'conf_key=?', $key ) );
}
else
{
$inserts[] = array(
'conf_key' => $key,
'conf_value' => $setting['default'],
'conf_default' => $setting['default'],
'conf_plugin' => $plugin->id
);
}
}
if( count( $inserts ) )
{
\IPS\Db::i()->insert( 'core_sys_conf_settings', $inserts , TRUE );
}
unset( \IPS\Data\Store::i()->settings );
}
}
/* Uninstall Code */
if ( file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/uninstall.php" ) )
{
$xml->addChild( 'uninstall', file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/uninstall.php" ) );
$xml->addChild( 'uninstall', file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/uninstall.php" ) );
}
/* Add the settings code */
if ( file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/settings.php" ) )
{
$xml->addChild( 'settingsCode', file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/settings.php" ) );
@@ -1442,6 +1559,20 @@ class _plugins extends \IPS\Node\Controller
$taskNode = $tasksNode->addChild( 'task', file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/tasks/{$key}.php" ) );
$taskNode->addAttribute( 'key', $key );
$taskNode->addAttribute( 'frequency', $frequency );
/* Insert into DB */
try
{
$task = \IPS\Task::load( $key, 'key', array( 'plugin=?', $plugin->id ) );
}
catch ( \OutOfRangeException $e )
{
$task = new \IPS\Task;
}
$task->plugin = $plugin->id;
$task->key = $key;
$task->frequency = $frequency;
$task->save();
}
}
@@ -1454,6 +1585,7 @@ class _plugins extends \IPS\Node\Controller
$content = file_get_contents( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/widgets/{$key}.php" );
$content = str_replace( "namespace IPS\\plugins\\{$plugin->location}\\widgets", "namespace IPS\\plugins\\<{LOCATION}>\\widgets", $content );
$content = str_replace( "public \$plugin = '{$plugin->id}';", "public \$plugin = '<{ID}>';", $content );
$content = str_replace( "public \$app = '';", "", $content );
$widgetNode = $widgetsNode->addChild( 'widget', $content );
$widgetNode->addAttribute('key', $key );
@@ -1466,10 +1598,45 @@ class _plugins extends \IPS\Node\Controller
$widgetNode->addAttribute( $dataKey, $value );
}
/* Automatically import everything into the local database to avoid having to toggle IN_DEV to import data first */
try
{
$widget = \IPS\Db::i()->select( '*', 'core_widgets', array( '`key`=? and plugin=?', $key, $plugin->id ) )->first();
\IPS\Db::i()->update( 'core_widgets', array(
'plugin' => $plugin->id,
'key' => $key,
'class' => $json['class'],
'restrict' => json_encode( $json['restrict'] ),
'default_area' => $json['default_area'],
'allow_reuse' => intval( $json['allow_reuse'] ),
'menu_style' => $json['menu_style'],
'embeddable' => intval( $json['embeddable'] )
), array( '`id`=?', $widget['id'] ) );
}
catch ( \UnderflowException $e )
{
$inserts[] = array(
'plugin' => $plugin->id,
'key' => $key,
'class' => $json['class'],
'restrict' => json_encode( $json['restrict'] ),
'default_area' => $json['default_area'],
'allow_reuse' => intval( $json['allow_reuse'] ),
'menu_style' => $json['menu_style'],
'embeddable' => intval( $json['embeddable'] )
);
\IPS\Db::i()->insert( 'core_widgets', $inserts, TRUE );
}
}
}
/* If we're upgrading, remove current HTML, CSS, etc. We'll insert again in a moment */
\IPS\Theme::removeTemplates( 'core', 'global', 'plugins', $plugin->id );
\IPS\Theme::removeCss( 'core', 'front', 'custom', $plugin->id );
\IPS\Theme::removeResources( 'core', 'global', 'plugins', $plugin->id );
/* Get HTML, CSS, JS, Resources */
foreach ( array( 'html' => 'phtml', 'css' => 'css', 'js' => 'js', 'resources' => '*' ) as $k => $ext )
{
@@ -1478,7 +1645,69 @@ class _plugins extends \IPS\Node\Controller
{
if ( !$file->isDot() and mb_substr( $file, 0, 1 ) != '.' and ( $ext === '*' or mb_substr( $file, - ( mb_strlen( $ext ) + 1 ) ) === ".{$ext}" ) )
{
$resourcesNode->addChild( $k, base64_encode( file_get_contents( $file->getPathname() ) ) )->addAttribute( 'filename', $file );
$content = file_get_contents( $file->getPathname() );
$resourcesNode->addChild( $k, base64_encode( $content ) )->addAttribute( 'filename', $file );
/* Automatically import everything into the local database to avoid having to toggle IN_DEV to import data first */
switch( $k )
{
case 'html':
preg_match('/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $content, $matches );
$output = preg_replace( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', '', $content );
\IPS\Theme::addTemplate( array(
'app' => 'core',
'location' => 'global',
'group' => 'plugins',
'name' => mb_substr( $file, 0, -6 ),
'variables' => $matches[1],
'content' => $output,
'plugin' => $plugin->id,
'_default_template' => TRUE
), TRUE );
break;
case 'css':
\IPS\Theme::addCss( array(
'app' => 'core',
'location' => 'front',
'path' => 'custom',
'name' => $file,
'content' => $content,
'plugin' => $plugin->id
), TRUE );
break;
case 'js':
try
{
$js = \IPS\Output\Javascript::find( 'core', 'plugins', '/', (string) $file );
$js->delete();
}
catch ( \OutOfRangeException $e ) {}
$js = new \IPS\Output\Javascript;
$js->plugin = $plugin->id;
$js->name = (string) $file;
$js->content = $content;
$js->version = $plugin->version_long;
$js->save();
break;
case 'resources':
\IPS\Theme::addResource( array(
'app' => 'core',
'location' => 'global',
'path' => '/plugins/',
'name' => $file,
'content' => $content,
'plugin' => $plugin->id
) );
break;
}
}
}
}
@@ -1486,6 +1715,10 @@ class _plugins extends \IPS\Node\Controller
/* Get language strings */
if ( file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/lang.php" ) or file_exists( \IPS\ROOT_PATH . "/plugins/{$plugin->location}/dev/jslang.php" ) )
{
$existingLanguageKeys = iterator_to_array( \IPS\Db::i()->select( 'word_key', 'core_sys_lang_words', array( 'word_plugin=? and lang_id=?', $plugin->id, \IPS\Lang::defaultLanguage() ) ) );
$keysToDelete = $existingLanguageKeys;
$inserts = array();
$langNode = $xml->addChild( 'lang' );
foreach ( array( 'lang' => 0, 'jslang' => 1 ) as $file => $js )
{
@@ -1497,9 +1730,52 @@ class _plugins extends \IPS\Node\Controller
$word = $langNode->addChild( 'word', $v );
$word->addAttribute( 'key', $k );
$word->addAttribute( 'js', $js );
/* Automatically import everything into the local database to avoid having to toggle IN_DEV to import data first */
foreach ( \IPS\Lang::languages() as $lang )
{
if ( count( $existingLanguageKeys ) and in_array( $k, $existingLanguageKeys ) )
{
/* Exists so do not delete */
$keysToDelete = array_diff( $keysToDelete, array( $k ) );
\IPS\Db::i()->update( 'core_sys_lang_words', array(
'word_default' => $v,
'word_default_version' => $plugin->version_long,
'word_js' => $js
),
array( 'lang_id=? and word_plugin=? and word_key=?', $lang->id, $plugin->id, $k )
);
}
else
{
$inserts[] = array(
'lang_id' => $lang->id,
'word_app' => NULL,
'word_plugin' => $plugin->id,
'word_key' => $k,
'word_default' => $v,
'word_custom' => NULL,
'word_default_version' => $plugin->version_long,
'word_custom_version' => NULL,
'word_js' => $js,
'word_export' => 1,
);
}
}
}
}
}
if( count( $inserts ) )
{
\IPS\Db::i()->replace( 'core_sys_lang_words', $inserts );
}
if ( count( $keysToDelete ) )
{
\IPS\Db::i()->delete( 'core_sys_lang_words', array( 'word_plugin=? AND ' . \IPS\Db::i()->in( 'word_key', $keysToDelete ), $plugin->id ) );
}
}
/* Get versions */
@@ -1536,9 +1812,45 @@ class _plugins extends \IPS\Node\Controller
{
\IPS\Output::i()->error( 'node_error', '2C145/B', 404, '' ); //@todo duplicate error code
}
/* Work out tab */
$tabs = array( 'details' => 'plugin_details', 'hooks' => 'plugin_hooks' );
$activeTab = ( \IPS\Request::i()->tab and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'details';
$activeTabContents = '';
/* Tab contents */
if ( $activeTab === 'details' )
{
$activeTabContents = \IPS\Theme::i()->getTemplate( 'plugins' )->details( $plugin );
}
elseif ( $activeTab === 'hooks' )
{
$table = new \IPS\Helpers\Table\Db( 'core_hooks', \IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=details&id={$plugin->id}&tab=hooks" ), array( 'plugin=?', $plugin->id ) );
$table->include = array( 'filename', 'class' );
$table->langPrefix = 'plugin_hook_';
if ( !$table->sortBy )
{
$table->sortBy = 'class';
$table->sortDirection = 'asc';
}
$table->parsers = array(
'filename' => function( $val, $row )
{
return $val . '.php';
}
);
$activeTabContents = (string) $table;
}
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'plugin_details' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'plugins' )->details( $plugin );
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->tab ) )
{
\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=applications&controller=plugins&do=details&id={$plugin->id}" ) );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Bulk mail handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -119,13 +119,14 @@ class _bulkmail extends \IPS\Dispatcher\Controller
'title' => 'cancel',
'link' => \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail&do=cancel&id=' ) . $row['mail_id'],
);
if ( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
$classToUse = \IPS\Email::classToUse( \IPS\Email::TYPE_BULK );
if( !$classToUse::REQUIRES_TIME_BREAK )
{
$return['resend'] = array(
'icon' => 'share',
'title' => 'continue_sending',
'link' => \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail&resetTask=1&do=sendMandrill&id=' ) . $row['mail_id'],
'link' => \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail&resetTask=1&do=sendImmediately&id=' ) . $row['mail_id'],
);
}
}
@@ -152,17 +153,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
return $return;
};
/* Shortcut to Mandrill configuration */
\IPS\Output::i()->sidebar['actions'] = array(
'configure' => array(
'title' => 'mandrill_cross_link',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=enhancements&do=edit&id=core_Mandrill" ),
),
);
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('manage_bulk_mail');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'title', (string) $table );
}
@@ -174,6 +165,9 @@ class _bulkmail extends \IPS\Dispatcher\Controller
*/
public function delete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Retrieve the bulk mail details for the log */
try
{
@@ -187,9 +181,6 @@ class _bulkmail extends \IPS\Dispatcher\Controller
/* Delete the bulk mail */
$mail->delete();
/* Reset bulk mail task */
\IPS\core\BulkMail\Bulkmailer::updateTask();
/* Log and redirect */
\IPS\Session::i()->log( 'acplog__bulkmail_deleted', array( $mail->subject => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'deleted' );
@@ -216,9 +207,16 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$mail->updated = time();
$mail->active = 0;
$mail->save();
/* Reset bulk mail task */
\IPS\core\BulkMail\Bulkmailer::updateTask();
/* Remove any queue tasks */
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( "`key`=?", 'Bulkmail' ) ) AS $task )
{
$data = json_decode( $task['data'], TRUE );
if ( isset( $data['mail_id'] ) AND $data['mail_id'] == $mail->id )
{
\IPS\Db::i()->delete( 'core_queue', array( "id=?", $task['id'] ) );
}
}
/* Log and redirect */
\IPS\Session::i()->log( 'acplog__bulkmail_cancelled', array( $mail->subject => FALSE ) );
@@ -259,7 +257,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$results = $mail->getQuery( array( 0, 1000 ) );
/* Get a count of the members */
$total = $results->count( TRUE );
$total = $mail->getQuery( \IPS\core\BulkMail\Bulkmailer::GET_COUNT_ONLY )->first();
/* Do we have anyone to send to? */
if( !$total )
@@ -276,12 +274,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('bm_send_preview');
if( !\IPS\Settings::i()->mandrill_api_key )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->message( 'bulkmail_send_info', 'information' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->message( 'bulkmail_send_info', 'information' );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'members' )->bulkMailPreview( $mail, $results, $total );
}
@@ -301,12 +294,46 @@ class _bulkmail extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->error( 'couldnt_find_bulkmail', '2C125/2', 404, '' );
}
/* For the preview we need to display the tags replaced with this member's data */
$content = $mail->content;
foreach ( $mail->returnTagValues( 0, \IPS\Member::loggedIn() ) as $k => $v )
{
$content = str_replace( $k, $v, $content );
}
/* Display */
$email = \IPS\Email::buildFromContent( $mail->subject, $content, NULL, \IPS\Email::TYPE_BULK )->setUnsubscribe( 'core', 'unsubscribeBulk' );
/* Format the email */
$email = \IPS\Email::buildFromContent( $mail->subject, $mail->formatBody( \IPS\Member::loggedIn() ) );
$email->buildUnsubscribe( 'bulk', \IPS\Member::loggedIn() );
\IPS\Output::i()->sendOutput( $email->compileContent( 'html', \IPS\Member::loggedIn() ) );
}
/**
* Format a bulk mail by replacing out the tags with the proper values
*
* @param \IPS\Member $member Member data
* @return string
*/
public function formatBody( $member )
{
if( empty($this->_data['content']) )
{
return '';
}
\IPS\Output::i()->sendOutput( $email->body['html'] );
/* Default tags */
$tags = $this->returnTagValues( 0, $member );
/* Work on a copy rather than the original template */
$body = $this->_data['content'];
/* Loop over the tags and swap out as appropriate */
foreach( $tags as $key => $value )
{
$body = str_replace( $key, $value, $body );
}
return $body;
}
/**
@@ -332,37 +359,32 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$mail->sentto = 0;
$mail->save();
/* Reset bulk mail task */
\IPS\core\BulkMail\Bulkmailer::updateTask();
\IPS\Session::i()->log( 'acplogs__bulkmail_sent', array( $mail->subject => FALSE ) );
/* And redirect */
if( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
$classToUse = \IPS\Email::classToUse( \IPS\Email::TYPE_BULK );
if( !$classToUse::REQUIRES_TIME_BREAK )
{
return $this->sendMandrill();
return $this->sendImmediately();
}
else
{
\IPS\Task::queue( 'core', 'Bulkmail', array( 'mail_id' => $mail->id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'bm_initiated' );
}
}
/**
* Send Mandrill bulk mails immediately
* Send bulk mails immediately
*
* @return void
*/
public function sendMandrill()
public function sendImmediately()
{
/* If we are "continuing" an existing bulk mail send, update the task first */
if( isset( \IPS\Request::i()->resetTask ) AND \IPS\Request::i()->resetTask == 1 )
{
\IPS\core\BulkMail\Bulkmailer::updateTask();
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('bm_initiated');
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( "app=core&module=bulkmail&controller=bulkmail&do=sendMandrill&id=" . intval( \IPS\Request::i()->id ) ),
\IPS\Http\Url::internal( "app=core&module=bulkmail&controller=bulkmail&do=sendImmediately&id=" . intval( \IPS\Request::i()->id ) ),
function( $data )
{
/* Retrieve the bulk mail details */
@@ -378,7 +400,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
/* On first cycle return data */
if ( !is_array( $data ) )
{
return array( array( 'total' => $mail->getQuery()->count( TRUE ), 'done' => 0 ),
return array( array( 'total' => $mail->getQuery( \IPS\core\BulkMail\Bulkmailer::GET_COUNT_ONLY )->first() ),
\IPS\Member::loggedIn()->language()->addToStack('bulkmail_sent_sofar', FALSE, array( 'sprintf' => array( $mail->subject, \IPS\Member::loggedIn()->language()->addToStack( 'bm_users', FALSE, array( 'pluralize' => array( 0 ) ) ) ) ) ),
1
);
@@ -394,18 +416,16 @@ class _bulkmail extends \IPS\Dispatcher\Controller
}
else
{
$data['done'] += (int) $result;
return array( $data,
\IPS\Member::loggedIn()->language()->addToStack('bulkmail_sent_sofar', FALSE, array( 'sprintf' => array( $mail->subject, \IPS\Member::loggedIn()->language()->addToStack( 'bm_users', FALSE, array( 'pluralize' => array( $result ) ) ) ) ) ),
( $result / $data['total'] * $data['done'] )
\IPS\Member::loggedIn()->language()->addToStack('bulkmail_sent_sofar', FALSE, array( 'sprintf' => array( $mail->subject, \IPS\Member::loggedIn()->language()->addToStack( 'bm_users', FALSE, array( 'pluralize' => array( $mail->sentto ) ) ) ) ) ),
min( ( 100 / $data['total'] * $mail->offset ), 100 )
);
}
},
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_mandrill_sent' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'bm_sparkpost_sent' );
}
);
}
@@ -445,12 +465,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$form->class = 'ipsForm_vertical';
$form->addTab( 'bulkmail__main' );
$form->add( new \IPS\Helpers\Form\Text( 'mail_subject', $mail->subject, TRUE ) );
$form->add( new \IPS\Helpers\Form\Editor( 'mail_body', $mail->content ?: "<p>{member_name},</p><p>&nbsp;</p>", TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'bulkmail' . ( $mail->id ? '-' . $mail->id : '' ), 'tags' => $tags, 'attachIds' => array( $mail->id, NULL, 'bulkmail' ) ) ) );
if( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
{
$form->add( new \IPS\Helpers\Form\Stack( 'mandrill_tags', ( !empty( $mail->_options['mandrill_tags'] ) ) ? $mail->_options['mandrill_tags'] : array(), FALSE ) );
}
$form->add( new \IPS\Helpers\Form\Editor( 'mail_body', $mail->content ?: '', TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'bulkmail' . ( $mail->id ? '-' . $mail->id : '' ), 'tags' => $tags, 'attachIds' => array( $mail->id, NULL, 'bulkmail' ) ) ) );
/* Add the filters tab and the "generic filters" header */
$form->addTab( 'bulkmail__filters' );
@@ -459,7 +474,7 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$lastApp = 'core';
/* Now grab bulk mail extensions */
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
foreach ( \IPS\Application::allExtensions( 'core', 'MemberFilter', TRUE, 'core' ) as $key => $extension )
{
if( method_exists( $extension, 'getSettingField' ) )
{
@@ -494,13 +509,8 @@ class _bulkmail extends \IPS\Dispatcher\Controller
$_options = array();
if( \IPS\Settings::i()->mandrill_api_key AND \IPS\Settings::i()->mandrill_use_for )
{
$_options['mandrill_tags'] = $values['mandrill_tags'];
}
/* Loop over bulk mail extensions to format the options */
foreach ( \IPS\Application::allExtensions( 'core', 'BulkMail', TRUE, 'core' ) as $key => $extension )
foreach ( \IPS\Application::allExtensions( 'core', 'MemberFilter', TRUE, 'core' ) as $key => $extension )
{
if( method_exists( $extension, 'save' ) )
{
@@ -2,9 +2,9 @@
/**
* @brief Customization AJAX actions
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 07 May 2013
* @version SVN_VERSION_NUMBER
*/
@@ -84,17 +84,7 @@ class _ajax extends \IPS\Dispatcher\Controller
{
foreach( $templateNames[ $app ][ $location ] as $path => $items )
{
if ( $path === 'custom' )
{
foreach( $items as $name => $data )
{
if ( $name !== 'custom.css' )
{
unset( $templateNames[ $app ][ $location ][ $path ][ $name ] );
}
}
}
else
if ( $path != 'custom' )
{
unset( $templateNames[ $app ][ $location ][ $path ] );
}
@@ -181,7 +171,24 @@ class _ajax extends \IPS\Dispatcher\Controller
$where = array();
if ( \IPS\Request::i()->term )
{
$where[] = array( 'LOWER(template_content) LIKE ?', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
$where[] = array( '( LOWER(template_name) LIKE ? OR LOWER(template_content) LIKE ? )', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
/* If searching content we need to specifically only search the templates *actually* being used */
$uniqueIds = array();
foreach ( $theme->getRawTemplates( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT ) as $locations )
{
foreach ( $locations as $groups )
{
foreach ( $groups as $templates )
{
foreach ( $templates as $template )
{
$uniqueIds[] = "'" . $template['template_unique_key'] . "'";
}
}
}
}
$where[] = array( 'template_unique_key IN (' . implode( ',' , $uniqueIds ) . ')' );
}
if ( in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
{
@@ -203,6 +210,10 @@ class _ajax extends \IPS\Dispatcher\Controller
{
$where[] = array( 'template_user_edited>0 or template_added_to > 0' );
}
if ( !in_array( 'modified', explode( ',', \IPS\Request::i()->filters ) ) )
{
$where[] = array( 'template_added_to=0' );
}
$where[] = array( 'template_set_id IN (' . implode( ',' , $parents ) . ')' );
$select = \IPS\Db::i()->select(
@@ -247,7 +258,24 @@ class _ajax extends \IPS\Dispatcher\Controller
$where = array();
if ( \IPS\Request::i()->term )
{
$where[] = array( 'LOWER(css_content) LIKE ?', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
$where[] = array( '( LOWER(css_name) LIKE ? OR LOWER(css_content) LIKE ? )', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
/* If searching content we need to specifically only search the css files *actually* being used */
$uniqueIds = array();
foreach ( $theme->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT ) as $locations )
{
foreach ( $locations as $groups )
{
foreach ( $groups as $templates )
{
foreach ( $templates as $template )
{
$uniqueIds[] = "'" . $template['css_unique_key'] . "'";
}
}
}
}
$where[] = array( 'css_unique_key IN (' . implode( ',' , $uniqueIds ) . ')' );
}
if ( in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
{
@@ -2,9 +2,9 @@
/**
* @brief Email template management
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 02 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -82,6 +82,7 @@ class _emails extends \IPS\Dispatcher\Controller
'icon' => 'undo',
'title' => 'revert',
'link' => \IPS\Http\Url::internal( 'app=core&module=customization&controller=emails&do=revert&key=' ) . $row['template_key'],
'data' => array( 'delete' => '', 'delete-warning' => \IPS\Member::loggedIn()->language()->addToStack('email_revert_confirm') )
);
$return['export'] = array(
@@ -125,7 +126,7 @@ class _emails extends \IPS\Dispatcher\Controller
/* Get the template info */
try
{
$template = \IPS\DB::i()->select( '*', 'core_email_templates', array( 'template_parent>0 AND template_key=?', \IPS\Request::i()->key ) )->first();
$template = \IPS\Db::i()->select( '*', 'core_email_templates', array( 'template_parent>0 AND template_key=?', \IPS\Request::i()->key ) )->first();
}
catch ( \UnderflowException $e )
{
@@ -182,7 +183,7 @@ class _emails extends \IPS\Dispatcher\Controller
try
{
$existing = \IPS\DB::i()->select( '*', 'core_email_templates', array( 'template_parent=0 AND template_key=?', $update['template_key'] ) )->first();
$existing = \IPS\Db::i()->select( '*', 'core_email_templates', array( 'template_parent=0 AND template_key=?', $update['template_key'] ) )->first();
}
catch ( \UnderflowException $e )
{
@@ -190,8 +191,8 @@ class _emails extends \IPS\Dispatcher\Controller
}
$update['template_parent'] = $existing['template_id'];
\IPS\DB::i()->replace( 'core_email_templates', $update );
\IPS\DB::i()->update( 'core_email_templates', array( 'template_edited' => 1 ), array( 'template_id=?', $existing['template_id'] ) );
\IPS\Db::i()->replace( 'core_email_templates', $update );
\IPS\Db::i()->update( 'core_email_templates', array( 'template_edited' => 1 ), array( 'template_id=?', $existing['template_id'] ) );
}
/* Redirect */
@@ -210,11 +211,14 @@ class _emails extends \IPS\Dispatcher\Controller
*/
public function revert()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Get the template info for the log */
$template = \IPS\DB::i()->select( '*', 'core_email_templates', array( 'template_parent=0 AND template_key=?', \IPS\Request::i()->key ) )->first();
$template = \IPS\Db::i()->select( '*', 'core_email_templates', array( 'template_parent=0 AND template_key=?', \IPS\Request::i()->key ) )->first();
/* Revert any user-edited copies of the specified template */
\IPS\DB::i()->delete( 'core_email_templates', array( 'template_parent>0 AND template_key=?', \IPS\Request::i()->key ) );
\IPS\Db::i()->delete( 'core_email_templates', array( 'template_parent>0 AND template_key=?', \IPS\Request::i()->key ) );
/* Reset edited flag on parent */
\IPS\Db::i()->update( 'core_email_templates', array( 'template_edited' => 0 ), array( 'template_id=?', $template['template_id'] ) );
@@ -242,7 +246,7 @@ class _emails extends \IPS\Dispatcher\Controller
try
{
$template = \IPS\DB::i()->select( '*', 'core_email_templates', array( 'template_key=?', \IPS\Request::i()->key ), 'template_parent DESC', 1 )->first();
$template = \IPS\Db::i()->select( '*', 'core_email_templates', array( 'template_key=?', \IPS\Request::i()->key ), 'template_parent DESC', 1 )->first();
}
catch ( \UnderflowException $e )
{
@@ -337,19 +341,7 @@ class _emails extends \IPS\Dispatcher\Controller
*/
public function emailPreview()
{
/* Add some dummy content */
$body = \IPS\Theme::i()->getTemplate( 'customization', 'core', 'admin' )->emailPreview();
$templateData = \IPS\Db::i()->select( '*', 'core_email_templates', array( "template_app=? AND template_name=?", 'core', 'emailWrapper' ) )->first();
$template = "namespace IPS\Theme;\n" . \IPS\Theme::compileTemplate( $templateData['template_content_html'], "email_html_core_emailWrapper", $templateData['template_data'] );
if( !function_exists( 'IPS\\Theme\\email_html_core_emailWrapper' ) )
{
eval( $template );
}
$output = call_user_func_array( 'IPS\\Theme\\email_html_core_emailWrapper', array( NULL, new \IPS\Member, $body, NULL, FALSE, '', NULL ) );
\IPS\Output::i()->sendOutput( $output, 200, 'text/html' );
$email = \IPS\Email::buildFromContent( '', \IPS\Member::loggedIn()->language()->addToStack( 'email_preview_content' ) );
\IPS\Output::i()->sendOutput( $email->compileContent( 'html' ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief themes
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 15 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -37,7 +37,19 @@ class _themes extends \IPS\Node\Controller
* Description can contain HTML?
*/
public $_descriptionHtml = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'theme_sets_manage' );
parent::execute();
}
/**
* Manage
*
@@ -51,7 +63,7 @@ class _themes extends \IPS\Node\Controller
}
/* Add a button for designer's mode */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'customization', 'theme_designers_mode' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'customization', 'theme_designers_mode' ) and !\IPS\NO_WRITES and !\IPS\CIC )
{
\IPS\Output::i()->sidebar['actions']['designersmode'] = array(
'title' => ( \IPS\Theme::designersModeEnabled() ) ? 'theme_designers_mode_on_title' : 'theme_designers_mode_title',
@@ -154,6 +166,11 @@ class _themes extends \IPS\Node\Controller
return;
}
if ( \IPS\NO_WRITES or \IPS\CIC )
{
\IPS\Output::i()->error( 'no_writes', '1C163/9', 403, '' );
}
$form = new \IPS\Helpers\Form( 'form', 'next' );
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('theme_designers_mode_explain', FALSE, array( 'sprintf' => array( \IPS\ROOT_PATH, \IPS\Http\Url::ips('docs/designers_mode') ) ) ), 'ipsMessage ipsMessage_general', TRUE );
@@ -207,6 +224,11 @@ class _themes extends \IPS\Node\Controller
*/
public function designersmodeoff()
{
if ( \IPS\NO_WRITES or \IPS\CIC )
{
\IPS\Output::i()->error( 'no_writes', '1C163/B', 403, '' );
}
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=designersmodeoff' ),
function( $data )
@@ -406,6 +428,11 @@ class _themes extends \IPS\Node\Controller
*/
public function designersmodeon()
{
if ( \IPS\NO_WRITES or \IPS\CIC )
{
\IPS\Output::i()->error( 'no_writes', '1C163/A', 403, '' );
}
/* Nothing to build, its all up to date */
$needsBuilding = \IPS\Theme\Advanced\Theme::getToBuild();
@@ -530,7 +557,8 @@ class _themes extends \IPS\Node\Controller
}
\IPS\Theme\Advanced\Theme::$currentThemeId = $themeId;
\IPS\Theme\Advanced\Theme::$buildingFiles = true;
foreach ( \IPS\Application::applications() as $app )
{
switch ( $type )
@@ -619,7 +647,7 @@ class _themes extends \IPS\Node\Controller
},
'resource_filename' => function( $val, $row )
{
return '{resource="' . ltrim( $row['resource_path'], '/' ) . $row['resource_name'] . '" app="' . $row['resource_app'] . '" location="' . $row['resource_location'] . '"}';
return \IPS\Theme::i()->getTemplate( 'customization' )->resourceTag( '{resource="' . ltrim( $row['resource_path'], '/' ) . $row['resource_name'] . '" app="' . $row['resource_app'] . '" location="' . $row['resource_location'] . '"}' );
}
);
@@ -675,6 +703,9 @@ class _themes extends \IPS\Node\Controller
*/
public function resourceDelete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$id = intval( \IPS\Request::i()->id );
try
@@ -698,6 +729,12 @@ class _themes extends \IPS\Node\Controller
/* Don't delete master resources */
if ( $current['resource_set_id'] > 0 )
{
try
{
\IPS\File::get( 'core_Theme', $current['resource_filename'] )->delete();
}
catch( \Exception $ex ) { }
\IPS\Db::i()->delete( 'core_theme_resources', array( 'resource_id=?', $id ) );
}
@@ -951,7 +988,9 @@ class _themes extends \IPS\Node\Controller
/* Move it to a temporary location */
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
move_uploaded_file( $values['core_theme_set_new_import'], $tempFile );
$max = \IPS\Db::i()->select( 'MAX(set_order)', 'core_themes' )->first();
/* Create a default theme */
$theme = new \IPS\Theme;
$theme->parent_array = '[]';
@@ -959,12 +998,13 @@ class _themes extends \IPS\Node\Controller
$theme->parent_id = 0;
$theme->by_skin_gen = 0;
$theme->editor_skin = 'ips';
$theme->order = $max + 1;
$theme->save();
$theme->copyResourcesFromSet();
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) . '&id=' . $theme->id) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ), 'id' => $theme->id ) ) );
}
else
{
@@ -988,7 +1028,7 @@ class _themes extends \IPS\Node\Controller
}
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import&file=' . urlencode( \IPS\Request::i()->file ) . '&key=' . \IPS\Request::i()->key . '&id=' . \IPS\Request::i()->id ),
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key, 'id' => \IPS\Request::i()->id ) ),
function( $data )
{
$set = \IPS\Theme::load( \IPS\Request::i()->id );
@@ -996,28 +1036,34 @@ class _themes extends \IPS\Node\Controller
$templates = \IPS\Theme::load( \IPS\Request::i()->id )->getRawTemplates( null, null, null, \IPS\Theme::RETURN_ALL_NO_CONTENT, true );
$css = \IPS\Theme::load( \IPS\Request::i()->id )->getRawCss( null, null, null, \IPS\Theme::RETURN_ALL_NO_CONTENT, true );
$masterCss = \IPS\Theme::load( \IPS\Request::i()->id )->getRawCss( null, null, null, \IPS\Theme::RETURN_BIT_NAMES, false );
/* Open XML file */
$xml = new \XMLReader;
$xml = new \IPS\Xml\XMLReader;
$xml->open( \IPS\Request::i()->file );
if ( ! @$xml->read() )
{
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->error( 'xml_upload_invalid', '2C163/1', 403, '' );
}
/* Is this the first batch? */
if ( !is_array( $data ) )
{
$_SESSION['theme_import'] = array( 'css' => array(), 'isNewSet' => false );
/* Save snaphot */
\IPS\Theme::load( \IPS\Request::i()->id )->saveHistorySnapshot();
/* Wipe clean conflicts */
\IPS\Db::i()->delete( 'core_theme_conflict', array( 'conflict_set_id=?', \IPS\Request::i()->id ) );
/* No Name? */
/* No Name? Then this is a brand new theme */
if ( empty( $set->name ) )
{
$_SESSION['theme_import']['isNewSet'] = TRUE;
while ( $xml->read() )
{
if ( $xml->name == 'theme' )
@@ -1033,13 +1079,15 @@ class _themes extends \IPS\Node\Controller
}
$set->saveSet( array(
'set_name' => $xml->getAttribute('name'),
'set_author_name' => $xml->getAttribute('author_name'),
'set_author_url' => $xml->getAttribute('author_url'),
'set_version' => $xml->getAttribute('version'),
'set_long_version' => ( $xml->getAttribute('long_version') ) ? $xml->getAttribute('long_version') : \IPS\Application::load('core')->long_version,
'set_is_default' => $set->is_default,
'set_permissions' => $set->id ? $set->permissions : implode( ',', $groups )
'set_name' => $xml->getAttribute('name'),
'set_author_name' => $xml->getAttribute('author_name'),
'set_author_url' => $xml->getAttribute('author_url'),
'set_version' => $xml->getAttribute('version'),
'set_update_check' => $xml->getAttribute('update_check'),
'set_long_version' => ( $xml->getAttribute('long_version') ) ? $xml->getAttribute('long_version') : \IPS\Application::load('core')->long_version,
'set_is_default' => $set->is_default,
'set_is_acp_default' => $set->is_acp_default,
'set_permissions' => $set->id ? $set->permissions : implode( ',', $groups )
) );
if ( $xml->getAttribute('editor_skin') )
@@ -1063,6 +1111,25 @@ class _themes extends \IPS\Node\Controller
}
}
}
else
{
/* We are importing an update to a theme */
while ( $xml->read() )
{
if ( $xml->name == 'theme' )
{
$set->saveSet( array(
'set_author_name' => $xml->getAttribute('author_name'),
'set_author_url' => $xml->getAttribute('author_url'),
'set_version' => $xml->getAttribute('version'),
'set_update_check' => $xml->getAttribute('update_check'),
'set_long_version' => ( $xml->getAttribute('long_version') ) ? $xml->getAttribute('long_version') : \IPS\Application::load('core')->long_version
) );
break;
}
}
}
/* Start impoprting */
$data = array( 'apps' => array() );
@@ -1083,7 +1150,17 @@ class _themes extends \IPS\Node\Controller
{
try
{
$application = \IPS\Application::load( $appKey );
try
{
$application = \IPS\Application::load( $appKey );
}
/* Application is out of date */
catch( \UnexpectedValueException $e )
{
$xml->next();
continue;
}
if ( $application->enabled )
{
/* Import */
@@ -1093,23 +1170,35 @@ class _themes extends \IPS\Node\Controller
switch ( $xml->name )
{
case 'field':
$current = NULL;
try
{
$field = \IPS\Db::i()->select( 'sc_id', 'core_theme_settings_fields', array( 'sc_set_id=? AND sc_app=? AND sc_key=?', \IPS\Request::i()->id, $appKey, $xml->getAttribute('sc_key') ) )->first();
$current = \IPS\Db::i()->select( 'sv_value', 'core_theme_settings_values', array( 'sv_id=?', $field ) )->first();
}
catch ( \UnderflowException $e ) {}
\IPS\Db::i()->delete( 'core_theme_settings_fields', array( 'sc_set_id=? AND sc_app=? AND sc_key=?', \IPS\Request::i()->id, $appKey, $xml->getAttribute('sc_key') ) );
$default = $xml->getAttribute('sc_default');
$fieldId = \IPS\Db::i()->insert( 'core_theme_settings_fields', array(
'sc_set_id' => \IPS\Request::i()->id,
'sc_key' => $xml->getAttribute('sc_key'),
'sc_type' => $xml->getAttribute('sc_type'),
'sc_multiple' => $xml->getAttribute('sc_multiple'),
'sc_default' => $xml->getAttribute('sc_default'),
'sc_default' => $default,
'sc_content' => $xml->getAttribute('sc_content'),
'sc_app' => $appKey,
'sc_tab_key' => $xml->getAttribute('sc_tab_key'),
'sc_show_in_vse' => $xml->getAttribute('sc_show_in_vse'),
'sc_title' => $xml->getAttribute('sc_title'),
'sc_order' => (int) $xml->getAttribute('sc_order')
'sc_order' => (int) $xml->getAttribute('sc_order'),
'sc_condition' => $xml->getAttribute('sc_condition')
) );
$value = $xml->readString();
$custom = $xml->readString();
$value = ( trim( $custom ) !== "" ) ? $custom : $default;
$node = new \SimpleXMLElement( $xml->readOuterXml() );
/* Any kids of your own? */
@@ -1134,7 +1223,7 @@ class _themes extends \IPS\Node\Controller
}
\IPS\Db::i()->insert( 'core_theme_settings_values', array( 'sv_id' => $fieldId, 'sv_value' => $value ) );
\IPS\Db::i()->insert( 'core_theme_settings_values', array( 'sv_id' => $fieldId, 'sv_value' => ( $current !== NULL ) ? $current : $value ) );
break;
case 'template':
$location = $xml->getAttribute('template_location');
@@ -1184,6 +1273,9 @@ class _themes extends \IPS\Node\Controller
if ( isset( $css[ $appKey ][ $location ][ $path ][ $name ] ) AND $css[ $appKey ][ $location ][ $path ][ $name ]['css_user_edited'] )
{
/* Keep this */
$_SESSION['theme_import']['css'][] = $css[ $appKey ][ $location ][ $path ][ $name ]['css_id'];
\IPS\Db::i()->insert( 'core_theme_conflict', array(
'conflict_set_id' => \IPS\Request::i()->id,
'conflict_item_id' => $css[ $appKey ][ $location ][ $path ][ $name ]['css_id'],
@@ -1200,7 +1292,17 @@ class _themes extends \IPS\Node\Controller
}
else
{
\IPS\Db::i()->replace( 'core_theme_css', array(
$edited = 0;
$addedTo = \IPS\Request::i()->id;
if ( in_array( $name, $masterCss[ $appKey ][ $location ][ $path ] ) )
{
$edited = time();
$addedTo = 0;
}
/* Keep this */
$_SESSION['theme_import']['css'][] = \IPS\Db::i()->replace( 'core_theme_css', array(
'css_set_id' => \IPS\Request::i()->id,
'css_app' => $appKey,
'css_location' => $xml->getAttribute('css_location'),
@@ -1209,10 +1311,10 @@ class _themes extends \IPS\Node\Controller
'css_attributes' => $xml->getAttribute('css_attributes'),
'css_content' => $xml->readString(),
'css_version' => $version,
'css_user_edited'=> 0,
'css_added_to' => \IPS\Request::i()->id,
'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') )
) );
), true );
}
break;
case 'resource':
@@ -1252,10 +1354,6 @@ class _themes extends \IPS\Node\Controller
'resource_filename' => $fileName,
'resource_user_edited' => intval( $xml->getAttribute('user_edited') )
) );
$thisKey = \IPS\Theme::makeBuiltTemplateLookupHash( $xml->getAttribute('app'), $xml->getAttribute('location'), $xml->getAttribute('path') ) . '_' . $xml->getAttribute('name');
#$iMap[ $thisKey ] = $fileName;
break;
}
@@ -1352,6 +1450,12 @@ class _themes extends \IPS\Node\Controller
},
function()
{
/* Do we need to clean up orphaned CSS files? */
if ( $_SESSION['theme_import']['isNewSet'] === false and isset( $_SESSION['theme_import']['css'] ) )
{
\IPS\Db::i()->delete( 'core_theme_css', array( 'css_added_to=? AND ' . \IPS\Db::i()->in( 'css_id', $_SESSION['theme_import']['css'], true ), \IPS\Request::i()->id ) );
}
$set = \IPS\Theme::load( \IPS\Request::i()->id );
\IPS\Theme::deleteCompiledResources( null, null, null, null, $set->id );
\IPS\Theme::deleteCompiledTemplate( null, null, null, $set->id );
@@ -1360,6 +1464,14 @@ class _themes extends \IPS\Node\Controller
\IPS\Data\Store::i()->delete( 'core_theme_import_' . md5_file( \IPS\Request::i()->file ) );
unset( \IPS\Data\Store::i()->themes );
@unlink( \IPS\Request::i()->file );
/* Update theme settings */
foreach( \IPS\Application::applications() as $app )
{
$app->installThemeSettings( true );
}
/* Conflicts to fix? */
if ( \IPS\Db::i()->select( 'count(*)', 'core_theme_conflict', array( 'conflict_set_id=?', \IPS\Request::i()->id ) )->first() )
@@ -1408,7 +1520,7 @@ class _themes extends \IPS\Node\Controller
}
else
{
$conflicts['templates'] = array();
$conflicts['template'] = array();
}
if ( isset( $conflicts['css'] ) AND count( $conflicts['css'] ) )
@@ -1428,9 +1540,19 @@ class _themes extends \IPS\Node\Controller
foreach( $conflicts['template'] as $key => $data )
{
if ( md5( $data['conflict_content'] ) != md5( $templates[ $key ]['template_content'] ) )
if( !\IPS\Login::compareHashes( md5( $data['conflict_content'] ), md5( $templates[ $key ]['template_content'] ) ) )
{
$conflicts['template'][ $key ]['diff'] = \Diff::toTable( \Diff::compare( $templates[ $key ]['template_content'], $data['conflict_content'] ) );
if ( mb_strlen( $data['conflict_content'] ) <= 10000 )
{
$conflicts['template'][ $key ]['diff'] = \Diff::toTable( \Diff::compare( $templates[ $key ]['template_content'], $data['conflict_content'] ) );
$conflicts['template'][ $key ]['large'] = false;
}
else
{
$conflicts['template'][ $key ]['diff'] = \IPS\Theme::i()->getTemplate('customization')->templateConflictLarge( $css[ $key ]['css_content'], $data['conflict_content'], 'html' );
$conflicts['template'][ $key ]['large'] = true;
}
$form->add( new \IPS\Helpers\Form\Radio( 'conflict_' . $data['conflict_id'], 'old', false, array( 'options' => array( 'old' => '', 'new' => '' ) ) ) );
}
else
@@ -1441,9 +1563,19 @@ class _themes extends \IPS\Node\Controller
foreach( $conflicts['css'] as $key => $data )
{
if ( md5( $data['conflict_content'] ) != md5( $css[ $key ]['css_content'] ) )
if( !\IPS\Login::compareHashes( md5( $data['conflict_content'] ), md5( $css[ $key ]['css_content'] ) ) )
{
$conflicts['css'][ $key ]['diff'] = \Diff::toTable( \Diff::compare( $css[ $key ]['css_content'], $data['conflict_content'] ) );
if ( mb_strlen( $data['conflict_content'] ) <= 10000 )
{
$conflicts['css'][ $key ]['diff'] = \Diff::toTable( \Diff::compare( $css[ $key ]['css_content'], $data['conflict_content'] ) );
$conflicts['css'][ $key ]['large'] = false;
}
else
{
$conflicts['css'][ $key ]['diff'] = \IPS\Theme::i()->getTemplate('customization')->templateConflictLarge( $css[ $key ]['css_content'], $data['conflict_content'], 'css' );
$conflicts['css'][ $key ]['large'] = true;
}
$form->add( new \IPS\Helpers\Form\Radio( 'conflict_' . $data['conflict_id'], 'old', false, array( 'options' => array( 'old' => '', 'new' => '' ) ) ) );
}
else
@@ -1538,6 +1670,9 @@ class _themes extends \IPS\Node\Controller
if ( count( $conflicts['css'] ) OR count( $conflicts['template'] ) )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/diff.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/codemirror.js', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'customization/themes.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_templates.js', 'core', 'admin' ) );
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'customization', 'core' ), 'templateConflict' ), $themeSet, $conflicts, $templates, $css );
@@ -1579,7 +1714,7 @@ class _themes extends \IPS\Node\Controller
/* Make sure key is unique */
try
{
$row = \IPS\Db::i()->select( '*', 'core_theme_css', array( "css_set_id=? AND css_app=? AND css_path=? AND css_location=? AND css_name=?", 0, \IPS\Request::i()->theme_css_app, $path, $location, $val ) )->first();
$row = \IPS\Db::i()->select( '*', 'core_theme_css', array( \IPS\Db::i()->in( 'css_set_id', array( 0, \IPS\Request::i()->id ) ) . " AND css_app=? AND css_path=? AND css_location=? AND css_name=?", \IPS\Request::i()->theme_css_app, $path, $location, $val ) )->first();
if ( isset( $row['css_id'] ) )
{
@@ -1649,7 +1784,7 @@ class _themes extends \IPS\Node\Controller
'content' => $values['theme_css_content'] );
$newId = \IPS\Theme::addCss( $save );
\IPS\Theme::i()->load( $id )->compileCss( $save['app'], $save['location'], $save['path'] );
if( \IPS\Request::i()->isAjax() )
@@ -1704,7 +1839,7 @@ class _themes extends \IPS\Node\Controller
move_uploaded_file( $values['core_theme_set_new_import'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) . '&id=' . \IPS\Request::i()->id) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ), 'id' => \IPS\Request::i()->id) ) );
}
/* Display */
@@ -1740,6 +1875,12 @@ class _themes extends \IPS\Node\Controller
if ( \IPS\IN_DEV OR \IPS\Theme::designersModeEnabled() )
{
if ( ! isset( \IPS\Request::i()->rebuildDone ) )
{
$url = \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=devImportBeforeExport&id=' . $id );
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('theme_export_designer_mode_build_message', NULL, array( 'sprintf' => array( $url ) ) ), 'ipsMessage ipsMessage_info', FALSE );
}
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_export_author_name', ( $storedAuthor !== null ) ? $storedAuthor['name'] : false, false ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_export_author_url' , ( $storedAuthor !== null ) ? $storedAuthor['url'] : false, false ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_update_check' , $themeSet->update_check, false ) );
@@ -1794,7 +1935,11 @@ class _themes extends \IPS\Node\Controller
$xml->startAttribute('long_version');
$xml->text( $longVersion );
$xml->endAttribute();
$xml->startAttribute('update_check');
$xml->text( $updateCheck );
$xml->endAttribute();
/* Copy logos */
if( $themeSet->logo_data )
{
@@ -1860,6 +2005,15 @@ class _themes extends \IPS\Node\Controller
{
foreach( $templates[ $appDir->directory ][ $loc ][ $group ] as $name => $data )
{
/* Skip custom bits from other themes */
if ( ( $data['InheritedValue'] != 'inherit' and $data['InheritedValue'] != 'changed' ) and ( $data['template_user_added'] and $data['template_added_to'] != $themeSet->_id ) )
{
if ( $data['template_set_id'] != $themeSet->_id )
{
continue;
}
}
/* Remove original template bits */
if ( $data['InheritedValue'] != 'original' OR $data['template_user_added'] )
{
@@ -2104,7 +2258,7 @@ class _themes extends \IPS\Node\Controller
$name = addslashes( str_replace( array( ' ', '.', ',' ), '_', \IPS\Member::loggedIn()->language()->get('core_theme_set_title_' . $themeSet->_id ) ) . '.xml' );
\IPS\Output::i()->sendOutput( $xml->outputMemory(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', $name ) ) );
\IPS\Output::i()->sendOutput( $xml->outputMemory(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', $name ), FALSE, FALSE ) );
}
/* Display */
@@ -2123,7 +2277,8 @@ class _themes extends \IPS\Node\Controller
try
{
if ( \IPS\Theme::load( \IPS\Request::i()->id )->is_default )
$theme = \IPS\Theme::load( \IPS\Request::i()->id );
if ( $theme->is_default or $theme->is_acp_default )
{
\IPS\Output::i()->error( 'cannot_delete_default_theme', '1C163/3', 403, '' );
}
@@ -2155,10 +2310,10 @@ class _themes extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form();
$form->hiddenValues['id'] = $id;
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_name', NULL, TRUE, array( 'regex' => '/^([A-Z0-9_]+?)$/i' ),
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_name', NULL, TRUE, array( 'regex' => '/^([a-z_][A-Z0-9_]+?)$/i' ),
function( $val )
{
if ( ! preg_match( '/^([A-Z0-9_]+?)$/i', $val ) )
if ( ! preg_match( '/^([a-z_][A-Z0-9_]+?)$/i', $val ) )
{
throw new \InvalidArgumentException( 'form_bad_value' );
}
@@ -2209,7 +2364,7 @@ class _themes extends \IPS\Node\Controller
'new' => array( 'location_new' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_location_new', NULL, FALSE, array( 'regex' => '/^([A-Z]+?)?$/i' ), NULL, NULL, NULL, 'location_new' ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_location_new', NULL, FALSE, array( 'regex' => '/^([A-Z][A-Z0-9]+?)$/i' ), NULL, NULL, NULL, 'location_new' ) );
$form->add( new \IPS\Helpers\Form\Select( 'theme_template_location_existing', NULL, FALSE, array( 'options' => $locations ), NULL, NULL, NULL, 'location_existing' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'theme_template_group_type', 'existing', FALSE, array(
@@ -2219,7 +2374,7 @@ class _themes extends \IPS\Node\Controller
'new' => array( 'group_new' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_group_new', NULL, FALSE, array( 'regex' => '/^([a-z0-9_]+?)?$/' ), NULL, NULL, NULL, 'group_new' ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_group_new', NULL, FALSE, array( 'regex' => '/^([a-z_][a-z0-9_]+?)?$/' ), NULL, NULL, NULL, 'group_new' ) );
$form->add( new \IPS\Helpers\Form\Select( 'theme_template_group_existing', NULL, FALSE, array( 'options' => $groups, 'parse' => 'normal' ), NULL, NULL, NULL, 'group_existing' ) );
$form->add( new \IPS\Helpers\Form\Select( 'theme_template_app', NULL, TRUE, array( 'options' => $apps ) ) );
@@ -2299,6 +2454,9 @@ class _themes extends \IPS\Node\Controller
{
/* Check permission */
\IPS\Dispatcher::i()->checkAcpPermission( 'theme_templates_manage' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$type = \IPS\Request::i()->t_type;
$id = intval( \IPS\Request::i()->id );
@@ -2437,16 +2595,37 @@ class _themes extends \IPS\Node\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=templates&id=' . $save['set_id'] . '&t_type=' . $type . '&' . implode( '&', $url ) ), 'completed' );
}
}
/**
* Rebuild master templates
*
* @return void
*/
public function devImportBeforeExport()
{
$this->devImportMultipleRedirect( "app=core&module=customization&controller=themes&do=exportForm&id=" . \IPS\Request::i()->id . '&rebuildDone=1' );
}
/**
* Rebuild master templates
*
* @return void
*/
public function devImport()
{
$this->devImportMultipleRedirect( 'app=core&module=customization&controller=themes' );
}
/**
* Rebuild master templates
*
* @param string|NULL $finalUrl Final redirect URL
* @return void
*/
public function devImportMultipleRedirect( $finalUrl=NULL )
{
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=devImport&id=' . \IPS\Request::i()->id ),
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=devImportMultipleRedirect&id=' . \IPS\Request::i()->id . '&finalUrl=' . base64_encode( $finalUrl ) ),
function( $data )
{
/* Is this the first cycle? */
@@ -2506,7 +2685,7 @@ class _themes extends \IPS\Node\Controller
function()
{
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes' ), 'completed' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( base64_decode( \IPS\Request::i()->finalUrl ) ), 'completed' );
}
);
}
@@ -2700,17 +2879,7 @@ class _themes extends \IPS\Node\Controller
{
foreach( $templateNames[ $app ][ $location ] as $path => $items )
{
if ( $path === 'custom' )
{
foreach( $items as $name => $data )
{
if ( $name !== 'custom.css' )
{
unset( $templateNames[ $app ][ $location ][ $path ][ $name ] );
}
}
}
else
if ( $path != 'custom' )
{
unset( $templateNames[ $app ][ $location ][ $path ] );
}
@@ -2787,11 +2956,18 @@ class _themes extends \IPS\Node\Controller
$where = \IPS\Db::i()->in( 'member_group_id', $values['member_reset_where'] );
}
\IPS\Db::i()->update( 'core_members', array( 'skin' => \IPS\Request::i()->id ), $where );
if ( $where )
{
\IPS\Db::i()->update( 'core_members', array( 'skin' => \IPS\Request::i()->id ), $where );
}
else
{
\IPS\Member::updateAllMembers( array( 'skin' => \IPS\Request::i()->id ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes' ), 'reset' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes' ), 'member_theme_reset' );
}
\IPS\Output::i()->output = $form;
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief theme Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 17 May 2013
* @version SVN_VERSION_NUMBER
*/
@@ -29,7 +29,9 @@ class _themesettings extends \IPS\Dispatcher\Controller
* @return void
*/
public function execute()
{
{
\IPS\Dispatcher::i()->checkAcpPermission( 'theme_sets_manage' );
parent::execute();
/* Display */
@@ -84,7 +86,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
$_tabs = array_keys( $tabs );
$activeTab = array_shift( $_tabs );
}
/* Create tree */
$self = $this;
$tree = new \IPS\Helpers\Tree\Tree(
@@ -299,7 +301,10 @@ class _themesettings extends \IPS\Dispatcher\Controller
throw new \InvalidArgumentException('core_theme_settings_error_key_not_unique');
}
}
else
{
throw new \InvalidArgumentException('core_theme_settings_error_key_not_unique');
}
}
catch( \UnderflowException $e )
{
@@ -328,13 +333,10 @@ class _themesettings extends \IPS\Dispatcher\Controller
$form->hiddenValues['theme_custom_setting_tab_key_type'] = 'new';
}
$form->add( new \IPS\Helpers\Form\Translatable( 'theme_template_tab_key_new', NULL, FALSE, array(
'app' => 'core',
'key' => ( $current ? "theme_custom_tab_{$current['sc_tab_key']}" : NULL )
),
$form->add( new \IPS\Helpers\Form\Text( 'theme_template_tab_key_new', NULL, FALSE, array( 'regex' => '#[0-9a-z_]+#' ),
function( $val )
{
$val = preg_replace( '#[^0-9a-z_]#', '', mb_strtolower( $val[ \IPS\Lang::defaultLanguage() ] ) );
$val = preg_replace( '#[^0-9a-z_]#', '', mb_strtolower( $val ) );
if ( \IPS\Request::i()->theme_custom_setting_tab_key_type === 'new' )
{
@@ -384,7 +386,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\Stack( 'theme_custom_setting_type_content', ( $id and $current['sc_type'] != 'other' ) ? json_decode( $current['sc_content'], TRUE ) : array(), FALSE, array( 'stackFieldType' => 'KeyValue' ), NULL, NULL, NULL, 'sc_content' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'theme_custom_setting_type_multiple', $id ? $current['sc_multiple'] : FALSE, FALSE, array(), NULL, NULL, NULL, 'sc_multiple' ) );
$form->add( new \IPS\Helpers\Form\Codemirror( 'theme_custom_setting_manual_code', '<?php' . "\n\n" . ( ( $id and $current['sc_type'] == 'other' ) ? $current['sc_content'] : 'return new \IPS\Helpers\Form\Text( "core_theme_setting_title_{$row[\'sc_id\']}", $value, FALSE, array(), NULL, NULL, NULL, \'theme_setting_\' . $row[\'sc_key\'] );' ), NULL, array( 'mode' => 'php' ), function( $val )
$form->add( new \IPS\Helpers\Form\Codemirror( 'theme_custom_setting_manual_code', '<?php' . "\n\n" . ( ( $id and $current['sc_type'] == 'other' ) ? $current['sc_content'] : 'return new \IPS\Helpers\Form\Text( "core_theme_setting_title_{$row[\'sc_id\']}", $value, FALSE, array(), NULL, NULL, NULL, \'theme_setting_\' . $row[\'sc_key\'] );' ), NULL, array( 'mode' => 'php' ), function( $val ) use ( $set )
{
$val = trim( preg_replace( '/^<\?php(.*)$/is', '$1', trim( $val ) ) );
@@ -392,6 +394,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
{
$row = array( 'sc_id' => 0, 'sc_key' => \IPS\Request::i()->theme_custom_setting_key );
$value = NULL;
$theme = $set;
if ( !( eval( $val ) instanceof \IPS\Helpers\Form\FormAbstract ) )
{
throw new \DomainException('theme_custom_setting_manual_code_bad');
@@ -410,6 +413,9 @@ class _themesettings extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'theme_custom_setting_show_in_vse', $id ? $current['sc_show_in_vse'] : FALSE, FALSE, array(), NULL, NULL, NULL, 'sc_show_in_vse' ) );
}
$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' ) );
if ( $values = $form->values() )
{
$save = array(
@@ -423,6 +429,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
'sc_show_in_vse' => ( isset( $values['theme_custom_setting_show_in_vse'] ) ) ? $values['theme_custom_setting_show_in_vse'] : 0,
'sc_content' => ( $values['theme_custom_setting_type'] === 'other' ) ? trim( preg_replace( '/^<\?php(.*)$/is', '$1', trim( $values['theme_custom_setting_manual_code'] ) ) ) : json_encode( $values['theme_custom_setting_type_content'] ),
'sc_title' => $values['theme_custom_setting_title'],
'sc_condition' => $values['theme_custom_setting_conditional'] ? trim( preg_replace( '/^<\?php(.*)$/is', '$1', trim( $values['theme_custom_setting_condition'] ) ) ) : NULL
);
$type = ( isset( \IPS\Request::i()->theme_custom_setting_tab_key_type ) ) ? \IPS\Request::i()->theme_custom_setting_tab_key_type : $values['theme_custom_setting_tab_key_type'];
@@ -433,7 +440,7 @@ class _themesettings extends \IPS\Dispatcher\Controller
}
else
{
$save['sc_tab_key'] = preg_replace( '#[^0-9a-z]#', '', mb_strtolower( $values['theme_template_tab_key_new'][ \IPS\Lang::defaultLanguage() ] ) );
$save['sc_tab_key'] = mb_strtolower( $values['theme_template_tab_key_new'] );
}
if ( $current )
@@ -501,6 +508,9 @@ class _themesettings extends \IPS\Dispatcher\Controller
$setId = intval( \IPS\Request::i()->set_id );
\IPS\Dispatcher::i()->checkAcpPermission( 'theme_settings_remove' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
@@ -0,0 +1,54 @@
<?php
/**
* @brief rss
* @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 13 Oct 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\discovery;
/* 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;
}
/**
* rss
*/
class _rss extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\core\Rss';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'rss_export_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
public function manage()
{
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'forms', 'core' )->blurb( \IPS\Member::loggedIn()->language()->addToStack( 'rss_feed_blurb' ) );
parent::manage();
}
}
@@ -2,9 +2,9 @@
/**
* @brief Search settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 14 Apr 2014
* @version SVN_VERSION_NUMBER
*/
@@ -80,6 +80,10 @@ class _search extends \IPS\Dispatcher\Controller
*/
protected function queueIndexRebuild()
{
/* Clear MySQL minimum word length cached value */
unset( \IPS\Data\Store::i()->mysqlMinWord );
unset( \IPS\Data\Store::i()->mysqlMaxWord );
\IPS\Content\Search\Index::i()->rebuild();
\IPS\Session::i()->log( 'acplogs__queued_search_index' );
@@ -2,9 +2,9 @@
/**
* @brief streams
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 01 Jul 2015
* @version SVN_VERSION_NUMBER
*/
@@ -72,11 +72,35 @@ class _streams extends \IPS\Node\Controller
{
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/core/data/schema.json" ), TRUE );
/* Get the default language strings */
if( file_exists( \IPS\ROOT_PATH . "/applications/core/data/lang.xml" ) )
{
/* Open XML file */
$dom = new \IPS\Xml\DOMDocument( '1.0', 'UTF-8' );
$dom->load( \IPS\ROOT_PATH . "/applications/core/data/lang.xml" );
$xp = new \DomXPath( $dom );
$results = $xp->query('//language/app/word[contains(@key, "stream_title_")]');
$defaultLanguages = array();
foreach( $results as $lang )
{
$defaultLanguages[ str_replace( 'stream_title_', '', $lang->getAttribute('key') ) ] = $lang->nodeValue;
}
}
foreach ( $schema['core_streams']['inserts'] as $insertData )
{
try
{
\IPS\Db::i()->replace( 'core_streams', $insertData );
$newId = \IPS\Db::i()->replace( 'core_streams', $insertData, TRUE );
$oldId = $insertData['id'];
if ( $oldId and $newId )
{
\IPS\Lang::saveCustom( 'core', "stream_title_{$newId}", $defaultLanguages[ $oldId ] );
}
}
catch( \IPS\Db\Exception $e )
{}
@@ -128,7 +152,8 @@ class _streams extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'all_activity_extra_stream', $currentValuesStream, FALSE, array( 'options' => $options ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'activity_stream_rss', \IPS\Settings::i()->activity_stream_rss ) );
if ( $values = $form->values() )
{
$toSave = array();
@@ -136,6 +161,9 @@ class _streams extends \IPS\Node\Controller
{
$toSave[ "all_activity_{$k}" ] = intval( in_array( $k, $values['all_activity_extra_stream'] ) );
}
$toSave[ 'activity_stream_rss' ] = $values['activity_stream_rss'];
$form->saveAsSettings( $toSave );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=discovery&controller=streams' ), 'saved' );
}
@@ -2,9 +2,9 @@
/**
* @brief Emoticons
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 02 May 2013
* @version SVN_VERSION_NUMBER
*/
@@ -132,14 +132,14 @@ class _emoticons extends \IPS\Dispatcher\Controller
{
$filename_2x = preg_replace( "/^(.+?)\.[0-9a-f]{32}(?:\..+?)$/i", "$1", str_replace( '@2x', '', $file->filename ) );
$images2x[ $filename_2x ] = (string) $file;
$images2x[ $this->_getRawFilename( $filename_2x ) ] = (string) $file;
continue;
}
$filename = preg_replace( "/^(.+?)\.[0-9a-f]{32}(?:\..+?)$/i", "$1", $file->filename );
$inserts[] = array(
'typed' => ':' . mb_substr( $filename, 0, mb_strrpos( $filename, '.' ) ) . ':',
'typed' => ':' . preg_replace( "#\s#", "", $this->_getRawFilename( $filename ) ) . ':',
'image' => (string) $file,
'clickable' => TRUE,
'emo_set' => $setId,
@@ -158,21 +158,24 @@ class _emoticons extends \IPS\Dispatcher\Controller
foreach( \IPS\Db::i()->select( '*', 'core_emoticons', array( 'emo_set=?', $setId ) ) as $emo )
{
$file = \IPS\File::get( 'core_Emoticons', $emo['image'] );
$imageDimensions = $file->getImageDimensions();
$filename = $this->_getRawFilename( $file->filename );
/* There isn't an original for the 2x emo */
if( !isset( $images2x[ $file->filename ] ) )
if( !isset( $images2x[ $filename ] ) )
{
continue;
}
/* Get the dimensions of the smaller emoticon */
$imageDimensions = $file->getImageDimensions();
\IPS\Db::i()->update( 'core_emoticons', array(
'image_2x' => $images2x[ $file->filename ],
'image_2x' => $images2x[ $filename ],
'width' => $imageDimensions[0],
'height' => $imageDimensions[1]
), 'id=' . $emo['id']);
), 'id=' . $emo['id'] );
unset( $images2x[ $file->filename ] );
unset( $images2x[ $filename ] );
}
/* Delete any unused 2x files */
@@ -203,7 +206,7 @@ class _emoticons extends \IPS\Dispatcher\Controller
protected function edit()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_edit' );
$position = 0;
$set = NULL;
@@ -242,15 +245,9 @@ class _emoticons extends \IPS\Dispatcher\Controller
}
$emoticons = $this->_getEmoticons( FALSE );
foreach ( \IPS\Request::i()->emo as $id => $data )
{
if ( isset( $data['__set__'] ) )
{
$set = mb_substr( $data['__set__'], \strlen( 'core_emoticon_group_' ) );
continue;
}
if ( isset( $emoticons[ $id ] ) )
{
if ( !$data['name'] )
@@ -260,30 +257,30 @@ class _emoticons extends \IPS\Dispatcher\Controller
if ( !isset( $data['order'] ) )
{
if ( !isset( $orders[ $set ] ) )
if ( !isset( $orders[ $data['set'] ] ) )
{
$orders[ $set ] = 0;
$orders[ $data['set'] ] = 0;
}
$data['order'] = ++$orders[ $set ];
$data['order'] = ++$orders[ $data['set'] ];
}
if ( $emoticons[ $id ]['typed'] !== $data['name'] or $data['order'] != $emoticons[ $id ]['emo_position'] )
{
$save = array( 'typed' => $data['name'] );
$save = array( 'typed' => preg_replace( "#\s#", "", $data['name'] ) );
if ( isset( $data['order'] ) )
{
$save['emo_position'] = $data['order'];
}
if ( $set !== NULL )
{
$save['emo_set'] = $set;
$save['emo_set'] = str_replace( 'core_emoticon_group_', '', $data['set'] );
}
\IPS\Db::i()->update( 'core_emoticons', $save, array( 'id=?', $id ) );
}
}
}
unset( \IPS\Data\Store::i()->emoticons );
/* Clear guest page caches */
@@ -302,7 +299,10 @@ class _emoticons extends \IPS\Dispatcher\Controller
protected function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$emoticon = \IPS\Db::i()->select( '*', 'core_emoticons', array( 'id=?', \IPS\Request::i()->id ) )->first();
@@ -342,6 +342,9 @@ class _emoticons extends \IPS\Dispatcher\Controller
public function deleteSet()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$set = preg_replace( '/^core_emoticon_group_/', '', \IPS\Request::i()->key );
@@ -417,4 +420,19 @@ class _emoticons extends \IPS\Dispatcher\Controller
return $emoticons;
}
/**
* Returns the filename and extension for given emoticon path
*
* @param string $path Emoticon path
* @return array
*/
protected function _getRawFilename( $path )
{
$parts = explode( '/', $path );
$filenamePart = array_pop( $parts );
$filename = mb_substr( $filenamePart, 0, mb_strrpos( $filenamePart, '.' ) );
return $filename;
}
}
@@ -2,9 +2,9 @@
/**
* @brief settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Aug 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Editor Toolbars
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 30 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -23,6 +23,55 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _toolbar extends \IPS\Dispatcher\Controller
{
protected static $defaultPlugins = array(
'basicstyles',
'button',
'clipboard',
'colorbutton',
'dialog',
'dialogui',
'divarea',
'elementspath',
'enterkey',
'entities',
'floatingspace',
'floatpanel',
'font',
'htmlwriter',
'indent',
'indentblock',
'indentlist',
'index.html',
'ipsautogrow',
'ipsautolink',
'ipsautosave',
'ipscode',
'ipscontextmenu',
'ipsemoticon',
'ipsimage',
'ipslink',
'ipsmentions',
'ipspage',
'ipspaste',
'ipspreview',
'ipsquote',
'ipssource',
'ipsspoiler',
'justify',
'lineutils',
'list',
'listblock',
'menu',
'panel',
'panelbutton',
'removeformat',
'richcombo',
'sourcearea',
'toolbar',
'undo',
'widget',
);
/**
* Execute
*
@@ -134,9 +183,16 @@ class _toolbar extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form;
/* Custom Plugin */
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV )
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV and !\IPS\NO_WRITES )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/plugin.js" );
$option = file_exists( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
if ( $option )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
}
$type = 'inline';
if ( mb_strpos( $code, 'ips.utils.defaultEditorPlugins.singleblock' ) !== FALSE )
{
@@ -146,14 +202,11 @@ class _toolbar extends \IPS\Dispatcher\Controller
{
$type = 'block';
}
$option = file_exists( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
if ( $option )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
}
if ( $type == 'block' or $type == 'singleblock' )
{
preg_match( "/ips.utils.defaultEditorPlugins.{$type}\( '{$matches[0]}', '(.+?)', ([{\[].*[}\]]), (\".*\"), (true|false), (\".*\") \)/", $code, $matches2 );
preg_match( "/ips.utils.defaultEditorPlugins.{$type}\( '{$matches[0]}', '(.+?)', ([{\[].*[}\]]), (\".*\"), (true|false), (\".*\")/", $code, $matches2 );
$attributes = array();
foreach ( json_decode( $matches2[2] ) as $k => $v )
{
@@ -188,13 +241,13 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* If this is a custom one, add a delete button */
if ( in_array( mb_strtolower( $button ), explode( ',', mb_strtolower( \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) or preg_match( '/^custom-\w{32}$/i', $button ) )
{
$form->addButton( 'delete', 'link', (string) \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar&do=deletePlugin&key={$button}" ), 'ipsButton_alternate' );
$form->addButton( 'delete', 'link', (string) \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar&do=deletePlugin&key={$button}" ), 'ipsButton ipsButton_negative' );
}
/* Handle Saves */
if ( $values = $form->values() )
{
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV )
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV and !\IPS\NO_WRITES )
{
$this->_saveCustomPlugin( $matches[0], $values );
}
@@ -208,6 +261,9 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=editor&controller=toolbar') );
}
@@ -265,6 +321,9 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
}
@@ -287,7 +346,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
$plugins = array();
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins' ) as $f )
{
if ( !$f->isDot() and $f->isDir() and $f !== 'index.html' and !in_array( (string) $f, array_merge( array( 'autogrow', 'basicstyles', 'button', 'clipboard', 'colorbutton', 'dialog', 'dialogui', 'enterkey', 'entities', 'fakeobjects', 'floatingspace', 'floatpanel', 'font', 'indent', 'indentblock', 'indentlist', 'index.html', 'ipsattach', 'ipsautolink', 'ipsemoticon', 'ipsimage', 'ipslink', 'ipsmentions', 'ipspage', 'ipsprefs', 'ipsquote', 'ipsspoiler', 'justify', 'link', 'list', 'listblock', 'magicline', 'panel', 'panelbutton', 'pastetext', 'pbckcode', 'removeformat', 'richcombo', 'sourcearea', 'toolbar', 'undo', 'wysiwygarea' ), explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
if ( !$f->isDot() and $f->isDir() and $f !== 'index.html' and !in_array( (string) $f, array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
{
$plugins[ (string) $f ] = (string) $f;
}
@@ -309,9 +368,12 @@ class _toolbar extends \IPS\Dispatcher\Controller
break;
}
$tmpName = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
move_uploaded_file( $values['editor_plugin_zip'], $tmpName );
/* Get the plugin name */
$inRoot = TRUE;
$zip = zip_open( $values['editor_plugin_zip'] );
$zip = zip_open( $tmpName );
while( $resource = zip_read( $zip ) )
{
$name = mb_substr( zip_entry_name( $resource ), 0, -1 );
@@ -335,14 +397,21 @@ class _toolbar extends \IPS\Dispatcher\Controller
$extractTo .= '/' . $name;
}
/* Check it isn't already installed */
if ( in_array( $name, array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('editor_plugin_already_installed');
goto displayForm;
}
/* Extract it */
$zip = new \ZipArchive;
$zip->open( $values['editor_plugin_zip'] );
$zip->open( $tmpName );
$zip->extractTo( $extractTo );
$zip->close();
/* Delete the temp file */
unlink( $values['editor_plugin_zip'] );
unlink( $tmpName );
}
else
{
@@ -361,19 +430,32 @@ class _toolbar extends \IPS\Dispatcher\Controller
}
$file = \file_get_contents( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $name . '/plugin.js' );
preg_match( "#requires: \'(.+?)\',#i", $file, $matches );
if ( isset( $matches[1] ) )
{
$required = explode( ',', $matches[1] );
$current = array_merge( array( 'basicstyles', 'button', 'panelbutton', 'panel', 'floatpanel', 'colorbutton', 'dialogui', 'enterkey', 'entities', 'fakeobjects', 'floatingspace', 'listblock', 'richcombo', 'font', 'indent', 'indentblock', 'indentlist', 'justify', 'list', 'magicline', 'dialog', 'clipboard', 'pastetext', 'pbckcode', 'removeformat', 'sourcearea', 'toolbar', 'undo', 'wysiwygarea', 'ipsattach', 'ipsautolink', 'ipsemoticon', 'ipsimage', 'ipslink', 'ipsmentions', 'ipsquote', 'ipsspoiler', 'ipsprefs' ), explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) );
$rewriteFileWithIpsContextMenuRequirement = FALSE;
if ( in_array( 'contextmenu', $required ) )
{
$required[ array_search( 'contextmenu', $required ) ] = 'ipscontextmenu';
$rewriteFileWithIpsContextMenuRequirement = TRUE;
}
$current = array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) );
$missing = array_diff( $required, $current );
if ( count( $missing ) > 0 )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'editor_missing_requirements', FALSE, array( 'sprintf' => array( count( $missing ), implode( ', ', $missing ) ) ) ), '2C120/5', 404, '' );
}
if ( $rewriteFileWithIpsContextMenuRequirement )
{
$file = preg_replace_callback( "#requires: \'(.+?)\',#i", function( $matches )
{
return str_replace( 'contextmenu', 'ipscontextmenu', $matches[0] );
}, $file );
\file_put_contents( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $name . '/plugin.js', $file );
}
}
/* Save */
@@ -385,13 +467,17 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
}
}
/* If this is an AJAX request, just return it */
displayForm:
if( \IPS\Request::i()->isAjax() )
{
if ( \IPS\Request::i()->existing )
@@ -591,7 +677,7 @@ contents: [
}
],
onOk: function() {
var cmd = ips.utils.defaultEditorPlugins.inline( '{$key}', {$html}.replace( '{option}', this.getValueOf( 'tab', 'option' ) ) );
var cmd = ips.utils.defaultEditorPlugins.inline( '{$key}', {$html}.replace( /\{option\}/g, this.getValueOf( 'tab', 'option' ) ) );
cmd.exec( editor );
}
};
@@ -669,6 +755,9 @@ JS;
{
\IPS\Output::i()->error( 'no_writes', '1C120/3', 403, '' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Check it's not required for something else */
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins' ) as $file )
@@ -687,7 +776,7 @@ JS;
}
/* Delete it */
$key = \IPS\Request::i()->key;
$key = mb_strtolower( \IPS\Request::i()->key );
$dir = \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $key;
if ( is_dir( $dir ) )
{
@@ -695,7 +784,7 @@ JS;
}
/* Remove from plugin list */
$extraPlugins = explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins );
$extraPlugins = explode( ',', mb_strtolower( \IPS\Settings::i()->ckeditor_extraPlugins ) );
foreach ( $extraPlugins as $k => $v )
{
if ( $v == $key )
@@ -708,6 +797,9 @@ JS;
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
@@ -767,7 +859,11 @@ JS;
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar" ), 'saved' );
}
@@ -2,9 +2,9 @@
/**
* @brief languages
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 25 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -35,7 +35,7 @@ class _languages extends \IPS\Node\Controller
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'lang_packs' );
\IPS\Dispatcher::i()->checkAcpPermission( 'lang_words' );
parent::execute();
}
@@ -96,7 +96,7 @@ class _languages extends \IPS\Node\Controller
/* reset default language if we want this to be default */
if( isset( $values['lang_default'] ) and $values['lang_default'] )
{
\IPS\DB::i()->update( 'core_sys_lang', array( 'lang_default' => 0 ) );
\IPS\Db::i()->update( 'core_sys_lang', array( 'lang_default' => 0 ) );
}
/* Add "UTF8" if we can */
@@ -511,7 +511,7 @@ class _languages extends \IPS\Node\Controller
{
if ( !is_array( $data ) )
{
$lang = \IPS\DB::i()->select( '*', 'core_sys_lang', array( 'lang_id=?', \IPS\Request::i()->id ) )->first();
$lang = \IPS\Db::i()->select( '*', 'core_sys_lang', array( 'lang_id=?', \IPS\Request::i()->id ) )->first();
unset( $lang['lang_id'] );
$lang['lang_title'] = $lang['lang_title'] . ' ' . \IPS\Member::loggedIn()->language()->get('copy_noun');
@@ -550,6 +550,7 @@ class _languages extends \IPS\Node\Controller
function()
{
unset( \IPS\Data\Store::i()->languages );
unset( \IPS\Data\Store::i()->listFormats );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -575,8 +576,15 @@ class _languages extends \IPS\Node\Controller
{
\IPS\Output::i()->error( 'node_error', '2C126/5', 404, '' );
}
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_sys_lang_words', array( 'lang_id=? AND word_export=1 AND word_custom IS NOT NULL', $lang->id ), 'word_id' )->first() < 1 )
$count = 0;
try
{
$count = \IPS\Db::i()->select( 'COUNT(word_id)', 'core_sys_lang_words', array( 'lang_id=? AND word_export=1 AND word_custom IS NOT NULL', $lang->id ), 'word_id', NULL, 'word_id' )->first();
}
catch ( \UnderflowException $e ) {}
if ( $count < 1 )
{
\IPS\Output::i()->error( 'core_lang_download_empty', '1C126/7', 404, '' );
}
@@ -671,7 +679,7 @@ class _languages extends \IPS\Node\Controller
move_uploaded_file( $values['lang_upload'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages&do=import&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) . '&into=' . \IPS\Request::i()->id ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ), 'into' => \IPS\Request::i()->id ) ) );
}
\IPS\Output::i()->output = $form;
@@ -700,7 +708,7 @@ class _languages extends \IPS\Node\Controller
function( $data )
{
/* Open XML file */
$xml = new \XMLReader;
$xml = new \IPS\Xml\XMLReader;
$xml->open( \IPS\Request::i()->file );
$xml->read();
@@ -748,9 +756,9 @@ class _languages extends \IPS\Node\Controller
/* Copy over default language strings */
$default = \IPS\Lang::defaultLanguage();
$prefix = \IPS\Db::i()->prefix;
$defaultStmt = \IPS\Db::i()->prepare( "INSERT INTO `{$prefix}core_sys_lang_words` ( `lang_id`, `word_app`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` ) SELECT {$insertId} AS `lang_id`, `word_app`, `word_key`, `word_default`, NULL AS `word_custom`, `word_default_version`, NULL AS `word_custom_version`, `word_js`, `word_export` FROM `{$prefix}core_sys_lang_words` WHERE `lang_id`={$default} AND `word_export`=1" );
$defaultStmt = \IPS\Db::i()->prepare( "INSERT INTO `{$prefix}core_sys_lang_words` ( `lang_id`, `word_app`, `word_plugin`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` ) SELECT {$insertId} AS `lang_id`, `word_app`, `word_plugin`, `word_key`, `word_default`, NULL AS `word_custom`, `word_default_version`, NULL AS `word_custom_version`, `word_js`, `word_export` FROM `{$prefix}core_sys_lang_words` WHERE `lang_id`={$default} AND `word_export`=1" );
$defaultStmt->execute();
$customStmt = \IPS\Db::i()->prepare( "INSERT INTO `{$prefix}core_sys_lang_words` ( `lang_id`, `word_app`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` ) SELECT {$insertId} AS `lang_id`, `word_app`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` FROM `{$prefix}core_sys_lang_words` WHERE `lang_id`={$default} AND `word_export`=0" );
$customStmt = \IPS\Db::i()->prepare( "INSERT INTO `{$prefix}core_sys_lang_words` ( `lang_id`, `word_app`, `word_plugin`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` ) SELECT {$insertId} AS `lang_id`, `word_app`, `word_plugin`, `word_key`, `word_default`, `word_custom`, `word_default_version`, `word_custom_version`, `word_js`, `word_export` FROM `{$prefix}core_sys_lang_words` WHERE `lang_id`={$default} AND `word_export`=0" );
$customStmt->execute();
}
@@ -810,6 +818,8 @@ class _languages extends \IPS\Node\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages' ) );
}
);
@@ -922,7 +932,14 @@ class _languages extends \IPS\Node\Controller
$where = \IPS\Db::i()->in( 'member_group_id', $values['member_reset_where'] );
}
\IPS\Db::i()->update( 'core_members', array( 'language' => \IPS\Request::i()->id ), $where );
if ( $where )
{
\IPS\Db::i()->update( 'core_members', array( 'language' => \IPS\Request::i()->id ), $where );
}
else
{
\IPS\Member::updateAllMembers( array( 'language' => \IPS\Request::i()->id ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages' ), 'reset' );
}
@@ -2,9 +2,9 @@
/**
* @brief Groups
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 25 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -50,6 +50,7 @@ class _groups extends \IPS\Dispatcher\Controller
$table = new \IPS\Helpers\Table\Db( 'core_groups', \IPS\Http\Url::internal( 'app=core&module=members&controller=groups' ) );
$table->include = array( 'word_custom', 'members' );
$table->noSort = array( 'members' );
$table->langPrefix = 'acpgroups_';
$table->joins = array(
@@ -68,9 +69,8 @@ class _groups extends \IPS\Dispatcher\Controller
$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();
return \IPS\Member::loggedIn()->language()->addToStack( 'online_guests', FALSE, array( 'pluralize' => array( $onlineGuests ) ) );
}
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'member_group_id=? OR FIND_IN_SET( ?, mgroup_others )', $row['g_id'], $row['g_id'] ) )->first();
return "<!--{$count}--><a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&advanced_search_submitted=1&csrfKey=' . \IPS\Session::i()->csrfKey . '&members_member_group_id=' . $row['g_id'] ) . "'>{$count}</a>";
return \IPS\Theme::i()->getTemplate( 'members' )->memberCounts( $row );
}
);
@@ -123,6 +123,15 @@ class _groups extends \IPS\Dispatcher\Controller
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_export' ) )
{
$return['download'] = array(
'icon' => 'cloud-download',
'title' => 'members_export',
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=export&_new=1&group=' ) . $row['g_id'],
);
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'groups_delete' ) AND !in_array( $row['g_id'], array( \IPS\Settings::i()->guest_group, \IPS\Settings::i()->member_group, \IPS\Settings::i()->admin_group ) ) )
{
$return['delete'] = array(
@@ -140,6 +149,17 @@ class _groups extends \IPS\Dispatcher\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('groups');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'groups', (string) $table );
}
/**
* Fetch the number of members in this group
*
* @note Fetched via AJAX after the page is loaded as this can be intensive with lots of groups and lots of members
* @return void
*/
public function getCount()
{
\IPS\Output::i()->sendOutput( \IPS\Member\Group::load( \IPS\Request::i()->group )->getCount(), 200, 'text/html' );
}
/**
* Add/Edit Group
@@ -239,7 +259,7 @@ class _groups extends \IPS\Dispatcher\Controller
/* Start a new section */
$form->addTab( '__app_' . $class::$permApp );
$matrix = new \IPS\Helpers\Form\Matrix;
$matrix = new \IPS\Helpers\Form\Matrix( $class );
$matrix->classes = array( 'cGroupPermissions' );
$matrix->showTooltips = TRUE;
@@ -268,7 +288,7 @@ class _groups extends \IPS\Dispatcher\Controller
foreach( $current[ $class::$permApp ][ $class::$permType ] AS $x => $y )
{
$matrix->checkAlls[ $class::$permissionLangPrefix . 'perm__' . $k ] = TRUE;
if ( mb_stripos( $y["perm_{$v}"], $group->g_id ) === FALSE AND $y["perm_{$v}"] !== '*' )
if ( $y["perm_{$v}"] !== '*' AND !in_array( $group->g_id, explode( ',', $y["perm_{$v}"] ) ) )
{
$matrix->checkAlls[ $class::$permissionLangPrefix . 'perm__' . $k ] = FALSE;
break;
@@ -304,6 +324,8 @@ class _groups extends \IPS\Dispatcher\Controller
$class::load( $permTypeId )->changePermissions( $group, $perms );
}
}
/* Log */
\IPS\Session::i()->log( 'permissions_adjusted_node', array( "core_group_". $group->g_id => TRUE ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=groups' ), 'saved' );
@@ -351,6 +373,9 @@ 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
@@ -362,6 +387,7 @@ class _groups extends \IPS\Dispatcher\Controller
{
$form = new \IPS\Helpers\Form( 'form', 'delete' );
$form->add( new \IPS\Helpers\Form\Select( 'delete_group_move_to', NULL, TRUE, array( 'options' => \IPS\Member\Group::groups( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_move_admin2' ), FALSE ), 'parse' => 'normal' ) ) );
$form->hiddenValues['wasConfirmed'] = 1;
if ( $values = $form->values() )
{
\IPS\Db::i()->update( 'core_members', array( 'member_group_id' => $values['delete_group_move_to'] ), array( 'member_group_id=?', $group->g_id ) );
+37 -15
View File
@@ -2,9 +2,9 @@
/**
* @brief IP Address Tools
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 19 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -66,24 +66,38 @@ class _ip extends \IPS\Dispatcher\Controller
$exploded = explode( '_', \IPS\Request::i()->area );
$extensions = \IPS\Application::load( $exploded[0] )->extensions( 'core', 'IpAddresses' );
$class = $extensions[ mb_substr( \IPS\Request::i()->area, mb_strlen( $exploded[0] ) + 1 ) ];
\IPS\Output::i()->output = $class->findByIp( $ip, $url->setQueryString( 'area', \IPS\Request::i()->area ) );
\IPS\Output::i()->output = $class->findByIp( str_replace( '*', '%', $ip ), $url->setQueryString( 'area', \IPS\Request::i()->area ) );
}
else
{
$geolocation = NULL;
$map = NULL;
try
$geolocation = NULL;
$map = NULL;
$hostName = $ip;
if( filter_var( $ip, FILTER_VALIDATE_IP ) !== false )
{
$geolocation = \IPS\GeoLocation::getByIp( $ip );
$map = $geolocation->map()->render( 400, 350, 0.6 );
try
{
$geolocation = \IPS\GeoLocation::getByIp( $ip );
$map = $geolocation->map()->render( 400, 350, 0.6 );
}
catch ( \Exception $e ) {}
$hostName = @gethostbyaddr( $ip );
}
catch ( \Exception $e ) {}
$contentCounts = array();
$otherCounts = array();
foreach ( \IPS\Application::allExtensions( 'core', 'IpAddresses' ) as $k => $ext )
{
$count = $ext->findByIp( $ip );
{
/* If the method does not exist, we presume it is supported - this is for legacy purposes as the method is new so
third parties won't have it present */
if( method_exists( $ext, 'supportedInAcp' ) AND !$ext->supportedInAcp() )
{
continue;
}
$count = $ext->findByIp( str_replace( '*', '%', $ip ) );
if ( $count !== NULL )
{
if ( isset( $ext->class ) )
@@ -101,7 +115,7 @@ class _ip extends \IPS\Dispatcher\Controller
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' )->ipLookup( $url, $geolocation, $map, array_merge( $otherCounts, $contentCounts ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' )->ipLookup( $url, $geolocation, $map, $hostName, array_merge( $otherCounts, $contentCounts ) );
}
}
else
@@ -109,9 +123,9 @@ class _ip extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form( 'form', 'continue' );
$form->add( new \IPS\Helpers\Form\Text( 'ip_address', NULL, TRUE, array(), function( $val )
{
if( filter_var( $val, FILTER_VALIDATE_IP ) === false )
if( trim( $val, '*' ) == '' )
{
throw new \DomainException('ip_address_bad');
throw new \DomainException('not_just_asterisk');
}
} ) );
@@ -119,9 +133,17 @@ class _ip extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=ip' )->setQueryString( 'ip', $values['ip_address'] ) );
}
$members = new \IPS\Helpers\Form( 'members', 'continue' );
$members->add( new \IPS\Helpers\Form\Member( 'ip_username', NULL, TRUE ) );
if ( $values = $members->values() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=ip' )->setQueryString( 'id', $values['ip_username']->member_id ) );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_members_ip');
\IPS\Output::i()->output = $form;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->ipform( $form, $members );
}
}
}
File diff suppressed because it is too large. Load diff
@@ -2,9 +2,9 @@
/**
* @brief Recount and Reset Tools
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 24 Oct 2013
* @version SVN_VERSION_NUMBER
*/
@@ -33,96 +33,26 @@ class _reset extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'member_recount_content' );
return parent::execute();
}
/**
* Redirector to rebuild things
*
* Queue the content recount task
*
* @return void
*/
public function __call( $method, $args )
public function posts()
{
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=core&module=members&controller=reset&do=redirector&member_recount_each_content_check=' . intval( $method == 'posts' ) . '&member_recount_each_reputation_check=' . intval( $method == 'rep' ) ),
function( $data )
{
/* Is this the first cycle? */
if ( ! is_array( $data ) )
{
/* Start importing */
$data = array(
'member_recount_each_content_check' => \IPS\Request::i()->member_recount_each_content_check,
'member_recount_each_reputation_check' => \IPS\Request::i()->member_recount_each_reputation_check,
'lastId' => 0,
'processing' => true,
'total' => \IPS\Db::i()->select( 'COUNT(*)', 'core_members' )->first(),
'done' => 0
);
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('processing') );
}
/* Grab something to build */
if ( $data['processing'] )
{
try
{
$member_id = \IPS\Db::i()->select( 'member_id', 'core_members', array( 'member_id > ?', intval( $data['lastId'] ) ), 'member_id ASC', array( 0, 1 ) )->first();
if ( ! empty( $member_id ) )
{
$member = \IPS\Member::load( $member_id );
if ( $data['member_recount_each_content_check'] )
{
$member->recountContent();
}
if ( $data['member_recount_each_reputation_check'] )
{
$member->recountReputation();
}
$data['lastId'] = $member_id;
$data['done']++;
}
else
{
$data['lastId'] = 0;
$data['processing'] = false;
}
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('processing'), 100 / $data['total'] * $data['done'] );
}
catch( \UnderflowException $ex )
{
return null;
}
}
else
{
/* All Done.. */
return null;
}
},
function()
{
/* Finished */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), 'completed' );
}
);
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('member_reset_recount_title');
/* Output */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Output::i()->output ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
else
{
\IPS\Output::i()->buildMetaTags();
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
return;
\IPS\Task::queue( 'core', 'RecountMemberContent', array(), 4 );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), \IPS\Member::loggedIn()->language()->addToStack( 'member_recount_content_process' ) );
}
/**
* Queue the reputation recount task
*
* @return void
*/
public function rep()
{
\IPS\Task::queue( 'core', 'RecountMemberReputation', array(), 4 );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), \IPS\Member::loggedIn()->language()->addToStack( 'member_recount_rep_process' ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief ban
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 12 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -183,6 +183,9 @@ class _ban extends \IPS\Dispatcher\Controller
*/
public function delete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$current = \IPS\Db::i()->select( '*', 'core_banfilters', array( 'ban_id=?', \IPS\Request::i()->id ) )->first();
@@ -2,9 +2,9 @@
/**
* @brief Notification Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 23 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -150,12 +150,16 @@ class _notifications extends \IPS\Dispatcher\Controller
protected function settings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profiles_manage' );
$form = new \IPS\Helpers\Form;
$form->addHeader('auto_follow_preferences');
$form->addMessage( 'auto_follow_update_all' );
$form->add( new \IPS\Helpers\Form\YesNo( 'auto_follow_new_content', \IPS\Settings::i()->auto_follow_new_content, FALSE, array(), NULL, NULL, NULL, 'auto_follow_new_content' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'auto_follow_replied_to', \IPS\Settings::i()->auto_follow_replied_to, FALSE, array(), NULL, NULL, NULL, 'auto_follow_replied_to' ) );
$form->addHeader('notification_pruning');
$form->add( new \IPS\Helpers\Form\Number( 'subs_autoprune', \IPS\Settings::i()->subs_autoprune, FALSE, array(), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days') ) );
$form->add( new \IPS\Helpers\Form\Number( 'prune_notifications', \IPS\Settings::i()->prune_notifications, FALSE, array(), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('months') ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
@@ -167,4 +171,22 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('notificationsettings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'notificationsettings', $form, FALSE );
}
/**
* Member Auto Follow Preferences
*
* @return void
*/
protected function updateMemberFollowPrefs()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'profiles_manage' );
$autoTrack = json_encode( array(
'content' => \IPS\Settings::i()->auto_follow_new_content ? 1 : 0,
'comments' => \IPS\Settings::i()->auto_follow_replied_to ? 1 : 0,
'method' => 'immediate'
) );
\IPS\Db::i()->update( 'core_members', array( 'auto_track' => $autoTrack ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=notifications' ), 'saved' );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Profile Fields and Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 09 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -72,17 +72,43 @@ class _profiles extends \IPS\Node\Controller
$form->addHeader( 'photos' );
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_gravatars', \IPS\Settings::i()->allow_gravatars ) );
$form->addHeader( 'usernames' );
$form->add( new \IPS\Helpers\Form\Number( 'max_user_name_length', \IPS\Settings::i()->max_user_name_length, FALSE, array(), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('characters') ) );
$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 ( $values = $form->values() )
{
$form->saveAsSettings();
$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'] );
$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' );
}
@@ -2,9 +2,9 @@
/**
* @brief ranks
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 10 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -220,6 +220,9 @@ class _ranks extends \IPS\Dispatcher\Controller
public function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'ranks_manage' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
@@ -2,9 +2,9 @@
/**
* @brief Registration
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Jul 2013
* @version SVN_VERSION_NUMBER
*/
@@ -52,7 +52,8 @@ class _registration extends \IPS\Dispatcher\Controller
), 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->addHeader('coppa');
$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' ) ) );
$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' ) );
@@ -2,9 +2,9 @@
/**
* @brief Reputation
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 27 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -52,6 +52,7 @@ class _reputation extends \IPS\Dispatcher\Controller
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'reps_settings' ) )
{
$tabs['settings'] = 'reputation_settings';
$tabs['leaderboard'] = 'reputation_leaderboard';
}
/* Levels */
@@ -138,7 +139,7 @@ class _reputation extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'reputation_can_self_vote', \IPS\Settings::i()->reputation_can_self_vote, FALSE, array(), NULL, NULL, NULL, 'reputation_can_self_vote' ) );
$form->add( new \IPS\Helpers\Form\Number( 'reputation_highlight', \IPS\Settings::i()->reputation_highlight, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('reputation_highlight_prefix'), \IPS\Member::loggedIn()->language()->addToStack('reputation_highlight_suffix'), 'reputation_highlight' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'reputation_show_profile', \IPS\Settings::i()->reputation_show_profile, FALSE, array(), NULL, NULL, NULL, 'reputation_show_profile' ) );
/* Save */
if ( $form->saveAsSettings() )
{
@@ -152,6 +153,44 @@ class _reputation extends \IPS\Dispatcher\Controller
/* Display */
$activeTabContents = (string) $form;
}
else if ( $activeTab === 'leaderboard' )
{
\IPS\Dispatcher::i()->checkAcpPermission( 'reps_settings' );
/* Build Form */
$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_timezone', 'reputation_show_days_won_trophy', 'reputation_leaderboard_default_tab', 'reputation_max_members' ) ), NULL, NULL, NULL, 'reputation_leaderboard_on' ) );
$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\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\Number( 'reputation_max_members', \IPS\Settings::i()->reputation_max_members, FALSE, array( 'min' => 3, 'max' => '100' ), NULL, NULL, NULL, 'reputation_max_members' ) );
$timezones = array();
foreach ( \DateTimeZone::listIdentifiers() as $tz )
{
if ( $pos = mb_strpos( $tz, '/' ) )
{
$timezones[ 'timezone__' . mb_substr( $tz, 0, $pos ) ][ $tz ] = 'timezone__' . $tz;
}
else
{
$timezones[ $tz ] = 'timezone__' . $tz;
}
}
$form->add( new \IPS\Helpers\Form\Select( 'reputation_timezone', \IPS\Settings::i()->reputation_timezone, FALSE, array( 'options' => $timezones, 'sort' => TRUE ), NULL, NULL, NULL, 'reputation_timezone' ) );
/* Save */
if ( $form->saveAsSettings() )
{
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__rep_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=reputation&tab=leaderboard' ), 'saved' );
}
/* Display */
$activeTabContents = (string) $form;
}
else
{
/* Create the table */
@@ -284,7 +323,10 @@ class _reputation extends \IPS\Dispatcher\Controller
public function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'reps_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$current = \IPS\Db::i()->select( '*', 'core_reputation_levels', array( 'level_id=?', \IPS\Request::i()->id ) )->first();
@@ -302,4 +344,24 @@ class _reputation extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=reputation&tab=levels' ) );
}
/**
* Rebuild leaderboard
*
* @return void
*/
public function rebuildLeaderboard()
{
if ( ! isset( \IPS\Request::i()->process ) )
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reputation_leaderboard_rebuild_title');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'settings' )->reputationLeaderboardRebuild();
}
else
{
\IPS\Task::queue( 'core', 'RebuildReputationLeaderboard', array(), 4 );
\IPS\Db::i()->delete('core_reputation_leaderboard_history');
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=membersettings&controller=reputation&tab=leaderboard' ), 'reputation_leaderboard_rebuilding' );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Spam Prevention Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -79,6 +79,33 @@ class _spam extends \IPS\Dispatcher\Controller
\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" ) );
}
/**
* Return the CAPTCHA options - abstracted for third parties
*
* @param string $type 'options' for the select options, 'toggles' for the toggles
* @return array
*/
protected function getCaptchaOptions( $type='options' )
{
switch( $type )
{
case 'options':
return array( 'none' => 'captcha_type_none', 'recaptcha2' => 'captcha_type_recaptcha2', 'recaptcha' => 'captcha_type_recaptcha', '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' ),
'keycaptcha' => array( 'guest_captcha', 'keycaptcha_privatekey' )
);
break;
}
return array();
}
/**
* Show CAPTCHA settings
@@ -90,28 +117,13 @@ class _spam extends \IPS\Dispatcher\Controller
/* Build Form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Radio( 'bot_antispam_type', \IPS\Settings::i()->bot_antispam_type, TRUE, array(
'options' => array( 'none' => 'captcha_type_none', 'recaptcha2' => 'captcha_type_recaptcha2', 'recaptcha' => 'captcha_type_recaptcha', 'keycaptcha' => 'captcha_type_keycaptcha' ),
'toggles' => array(
'none' => array( 'bot_antispam_type_warning' ),
'recaptcha2' => array( 'guest_captcha', 'recaptcha2_public_key', 'recaptcha2_private_key', 'recaptcha2_theme' ),
'recaptcha' => array( 'guest_captcha', 'recaptcha_public_key', 'recaptcha_private_key', 'recaptcha_theme' ),
'keycaptcha' => array( 'guest_captcha', 'keycaptcha_privatekey' )
),
'options' => $this->getCaptchaOptions( 'options' ),
'toggles' => $this->getCaptchaOptions( 'toggles' ),
), 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\Radio( 'recaptcha2_theme', \IPS\Settings::i()->recaptcha2_theme, FALSE, array( 'options' => array(
'light' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha2/light.png', 'core' ) . "' alt='light'>",
'dark' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha2/dark.png', 'core' ) . "' alt='dark'>",
), 'parse' => 'raw' ), NULL, NULL, NULL, 'recaptcha2_theme' ) );
$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\Radio( 'recaptcha_theme', \IPS\Settings::i()->recaptcha_theme, FALSE, array( 'options' => array(
'clean' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha/clean.png', 'core' ) . "' alt='clean'>",
'red' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha/red.png', 'core' ) . "' alt='clean'>",
'white' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha/white.png', 'core' ) . "' alt='clean'>",
'blackglass' => "<img src='" . \IPS\Theme::i()->resource( 'recaptcha/blackglass.png', 'core' ) . "' alt='clean'>",
), 'parse' => 'raw' ), NULL, NULL, NULL, 'recaptcha_theme' ) );
$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' ) );
@@ -168,16 +180,16 @@ class _spam extends \IPS\Dispatcher\Controller
$form->addHeader( 'enhancements__core_SpamMonitoring' );
$disabled = FALSE;
if( !$licenseData or !$licenseData['products']['spam'] or strtotime( $licenseData['expires'] ) < time() )
if( !$licenseData or !isset( $licenseData['products']['spam'] ) or !$licenseData['products']['spam'] or strtotime( $licenseData['expires'] ) < time() )
{
$disabled = TRUE;
if( !\IPS\Settings::i()->ipb_reg_number )
{
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'spam_service_nokey', FALSE, array( 'sprintf' => array( \IPS\Http\Url::internal( 'app=core&module=settings&controller=licensekey', null ) ) ) );
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '__ipbmafia__nulling_null_alert' ); //Changing error message to custom
}
else
{
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'spam_service_noservice' );
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '__ipbmafia__nulling_null_alert' ); //Changing error message to custom
}
}
@@ -333,7 +345,10 @@ class _spam extends \IPS\Dispatcher\Controller
{
$id = intval( \IPS\Request::i()->id );
\IPS\Dispatcher::i()->checkAcpPermission( 'qanda_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\Db::i()->delete( 'core_question_and_answer', array( 'qa_id=?', $id ) );
\IPS\Session::i()->log( 'acplogs__question_deleted' );
@@ -369,6 +384,8 @@ class _spam extends \IPS\Dispatcher\Controller
'ip_address' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'log_code' => \IPS\Helpers\Table\SEARCH_NUMERIC,
);
$table->quickSearch = 'email_address';
/* Custom parsers */
$table->parsers = array(
@@ -2,9 +2,9 @@
/**
* @brief Warnings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 23 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -256,7 +256,10 @@ class _warnings extends \IPS\Node\Controller
protected function actionDelete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'actions_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$current = \IPS\Db::i()->select( '*', 'core_members_warn_actions', array( 'wa_id=?', \IPS\Request::i()->id ) )->first();
@@ -2,9 +2,9 @@
/**
* @brief ACP Dashboard
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 2 July 2013
* @version SVN_VERSION_NUMBER
*/
@@ -30,6 +30,8 @@ class _dashboard extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'view_dashboard' );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_dashboard.js', 'core') );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/dashboard.css', 'core', 'admin' ) );
@@ -72,7 +74,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
$bulletins = \IPS\Http\Url::ips('bulletin')->request()->get()->decodeJson();
\IPS\Data\Store::i()->acpBulletin = array(
'time' => time(),
'content' => $bulletins
'content' => $bulletins ?: array()
);
}
catch( \RuntimeException $e )
@@ -84,21 +86,24 @@ class _dashboard extends \IPS\Dispatcher\Controller
{
$bulletins = $bulletin['content'];
}
foreach ( $bulletins as $k => $data )
if( !empty( $bulletins ) )
{
if ( count( $data['files'] ) )
foreach ( $bulletins as $k => $data )
{
$skip = TRUE;
foreach ( $data['files'] as $file )
if ( count( $data['files'] ) )
{
if ( filemtime( \IPS\ROOT_PATH . '/' . $file ) < $data['timestamp'] )
$skip = TRUE;
foreach ( $data['files'] as $file )
{
$skip = FALSE;
if ( filemtime( \IPS\ROOT_PATH . '/' . $file ) < $data['timestamp'] )
{
$skip = FALSE;
}
}
if ( $skip )
{
unset( $bulletins[ $k ] );
}
}
if ( $skip )
{
unset( $bulletins[ $k ] );
}
}
}
@@ -139,6 +144,61 @@ class _dashboard extends \IPS\Dispatcher\Controller
);
}
/* Check Tasks */
try
{
$task = \IPS\DateTime::ts( \IPS\Db::i()->select( 'next_run', 'core_tasks', array( 'enabled=?', TRUE ), 'next_run ASC' )->first() );
$today = new \IPS\DateTime;
$difference = $today->diff( $task )->h + ( $today->diff( $task )->days * 24 );
if ( $difference >= 36 )
{
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' )
);
}
elseif( \IPS\Settings::i()->task_use_cron == 'web' )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_web_broken_desc' )
);
}
else
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_not_enough_desc' )
);
}
}
}
catch ( \UnderflowException $e ) { }
if ( !\IPS\Settings::i()->site_online AND \IPS\Settings::i()->task_use_cron == 'normal' AND !\IPS\CIC )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('dasbhoard_tasks_site_offline'),
'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( !\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 */
if( \IPS\Settings::i()->last_data_store_update < \IPS\DateTime::create()->sub( new \DateInterval( 'PT24H' ) )->getTimestamp() )
{
$warnings[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_datastore_broken' ),
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_datastore_broken_desc' )
);
}
}
/* Get new core update available data */
$update = \IPS\Application::load( 'core' )->availableUpgrade( TRUE );
@@ -171,8 +231,8 @@ class _dashboard extends \IPS\Dispatcher\Controller
if( !$toShow OR !isset( $toShow['main'] ) OR !isset( $toShow['side'] ) )
{
$toShow = array(
'main' => array( 'core_BackgroundQueue', 'core_Registrations' ),
'side' => array( 'core_AdminNotes', 'core_OnlineUsers' ),
'main' => array( 'core_AdminNotes', 'core_Registrations', 'core_AwaitingValidation', 'core_BackgroundQueue' ),
'side' => array( 'core_OnlineAdmins', 'core_FailedLogins', 'core_OnlineUsers' ),
);
$blocks[ \IPS\Member::loggedIn()->member_id ] = $toShow;
@@ -2,9 +2,9 @@
/**
* @brief File Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 06 May 2013
* @version SVN_VERSION_NUMBER
*/
@@ -61,6 +61,7 @@ class _files extends \IPS\Dispatcher\Controller
);
}
/* @todo - This needs fixing but has been temporarily been disabled
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'overview', 'orphaned_files' ) )
{
\IPS\Output::i()->sidebar['actions']['orphaned'] = array(
@@ -69,7 +70,7 @@ class _files extends \IPS\Dispatcher\Controller
'title' => 'orphaned_files',
'data' => array( 'confirm' => '', 'confirmMessage' => \IPS\Member::loggedIn()->language()->addToStack('orphaned_files_confirm') )
);
}
}*/
$table = new \IPS\Helpers\Table\Db( 'core_attachments', \IPS\Http\Url::internal( 'app=core&module=overview&controller=files' ) );
$table->filters = array(
@@ -127,7 +128,15 @@ class _files extends \IPS\Dispatcher\Controller
},
'attach_member_id' => function( $val )
{
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>';
if ( $val == 0 )
{
return \IPS\Member::load( $val )->name;
}
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>';
}
}
);
$table->advancedSearch = array(
@@ -216,6 +225,9 @@ class _files extends \IPS\Dispatcher\Controller
public function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'files_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
@@ -249,9 +261,9 @@ class _files extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Radio( 'image_suite', \IPS\Settings::i()->image_suite, TRUE, array(
$form->add( new \IPS\Helpers\Form\Radio( 'image_suite', class_exists( 'Imagick', FALSE ) ? \IPS\Settings::i()->image_suite : 'gd', TRUE, array(
'options' => array( 'gd' => 'imagesuite_gd', 'imagemagick' => 'imagesuite_imagemagick' ),
'toggles' => array( 'imagemagick' => array(), 'gd' => array( 'image_jpg_quality', 'image_png_quality_gd' ) ),
'toggles' => array( 'imagemagick' => array( 'image_jpg_quality' ), 'gd' => array( 'image_jpg_quality', 'image_png_quality_gd' ) ),
'disabled'=> class_exists( 'Imagick', FALSE ) ? array() : array( 'imagemagick' )
) ) );
@@ -314,8 +326,8 @@ class _files extends \IPS\Dispatcher\Controller
$value = $settings[ "filestorage__{$name}" ];
}
}
$form->add( new \IPS\Helpers\Form\Select( 'filestorage__' . $name, $value, TRUE, array( 'options' => $configurations, 'disabled' => $disabled ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'filestorage__' . $name, (int) $value, TRUE, array( 'options' => $configurations, 'disabled' => $disabled ) ) );
if ( $disabled )
{
@@ -344,19 +356,34 @@ class _files extends \IPS\Dispatcher\Controller
{
if ( $settings[ $k ] != $v and $k != 'filestorage__core_Theme' )
{
$rebuild = TRUE;
/* Do we need to move files at all? */
$configurations = \IPS\File::getConfigurations();
$exploded = explode( '_', $k );
$classname = "IPS\\{$exploded[2]}\\extensions\\core\\FileStorage\\{$exploded[3]}";
$extension = new $classname;
$count = $extension->count();
$currentClass = \IPS\File::getClass( intval( $settings[ $k ] ) );
$newClass = \IPS\File::getClass( intval( $v ) );
if ( $count )
if ( ( isset( $configurations[ $v ] ) and isset( $configurations[ $settings[ $k ] ] ) ) and ( get_class( $currentClass ) == get_class( $newClass ) ) and ! $newClass::moveCheck( $newClass->configuration, $currentClass->configuration ) )
{
\IPS\Task::queue( 'core', 'MoveFiles', array( 'storageExtension' => $k, 'oldConfiguration' => $settings[ $k ], 'newConfiguration' => $values[ $k ], 'count' => $count ), 2 );
$rebuild = FALSE;
}
else
{
$rebuild = TRUE;
}
if ( $rebuild )
{
$count = $extension->count();
/* Add to allowed storage methods so when moving files, we can accept old config or new config if move is in progress. Important: order is array(x, y) x is the new location (pos 0), y is the old location (pos 1)*/
$values[ $k ] = array( $v, $settings[ $k ] );
if ( $count )
{
\IPS\Task::queue( 'core', 'MoveFiles', array( 'storageExtension' => $k, 'oldConfiguration' => $settings[ $k ], 'newConfiguration' => $values[ $k ], 'count' => $count ), 2 );
/* Add to allowed storage methods so when moving files, we can accept old config or new config if move is in progress. Important: order is array(x, y) x is the new location (pos 0), y is the old location (pos 1)*/
$values[ $k ] = array( $v, $settings[ $k ] );
}
}
}
}
@@ -421,6 +448,16 @@ class _files extends \IPS\Dispatcher\Controller
$activeTabContents = $table;
}
/* Add a button for settings */
\IPS\Output::i()->sidebar['actions'] = array(
'settings' => array(
'title' => 'settings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=overview&controller=files&do=fileLogSettings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('settings') )
),
);
/* Display */
if ( \IPS\Request::i()->isAjax() and !isset( \IPS\Request::i()->ajaxValidate ) )
@@ -434,6 +471,27 @@ class _files extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( array( 'settings' => 'filestorage_settings', 'configurations' => 'filestorage_configurations' ), $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=overview&controller=files&do=settings" ) );
}
}
/**
* Settings
*
* @return void
*/
protected function fileLogSettings()
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Number( 'file_log_pruning', \IPS\Settings::i()->file_log_pruning, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'file_log_pruning' ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Session::i()->log( 'acplog__filelog_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=overview&controller=files&do=settings' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('filelog_settings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'filelog_settings', $form, FALSE );
}
/**
* Add/Edit Configuration
@@ -563,7 +621,7 @@ class _files extends \IPS\Dispatcher\Controller
{
foreach ( $toggles[ $values['filestorage_method'] ] as $k => $v )
{
$currentHandlerSettings[ $k ] = str_replace( \IPS\ROOT_PATH, '{root}', $values[ 'filehandler__' . $v ] );
$currentHandlerSettings[ $k ] = ( \IPS\ROOT_PATH !== '/' ) ? str_replace( \IPS\ROOT_PATH, '{root}', $values[ 'filehandler__' . $v ] ) : $values[ 'filehandler__' . $v ];
}
}
@@ -572,6 +630,37 @@ class _files extends \IPS\Dispatcher\Controller
{
$classname::testSettings( $currentHandlerSettings );
}
$existingWithSameConfig = false;
/* Make sure there are no other configurations that are exactly the same */
foreach( \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', $values['filestorage_method'] ) ) as $existing )
{
if ( $current and $current['id'] == $existing['id'] )
{
continue;
}
$existingWithSameConfig = true;
$existingConfiguration = json_decode( $existing['configuration'], true );
foreach( $existingConfiguration as $k => $v )
{
$v = str_replace( \IPS\ROOT_PATH, '{root}', $v );
if ( array_key_exists( $k, $currentHandlerSettings ) )
{
if ( $v != $currentHandlerSettings[ $k ] )
{
$existingWithSameConfig = false;
}
}
}
}
if ( $existingWithSameConfig )
{
/* Let's not allow this to be saved as someone can start a move to the same location, which will end up deleting the files */
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'file_config_is_the_same_as_existing', FALSE ) );
}
/* Do we really need to create and move? */
if ( $current AND $createNewAndMove )
@@ -2,9 +2,9 @@
/**
* @brief Security Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 11 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -146,7 +146,7 @@ class _security extends \IPS\Dispatcher\Controller
}
/* ACP Directory Name */
if ( \IPS\CP_DIRECTORY == 'admin' )
if ( \IPS\CP_DIRECTORY == 'admin' and !\IPS\CIC )
{
$content[] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack('rename_admin_title'),
@@ -182,12 +182,38 @@ class _security extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'security_remove_acp_link', !\IPS\Settings::i()->security_remove_acp_link, FALSE ) );
$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\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 we are overriding IP address checking for the ACP, show a warning */
if( \IPS\BYPASS_ACP_IP_CHECK === TRUE )
{
\IPS\Member::loggedIn()->language()->words['match_ipaddress_warning'] = \IPS\Member::loggedIn()->language()->addToStack('ip_override_warn');
}
/* Password Strength */
$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' ) );
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' );
@@ -210,7 +236,7 @@ class _security extends \IPS\Dispatcher\Controller
$done = FALSE;
/* Try... */
if ( !@chmod( \IPS\ROOT_PATH . '/conf_global.php', 0444 ) )
if ( \IPS\NO_WRITES or !@chmod( \IPS\ROOT_PATH . '/conf_global.php', 0444 ) )
{
\IPS\Output::i()->error( 'conf_not_altered', '2C258/2', 500, '' );
}
@@ -227,11 +253,16 @@ class _security extends \IPS\Dispatcher\Controller
*/
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)">
<Files ~ "^.*\.(php|cgi|pl|php3|php4|php5|php6|phtml|shtml|([a-z0-9]{32}))$">
Order allow,deny
Deny from all
</Files>
@@ -306,14 +337,19 @@ EOF;
*/
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( 'username', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE ) );
$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() )
{
@@ -325,8 +361,8 @@ EOF;
. 'AuthUserFile "' . \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . "/.htpasswd\"\n"
. "Require valid-user\n";
$htaccess_pw = $values['username'] . ":" .
( ( mb_strtoupper( mb_substr( PHP_OS, 0, 3 ) ) === 'WIN' ) ? $values['password'] : crypt( $values['password'], base64_encode( $values['password'] ) ) );
$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' ) )
{
@@ -340,6 +376,7 @@ EOF;
$done = TRUE;
\IPS\Session::i()->log( 'acplogs__security_acp_password' );
\IPS\IPS::resyncIPSCloud();
}
/* All Done */
@@ -2,9 +2,9 @@
/**
* @brief Advertisements
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 24 Sep 2013
* @version SVN_VERSION_NUMBER
*/
@@ -46,9 +46,12 @@ class _advertisements extends \IPS\Dispatcher\Controller
$table->langPrefix = 'ads_';
/* Columns we need */
$table->include = array( 'ad_title', 'ad_html', 'ad_impressions', 'ad_clicks', 'ad_start', 'ad_end', 'ad_maximum_value', 'ad_active' );
$table->include = array( 'word_custom', 'ad_html', 'ad_impressions', 'ad_clicks', 'ad_start', 'ad_end', 'ad_maximum_value', 'ad_active' );
$table->mainColumn = 'ad_html';
$table->noSort = array( 'ad_images', 'ad_html' );
$table->joins = array(
array( 'select' => 'w.word_custom', 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'core_advert_', core_advertisements.ad_id ) AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
);
/* Default sort options */
$table->sortBy = $table->sortBy ?: 'ad_start';
@@ -65,8 +68,8 @@ class _advertisements extends \IPS\Dispatcher\Controller
/* Filters */
$table->filters = array(
'ad_filters_active' => 'ad_active=1',
'ad_filters_inactive' => 'ad_active=0',
'ad_filters_active' => array('ad_active=1 AND ( ad_end=0 OR ad_end > ? )', time() ),
'ad_filters_inactive' => array('ad_active=0 OR ad_end<? ', time() ),
);
/* If Nexus is installed, we get the pending filter too */
@@ -77,7 +80,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
/* Custom parsers */
$table->parsers = array(
'ad_title' => function( $val, $row )
'word_custom' => function( $val, $row )
{
return \IPS\Member::loggedIn()->language()->checkKeyExists( "core_advert_{$row['ad_id']}" ) ? \IPS\Member::loggedIn()->language()->addToStack( "core_advert_{$row['ad_id']}" ) : \IPS\Theme::i()->getTemplate( 'global' )->shortMessage( 'ad_title_none', array( 'ipsType_light' ) );
},
@@ -243,6 +246,9 @@ class _advertisements extends \IPS\Dispatcher\Controller
/* Permission check */
\IPS\Dispatcher::i()->checkAcpPermission( 'advertisements_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Get our record */
try
{
@@ -349,7 +355,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
/* Start the form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Translatable( 'ad_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( !$record->id ) ? NULL : "core_advert_{$record->id}" ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'ad_type', ( $record->id ) ? ( $record->html ? 'html' : 'image' ) : 'html', TRUE, array( 'options' => array( 'html' => 'ad_type_html', 'image' => 'ad_type_image' ), 'toggles' => array( 'html' => array( 'ad_html', 'ad_html_specify_https', 'ad_maximums_html' ), 'image' => array( 'ad_url', 'ad_image', 'ad_image_more', 'ad_clicks', 'ad_maximums_image' ) ) ), NULL, NULL, NULL, 'ad_type' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'ad_type', ( $record->id ) ? ( $record->html ? 'html' : 'image' ) : 'html', TRUE, array( 'options' => array( 'html' => 'ad_type_html', 'image' => 'ad_type_image' ), 'toggles' => array( 'html' => array( 'ad_html', 'ad_html_specify_https', 'ad_maximums_html' ), 'image' => array( 'ad_url', 'ad_new_window', 'ad_image', 'ad_image_more', 'ad_clicks', 'ad_maximums_image' ) ) ), NULL, NULL, NULL, 'ad_type' ) );
/* Show the fields for an HTML advertisement */
$form->add( new \IPS\Helpers\Form\Codemirror( 'ad_html', ( $record->id ) ? $record->html : NULL, FALSE, array(), NULL, NULL, NULL, 'ad_html' ) );
@@ -358,10 +364,11 @@ class _advertisements extends \IPS\Dispatcher\Controller
/* Show the fields for an image advertisement */
$form->add( new \IPS\Helpers\Form\Url( 'ad_url', ( $record->id ) ? $record->link : NULL, FALSE, array(), NULL, NULL, NULL, 'ad_url' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image', ( $record->id ) ? ( ( isset( $record->_images['large'] ) ) ? \IPS\File::get( 'core_Advertisements', $record->_images['large'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ad_image_more', ( $record->id ) ? ( ( isset( $record->_images['medium'] ) OR ( isset( $record->_images['small'] ) ) ) ? TRUE : FALSE ) : FALSE, FALSE, array( 'togglesOn' => array( 'ad_image_small', 'ad_image_medium' ) ), NULL, NULL, NULL, 'ad_image_more' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image_small', ( $record->id ) ? ( ( isset( $record->_images['small'] ) ) ? \IPS\File::get( 'core_Advertisements', $record->_images['small'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image_small' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image_medium', ( $record->id ) ? ( ( isset( $record->_images['medium'] ) ) ? \IPS\File::get( 'core_Advertisements', $record->_images['medium'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image_medium' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ad_new_window', ( $record->id ) ? $record->new_window : FALSE, FALSE, array(), NULL, NULL, NULL, 'ad_new_window' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image', ( $record->id ) ? ( ( isset( $record->_images['large'] ) and $record->_images['large'] ) ? \IPS\File::get( 'core_Advertisements', $record->_images['large'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ad_image_more', ( $record->id ) ? ( ( ( isset( $record->_images['medium'] ) and $record->_images['medium'] ) OR ( ( isset( $record->_images['small'] ) and $record->_images['small'] ) ) ) ? TRUE : FALSE ) : FALSE, FALSE, array( 'togglesOn' => array( 'ad_image_small', 'ad_image_medium' ) ), NULL, NULL, NULL, 'ad_image_more' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image_small', ( $record->id ) ? ( ( isset( $record->_images['small'] ) and $record->_images['small'] ) ? \IPS\File::get( 'core_Advertisements', $record->_images['small'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image_small' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'ad_image_medium', ( $record->id ) ? ( ( isset( $record->_images['medium'] ) and $record->_images['medium'] ) ? \IPS\File::get( 'core_Advertisements', $record->_images['medium'] ) : NULL ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Advertisements' ), NULL, NULL, NULL, 'ad_image_medium' ) );
/* Add the location fields, remember to call extensions for additional locations.
Array format: location => array of toggle fields to show */
@@ -465,6 +472,7 @@ class _advertisements extends \IPS\Dispatcher\Controller
$record->location = implode( ',', $locations );
$record->html = ( $values['ad_type'] == 'html' ) ? $values['ad_html'] : NULL;
$record->link = ( $values['ad_type'] == 'image' ) ? $values['ad_url'] : NULL;
$record->new_window = ( $values['ad_type'] == 'image' ) ? $values['ad_new_window'] : 0;
$record->impressions = ( isset( $values['ad_impressions'] ) ) ? $values['ad_impressions'] : 0;
$record->clicks = ( $values['ad_type'] == 'image' AND isset( $values['ad_clicks'] ) ) ? $values['ad_clicks'] : 0;
$record->active = ( $record->id ) ? $record->active : 1;
@@ -0,0 +1,101 @@
<?php
/**
* @brief Analytics
* @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 03 Nov 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\promotion;
/* 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;
}
/**
* Analytics
*/
class _analytics extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'analytics_manage' );
parent::execute();
}
/**
* Analytics Settings
*
* @return void
*/
protected function manage()
{
$providers = array(
'none' => 'analytics_provider_none',
'ga' => 'analytics_provider_ga',
'piwik' => 'analytics_provider_piwik',
'custom' => 'analytics_provider_custom'
);
$toggles = array(
'ga' => array('analytics_ga'),
'piwik' => array('analytics_piwik'),
'custom' => array('analytics_custom', 'ipbseo_ga_paginatecode')
);
$form = new \IPS\Helpers\Form;
$form->addMessage('analytics_description');
$form->add( new \IPS\Helpers\Form\Radio( 'ipbseo_ga_provider', \IPS\Settings::i()->ipbseo_ga_provider, FALSE, array( 'options' => $providers, 'toggles' => $toggles ) ) );
/* Add a CodeMirror element for each supported provider */
foreach( $providers as $key => $provider )
{
if( $key == 'none' )
{
continue;
}
$form->add( new \IPS\Helpers\Form\Codemirror( 'analytics_' . $key, \IPS\Settings::i()->ipbseo_ga_provider == $key ? \IPS\Settings::i()->ipseo_ga : '', FALSE, array('height' => 150, 'mode' => 'javascript'), NULL, NULL, NULL, 'analytics_' . $key ) );
}
$form->add( new \IPS\Helpers\Form\Codemirror( 'ipbseo_ga_paginatecode', \IPS\Settings::i()->ipbseo_ga_paginatecode, FALSE, array('height' => 150, 'mode' => 'javascript'), NULL, NULL, NULL, 'ipbseo_ga_paginatecode' ) );
if ( $values = $form->values() )
{
/* Fix up values to ensure the correct snippet is saved */
if ( !isset( $providers[ $values['ipbseo_ga_provider'] ] ) || $values['ipbseo_ga_provider'] == 'none' )
{
$values['ipbseo_ga_enabled'] = FALSE;
$values['ipseo_ga'] = '';
$values['ipbseo_ga_paginatecode'] = '';
}
else
{
$values['ipbseo_ga_enabled'] = TRUE;
$values['ipseo_ga'] = $values['analytics_' . $values['ipbseo_ga_provider'] ];
}
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplog__analytics_edited' );
\IPS\Output::i()->inlineMessage = \IPS\Member::loggedIn()->language()->addToStack('saved');
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_promotion_analytics');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'analytics', $form );
}
}
@@ -2,9 +2,9 @@
/**
* @brief SEO
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 07 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -62,23 +62,24 @@ class _seo extends \IPS\Dispatcher\Controller
/* Build tab list */
$tabs = array();
$tabs['urls'] = 'seo_tab_furls';
if ( !\IPS\CIC )
{
$tabs['urls'] = 'seo_tab_furls';
}
$tabs['sitemap'] = 'seo_tab_sitemap';
$tabs['metatags'] = 'seo_tab_metatags';
/* Display */
if ( $activeTabContents )
{
\IPS\Output::i()->sidebar['actions']['ga'] = array(
'title' => 'configure_google_analytics',
'icon' => 'cogs',
'link' => \IPS\Http\Url::internal( "app=core&module=applications&controller=enhancements&do=edit&id=core_GoogleAnalytics" ),
);
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_promotion_seo');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $this->activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=promotion&controller=seo" ) );
}
\IPS\Output::i()->sidebar['actions']['seo_visitors'] = array(
'title' => 'Посетители с поисковых систем',
'icon' => 'bar-chart-o',
'link' => \IPS\Http\Url::internal( "app=core&module=promotion&controller=seovisitors" ),
);
}
/**
@@ -102,7 +103,8 @@ class _seo extends \IPS\Dispatcher\Controller
{
try
{
$response = \IPS\Http\Url::external( \IPS\Settings::i()->base_url . 'login' )->request( 5, '1.1', FALSE )->get();
$furlDefinition = \IPS\Http\Url::furlDefinition();
$response = \IPS\Http\Url::external( \IPS\Settings::i()->base_url . $furlDefinition['login']['friendly'] )->request( NULL, NULL, FALSE )->get();
if ( !in_array( mb_substr( $response->httpResponseCode, 0, 1 ), array( '2', '3' ) ) and ( \IPS\Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
{
\IPS\Member::loggedIn()->language()->words['htaccess_mod_rewrite_warning'] = \IPS\Member::loggedIn()->language()->get( $isApache ? 'htaccess_mod_rewrite_err' : 'htaccess_mod_rewrite_err_na' );
@@ -122,6 +124,9 @@ class _seo extends \IPS\Dispatcher\Controller
$form->saveAsSettings();
\IPS\Member::clearCreateMenu();
/* Clear front navigation data store, otherwise it could still contain the non-rewrite furl for some items */
unset( \IPS\Data\Store::i()->frontNavigation );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -187,6 +192,11 @@ class _seo extends \IPS\Dispatcher\Controller
try
{
if( !( $values['sitemap_url'] instanceof \IPS\Http\Url ) )
{
throw new \RuntimeException;
}
$response = $values['sitemap_url']->setQueryString( 'testsettings', 1 )->request()->get();
if ( $response->httpResponseCode != 200 or !mb_strpos( $values['sitemap_url'], "sitemap.php" ) )
@@ -195,7 +205,7 @@ class _seo extends \IPS\Dispatcher\Controller
}
}
catch ( \IPS\Http\Request\Exception $e )
catch ( \RuntimeException $e )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'form_url_bad' );
}
@@ -232,6 +242,9 @@ class _seo extends \IPS\Dispatcher\Controller
/* Are we deleting? */
if ( isset( \IPS\Request::i()->delete ) )
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
if( isset( \IPS\Request::i()->root ) )
{
$meta = \IPS\Db::i()->select( '*', 'core_seo_meta', array( 'meta_id=?', (int) \IPS\Request::i()->root ) )->first();
@@ -241,7 +254,7 @@ class _seo extends \IPS\Dispatcher\Controller
}
else
{
\IPS\DB::i()->delete( 'core_seo_meta', array( "meta_id=?", (int) \IPS\Request::i()->delete ) );
\IPS\Db::i()->delete( 'core_seo_meta', array( "meta_id=?", (int) \IPS\Request::i()->delete ) );
}
unset( \IPS\Data\Store::i()->metaTags );
@@ -440,12 +453,12 @@ class _seo extends \IPS\Dispatcher\Controller
$tags[ $data['name'] ] = $data['content'];
}
\IPS\DB::i()->delete( 'core_seo_meta', array( 'meta_url=?', $url ) );
\IPS\DB::i()->delete( 'core_seo_meta', array( 'meta_url=?', \IPS\Request::i()->original_url ) );
\IPS\Db::i()->delete( 'core_seo_meta', array( 'meta_url=?', $url ) );
\IPS\Db::i()->delete( 'core_seo_meta', array( 'meta_url=?', \IPS\Request::i()->original_url ) );
if( $title or count( $tags ) )
{
\IPS\DB::i()->insert( 'core_seo_meta', array( 'meta_url' => $url, 'meta_title' => $title, 'meta_tags' => json_encode( $tags ) ) );
\IPS\Db::i()->insert( 'core_seo_meta', array( 'meta_url' => $url, 'meta_title' => $title, 'meta_tags' => json_encode( $tags ) ) );
}
\IPS\Session::i()->log( 'acplogs__seo_metatag_settings' );
@@ -484,7 +497,7 @@ Options -MultiViews
RewriteEngine On
RewriteBase {$dir}
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule \\.(js|css|jpeg|jpg|gif|png|ico)(\\?|$) {$dir}404error.php [L,NC]
RewriteRule \\.(js|css|jpeg|jpg|gif|png|ico|map)(\\?|$) {$dir}404error.php [L,NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
@@ -0,0 +1,273 @@
<?php
namespace IPS\core\modules\admin\promotion;
/* 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;
}
/**
* SEO
*/
class _seovisitors extends \IPS\Dispatcher\Controller
{
protected function manage()
{
\IPS\Output::i()->title = 'Посетители с поисковых систем';
$table = new \IPS\Helpers\Table\Db( 'search_visitors', \IPS\Http\Url::internal('app=core&module=promotion&controller=seovisitors'));
if(\IPS\Request::i()->filter) {
if(\IPS\Request::i()->keywords) $table->baseUrl = $table->baseUrl->setQueryString('keywords',\IPS\Request::i()->keywords);
if(\IPS\Request::i()->engine) $table->baseUrl = $table->baseUrl->setQueryString('engine',\IPS\Request::i()->engine);
}
$table->include = array('keywords','engine','url','name','date');
$table->sortBy = $table->sortBy ?: 'date';
$table->sortDirection = $table->sortDirection ?: 'desc';
$table->langPrefix = 'seovisitors_';
$table->joins = array(
array(
'select' => 'm.name',
'from' => array( 'core_members', 'm' ),
'where' => 'm.member_id=search_visitors.member'
)
);
$table->parsers = array(
'date'=>function($val,$row) {
return \IPS\DateTime::ts( $val )->relative();
},
'name' => function( $val, $row )
{
if($val) return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=edit&id=' ) . $row['member'] . "'>" . htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . "</a>";
else return \IPS\Member::loggedIn()->language()->addToStack( 'guest' );
},
'keywords'=>function ($val,$row) {
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=promotion&controller=seovisitors&filter=keywords&keywords=' ) . $val . "'>" . htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . "</a>";
},
'engine'=>function ($val,$row) {
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=promotion&controller=seovisitors&filter=engine&engine=' ) . $val . "'>" . htmlentities( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) . "</a>";
}
);
$table->filters = array(
'keywords'=>"keywords LIKE '".htmlentities( \IPS\Request::i()->keywords, \IPS\HTMLENTITIES, 'UTF-8', FALSE )."'",
'engine'=>"engine LIKE '".htmlentities( \IPS\Request::i()->engine, \IPS\HTMLENTITIES, 'UTF-8', FALSE )."'"
);
$table = preg_replace(array("/data-page='[0-9]*'/",'/data-action="tableFilter"/','/data-action="tableSort"/'), '', (string) $table);
\IPS\Member::loggedIn()->language()->parseOutputForDisplay($table);
\IPS\Output::i()->output = str_replace(array(
'seovisitors_keywords',
'seovisitors_engine',
'seovisitors_url',
'seovisitors_name',
'seovisitors_date'),
array('Ключевики','Поисковик','Страница','Пользователь','Дата'),$table);
}
protected static $engines = array(
array( 'name' => 'Google', 'match' => '/http(s)?\:\/\/www\.google/', 'parser' => 'parseGoogleUrl' ),
array( 'name' => 'Bing', 'match' => '/http\:\/\/www\.bing/', 'parser' => 'parseBingUrl' ),
array( 'name' => 'Bing', 'match' => '/http\:\/\/www\.bing/', 'parser' => 'parseBingUrl' ),
array( 'name' => 'Facebook', 'match' => '/http\:\/\/www\.facebook/', 'parser' => 'parseFacebookUrl' ),
array( 'name' => 'Yandex', 'match' => '/http\:\/\/(www\.)?yandex/', 'parser' => 'parseYandexUrl'),
array( 'name' => 'Rambler', 'match' => '/http\:\/\/(nova\.)?rambler/', 'parser' => 'parseRamblerUrl'),
array( 'name' => 'Mail.ru', 'match' => '/http\:\/\/(go\.)?mail/', 'parser' => 'parseMailruUrl')
);
public static function track( $referrer, $queryString, $memberId )
{
/*
CREATE TABLE IF NOT EXISTS `search_visitors` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`member` int(11) DEFAULT NULL,
`date` int(11) NOT NULL DEFAULT '0',
`engine` varchar(50) NOT NULL,
`keywords` varchar(250) NOT NULL,
`url` varchar(2048) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_date_engine` (`date`,`engine`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
*/
foreach( self::$engines as $engine )
{
if( preg_match( $engine['match'], $referrer ) )
{
$obj = new self;
$keywords = trim( $obj->{$engine['parser']}( $referrer ) );
if ( !empty( $keywords ) )
{
\IPS\DB::i()->insert( 'search_visitors', array( 'date' => time(), 'member' => intval( $memberId ), 'engine' => $engine['name'], 'keywords' => $keywords, 'url' => $queryString ) );
}
break;
}
}
}
protected function parseGoogleUrl($url)
{
$matches = array();
if(preg_match('/imgres/', $url) && preg_match('/prev\=([^\&]+)/', $url, $matches))
{
$url = urldecode($matches[1]);
}
$matches = array();
if(preg_match('/q\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
protected function parseBingUrl($url)
{
$matches = array();
if(preg_match('/q\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
protected function parseYahooUrl($url)
{
$matches = array();
if(preg_match('/p\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
protected function parseFacebookUrl($url)
{
$matches = array();
if(preg_match('/l\.php\?u\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('http://', '', $keywords);
$keywords = str_replace('https://', '', $keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
elseif(preg_match('/end\.php/', $url))
{
return 'Sponsored Ad';
}
return null;
}
protected function parseYandexUrl($url)
{
$matches = array();
if(preg_match('/text\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
protected function parseRamblerUrl($url)
{
$matches = array();
if(preg_match('/query\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
if(preg_match('/words\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
protected function parseMailruUrl($url)
{
$matches = array();
if(preg_match('/q\=([^\&]+)/', $url, $matches))
{
if(isset($matches[1]))
{
$keywords = $matches[1];
$keywords = urldecode($keywords);
$keywords = str_replace('+', ' ', $keywords);
$keywords = str_replace('%20', ' ', $keywords);
return $keywords;
}
}
return null;
}
}
@@ -2,9 +2,9 @@
/**
* @brief Share Link Services
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 10 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -54,7 +54,7 @@ class _sharelinks extends \IPS\Node\Controller
/* Now see if there are any new classes */
foreach( new \DirectoryIterator( \IPS\ROOT_PATH . '/system/Content/ShareServices/' ) as $file )
{
if( $file->isDir() OR $file->isDot() OR $file == 'index.html' )
if( $file->isDir() OR $file->isDot() OR $file->getExtension() !== 'php' )
{
continue;
}
@@ -104,6 +104,9 @@ class _sharelinks extends \IPS\Node\Controller
*/
public function delete()
{
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\Db::i()->delete( 'core_share_links', array( 'share_id=?', (int) \IPS\Request::i()->id ) );
/* Clear guest page caches */
@@ -2,9 +2,9 @@
/**
* @brief Advanced Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 10 June 2013
* @version SVN_VERSION_NUMBER
*/
@@ -63,11 +63,11 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Build tab list */
$tabs = array();
$tabs['settings'] = 'server_environment';
if ( \IPS\Settings::i()->use_friendly_urls )
if ( \IPS\Settings::i()->use_friendly_urls and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'advanced_manage_furls' ) )
{
$tabs['furl'] = 'furls';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'datastore' ) )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'datastore' ) and !\IPS\CIC )
{
$tabs['datastore'] = 'data_store';
}
@@ -116,6 +116,16 @@ class _advanced extends \IPS\Dispatcher\Controller
/* Init */
$form = new \IPS\Helpers\Form;
/* If the datastore isn't working properly, 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 */
if( \IPS\Settings::i()->last_data_store_update < \IPS\DateTime::create()->sub( new \DateInterval( 'PT24H' ) )->getTimestamp() )
{
$form->addMessage( 'dashboard_datastore_broken_settings', 'ipsMessage ipsMessage_warning' );
}
}
/* Cold storage */
$extra = array();
$toggles = array();
@@ -250,6 +260,10 @@ class _advanced extends \IPS\Dispatcher\Controller
/* 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'" );
/* 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 );
/* 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'] ) );
@@ -274,6 +288,8 @@ class _advanced extends \IPS\Dispatcher\Controller
*/
protected function downloadDatastoreConstants()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'datastore' );
$output = "<?php\n\n";
foreach ( \IPS\IPS::defaultConstants() as $k => $v )
{
@@ -314,22 +330,54 @@ class _advanced extends \IPS\Dispatcher\Controller
}
/* Sort stuff out for the cron setting */
\IPS\Member::loggedIn()->language()->words['task_use_cron_warning'] = sprintf( \IPS\Member::loggedIn()->language()->get( 'task_use_cron_warning', FALSE ), PHP_BINDIR . '/php -d memory_limit=-1 -d max_execution_time=0 ' . \IPS\ROOT_PATH . '/applications/core/interface/task/task.php ' . \IPS\Settings::i()->task_cron_key );
$cronOptions = array( 'togglesOn' => array( 'task_use_cron_warning' ) );
if ( \IPS\CIC )
{
$options = array( 'options' => array(
'ips' => 'task_method_ips'
) );
}
else
{
\IPS\Member::loggedIn()->language()->words['task_method_cron_warning'] = sprintf( \IPS\Member::loggedIn()->language()->get( 'task_method_cron_warning', FALSE ), PHP_BINDIR . '/php -d memory_limit=-1 -d max_execution_time=0 ' . \IPS\ROOT_PATH . '/applications/core/interface/task/task.php ' . \IPS\Settings::i()->task_cron_key );
\IPS\Member::loggedIn()->language()->words['task_method_web_warning'] = sprintf( \IPS\Member::loggedIn()->language()->get( 'task_method_web_warning', FALSE ), \IPS\Http\Url::internal( 'applications/core/interface/task/web.php?key=' . \IPS\Settings::i()->task_cron_key, 'none' ) );
$options = array(
'options' => array(
'normal' => 'task_method_normal',
'cron' => 'task_method_cron',
'web' => 'task_method_web',
),
'toggles' => array(
'cron' => array( 'task_use_cron_cron_warning' ),
'web' => array( 'task_use_cron_web_warning' )
)
);
}
/* Build and show form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'task_use_cron', \IPS\Settings::i()->task_use_cron, FALSE, $cronOptions, function ( $val )
$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';
if ( $val and ( mb_strtoupper( mb_substr( PHP_OS, 0, 3 ) ) !== 'WIN' AND !is_executable( $cronFile ) ) )
if ( $val == 'cron' and ( mb_strtoupper( mb_substr( PHP_OS, 0, 3 ) ) !== 'WIN' AND !is_executable( $cronFile ) ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('task_use_cron_executable', FALSE, array( 'sprintf' => array( $cronFile ) ) ) );
}
}, NULL, NULL, 'task_use_cron' ) );
$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 ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'theme_disk_cache_templates', \IPS\Settings::i()->theme_disk_cache_templates, FALSE, array( 'togglesOn' => array( 'theme_disk_cache_path' ) ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'theme_disk_cache_path', \IPS\Settings::i()->theme_disk_cache_path ? \IPS\Settings::i()->theme_disk_cache_path : \IPS\ROOT_PATH . '/uploads', FALSE, array(), function( $val )
{
if ( \IPS\Request::i()->theme_disk_cache_templates_checkbox )
{
if ( ! is_dir( \IPS\Request::i()->theme_disk_cache_path ) or ! is_readable( \IPS\Request::i()->theme_disk_cache_path ) or ! is_writable( \IPS\Request::i()->theme_disk_cache_path ) )
{
throw new \InvalidArgumentException( 'theme_disk_cache_path_wrong' );
}
}
}, NULL, NULL, 'theme_disk_cache_path' ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
@@ -351,7 +399,7 @@ class _advanced extends \IPS\Dispatcher\Controller
$table = new \IPS\Helpers\Table\Db( 'core_tasks', \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=tasks' ) );
$table->langPrefix = 'task_manager_';
$table->include = array( 'app', 'key', 'frequency', 'next_run' );
$table->include = array( 'app', 'key', 'frequency', 'next_run', 'last_run' );
$table->mainColumn = 'key';
$table->quickSearch = 'key';
$table->sortBy = $table->sortBy ?: 'next_run';
@@ -361,11 +409,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 ) );
return '(' . \IPS\Db::i()->in( '`key`', array_keys( $matches ) ) . " OR `key` LIKE '%{$val}%')";
}
else
{
return '1=0';
return "`key` LIKE '%{$val}%'";
}
};
@@ -376,6 +424,10 @@ class _advanced extends \IPS\Dispatcher\Controller
{
return $val ? \IPS\Application::load( $val )->_title : \IPS\Plugin::load( $row['plugin'] )->name;
}
catch ( \UnexpectedValueException $e )
{
return NULL;
}
catch ( \OutOfRangeException $e )
{
return NULL;
@@ -418,6 +470,10 @@ class _advanced extends \IPS\Dispatcher\Controller
{
return (string) \IPS\DateTime::ts( $row['next_run'] ?: time() );
}
},
'last_run' => function ( $v, $row )
{
return (string) $row['last_run'] ? \IPS\DateTime::ts( $row['last_run'] ) : \IPS\Member::loggedIn()->language()->addToStack( 'never' );
}
);
@@ -468,6 +524,8 @@ class _advanced extends \IPS\Dispatcher\Controller
*/
protected function taskSettings()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_tasks' );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Number( 'prune_log_tasks', \IPS\Settings::i()->prune_log_tasks, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'prune_log_tasks' ) );
@@ -627,7 +685,8 @@ class _advanced extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'furl_in_dev', '1C124/5', 403, '' );
}
$definition = \IPS\Http\Url::furlDefinition();
$definition = \IPS\Http\Url\Friendly::furlDefinition();
$table = new \IPS\Helpers\Table\Custom( $definition, \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&tab=furl' ) );
$table->include = array( 'friendly', 'real' );
$table->limit = 100;
@@ -645,14 +704,9 @@ class _advanced extends \IPS\Dispatcher\Controller
preg_match_all( '/{([@#])(.+?)}/', $row['friendly'], $matches );
if ( !empty( $matches[0] ) )
{
if ( $val )
{
$val .= '&';
}
foreach ( $matches[0] as $i => $m )
{
$val .= $matches[ 2 ][ $i ] . '=<strong><em>' . ( $matches[ 1 ][ $i ] == '#' ? '123' : 'abc' ) . '</em></strong>';
$val .= '&' . $matches[ 2 ][ $i ] . '=<strong><em>' . ( $matches[ 1 ][ $i ] == '#' ? '123' : 'abc' ) . '</em></strong>';
}
$val .= '</strong>';
}
@@ -684,7 +738,7 @@ class _advanced extends \IPS\Dispatcher\Controller
'data' => array( 'confirm' => '' )
);
}
$table->rowButtons = function( $row, $k ) use ( $definition )
{
$return = array(
@@ -698,17 +752,17 @@ class _advanced extends \IPS\Dispatcher\Controller
if( isset( $definition[ $k ]['custom'] ) )
{
$return['delete'] = array(
'icon' => 'times-circle',
'title' => 'delete',
$return['revert'] = array(
'icon' => 'undo',
'title' => 'revert',
'link' => \IPS\Http\Url::internal( "app=core&module=settings&controller=advanced&do=furlDelete&key={$k}" ),
'data' => array( 'delete' => '' )
'data' => array( 'confirm' => '', 'confirmMessage' => \IPS\Member::loggedIn()->language()->addToStack('revert_confirm') )
);
}
return $return;
};
return ( \IPS\Request::i()->advancedSearchForm ? '' : \IPS\Theme::i()->getTemplate('global')->message( 'furl_warning', 'warning' ) ) . $table;
}
@@ -722,7 +776,7 @@ class _advanced extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_furls' );
$current = NULL;
$config = \IPS\Http\Url::furlDefinition();
$config = \IPS\Http\Url\Friendly::furlDefinition();
if ( \IPS\Request::i()->key )
{
$current = ( isset( $config[ \IPS\Request::i()->key ] ) ) ? $config[ \IPS\Request::i()->key ] : NULL;
@@ -736,20 +790,51 @@ class _advanced extends \IPS\Dispatcher\Controller
{
$furl = \IPS\Settings::i()->furl_configuration ? json_decode( \IPS\Settings::i()->furl_configuration, TRUE ) : array();
$currentDefinition = \IPS\Http\Url::furlDefinition();
$save = \IPS\Request::i()->key ? $currentDefinition[ \IPS\Request::i()->key ] : array();
$save['friendly'] = $values['furl_friendly'];
$save['real'] = $values['furl_real'];
$save['custom'] = true;
$currentDefinition = \IPS\Http\Url\Friendly::furlDefinition();
$appTopLevel = NULL;
$appIsDefault = FALSE;
$alias = NULL;
$verify = NULL;
$friendly = $values['furl_friendly'];
if ( \IPS\Request::i()->key )
{
if ( isset( $currentDefinition[ \IPS\Request::i()->key ]['alias'] ) )
{
$alias = $currentDefinition[ \IPS\Request::i()->key ]['alias'];
}
if ( isset( $currentDefinition[ \IPS\Request::i()->key ]['verify'] ) )
{
$verify = $currentDefinition[ \IPS\Request::i()->key ]['verify'];
}
if ( isset( $currentDefinition[ \IPS\Request::i()->key ]['with_top_level'] ) )
{
$appIsDefault = TRUE;
$appTopLevel = mb_substr( $currentDefinition[ \IPS\Request::i()->key ]['with_top_level'], 0, -mb_strlen( $currentDefinition[ \IPS\Request::i()->key ]['friendly'] . '/' ) );
}
if ( isset( $currentDefinition[ \IPS\Request::i()->key ]['without_top_level'] ) )
{
$appIsDefault = FALSE;
if ( $currentDefinition[ \IPS\Request::i()->key ]['without_top_level'] )
{
$appTopLevel = mb_substr( $currentDefinition[ \IPS\Request::i()->key ]['friendly'], 0, -mb_strlen( $currentDefinition[ \IPS\Request::i()->key ]['without_top_level'] . '/' ) );
$friendly = rtrim( preg_replace( '/^' . preg_quote( $appTopLevel, '/' ) . '(\/|$)/', '', $friendly ), '/' );
}
}
}
$save = \IPS\Http\Url\Friendly::buildFurlDefinition( $friendly, $values['furl_real'], $appTopLevel, $appIsDefault, $alias, TRUE, $verify );
if ( \IPS\Request::i()->key )
{
$furl[ \IPS\Request::i()->key ] = $save;
}
else
{
$furl[] = $save;
$key = 'key' . ( count( $furl ) + 1 );
$furl[ $key ] = $save;
}
\IPS\Session::i()->log( 'acplogs__advanced_furl_edited' );
@@ -781,6 +866,9 @@ class _advanced extends \IPS\Dispatcher\Controller
protected function furlDelete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_furls' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$furlDefinition = \IPS\Settings::i()->furl_configuration ? json_decode( \IPS\Settings::i()->furl_configuration, TRUE ) : array();
if( isset( $furlDefinition[ \IPS\Request::i()->key ] ) )
@@ -0,0 +1,105 @@
<?php
/**
* @brief contactus
* @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 Sep 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\settings;
/* 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;
}
/**
* contactus
*/
class _contactus extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'contactus_manage' );
parent::execute();
}
/**
* Manage Settings
*
* @return void
*/
protected function manage()
{
$form = $this->_getConfigForm();
if ( $values = $form->values() )
{
$form->saveAsSettings();
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__contactus_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=contactus' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'r__contactus' );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( '', $form );
}
/**
* Build the configuration form
*
* @return \IPS\Helpers\Form
*/
protected function _getConfigForm()
{
$form = new \IPS\Helpers\Form;
$options = array();
$toggles = array();
$disabled = array();
$formFields = array();
$form->add( new \IPS\Helpers\Form\Select( 'contact_access', ( \IPS\Settings::i()->contact_access == '*' ) ? '*' : explode( ',', \IPS\Settings::i()->contact_access ), FALSE, array(
'options' => array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) ),
'multiple' => true,
'unlimited' => '*',
'unlimitedLang' => 'everyone'
), NULL, NULL, NULL, 'contact_access' ) );
/* Get extensions */
$extensions = \IPS\Application::allExtensions( 'core', 'ContactUs', FALSE, 'core', 'InternalEmail', TRUE );
foreach ( $extensions as $k => $class )
{
$class->process( $form, $formFields, $options, $toggles, $disabled );
}
$form->add( new \IPS\Helpers\Form\Radio( 'contact_type', \IPS\Settings::i()->contact_type, FALSE, array(
'options' => $options,
'toggles' => $toggles,
'disabled' => $disabled
) ) );
foreach ( $formFields AS $field )
{
$form->add( $field );
}
return $form;
}
// Create new methods with the same name as the 'do' parameter which should execute it
}
@@ -2,9 +2,9 @@
/**
* @brief email
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 17 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -46,17 +46,44 @@ class _email extends \IPS\Dispatcher\Controller
$settingsForm = new \IPS\Helpers\Form( 'settings_form' );
$settingsForm->addHeader( 'basic_settings' );
$settingsForm->add( new \IPS\Helpers\Form\Email( 'email_out', \IPS\Settings::i()->email_out, TRUE ) );
$settingsForm->add( new \IPS\Helpers\Form\Email( 'email_out', \IPS\Settings::i()->email_out, TRUE, array(), NULL, NULL, NULL, 'email_out' ) );
$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->addHeader( 'advanced_settings' );
$settingsForm->add( new \IPS\Helpers\Form\Select( 'mail_method', \IPS\Settings::i()->mail_method, TRUE, array(
'options' => array( 'mail' => 'mail_method_php', 'smtp' => 'mail_method_smtp' ),
$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 )
{
$method = 'sendgrid';
}
}
else
{
$disabled[] = 'sendgrid';
}
$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' ),
'disabled' => $disabled,
'toggles' => array(
'mail' => array( 'php_mail_extra' ),
'smtp' => array( 'smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_helo', 'smtp_protocol' )
'mail' => array( 'php_mail_extra' ),
'smtp' => array( 'smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_helo', 'smtp_protocol' ),
)
) ) );
$options = array( 'plain' => 'smtp_plaintext', 'ssl' => 'smtp_ssl', 'tls' => 'smtp_tls' );
@@ -65,7 +92,10 @@ class _email extends \IPS\Dispatcher\Controller
$settingsForm->add( new \IPS\Helpers\Form\Number( 'smtp_port', \IPS\Settings::i()->smtp_port, FALSE, array(), NULL, NULL, NULL, 'smtp_port' ) );
$settingsForm->add( new \IPS\Helpers\Form\Text( 'smtp_user', \IPS\Settings::i()->smtp_user, FALSE, array(), NULL, NULL, NULL, 'smtp_user' ) );
$settingsForm->add( new \IPS\Helpers\Form\Password( 'smtp_pass', \IPS\Settings::i()->smtp_pass, FALSE, array(), NULL, NULL, NULL, 'smtp_pass' ) );
$settingsForm->add( new \IPS\Helpers\Form\Text( 'php_mail_extra', \IPS\Settings::i()->php_mail_extra, FALSE, array(), NULL, NULL, NULL, 'php_mail_extra' ) );
if ( !\IPS\CIC )
{
$settingsForm->add( new \IPS\Helpers\Form\Text( 'php_mail_extra', \IPS\Settings::i()->php_mail_extra, FALSE, array(), NULL, NULL, NULL, 'php_mail_extra' ) );
}
if ( $values = $settingsForm->values() )
{
$sendTestEmail = FALSE;
@@ -77,28 +107,40 @@ class _email extends \IPS\Dispatcher\Controller
$sendTestEmail = TRUE;
}
}
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;
}
elseif ( $values['mail_method'] == 'sendgrid' )
{
$values['sendgrid_use_for'] = 2;
}
$settingsForm->saveAsSettings();
$settingsForm->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__email_settings' );
if( $sendTestEmail )
{
$email = \IPS\Email::buildFromContent( \IPS\Member::loggedIn()->language()->addToStack('email_test_subject'), \IPS\Member::loggedIn()->language()->addToStack('email_test_message'), \IPS\Member::loggedIn()->language()->addToStack('email_test_message') );
$email->from = \IPS\Settings::i()->email_out;
$result = $email->send( \IPS\Member::loggedIn()->email );
if ( $result === TRUE )
$email = \IPS\Email::buildFromContent( \IPS\Member::loggedIn()->language()->get('email_test_subject'), \IPS\Member::loggedIn()->language()->addToStack('email_test_message'), \IPS\Member::loggedIn()->language()->addToStack('email_test_message'), \IPS\Email::TYPE_TRANSACTIONAL );
try
{
$result = $email->_send( \IPS\Member::loggedIn(), array(), array(), \IPS\Settings::i()->email_out );
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay_auto', 'success' );
}
elseif( $result instanceof \IPS\Email\Outgoing\Exception )
catch ( \Exception $e )
{
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error_auto', 'error', $result->getMessage() );
}
/* If php mail fails it throws a regular PHP error */
elseif( $result instanceof \ErrorException )
{
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error_auto', 'error', $result->getMessage() );
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error_auto', 'error', $e->getMessage() );
}
}
}
@@ -122,22 +164,15 @@ class _email extends \IPS\Dispatcher\Controller
$testForm->add( new \IPS\Helpers\Form\TextArea( 'message', \IPS\Member::loggedIn()->language()->addToStack('email_test_message'), TRUE ) );
if ( $values = $testForm->values() )
{
$email = \IPS\Email::buildFromContent( $values['subject'], $values['message'], $values['message'] );
$email->from = $values['from'];
$result = $email->send( $values['to'] );
if ( $result === TRUE )
try
{
$email = \IPS\Email::buildFromContent( $values['subject'], $values['message'], $values['message'], \IPS\Email::TYPE_TRANSACTIONAL );
$result = $email->_send( $values['to'], array(), array(), $values['from'] );
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay', 'success' );
}
elseif( $result instanceof \IPS\Email\Outgoing\Exception )
catch ( \Exception $exception )
{
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error', 'error', $result->getMessage() );
}
/* If php mail fails it throws a regular PHP error */
elseif( $result instanceof \ErrorException )
{
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error', 'error', $result->getMessage() );
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( get_class( $exception ) . ": " . $exception->getMessage() . " (" . $exception->getCode() . ")", 'error' );
}
}
@@ -262,17 +297,32 @@ class _email extends \IPS\Dispatcher\Controller
{
\IPS\Dispatcher::i()->checkAcpPermission( 'email_errorlog' );
$id = (int) \IPS\Request::i()->id;
$log = \IPS\Db::i()->select( '*', 'core_mail_error_logs', array( 'mlog_id=?', $id ) )->first();
$email = json_decode( $log['mlog_resend_data'], true );
$id = (int) \IPS\Request::i()->id;
$log = \IPS\Db::i()->select( '*', 'core_mail_error_logs', array( 'mlog_id=?', $id ) )->first();
$emailData = json_decode( $log['mlog_resend_data'], true );
try
{
$emailHandler = \IPS\Email::buildFromRaw( $email['headers'], $email['body'] );
$emailHandler->subject = $log['mlog_subject'];
$emailHandler->to = explode( ',', $log['mlog_to'] );
$emailHandler->from = $log['mlog_from'];
$emailHandler->forceSend( $email['boundary'] );
$fromName = NULL;
if ( isset( $emailData['headers']['From'] ) and preg_match( '/=\?UTF-8\?B\?(.+?)?= /', $emailData['headers']['From'], $matches ) )
{
$fromName = base64_decode( $matches[1] );
}
/* Reset basic headers for failed mails */
unset( $emailData['headers']['MIME-Version'] );
unset( $emailData['headers']['Content-Type'] );
unset( $emailData['headers']['Content-Transfer-Encoding'] );
$email = \IPS\Email::buildFromContent( $log['mlog_subject'], $emailData['body']['html'], $emailData['body']['plain'], isset( $emailData['type'] ) ? $emailData['type'] : NULL );
$email->_send(
array_map( 'trim', explode( ',', $log['mlog_to'] ) ),
isset( $emailData['headers']['Cc'] ) ? array_map( 'trim', explode( ',', $emailData['headers']['Cc'] ) ) : array(),
isset( $emailData['headers']['Bcc'] ) ? array_map( 'trim', explode( ',', $emailData['headers']['Bcc'] ) ) : array(),
$log['mlog_from'],
$fromName,
$emailData['headers']
);
}
catch( \Exception $e )
{
@@ -2,9 +2,9 @@
/**
* @brief general
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 17 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -49,7 +49,8 @@ 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\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' ) ) );
$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 ) );
if ( $values = $form->values() )
{
@@ -2,9 +2,9 @@
/**
* @brief licensekey
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 17 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -50,14 +50,13 @@ class _licensekey extends \IPS\Dispatcher\Controller
$licenseData = \IPS\IPS::licenseKey();
/* If no license key has been supplied yet just show the form */
if( !isset( $licenseData['key'] ) )
if( !\IPS\Settings::i()->ipb_reg_number )
{
return $this->settings();
}
/* Output */
/* Init */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('license_settings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'licensekey', 'core' )->overview( $licenseData );
\IPS\Output::i()->sidebar['actions'] = array(
'refresh' => array(
'icon' => 'refresh',
@@ -71,6 +70,17 @@ class _licensekey extends \IPS\Dispatcher\Controller
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('license_change') )
),
);
/* If we have a license key, but the server doesn't recognise it, show an error */
if ( !$licenseData )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( 'license_not_recognised', 'error' );
}
/* Otherwise show the normal info */
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'licensekey', 'core' )->overview( $licenseData );
}
}
/**
@@ -94,10 +104,30 @@ class _licensekey extends \IPS\Dispatcher\Controller
*/
protected function settings()
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'ipb_reg_number', NULL, TRUE, array(), function( $val ){
\IPS\IPS::checkLicenseKey( $val, \IPS\Settings::i()->base_url );
} ) );
$$form = new \IPS\Helpers\Form;
$form->addHeader('ipb_license_edit_main');
$form->add( new \IPS\Helpers\Form\Text( 'ipb_reg_number', \IPS\Settings::i()->ipb_reg_number, TRUE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_active', \IPS\Settings::i()->ipb_license_active ) );
$form->add( new \IPS\Helpers\Form\Text( 'ipb_license_expires', \IPS\Settings::i()->ipb_license_expires ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_cloud', \IPS\Settings::i()->ipb_license_cloud ) );
$form->addHeader('ipb_license_urls');
$form->add( new \IPS\Helpers\Form\Text( 'ipb_license_url', \IPS\Settings::i()->ipb_license_url ) );
$form->add( new \IPS\Helpers\Form\Text( 'ipb_license_test_url', \IPS\Settings::i()->ipb_license_test_url ) );
$form->addHeader('ipb_license_components');
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_forums', \IPS\Settings::i()->ipb_license_product_forums ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_calendar', \IPS\Settings::i()->ipb_license_product_calendar ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_blog', \IPS\Settings::i()->ipb_license_product_blog ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_gallery', \IPS\Settings::i()->ipb_license_product_gallery ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_downloads', \IPS\Settings::i()->ipb_license_product_downloads ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_cms', \IPS\Settings::i()->ipb_license_product_cms ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_nexus', \IPS\Settings::i()->ipb_license_product_nexus ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_license_product_copyright', \IPS\Settings::i()->ipb_license_product_copyright ) );
$form->addHeader('ipb_license_services');
$form->add( new \IPS\Helpers\Form\Text( 'ipb_license_chat_limit', \IPS\Settings::i()->ipb_license_chat_limit ) );
$form->add( new \IPS\Helpers\Form\Text( 'ipb_license_support', \IPS\Settings::i()->ipb_license_support ) );
if ( $values = $form->values() )
{
@@ -2,9 +2,9 @@
/**
* @brief Login Handlers
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 15 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -64,7 +64,7 @@ class _login extends \IPS\Node\Controller
/* Show IPS Connect "master" information */
$masterUrl = \IPS\Http\Url::internal( 'applications/core/interface/ipsconnect/ipsconnect.php', 'none' );
$masterKey = md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start );
$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 );
@@ -117,6 +117,9 @@ class _login extends \IPS\Node\Controller
{
\IPS\Output::i()->error( 'login_atleast_one', '1C166/3', 403, '' );
}
/* Allow the login handler to do stuff on-disable */
$node->onDisable();
}
/* Clear guest page caches */
@@ -124,28 +127,6 @@ class _login extends \IPS\Node\Controller
return parent::enableToggle();
}
/**
* Delete
*
* @return void
*/
protected function delete()
{
$node = \IPS\Login\LoginAbstract::load( \IPS\Request::i()->id );
$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, '' );
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
return parent::delete();
}
/**
* Settings
@@ -158,7 +139,7 @@ class _login extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form();
$form->addHeader( 'ipb_bruteforce_attempts' );
$form->add( new \IPS\Helpers\Form\Number( 'ipb_bruteforce_attempts', \IPS\Settings::i()->ipb_bruteforce_attempts, FALSE, array( 'min' => 0, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('failed_logins'), 'ipb_bruteforce_attempts' ) );
$form->add( new \IPS\Helpers\Form\Number( 'ipb_bruteforce_period', \IPS\Settings::i()->ipb_bruteforce_period, FALSE, array( 'min' => 0, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('minutes'), 'ipb_bruteforce_period' ) );
$form->add( new \IPS\Helpers\Form\Number( 'ipb_bruteforce_period', \IPS\Settings::i()->ipb_bruteforce_period, FALSE, array( 'min' => 0, 'max' => 10000, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('minutes'), 'ipb_bruteforce_period' ) );
$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' );
@@ -193,9 +174,33 @@ class _login extends \IPS\Node\Controller
if ( $values = $form->values() )
{
$values['disable_anonymous'] = $values['disable_anonymous'] ? FALSE : TRUE;
/* unlock all locked members if we have disabled the locking */
if ( \IPS\Settings::i()->ipb_bruteforce_attempts > 0 AND $values['ipb_bruteforce_attempts'] == 0 )
{
\IPS\Member::updateAllMembers( array( 'failed_logins' => NULL , 'failed_login_count' => 0 ) );
/* disable task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='unlockmembers'" );
}
else if ( $values['ipb_bruteforce_attempts'] > 0 )
{
/* enable task */
\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();
@@ -262,8 +267,8 @@ class _login extends \IPS\Node\Controller
/* 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()->delete( 'core_ipsconnect_slaves', 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' )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
\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' )
@@ -293,7 +298,7 @@ class _login extends \IPS\Node\Controller
\IPS\Session::i()->log( 'acplog__connect_queue_cleared' );
/* Disable task */
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='ipsconnect'" );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='connect'" );
return NULL;
}
@@ -0,0 +1,268 @@
<?php
/**
* @brief Multi-Factor Authentication
* @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 30 Nov 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\settings;
/* 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;
}
/**
* Multi-Factor Authentication
*/
class _mfa extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'mfa_manage' );
parent::execute();
}
/**
* Manage
*
* @return void
*/
protected function manage()
{
$activeTabContents = '';
$tabs = array(
'handlers' => 'mfa_handlers',
'settings' => 'mfa_settings'
);
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'handlers';
if ( $activeTab === 'handlers' )
{
$activeTabContents = $this->_manageHandlers();
}
else
{
$activeTabContents = $this->_manageSettings();
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_mfa');
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=settings&controller=mfa" ) );
}
}
/**
* Manage Handlers
*
* @return string
*/
protected function _manageHandlers()
{
/* Create the tree */
$url = \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa&tab=handlers" );
$tree = new \IPS\Helpers\Tree\Tree(
$url,
NULL,
function() use( $url ) {
$return = array();
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
{
$return[] = \IPS\Theme::i()->getTemplate( 'trees', 'core' )->row(
$url,
$key,
\IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_title"),
FALSE,
array(
'settings' => array(
'icon' => 'cog',
'title' => 'settings',
'link' => $url->setQueryString( array( 'do' => 'settings', 'key' => $key ) ),
)
),
\IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_desc"),
NULL,
NULL,
TRUE,
$handler->isEnabled()
);
}
return $return;
},
NULL,
NULL,
NULL
);
/* Return */
return \IPS\Theme::i()->getTemplate( 'forms' )->blurb( 'mfa_blurb', TRUE, TRUE ) . $tree;
}
/**
* Enable/Disable Toggle
*
* @return void
*/
protected function enableToggle()
{
$key = \IPS\Request::i()->id;
$handlers = \IPS\MFA\MFAHandler::handlers();
if ( !isset( $handlers[ $key ] ) )
{
\IPS\Output::i()->error( 'node_error', '2C345/1', 404, '' );
}
try
{
$handlers[ $key ]->toggle( \IPS\Request::i()->status );
if ( \IPS\Request::i()->status )
{
\IPS\Session::i()->log( 'acplogs__mfa_handler_enabled', array( "mfa_{$key}_title" => TRUE ) );
}
else
{
\IPS\Session::i()->log( 'acplogs__mfa_handler_disabled', array( "mfa_{$key}_title" => TRUE ) );
}
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json('OK');
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa" ) );
}
}
catch ( \LogicException $e )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->error( $e->getMessage(), $e->getCode() );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=enhancements&do=edit&id=" . \IPS\Request::i()->id ) );
}
}
}
/**
* Handler Settings
*
* @return void
*/
protected function settings()
{
$key = \IPS\Request::i()->key;
$handlers = \IPS\MFA\MFAHandler::handlers();
if ( !isset( $handlers[ $key ] ) )
{
\IPS\Output::i()->error( 'node_error', '2C345/2', 404, '' );
}
$output = $handlers[ $key ]->acpSettings();
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_title");
\IPS\Output::i()->output = $output;
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal('app=core&module=settings&controller=mfa&tab=handlers'), \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_mfa') );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_title") );
}
/**
* Manage Settings
*
* @return string
*/
protected function _manageSettings()
{
$form = new \IPS\Helpers\Form;
$form->addHeader('mfa_header_setup');
$groups = array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) );
$form->add( new \IPS\Helpers\Form\Select( 'mfa_required_groups', \IPS\Settings::i()->mfa_required_groups == '*' ? '*' : explode( ',', \IPS\Settings::i()->mfa_required_groups ), FALSE, array(
'multiple' => TRUE,
'options' => $groups,
'unlimited' => '*',
'unlimitedLang' => 'everyone',
) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'mfa_required_prompt', \IPS\Settings::i()->mfa_required_prompt, FALSE, array(
'options' => array(
'immediate' => 'mfa_prompt_immediate',
'access' => 'mfa_prompt_access',
)
), NULL, NULL, NULL, 'mfa_required_prompt' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'mfa_optional_prompt', \IPS\Settings::i()->mfa_optional_prompt, FALSE, array(
'options' => array(
'immediate' => 'mfa_prompt_immediate',
'access' => 'mfa_prompt_access',
'none' => 'mfa_prompt_none',
),
'toggles' => array(
'immediate' => array( 'security_questions_opt_out_warning' ),
'access' => array( 'security_questions_opt_out_warning' ),
)
), NULL, NULL, NULL, 'mfa_optional_prompt' ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'security_questions_opt_out_warning', NULL, FALSE, array( 'app' => 'core', 'key' => 'security_questions_opt_out_warning_value' ), NULL, NULL, NULL, 'security_questions_opt_out_warning' ) );
$form->addHeader('mfa_header_authentication');
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'security_questions_areas', \IPS\Settings::i()->security_questions_areas ? explode( ',', \IPS\Settings::i()->security_questions_areas ) : array_keys( \IPS\MFA\MFAHandler::areas() ), FALSE, array( 'options' => \IPS\MFA\MFAHandler::areas() ), NULL, NULL, NULL, 'security_questions_areas' ) );
$form->add( new \IPS\Helpers\Form\Number( 'security_questions_timer', \IPS\Settings::i()->security_questions_timer, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'security_questions_timer_session' ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('minutes') ) );
$form->addHeader('mfa_header_recovery');
$form->add( new \IPS\Helpers\Form\Number( 'security_questions_tries', \IPS\Settings::i()->security_questions_tries, FALSE, array( 'min' => 1 ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'mfa_lockout_behaviour', \IPS\Settings::i()->mfa_lockout_behaviour, FALSE, array(
'options' => array(
'lock' => 'mfa_lockout_behaviour_lock',
'email' => 'mfa_lockout_behaviour_email',
'contact' => 'mfa_lockout_behaviour_contact',
),
'toggles' => array(
'lock' => array( 'mfa_lockout_time' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Number( 'mfa_lockout_time', \IPS\Settings::i()->mfa_lockout_time, FALSE, array( 'min' => 1 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('minutes'), 'mfa_lockout_time' ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'mfa_forgot_behaviour', explode( ',', \IPS\Settings::i()->mfa_forgot_behaviour ), FALSE, array(
'options' => array(
'email' => 'mfa_forgot_behaviour_email',
'contact' => 'mfa_forgot_behaviour_contact',
)
) ) );
if ( $values = $form->values() )
{
\IPS\Lang::saveCustom( 'core', 'security_questions_opt_out_warning_value', $values['security_questions_opt_out_warning'] );
unset( $values['security_questions_opt_out_warning'] );
$values['mfa_required_groups'] = ( $values['mfa_required_groups'] == '*' ) ? '*' : implode( ',', $values['mfa_required_groups'] );
$values['mfa_forgot_behaviour'] = implode( ',', $values['mfa_forgot_behaviour'] );
$values['security_questions_areas'] = implode( ',', $values['security_questions_areas'] );
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__mfa_settings_updated' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=mfa&tab=settings' ), 'saved' );
}
return (string) $form;
}
}
@@ -2,9 +2,9 @@
/**
* @brief Manage Posting Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 20 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -112,13 +112,15 @@ class _posting extends \IPS\Dispatcher\Controller
) ) );
$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');
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_remote_images', \IPS\Settings::i()->allow_remote_images, FALSE, array( 'togglesOn' => array( 'remote_image_proxy' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'remote_image_proxy', \IPS\Settings::i()->remote_image_proxy, FALSE, array(), NULL, NULL, NULL, 'remote_image_proxy' ) );
$form->add( new \IPS\Helpers\Form\WidthHeight( 'attachment_resample_size', \IPS\Settings::i()->attachment_resample_size ? explode( 'x', \IPS\Settings::i()->attachment_resample_size ) : array( 0, 0 ), FALSE, array( 'resizableDiv' => FALSE, 'unlimited' => array( 0, 0 ) ), NULL, NULL, NULL, 'attachment_resample_size' ) );
$current = ( isset( \IPS\Settings::i()->attachment_image_size ) ) ? explode( 'x', \IPS\Settings::i()->attachment_image_size ) : array( 1000, 750 );
$form->add( new \IPS\Helpers\Form\WidthHeight( 'attachment_image_size', $current, FALSE, array( 'resizableDiv' => FALSE ), NULL, NULL, NULL, 'attachment_image_size' ) );
$form->add( new \IPS\Helpers\Form\Number( 'max_video_width', \IPS\Settings::i()->max_video_width, FALSE, array( 'unlimited' => 0 ), NULL, NULL, 'px' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'editor_embeds', \IPS\Settings::i()->editor_embeds, FALSE, array( 'togglesOn' => array( 'max_video_width' ) ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'max_video_width', \IPS\Settings::i()->max_video_width, FALSE, array( 'unlimited' => 0 ), NULL, NULL, 'px', 'max_video_width' ) );
$form->addHeader('remote_images');
$form->add( new \IPS\Helpers\Form\YesNo( 'allow_remote_images', \IPS\Settings::i()->allow_remote_images, FALSE, array( 'togglesOn' => array( 'remote_image_proxy' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'remote_image_proxy', \IPS\Settings::i()->remote_image_proxy, FALSE, array( 'togglesOn' => array( 'remote_image_proxy_cache' ) ), NULL, NULL, NULL, 'remote_image_proxy' ) );
$form->add( new \IPS\Helpers\Form\Number( 'image_proxy_cache_period', \IPS\Settings::i()->image_proxy_cache_period, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'indefinitely' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('for'), \IPS\Member::loggedIn()->language()->addToStack('days'), 'remote_image_proxy_cache' ) );
$form->addHeader('posting_content');
$form->add( new \IPS\Helpers\Form\Number( 'max_title_length', \IPS\Settings::i()->max_title_length, FALSE, array( 'max' => 255 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('max_title_length_suffix') ) );
$form->add( new \IPS\Helpers\Form\Number( 'merge_concurrent_posts', \IPS\Settings::i()->merge_concurrent_posts, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('minutes') ) );
@@ -169,6 +171,8 @@ class _posting extends \IPS\Dispatcher\Controller
/* Save values */
if ( $values = $form->values() )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => (int) $values['allow_remote_images'] ), array( '`key`=?', 'imageproxy' ) );
$clearCss = ( $values['max_video_width'] !== \IPS\Settings::i()->max_video_width );
$values['attachment_resample_size'] = implode( 'x', $values['attachment_resample_size'] );
@@ -208,71 +212,7 @@ class _posting extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'posting_manage_profanity' );
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_profanity_filters', \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=profanityFilters' ) );
$table->langPrefix = 'profanity_';
$table->mainColumn = 'type';
/* Columns we need */
$table->include = array( 'type', 'swop', 'm_exact' );
/* Default sort options */
$table->sortBy = $table->sortBy ?: 'type';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Filters */
$table->filters = array(
'profanity_filter_exact' => 'm_exact=1',
'profanity_filter_loose' => 'm_exact=0',
);
/* Search */
$table->quickSearch = 'type';
/* Custom parsers */
$table->parsers = array(
'm_exact' => function( $val, $row )
{
return ( $val ) ? \IPS\Member::loggedIn()->language()->addToStack('profanity_filter_exact') : \IPS\Member::loggedIn()->language()->addToStack('profanity_filter_loose');
}
);
/* Specify the root buttons */
$table->rootButtons['add'] = array(
'icon' => 'plus',
'title' => 'profanity_add',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=profanity' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('profanity_add') )
);
$table->rootButtons['download'] = array(
'icon' => 'download',
'title' => 'download',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=downloadProfanity' ),
'data' => array( 'confirm' => '', 'confirmMessage' => \IPS\Member::loggedIn()->language()->addToStack('profanity_download'), 'confirmIcon' => 'info', 'confirmButtons' => json_encode( array( 'ok' => \IPS\Member::loggedIn()->language()->addToStack('download'), 'cancel' => \IPS\Member::loggedIn()->language()->addToStack('cancel') ) ) )
);
/* And the row buttons */
$table->rowButtons = function( $row )
{
$return = array();
$return['edit'] = array(
'icon' => 'pencil',
'title' => 'edit',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=profanity&id=' ) . $row['wid'],
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('edit') )
);
$return['delete'] = array(
'icon' => 'times',
'title' => 'delete',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=deleteProfanityFilters&id=' ) . $row['wid'],
'data' => array( 'delete' => '' ),
);
return $return;
};
$table = \IPS\core\Profanity::table();
/* So people don't set up filters, test with their admin account and think it's not working */
$groupsThatBypass = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_groups', array( 'g_bypass_badwords=1' ) ), 'IPS\Member\Group' );
@@ -311,14 +251,36 @@ class _posting extends \IPS\Dispatcher\Controller
'black' => 'url_blacklist',
'white' => "url_whitelist" ),
'toggles' => array(
'black' => array( 'ipb_url_blacklist' ),
'white' => array( 'ipb_url_whitelist' ),
'none' => array(),
'black' => array( 'ipb_url_blacklist', 'url_filter_action' ),
'white' => array( 'ipb_url_whitelist', 'url_filter_action' ),
'none' => array( 'url_filter_any_action' ),
)
) ) );
$form->add( new \IPS\Helpers\Form\Stack( 'ipb_url_whitelist', \IPS\Settings::i()->ipb_url_whitelist ? explode( ",", \IPS\Settings::i()->ipb_url_whitelist ) : array(), FALSE, array(), NULL, NULL, NULL, 'ipb_url_whitelist' ) );
$form->add( new \IPS\Helpers\Form\Stack( 'ipb_url_blacklist', \IPS\Settings::i()->ipb_url_blacklist ? explode( ",", \IPS\Settings::i()->ipb_url_blacklist ) : array(), FALSE, array(), NULL, NULL, NULL, 'ipb_url_blacklist' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'url_filter_action', \IPS\Settings::i()->url_filter_action, FALSE, array(
'options' => array(
'block' => 'url_filter_block',
'moderate' => 'url_filter_moderate'
),
'descriptions' => array(
'block' => 'url_filter_block_desc',
'moderate' => 'url_filter_moderate_desc'
)
), NULL, NULL, NULL, 'url_filter_action' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'url_filter_any_action', \IPS\Settings::i()->url_filter_any_action, FALSE, array(
'options' => array(
'allow' => 'url_filter_any_allow',
'moderate' => 'url_filter_any_moderate'
),
'description' => array(
'allow' => 'url_filter_any_allow_desc',
'moderate' => 'url_filter_any_moderate_desc'
)
), NULL, NULL, NULL, 'url_filter_any_action' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'links_external', \IPS\Settings::i()->links_external ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'posts_add_nofollow', \IPS\Settings::i()->posts_add_nofollow, FALSE, array( 'togglesOn' => array( 'posts_add_nofollow_exclude' ) ), NULL, NULL, NULL, 'posts_add_nofollow' ) );
@@ -336,6 +298,8 @@ class _posting extends \IPS\Dispatcher\Controller
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__url_filter_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=urlFilters' ), 'saved' );
}
return $form;
@@ -374,17 +338,14 @@ class _posting extends \IPS\Dispatcher\Controller
);
/* Specify the buttons */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'acronym', 'acronym_add' ) )
{
$table->rootButtons = array(
'add' => array(
'icon' => 'plus',
'title' => 'acronym_add',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=acronym' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acronym_add') )
)
);
}
$table->rootButtons = array(
'add' => array(
'icon' => 'plus',
'title' => 'acronym_add',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=acronym' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acronym_add') )
)
);
$table->rowButtons = function( $row )
{
@@ -498,29 +459,13 @@ class _posting extends \IPS\Dispatcher\Controller
{
try
{
$current = \IPS\Db::i()->select( '*', 'core_profanity_filters', array( 'wid=?', \IPS\Request::i()->id ) )->first();
$current = \IPS\core\Profanity::load( \IPS\Request::i()->id );
}
catch ( \UnderflowException $e ) { }
catch ( \OutOfRangeException $e ) { }
}
/* Build form */
$form = new \IPS\Helpers\Form();
if ( !$current )
{
$form->addTab('add');
}
$form->add( new \IPS\Helpers\Form\Text( 'profanity_type', ( $current ) ? $current['type'] : NULL, NULL, array() ) );
$form->add( new \IPS\Helpers\Form\Text( 'profanity_swop', ( $current ) ? $current['swop'] : NULL, NULL, array() ) );
$form->add( new \IPS\Helpers\Form\Radio( 'profanity_m_exact', ( $current ) ? $current['m_exact'] : NULL, FALSE, array(
'options' => array(
'1' => 'profanity_filter_exact',
'0' => 'profanity_filter_loose' ) )
) );
if ( !$current )
{
$form->addTab('upload');
$form->add( new \IPS\Helpers\Form\Upload( 'profanity_upload', NULL, NULL, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ) ) );
}
$form = \IPS\core\Profanity::form( $current );
/* Handle submissions */
if ( $values = $form->values() )
@@ -533,33 +478,34 @@ class _posting extends \IPS\Dispatcher\Controller
move_uploaded_file( $values['profanity_upload'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=importProfanity&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=importProfanity' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) ) );
}
/* Normal */
else
{
if ( $values['profanity_type'] and $values['profanity_swop'] )
if ( $values['profanity_type'] )
{
$save = array(
'type' => $values['profanity_type'],
'swop' => $values['profanity_swop'],
'm_exact' => $values['profanity_m_exact']
);
if( $current )
if ( $values['profanity_action'] == 'swap' AND !$values['profanity_swop'] )
{
\IPS\Db::i()->update( 'core_profanity_filters', $save, array( 'wid=?', $current['wid'] ) );
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'profanity_add_error' );
}
else
{
\IPS\Db::i()->insert( 'core_profanity_filters', $save );
$save = array(
'type' => $values['profanity_type'],
'swop' => $values['profanity_swop'],
'm_exact' => $values['profanity_m_exact'],
'action' => $values['profanity_action']
);
\IPS\core\Profanity::createFromForm( $save, $current );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=profanityFilters' ), 'saved' );
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=profanityFilters' ), 'saved' );
}
else
{
@@ -591,20 +537,24 @@ class _posting extends \IPS\Dispatcher\Controller
$xml->startDocument( '1.0', 'UTF-8' );
$xml->startElement('badwordexport');
$xml->startElement('badwordgroup');
foreach ( \IPS\Db::i()->select( '*', 'core_profanity_filters' ) as $profanity )
foreach ( \IPS\core\Profanity::getProfanity() as $profanity )
{
$xml->startElement('badword');
$xml->startElement('type');
$xml->text( $profanity['type'] );
$xml->text( $profanity->type );
$xml->endElement();
$xml->startElement('swop');
$xml->text( $profanity['swop'] );
$xml->text( $profanity->swop );
$xml->endElement();
$xml->startElement('m_exact');
$xml->text( $profanity['m_exact'] );
$xml->text( $profanity->m_exact );
$xml->endElement();
$xml->startElement('action');
$xml->text( $profanity->action );
$xml->endElement();
$xml->endElement();
@@ -628,13 +578,15 @@ class _posting extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'generic_error', '3C256/1', 500, '' );
}
$url = \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=importProfanity&file=' . urlencode( \IPS\Request::i()->file ) . '&key=' . \IPS\Request::i()->key );
$url = \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&do=importProfanity' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key ) );
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
$url,
function( $data )
{
$data = intval( $data );
/* Open XML file */
$xml = new \XMLReader;
$xml = new \IPS\Xml\XMLReader;
$xml->open( \IPS\Request::i()->file );
$xml->read(); //badwordexport
$xml->read(); //badwordexport
@@ -663,14 +615,17 @@ class _posting extends \IPS\Dispatcher\Controller
$xml->next();
$xml->read();
$save['m_exact'] = $xml->readString();
$xml->next();
$xml->read();
$save['action'] = $xml->readString();
try
{
$current = \IPS\Db::i()->select( 'wid', 'core_profanity_filters', array( 'type=?', $save['type'] ) )->first();
\IPS\Db::i()->update( 'core_profanity_filters', $save, array( 'wid=?', $current ) );
$current = \IPS\core\Profanity::load( $save['type'], 'type' );
\IPS\core\Profanity::createFromForm( $save, $current );
}
catch ( \UnderflowException $e )
catch ( \OutOfRangeException $e )
{
\IPS\Db::i()->insert( 'core_profanity_filters', $save );
\IPS\core\Profanity::createFromForm( $save );
}
/* Move to next */
@@ -683,6 +638,8 @@ class _posting extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=profanityFilters' ) );
}
);
@@ -731,9 +688,12 @@ class _posting extends \IPS\Dispatcher\Controller
public function deleteProfanityFilters()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'posting_manage_profanity' );
\IPS\Db::i()->delete( 'core_profanity_filters', array( 'wid=?', \IPS\Request::i()->id ) );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\core\Profanity::load( \IPS\Request::i()->id )->delete();
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
@@ -749,7 +709,10 @@ class _posting extends \IPS\Dispatcher\Controller
public function deleteAcronym()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'posting_manage_acronym' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
\IPS\core\Acronym::load( \IPS\Request::i()->id )->delete();
/* Clear guest page caches */
@@ -758,4 +721,17 @@ class _posting extends \IPS\Dispatcher\Controller
/* And redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=posting&tab=acronymExpansion" ) );
}
/**
* Rebuild attachment thumbnails
*
* @return void
*/
public function rebuildThumbnails()
{
\IPS\Task::queue( 'core', 'RebuildAttachmentThumbnails', array(), 4 );
/* And redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=posting" ), 'thumbnails_rebuilt' );
}
}
@@ -0,0 +1,72 @@
<?php
/**
* @brief Security Questions
* @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 26 Aug 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\settings;
/* 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 Questions
*/
class _securityquestions extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\MFA\SecurityQuestions\Question';
/**
* Form
*
* @return void
*/
public function form()
{
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal('app=core&module=settings&controller=mfa&tab=handlers'), \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_mfa') );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal('app=core&module=settings&controller=mfa&tab=questions&do=settings&key=questions'), \IPS\Member::loggedIn()->language()->addToStack("mfa_questions_title") );
parent::form();
}
/**
* Settings
*
* @return void
*/
protected function settings()
{
return $this->manage();
}
/**
* 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( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array() );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions&tab=questions'), 'saved' );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Manage Terms & Privacy Policy
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 07 Jun 2013
* @version SVN_VERSION_NUMBER
*/
@@ -76,6 +76,10 @@ class _terms extends \IPS\Dispatcher\Controller
$form->addHeader( 'terms_registration' );
$form->add( new \IPS\Helpers\Form\Translatable( 'reg_rules', NULL, FALSE, array( 'app' => 'core', 'key' => 'reg_rules_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'RegistrationRules', 'attachIds' => array( NULL, NULL, 'reg_rules' ) ) ), NULL, NULL, NULL, 'reg_rules_id' ) );
$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' ) );
if ( $values = $form->values() )
{
/* What were our previous values? */
@@ -83,8 +87,17 @@ class _terms extends \IPS\Dispatcher\Controller
$existingRegistrationTerms = iterator_to_array( \IPS\Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'reg_rules_value' ) ) );
/* Save */
foreach ( array( 'gl_guidelines' => 'guidelines_value', 'privacy_text' => 'privacy_text_value', 'reg_rules' => 'reg_rules_value' ) as $k => $v )
foreach ( array( 'gl_guidelines' => 'guidelines_value', 'privacy_text' => 'privacy_text_value', 'reg_rules' => 'reg_rules_value', 'guest_terms_bar_text' => 'guest_terms_bar_text_value' ) as $k => $v )
{
/* Guest terms bar text has special replacements that need to be swapped to sprintf parameters */
if ( $k == 'guest_terms_bar_text' )
{
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 );
}
}
\IPS\Lang::saveCustom( 'core', $v, $values[ $k ] );
unset( $values[ $k ] );
}
@@ -137,11 +150,11 @@ class _terms extends \IPS\Dispatcher\Controller
{
if ( isset( $values['admin_reconfirm_reg_terms'] ) and $values['admin_reconfirm_reg_terms'] )
{
\IPS\Db::i()->update( 'core_members', "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_terms'] );
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_terms'] ) );
}
if ( isset( $values['admin_reconfirm_privacy'] ) and $values['admin_reconfirm_privacy'] )
{
\IPS\Db::i()->update( 'core_members', "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_privacy'] );
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_privacy'] ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=terms') );
+29 -11
View File
@@ -2,9 +2,9 @@
/**
* @brief Admin CP Restrictions
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 04 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -241,6 +241,8 @@ class _admin extends \IPS\Dispatcher\Controller
$current = $current->first();
}
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']}" ) );
}
}
@@ -392,12 +394,22 @@ class _admin extends \IPS\Dispatcher\Controller
protected function delete()
{
$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 )
if ( $current['row_id_type'] === 'member' )
{
\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 ) );
\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 );
\IPS\Dispatcher::i()->checkAcpPermission( 'restrictions_delete_member' );
}
else
{
\IPS\Dispatcher::i()->checkAcpPermission( 'restrictions_delete_group' );
}
/* 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 ) );
\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 );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=staff&controller=admin' ) );
}
@@ -417,16 +429,24 @@ class _admin extends \IPS\Dispatcher\Controller
$table->include = array( 'member_id', 'action', 'ip_address', 'ctime' );
$table->mainColumn = 'action';
$table->parsers = array(
'member_id' => function( $val )
'member_id' => function( $val, $row )
{
try
$member = \IPS\Member::load( $val );
if ( $member->member_id )
{
return htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
catch ( \OutOfRangeException $e )
else if ( $row['member_name'] != '' )
{
return htmlentities( $row['member_name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
else
{
// Member doesn't exist anymore, but we also haven't stored the name
return '';
}
},
'action' => function( $val, $row )
{
@@ -467,9 +487,7 @@ class _admin extends \IPS\Dispatcher\Controller
'member_id' => \IPS\Helpers\Table\SEARCH_MEMBER,
'ip_address' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'ctime' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'note' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
);
$table->quickSearch = 'note';
/* Add a button for settings */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'restrictions_adminlogs_prune' ) )
@@ -2,9 +2,9 @@
/**
* @brief Staff directory management
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Sep 2013
* @version SVN_VERSION_NUMBER
*/
@@ -35,6 +35,7 @@ class _directory extends \IPS\Node\Controller
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'leaders_manage' );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'staffdirectory/staffdirectory.css', 'core', 'admin' ) );
return parent::execute();
}
@@ -2,9 +2,9 @@
/**
* @brief moderators
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 24 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -154,37 +154,37 @@ class _moderators extends \IPS\Dispatcher\Controller
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_member' ) and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_group' ) )
{
$form->add( new \IPS\Helpers\Form\Radio( 'acprestrictions_type', NULL, TRUE, array( 'options' => array( 'g' => 'group', 'm' => 'member' ), 'toggles' => array( 'g' => array( 'acprestrictions_group' ), 'm' => array( 'acprestrictions_member' ) ) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'moderators_type', NULL, TRUE, array( 'options' => array( 'g' => 'group', 'm' => 'member' ), 'toggles' => array( 'g' => array( 'moderators_group' ), 'm' => array( 'moderators_member' ) ) ) ) );
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_member' ) )
{
$form->add( new \IPS\Helpers\Form\Select( 'acprestrictions_group', NULL, FALSE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal' ), NULL, NULL, NULL, 'acprestrictions_group' ) );
$form->add( new \IPS\Helpers\Form\Select( 'moderators_group', NULL, FALSE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal' ), NULL, NULL, NULL, 'moderators_group' ) );
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_group' ) )
{
$form->add( new \IPS\Helpers\Form\Member( 'acprestrictions_member', NULL, ( \IPS\Request::i()->acprestrictions_type === 'member' ), array(), NULL, NULL, NULL, 'acprestrictions_member' ) );
$form->add( new \IPS\Helpers\Form\Member( 'moderators_member', NULL, ( \IPS\Request::i()->moderators_type === 'member' ), array(), NULL, NULL, NULL, 'moderators_member' ) );
}
if ( $values = $form->values() )
{
$rowId = NULL;
if ( $values['acprestrictions_type'] === 'g' or !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_member' ) )
if ( $values['moderators_type'] === 'g' or !\IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'staff', 'moderators_add_member' ) )
{
\IPS\Dispatcher::i()->checkAcpPermission( 'moderators_add_group' );
$rowId = $values['acprestrictions_group'];
$rowId = $values['moderators_group'];
}
elseif ( $values['acprestrictions_member'] )
elseif ( $values['moderators_member'] )
{
\IPS\Dispatcher::i()->checkAcpPermission( 'moderators_add_member' );
$rowId = $values['acprestrictions_member']->member_id;
$rowId = $values['moderators_member']->member_id;
}
if ( $rowId !== NULL )
{
try
{
$current = \IPS\Db::i()->select( '*', 'core_moderators', array( "id=? AND type=?", $rowId, $values['acprestrictions_type'] ) )->first();
$current = \IPS\Db::i()->select( '*', 'core_moderators', array( "id=? AND type=?", $rowId, $values['moderators_type'] ) )->first();
}
catch( \UnderflowException $e )
{
@@ -195,7 +195,7 @@ class _moderators extends \IPS\Dispatcher\Controller
{
$current = array(
'id' => $rowId,
'type' => $values['acprestrictions_type'],
'type' => $values['moderators_type'],
'perms' => '*',
'updated' => time()
);
@@ -207,7 +207,7 @@ class _moderators extends \IPS\Dispatcher\Controller
$ext->onChange( $current, $values );
}
\IPS\Session::i()->log( 'acplog__moderator_created', array( ( $values['acprestrictions_type'] == 'g' ? \IPS\Member::loggedIn()->language()->get( "core_group_{$values['acprestrictions_group']}" ) : $values['acprestrictions_member']->name ) => FALSE ) );
\IPS\Session::i()->log( 'acplog__moderator_created', array( ( $values['moderators_type'] == 'g' ? \IPS\Member::loggedIn()->language()->get( "core_group_{$values['moderators_group']}" ) : $values['moderators_member']->name ) => FALSE ) );
unset (\IPS\Data\Store::i()->moderators);
}
@@ -378,7 +378,8 @@ class _moderators extends \IPS\Dispatcher\Controller
/* For node fields, if the value is 0 translate it to -1 so mod permissions can merge properly */
if( in_array( $k, $nodeFields ) )
{
if( $v == 0 )
/* If nothing is checked we have '', but if 'all' is checked then the value is 0 */
if( $v === 0 )
{
$v = -1;
$values[ $k ] = $v;
@@ -489,11 +490,27 @@ class _moderators extends \IPS\Dispatcher\Controller
protected function delete()
{
/* Load */
$current = \IPS\Db::i()->select( '*', 'core_moderators', array( "id=? AND type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) )->first();
if ( !$current )
try
{
$current = \IPS\Db::i()->select( '*', 'core_moderators', array( "id=? AND type=?", intval( \IPS\Request::i()->id ), \IPS\Request::i()->type ) )->first();
}
catch( \UnderflowException $e )
{
\IPS\Output::i()->error( 'node_error', '2C118/4', 404, '' );
}
/* Check acp restrictions */
if ( $current['type'] === 'm' )
{
\IPS\Dispatcher::i()->checkAcpPermission( 'moderators_delete_member' );
}
else
{
\IPS\Dispatcher::i()->checkAcpPermission( 'moderators_delete_group' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Delete */
\IPS\Db::i()->delete( 'core_moderators', array( array( "id=? AND type=?", $current['id'], $current['type'] ) ) );
@@ -524,14 +541,20 @@ class _moderators extends \IPS\Dispatcher\Controller
$table->include = array( 'member_id', 'action', 'ip_address', 'ctime' );
$table->mainColumn = 'action';
$table->parsers = array(
'member_id' => function( $val )
'member_id' => function( $val, $row )
{
try
$member = \IPS\Member::load( $val );
if ( $member->member_id )
{
return htmlentities( \IPS\Member::load( $val )->name, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
catch ( \OutOfRangeException $e )
else if ( $row['member_name'] != '' )
{
return htmlentities( $row['member_name'], \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
else
{
// Member doesn't exist anymore, but we also haven't stored the name
return '';
}
},
@@ -2,9 +2,9 @@
/**
* @brief Messenger Stats
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 3 June 2013
* @version SVN_VERSION_NUMBER
*/
@@ -31,7 +31,7 @@ class _pmstats extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Check permission */
\IPS\Dispatcher::i()->checkAcpPermission( 'messages_manage' );
\IPS\Dispatcher::i()->checkAcpPermission( 'messages_manage', 'core', 'members' );
$chart = new \IPS\Helpers\Chart\Dynamic( \IPS\Http\Url::internal( 'app=core&module=stats&controller=pmstats' ), 'core_message_posts', 'msg_date', '', array( 'isStacked' => TRUE ) );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('new_conversations'), 'number', 'SUM(msg_is_first_post)' );
@@ -2,9 +2,9 @@
/**
* @brief Registration Stats
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 3 June 2013
* @version SVN_VERSION_NUMBER
*/
@@ -31,14 +31,17 @@ class _registrationstats extends \IPS\Dispatcher\Controller
protected function manage()
{
/* Check permission */
\IPS\Dispatcher::i()->checkAcpPermission( 'registrations_manage' );
\IPS\Dispatcher::i()->checkAcpPermission( 'registrations_manage', 'core', 'members' );
$chart = new \IPS\Helpers\Chart\Dynamic( \IPS\Http\Url::internal( 'app=core&module=stats&controller=registrationstats' ), 'core_members', 'joined', '', array( 'isStacked' => FALSE ) );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_new_registrations'), 'number', 'COUNT(*)', FALSE );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_registrations_title');
$chart->availableTypes = array( 'LineChart', 'ColumnChart', 'BarChart' );
/* fetch only successful registered members ; if this needs to be changed, please review the other areas where we have the name<>? AND email<>? condition */
$chart->where[] = array( '( name<>? AND email<>? )', '', '' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_registrationstats');
\IPS\Output::i()->output = (string) $chart;
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief Error Logs
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 06 Aug 2013
* @version SVN_VERSION_NUMBER
*/
@@ -30,7 +30,7 @@ class _errorLogs extends \IPS\Dispatcher\Controller
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'support_dashboard' );
\IPS\Dispatcher::i()->checkAcpPermission( 'system_logs_view' );
parent::execute();
}
@@ -0,0 +1,106 @@
<?php
/**
* @brief hookedFiles
* @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 11 Nov 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\support;
/* 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;
}
/**
* hookedFiles
*/
class _hookedFiles extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'app_manage' );
parent::execute();
}
/**
* ...
*
* @return void
*/
protected function manage()
{
$table = new \IPS\Helpers\Table\Db( 'core_hooks', \IPS\Http\Url::internal( 'app=core&module=support&controller=hookedFiles' ) );
$table->langPrefix = 'hooks_';
$table->quickSearch = array( 'class', 'hook_class' );
$table->include = array( 'hooks_app', 'hooks_plugin', 'hooks_type', 'hooks_class', 'hooks_file' );
$table->parsers = array(
'hooks_app' => function( $val, $row )
{
try
{
return \IPS\Application::load($row['app'])->_title;
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
}
},
'hooks_plugin' => function( $val, $row )
{
try
{
return \IPS\Plugin::load($row['plugin'])->name;
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
}
},
'hooks_type' => function( $val, $row )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'plugin_hook_type_' . mb_strtolower( $row['type'] ) );
},
'hooks_class' => function( $val, $row )
{
return $row['class'];
},
'hooks_file' => function( $val, $row )
{
if ( $row['app'] )
{
return '/applications/' . $row['app'] . '/hooks/' . $row['filename'] . '.php';
}
else if ( $row['plugin'] )
{
try
{
$plugin = \IPS\Plugin::load($row['plugin']);
return '/plugins' . ( $plugin->location ? '/' . $plugin->location . '/hooks/' : '/' ) . $row['filename'] . '.php';
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('hook_class_none');
}
}
}
);
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'hooked_classes' );
\IPS\Output::i()->output = $table;
}
}
@@ -0,0 +1,179 @@
<?php
/**
* @brief recovery
* @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 03 Nov 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\support;
/* 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;
}
/**
* recovery
*/
class _recovery extends \IPS\Dispatcher\Controller
{
/**
* Recover
*
* @return void
*/
protected function manage()
{
/* Are we even in recovery mode? */
if ( \IPS\RECOVERY_MODE === FALSE )
{
\IPS\Output::i()->error( 'recovery_mode_disabled', '1C342/1', 403, '' );
}
if ( \IPS\NO_WRITES === TRUE )
{
\IPS\Output::i()->error( 'no_writes', '1C342/2', 403, '' );
}
/* We are, let's set up a multi-redirect to disable things. At the end of the process, we'll list everything we did. */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'recovery_mode' );
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=recovery' ), function( $step )
{
$step = intval( $step );
switch( $step )
{
case 0: # Applications
$appsDisabled = array();
/* Disable All non-IPS Applications */
foreach( \IPS\Application::applications() AS $app )
{
if ( !in_array( $app->directory, \IPS\Application::$ipsApps ) )
{
$app->_enabled = FALSE;
$appDisabled[] = $app->_id;
}
}
$_SESSION['recoveryApps'] = $appsDisabled;
return array( 1, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_applications' ), 25 );
break;
case 1: # Plugins
$pluginsDisabled = array();
/* Disable All Plugins */
foreach( \IPS\Plugin::plugins() AS $plugin )
{
$plugin->_enabled = FALSE;
$plugin->save();
$pluginsDisabled[] = $plugin->_id;
}
$_SESSION['recoveryPlugins'] = $pluginsDisabled;
return array( 2, \IPS\Member::loggedIn()->language()->addToStack( 'disabled_plugins' ), 50 );
break;
case 2: # Reset Theme
$themeReset = FALSE;
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', array( "template_set_id>?", 0 ) )->first() OR \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', array( "css_set_id>?", 0 ) )->first() )
{
/* Create a new theme */
$theme = new \IPS\Theme;
$theme->permissions = \IPS\Member::loggedIn()->member_group_id;
$theme->save();
$theme->installThemeSettings();
$theme->copyResourcesFromSet();
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $theme->id, "IPS Support" );
/* Set this account to use that theme */
\IPS\Member::loggedIn()->skin = $theme->id;
\IPS\Member::loggedIn()->acp_skin = $theme->id;
\IPS\Member::loggedIn()->save();
$themeReset = TRUE;
}
$_SESSION['recoveryTheme'] = $themeReset;
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;
}
}, function()
{
\IPS\IPS::resyncIPSCloud();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=recovery&do=done' ) );
} );
}
/**
* "Done" Screen
*
* @return void
*/
public function done()
{
/* Did we disable any apps? */
$apps = array();
foreach( $_SESSION['recoveryApps'] AS $app )
{
$apps[] = \IPS\Application::load( $app );
}
/* Did we disable any plugins? */
$plugins = array();
foreach( $_SESSION['recoveryPlugins'] AS $plugin )
{
$plugins[] = \IPS\Plugin::load( $plugin );
}
/* 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 );
}
}
@@ -2,9 +2,9 @@
/**
* @brief sql
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 22 May 2014
* @version SVN_VERSION_NUMBER
*/
@@ -124,7 +124,7 @@ class _sql extends \IPS\Dispatcher\Controller
try
{
/* Strip quotes */
$q = trim( preg_replace( '#(--.*)|(((/\*)+?[\w\W]+?(\*/)+))#', '', $q ) );
$q = trim( preg_replace( '@(--.*)|(#.*)|(((/\*)+?[\w\W]+?(\*/)+))@', '', $q ) );
/* Check it's okay */
if ( preg_match( "/^(DROP|FLUSH)/i", $q ) )
@@ -2,9 +2,9 @@
/**
* @brief Support Wizard
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 21 May 2014
* @version SVN_VERSION_NUMBER
*/
@@ -40,15 +40,16 @@ class _support extends \IPS\Dispatcher\Controller
* @return void
*/
protected function manage()
{
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('get_support');
\IPS\Output::i()->output = \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->support( new \IPS\Helpers\Wizard( array( 'type_of_problem' => array( $this, '_typeOfProblem' ), 'self_service' => array( $this, '_selfService' ), 'contact_support' => array( $this, '_contactSupport' ) ), \IPS\Http\Url::internal('app=core&module=support&controller=support') ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_support.js', 'core', 'admin') );
\IPS\Output::i()->output = \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->support( new \IPS\Helpers\Wizard( array( 'type_of_problem' => array( $this, '_typeOfProblem' ), 'self_service' => array( $this, '_selfService' ), 'contact_support' => array( $this, '_contactSupport' ) ), \IPS\Http\Url::internal('app=core&module=support&controller=support') ), \IPS\Db::i()->select( 'COUNT(*)', 'core_hooks' )->first() );
\IPS\Output::i()->sidebar['actions']['systemcheck'] = array(
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=support&do=systemCheck' ),
'title' => 'requirements_checker',
);
);
}
/**
@@ -109,14 +110,14 @@ class _support extends \IPS\Dispatcher\Controller
*/
public function _selfService( $data )
{
if ( isset( \IPS\Request::i()->next ) )
{
return $data;
}
/* Advice */
if ( $data['type'] === 'advice' )
{
if ( isset( \IPS\Request::i()->next ) )
{
return $data;
}
{
$searchResults = array();
if ( $data['keyword'] )
{
@@ -143,65 +144,31 @@ class _support extends \IPS\Dispatcher\Controller
/* Issue */
else
{
if ( isset( \IPS\Request::i()->serviceDone ) )
{
return $data;
}
{
/* Get requirements and suggestions */
$requirementsCheck = \IPS\core\Setup\Upgrade::systemRequirements();
$this->_clearCaches();
$baseUrl = \IPS\Http\Url::internal('app=core&module=support&controller=support&_step=self_service');
$overrideThingToTry = NULL;
if ( isset( \IPS\Request::i()->next ) )
{
$overrideThingToTry = \IPS\Request::i()->next;
$baseUrl = $baseUrl->setQueryString( 'next', $overrideThingToTry );
}
$possibleSolutions = array( '_requirementsChecker', '_databaseChecker', '_clearCaches', '_connectionChecker', '_md5sumChecker', '_upgradeCheck', '_disableAdvertisements', '_disableThirdParty', '_knowledgebase' );
$self = $this;
return new \IPS\Helpers\MultipleRedirect(
$baseUrl,
function( $thingToTry ) use ( $self, $possibleSolutions, $overrideThingToTry )
{
if ( !is_null( $overrideThingToTry ) and $overrideThingToTry > $thingToTry )
{
$thingToTry = $overrideThingToTry;
}
if ( isset( $possibleSolutions[ $thingToTry ] ) )
{
$test = call_user_func( array( $self, $possibleSolutions[ $thingToTry ] ), $thingToTry );
if ( is_string( $test ) )
{
return array( $test );
}
else
{
return array( $thingToTry + 1, \IPS\Member::loggedIn()->language()->addToStack( 'looking_for_problems' ) );
}
}
else
{
return NULL;
}
},
function() use ( $baseUrl )
{
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'serviceDone', 1 ) );
}
);
return \IPS\Theme::i()->getTemplate( 'support' )->diagnostics(
(bool) $this->_requirementsChecker( $requirementsCheck ),
$this->_upgradeCheck(),
(bool) $this->_md5sumChecker(),
(bool) $this->_databaseChecker(),
$this->_connectionChecker(),
$this->_thirdPartyCustomizations(),
$this->_adviceChecker( $requirementsCheck ),
$requirementsCheck
);
}
}
/**
* Step 2: Self Service - Clear Caches
*
* @param int $thingToTry The current ID
* @return string|NULL
* @return NULL
*/
public function _clearCaches( $thingToTry )
protected function _clearCaches()
{
/* Clear JS Maps first */
\IPS\Output::clearJsFiles();
@@ -216,269 +183,323 @@ class _support extends \IPS\Dispatcher\Controller
\IPS\Data\Store::i()->clearAll();
\IPS\Data\Cache::i()->clearAll();
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$thingToTry, 'support_caches_cleared' );
\IPS\Member::clearCreateMenu();
}
/**
* Step 2: Self Service - Database Checker
*
* @param int $id The current ID
* @return string|NULL
* @return array Changes necessary
*/
public function _databaseChecker( $id )
protected function _databaseChecker()
{
$changesToMake = array();
$db = \IPS\Db::i();
/* Loop Apps */
foreach ( \IPS\Application::applications() as $app )
{
$changesToMake = array_merge( $changesToMake, $app->databaseCheck() );
}
/* Display */
if ( $changesToMake )
return $changesToMake;
}
/**
* Step 2: Self Service - Check for Uprade / known issues
*
* @return bool|string
*/
protected function _upgradeCheck()
{
return NULL;
}
/**
* Step 2: "Help me fix this" for database check fail
*
* @return void
*/
protected function databasefail()
{
$changesToMake = $this->_databaseChecker();
\IPS\Output::i()->httpHeaders['X-IPS-FormNoSubmit'] = "true";
if ( isset( \IPS\Request::i()->run ) )
{
if ( isset( \IPS\Request::i()->run ) )
$erroredQueries = array();
$errors = array();
foreach ( $changesToMake as $query )
{
$erroredQueries = array();
$errors = array();
foreach ( $changesToMake as $query )
try
{
try
{
\IPS\Db::i()->query( $query['query'] );
}
catch ( \Exception $e )
{
$erroredQueries[] = $query['query'];
$errors[] = $e->getMessage();
}
\IPS\Db::i()->query( $query['query'] );
}
if ( count( $erroredQueries ) )
catch ( \Exception $e )
{
return \IPS\Theme::i()->getTemplate( 'support' )->databaseChecker( $id, ++$id, $erroredQueries, $errors );
}
else
{
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$id, 'database_changes_made' );
$erroredQueries[] = $query['query'];
$errors[] = $e->getMessage();
}
}
if ( count( $erroredQueries ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->fixDatabase( $erroredQueries, $errors );
}
else
{
$queries = array();
foreach ( $changesToMake as $query )
{
$queries[] = $query['query'];
}
return \IPS\Theme::i()->getTemplate( 'support' )->databaseChecker( $id, ++$id, $queries );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
}
}
elseif ( isset( \IPS\Request::i()->recheck ) )
{
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( ++$id, 'database_changes_made' );
}
else
{
return NULL;
$queries = array();
foreach ( $changesToMake as $query )
{
$queries[] = $query['query'];
}
if ( count( $queries ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->fixDatabase( $queries, NULL );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
}
}
}
/**
* Step 2: Self Service - md5sum Checker
*
* @param int $id The current ID
* @return string|NULL
* @return array Modified files
*/
public function _md5sumChecker( $id )
protected function _md5sumChecker()
{
try
{
$files = \IPS\Application::md5Check();
if ( count( $files ) )
{
return \IPS\Theme::i()->getTemplate( 'support' )->md5sum( $files, $id );
}
}
catch ( \Exception $e ) {}
return NULL;
}
/**
* Step 2: "Help me fix this" for md5sum fail
*
* @return void
*/
protected function md5fail()
{
return NULL;
}
/**
* Step 2: Self Service - Requirements Checker (Includes File Permissions)
*
* @param int $id The current ID
* @return string|NULL
* @param array $requirements Requirements to check
* @return array Necessary changes
*/
public function _requirementsChecker( $id )
{
$check = \IPS\core\Setup\Upgrade::systemRequirements();
protected function _requirementsChecker( $check )
{
$return = array();
foreach ( $check['requirements'] as $group => $requirements )
{
foreach ( $requirements as $requirement )
{
if ( !$requirement['success'] )
{
return \IPS\Theme::i()->getTemplate( 'support' )->tryNow( $id, $requirement['message'], '', FALSE );
$return[] = $requirement['message'];
}
}
}
return NULL;
return $return;
}
/**
* Step 2: Self Service - Check advice and look for recommendations
*
* @param array $requirements Requirements to check
* @return array Necessary changes
*/
protected function _adviceChecker( $check )
{
$return = array();
if( isset( $check['advice'] ) )
{
foreach ( $check['advice'] as $suggestion )
{
$return[] = $suggestion;
}
}
if( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') !== TRUE )
{
$return[] = \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_generic_explain');
}
return $return;
}
/**
* Step 2: Self Service - Connection Checker
* Step 2: Self Service - Connection and server clock checker
*
* @param int $id The current ID
* @return string|NULL
* @return int or string with error
*/
public function _connectionChecker( $id )
protected function _connectionChecker()
{
try
{
\IPS\Http\Url::ips( 'connectionCheck' )->request()->get();
return NULL;
}
catch ( \Exception $e )
{
return \IPS\Theme::i()->getTemplate( 'support' )->connectionChecker( ++$id );
}
}
/**
* Step 2: Self Service - Check for Uprade
*
* @param int $id The current ID
* @return string|NULL
*/
public function _upgradeCheck( $id )
{
try
{
$response = \IPS\Http\Url::ips('updateCheck')->request()->get()->decodeJson();
if ( $response['longversion'] > \IPS\Application::load('core')->long_version )
{
return \IPS\Theme::i()->getTemplate( 'support' )->upgrade( ++$id, $response['updateurl'] );
}
}
catch ( \Exception $e ) { }
return NULL;
}
/**
* Step 2: Self Service - Disable advertisements
* Step 2: "Help me fix this" for connection check fail
*
* @param int $id The current ID
* @return string|NULL
* @return void
*/
public function _disableAdvertisements( $id )
protected function connectionfail()
{
if ( isset( \IPS\Request::i()->enableAds ) )
{
foreach ( explode( ',', \IPS\Request::i()->enableAds ) as $ad )
{
try
{
$ad = \IPS\core\Advertisement::load( $ad );
$ad->active = 1;
$ad->save();
}
catch ( \Exception $e ) {}
}
return NULL;
}
$disabledAds = array();
/* Loop ads */
foreach( \IPS\Db::i()->select( '*' ,'core_advertisements', array( 'ad_active=?', 1 ) ) as $ad )
{
$ad = \IPS\core\Advertisement::constructFromData( $ad );
$ad->active = 0;
$disabledAds[] = $ad->id;
}
/* Do any? */
if ( count( $disabledAds ) )
{
return \IPS\Theme::i()->getTemplate( 'support' )->disabledAdvertisements( $id, '&enableAds=' . implode( ',', $disabledAds ) );
}
else
{
return NULL;
}
return NULL;
}
/**
* Step 2: Self Service - Disable 3rd party apps/plugins
* Step 2: "Help me fix this" for server time fail
*
* @param int $id The current ID
* @return string|NULL
* @return void
*/
public function _disableThirdParty( $id )
protected function servertimefail()
{
/* Button to put stuff back */
if ( isset( \IPS\Request::i()->deleteTheme ) or isset( \IPS\Request::i()->enableApps ) or isset( \IPS\Request::i()->enablePlugins ) )
return NULL;
}
/**
* Step 2: Self Service - Are there any third party customizations?
*
* @return bool
*/
protected function _thirdPartyCustomizations()
{
return ( count( $this->_thirdPartyApps() ) or count( $this->_thirdPartyPlugins() ) or $this->_thirdPartyTheme() or $this->_thirdPartyEditor() or count( $this->_thirdPartyAds() ) );
}
/**
* Step 2: Self Service - Get third-party applications
*
* @return array
*/
protected function _thirdPartyApps()
{
if ( \IPS\NO_WRITES )
{
/* Theme */
if ( isset( \IPS\Request::i()->deleteTheme ) )
{
try
{
\IPS\Theme::load( \IPS\Request::i()->deleteTheme )->delete();
}
catch ( \Exception $e ) {}
if( isset( $_SESSION['old_acp_theme'] ) )
{
\IPS\Member::loggedIn()->acp_skin = $_SESSION['old_acp_theme'];
\IPS\Member::loggedIn()->save();
unset( $_SESSION['old_acp_theme'] );
}
}
/* Apps */
foreach ( explode( ',', \IPS\Request::i()->enableApps ) as $app )
{
try
{
$app = \IPS\Application::load( $app );
$app->enabled = TRUE;
$app->save();
}
catch ( \Exception $e ) {}
}
/* Plugins */
foreach ( explode( ',', \IPS\Request::i()->enablePlugins ) as $plugin )
{
try
{
$plugin = \IPS\Plugin::load( $plugin );
$plugin->enabled = TRUE;
$plugin->save();
}
catch ( \Exception $e ) {}
}
return NULL;
return array();
}
$apps = array();
foreach ( \IPS\Application::applications() as $app )
{
if ( $app->enabled and !in_array( $app->directory, \IPS\Application::$ipsApps ) )
{
$apps[] = $app;
}
}
return $apps;
}
/**
* Step 2: Self Service - Get third-party plugins
*
* @return array
*/
protected function _thirdPartyPlugins()
{
if ( \IPS\NO_WRITES )
{
return array();
}
$plugins = array();
foreach ( \IPS\Plugin::plugins() as $plugin )
{
if ( $plugin->enabled )
{
$plugins[] = $plugin;
}
}
return $plugins;
}
/**
* Step 2: Self Service - Has the theme been customised?
*
* @return bool
*/
protected function _thirdPartyTheme()
{
return (bool) \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', 'template_set_id>0' )->first() or \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', 'css_set_id>0' )->first();
}
/**
* Step 2: Self Service - Has the editor been customised?
*
* @return bool
*/
protected function _thirdPartyEditor()
{
return ( \IPS\Settings::i()->ckeditor_extraPlugins or \IPS\Settings::i()->ckeditor_toolbars != \IPS\Db::i()->select( 'conf_default', 'core_sys_conf_settings', array( 'conf_key=?', 'ckeditor_toolbars' ) )->first() );
}
/**
* Step 2: Self Service - Get third-party advertisements
*
* @return \IPS\Db\Select
*/
protected function _thirdPartyAds()
{
return \IPS\Db::i()->select( '*' ,'core_advertisements', array( 'ad_active=?', 1 ) );
}
/**
* Step 2: Disable Third Party Customizations
*
* @return void
*/
protected function thirdparty()
{
/* Init */
$restoredDefaultTheme = FALSE;
$disabledApps = array();
$disabledPlugins = array();
$disabledAppNames = array();
$disabledPluginNames = array();
$restoredDefaultTheme = FALSE;
$restoredEditor = FALSE;
$disabledAds = array();
/* Do we need to disable any third party apps/plugins? */
if ( !\IPS\NO_WRITES )
{
/* Loop Apps */
foreach ( $this->_thirdPartyApps() as $app )
{
$app->enabled = FALSE;
$app->save();
$disabledApps[] = $app->directory;
$disabledAppNames[ $app->directory ] = $app->_title;
}
/* Look Plugins */
foreach ( $this->_thirdPartyPlugins() as $plugin )
{
$plugin->enabled = FALSE;
$plugin->save();
$disabledPlugins[] = $plugin->id;
$disabledPluginNames[ $plugin->id ] = $plugin->_title;
}
}
/* Do we need to restore the default theme? */
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_templates', 'template_set_id>0' )->first() or \IPS\Db::i()->select( 'COUNT(*)', 'core_theme_css', 'css_set_id>0' )->first() )
if ( $this->_thirdPartyTheme() )
{
$newTheme = new \IPS\Theme;
$newTheme->permissions = \IPS\Member::loggedIn()->member_group_id;
@@ -486,7 +507,7 @@ class _support extends \IPS\Dispatcher\Controller
$newTheme->installThemeSettings();
$newTheme->copyResourcesFromSet();
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $newTheme->id, "IPS Support" );
\IPS\Lang::saveCustom( 'core', "core_theme_set_title_" . $newTheme->id, "IPS Default" );
\IPS\Member::loggedIn()->skin = $newTheme->id;
@@ -501,67 +522,135 @@ class _support extends \IPS\Dispatcher\Controller
$restoredDefaultTheme = TRUE;
}
/* Do we need to disable any third party apps/plugins? */
if ( !\IPS\NO_WRITES )
{
/* Loop Apps */
foreach ( \IPS\Application::applications() as $app )
{
if ( $app->enabled and !in_array( $app->directory, \IPS\Application::$ipsApps ) )
{
$app->enabled = FALSE;
$app->save();
$disabledApps[] = $app->directory;
$disabledAppNames[] = $app->_title;
}
}
/* Do we need to revert the editor? */
if ( $this->_thirdPartyEditor() )
{
\IPS\Data\Store::i()->editorConfiguationToRestore = array(
'extraPlugins' => \IPS\Settings::i()->ckeditor_extraPlugins,
'toolbars' => \IPS\Settings::i()->ckeditor_toolbars,
);
/* Look Plugins */
foreach ( \IPS\Plugin::plugins() as $plugin )
{
if ( $plugin->enabled )
{
$plugin->enabled = FALSE;
$plugin->save();
$disabledPlugins[] = $plugin->id;
$disabledPluginNames[] = $plugin->_title;
}
}
\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 );
$restoredEditor = TRUE;
}
/* Did we do anything? */
if ( $restoredDefaultTheme or count( $disabledApps ) or count( $disabledPlugins ) )
/* Do we need to disable any thid party ads? */
foreach ( $this->_thirdPartyAds() as $ad )
{
return \IPS\Theme::i()->getTemplate( 'support' )->thirdParty( $id, $disabledAppNames, $disabledPluginNames, $restoredDefaultTheme, '&enableApps=' . implode( ',', $disabledApps ) . '&enablePlugins=' . implode( ',', $disabledPlugins ) . ( $restoredDefaultTheme ? '&deleteTheme=' . $newTheme->id : '' ) );
}
else
{
return NULL;
$ad = \IPS\core\Advertisement::constructFromData( $ad );
$ad->active = 0;
$ad->save();
$disabledAds[] = $ad->id;
}
/* Clear cache */
\IPS\Data\Cache::i()->clearAll();
/* Display */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'support' )->thirdPartyDisabled(
$disabledAppNames,
$disabledPluginNames,
$restoredDefaultTheme ? $newTheme->id : 0,
$restoredEditor,
$disabledAds,
\IPS\Http\Url::internal('app=core&module=support&controller=support&do=thirdpartyEnable')->setQueryString( array(
'enableApps' => implode( ',', $disabledApps ),
'enablePlugins' => implode( ',', $disabledPlugins ),
'deleteTheme' => $restoredDefaultTheme ? $newTheme->id : 0,
'restoreEditor' => intval( $restoredEditor ),
'enableAds' => implode( ',', $disabledAds )
) )
);
}
/**
* Step 2: Self Service - Knowledgebase
* Step 2: Re-Enable Third Party Customizations
*
* @param int $id The current ID
* @return string|NULL
* @return void
*/
public function _knowledgebase( $id )
protected function thirdpartyEnable()
{
$kb = array();
try
/* Theme */
if ( isset( \IPS\Request::i()->deleteTheme ) and \IPS\Request::i()->deleteTheme )
{
$kb = \IPS\Http\Url::ips('kb')->request()->get()->decodeJson();
try
{
\IPS\Theme::load( \IPS\Request::i()->deleteTheme )->delete();
}
catch ( \Exception $e ) {}
if( isset( $_SESSION['old_acp_theme'] ) )
{
\IPS\Member::loggedIn()->acp_skin = $_SESSION['old_acp_theme'];
\IPS\Member::loggedIn()->save();
unset( $_SESSION['old_acp_theme'] );
}
}
catch ( \Exception $e ) { }
if ( count( $kb ) )
/* Apps */
foreach ( explode( ',', \IPS\Request::i()->enableApps ) as $app )
{
try
{
$app = \IPS\Application::load( $app );
$app->enabled = TRUE;
$app->save();
}
catch ( \Exception $e ) {}
}
/* Plugins */
foreach ( explode( ',', \IPS\Request::i()->enablePlugins ) as $plugin )
{
try
{
$plugin = \IPS\Plugin::load( $plugin );
$plugin->enabled = TRUE;
$plugin->save();
}
catch ( \Exception $e ) {}
}
/* Editor Plugins */
if ( isset( \IPS\Request::i()->restoreEditor ) and \IPS\Request::i()->restoreEditor )
{
return \IPS\Theme::i()->getTemplate( 'support' )->knowledgebase( ++$id, $kb );
$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 );
unset( \IPS\Data\Store::i()->editorConfiguationToRestore );
}
/* Ads Ads */
foreach ( explode( ',', \IPS\Request::i()->enableAds ) as $ad )
{
try
{
$ad = \IPS\core\Advertisement::load( $ad );
$ad->active = 1;
$ad->save();
}
catch ( \Exception $e ) {}
}
/* Clear cache */
\IPS\Data\Cache::i()->clearAll();
/* Output */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'OK' );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
}
return NULL;
}
/**
@@ -572,167 +661,7 @@ class _support extends \IPS\Dispatcher\Controller
*/
public function _contactSupport( $data )
{
$licenseData = \IPS\IPS::licenseKey();
if ( !$licenseData or strtotime( $licenseData['expires'] ) < time() )
{
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_no_license', 'warning' );
}
try
{
$supportedVerions = \IPS\Http\Url::ips('support/versions')->request()->get()->decodeJson();
if ( \IPS\Application::load('core')->long_version > $supportedVerions['max'] )
{
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_unsupported_prerelease', 'warning' );
}
if ( \IPS\Application::load('core')->long_version < $supportedVerions['min'] )
{
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_unsupported_obsolete', 'warning' );
}
}
catch ( \Exception $e ) {}
$form = new \IPS\Helpers\Form( 'contact_support', 'contact_support_submit' );
$form->class = 'ipsForm_vertical ipsPad';
$extraOptions = array( 'admin' => 'support_request_admin' );
if ( $this->_supportLog( TRUE ) )
{
$form->hiddenValues['_log'] = '1';
$extraOptions['log'] = 'support_request_log';
}
$form->add( new \IPS\Helpers\Form\Text( 'support_request_title', NULL, TRUE, array( 'maxLength' => 128 ) ) );
$form->add( new \IPS\Helpers\Form\Editor( 'support_request_body', NULL, TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'acp-support-request' ) ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'support_request_extra', array( 'admin', 'log' ), FALSE, array( 'options' => $extraOptions ) ) );
if ( $values = $form->values() )
{
$admin = NULL;
if ( in_array( 'admin', $values['support_request_extra'] ) )
{
$password = '';
$length = rand( 8, 15 );
for ( $i = 0; $i < $length; $i++ )
{
do {
$key = rand( 33, 126 );
} while ( in_array( $key, array( 34, 39, 60, 62, 92 ) ) );
$password .= chr( $key );
}
$supportAccount = \IPS\Member::load( 'nobody@invisionpower.com', 'email' );
if ( !$supportAccount->member_id )
{
$name = 'IPS Support';
$_supportAccount = \IPS\Member::load( $name, 'name' );
if ( $_supportAccount->member_id )
{
$number = 2;
while ( $_supportAccount->member_id )
{
$name = "IPS Support {$number}";
$_supportAccount = \IPS\Member::load( $name, 'name' );
$number++;
}
}
$supportAccount = new \IPS\Member;
$supportAccount->name = $name;
$supportAccount->email = 'nobody@invisionpower.com';
$supportAccount->member_group_id = \IPS\Settings::i()->admin_group;
}
$supportAccount->members_pass_salt = $supportAccount->generateSalt();
$supportAccount->members_pass_hash = $supportAccount->encryptedPassword( $password );
$supportAccount->save();
$admin = json_encode( array( 'name' => $supportAccount->name, 'email' => $supportAccount->email, 'password' => $password, 'dir' => \IPS\CP_DIRECTORY ) );
}
$log = NULL;
if ( in_array( 'log', $values['support_request_extra'] ) )
{
$log = $this->_supportLog( FALSE );
}
$key = md5( \IPS\Http\Url::internal('app=core&module=support&controller=support') );
unset( $_SESSION["wizard-{$key}-step"] );
unset( $_SESSION["wizard-{$key}-data"] );
\IPS\Output::i()->parseFileObjectUrls( $values['support_request_body'] );
$response = \IPS\Http\Url::ips('support')->request()->login( \IPS\Settings::i()->ipb_reg_number, '' )->post( array(
'title' => $values['support_request_title'],
'message' => $values['support_request_body'],
'admin' => $admin,
'log' => $log,
'_log' => intval( isset( $values['_log'] ) )
) );
switch ( $response->httpResponseCode )
{
case 200:
case 201:
return \IPS\Theme::i()->getTemplate( 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'get_support_done', FALSE, array( 'pluralize' => array( intval( (string) $response ) ) ) ), 'success' );
case 401:
case 403:
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_no_license', 'warning' );
case 429:
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_duplicate', 'error' );
case 502:
default:
return \IPS\Theme::i()->getTemplate( 'global' )->message( 'get_support_error', 'error' );
}
}
return (string) $form;
return \IPS\Theme::i()->getTemplate( 'global' )->message( '__ipbmafia__nulling_null_alert', 'error' );
}
/**
* Get the log that will be sent
*
* @param bool $checkOnly If TRUE, will just check if there is one to send
* @return void
*/
protected function _supportLog( $checkOnly )
{
$log = array();
$oneDayAgo = \IPS\DateTime::create()->sub( new \DateInterval('P1D') );
foreach( \IPS\Log::getUsedMethods() as $method => $levels )
{
if ( $method != 'none' and $logs = \IPS\Log::i( $method )->getLatestTitles( $oneDayAgo ) and !empty( $logs ) )
{
$log[ $method ] = $logs;
}
}
if ( $checkOnly )
{
return !empty( $log );
}
$output = '';
foreach ( $log as $method => $files )
{
foreach ( $files as $file )
{
$output = "/************************/\n" . $file . "\n/************************/\n\n";
$output .= \IPS\Log::i( $method )->getLog( $file );
}
}
return $output;
}
/**
* View the log that will be sent
*
* @return void
*/
public function supportLog()
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('support')->logToSend( $this->_supportLog( FALSE ) );
}
}
@@ -2,10 +2,10 @@
/**
* @brief System Logs
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 13 Nov 2013
* @package IPS Community Suite
* @since 29 Mar 2016
* @version SVN_VERSION_NUMBER
*/
@@ -41,78 +41,293 @@ class _systemLogs extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
/* Fetch the data */
$dataSource = array();
foreach( \IPS\Log::getUsedMethods() as $method => $levels )
{
$logs = \IPS\Log::i( $method )->getMostRecentLogsTitles( 50 );
foreach( $logs as $log )
{
$log['method'] = $method;
$dataSource[ $log['date'] . '.' . $log['suffix'] ] = $log;
}
}
krsort( $dataSource );
/* Create the table */
$table = new \IPS\Helpers\Table\Custom( $dataSource, \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ) );
$table->langPrefix = 'systemlogs_';
$table->mainColumn = 'title';
$table->widths = array( 'date' => 30, 'title' => 50, 'suffix' => 20 );
$table->parsers = array(
'suffix'=> function( $val )
{
return mb_strtoupper( $val );
},
'method'=> function( $val )
{
return ucfirst( $val );
},
'date' => function( $val )
{
return \IPS\DateTime::ts( $val );
},
'title' => function( $val, $row )
{
return "<a href='" . \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs&do=view&title=" . urlencode( $val ) . '&method=' . $row['method'] ) . "'>{$val}</a>";
}
);
$table->sortBy = $table->sortBy ?: 'date';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Button to settings */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'support', 'diagnostic_log_settings' ) )
{
\IPS\Output::i()->sidebar['actions'] = array(
'settings' => array(
'title' => 'prunesettings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=logSettings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
),
'settings' => array(
'title' => 'prunesettings',
'icon' => 'cog',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=logSettings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
),
);
}
/* Button to view filebased logs */
$dir = \IPS\Log::fallbackDir();
if ( !\IPS\NO_WRITES and is_dir( $dir ) )
{
$hasFiles = FALSE;
$dir = new \DirectoryIterator( $dir );
foreach ( $dir as $file )
{
if ( mb_substr( $file, 0, 1 ) !== '.' and $file != 'index.html' )
{
$hasFiles = TRUE;
break;
}
}
if ( $hasFiles )
{
\IPS\Output::i()->sidebar['actions']['files'] = array(
'title' => 'log_view_file_logs',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ),
);
}
}
/* Create table */
$table = new \IPS\Helpers\Table\Db( 'core_log', \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ) );
$table->langPrefix = 'log_';
$table->include = array( 'time', 'category', 'message' );
$table->parsers = array(
'message' => function( $val, $row ) {
if ( mb_strlen( $val ) > 100 )
{
$val = mb_substr( $val, 0, 100 ) . '...';
}
if ( $row['exception_class'] )
{
$val = "{$row['exception_class']} ({$row['exception_code']})\n{$val}";
}
$val = htmlspecialchars( $val, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return $val;
},
'time' => function( $val ) {
return \IPS\DateTime::ts( $val );
},
'member_id' => function ( $val ){
return \IPS\Member::load( $val )->name;
}
);
$table->sortBy = $table->sortBy ?: 'time';
$table->sortDirection = $table->sortDirection ?: 'desc';
$table->quickSearch = 'message';
$table->advancedSearch = array(
'category' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => iterator_to_array( \IPS\Db::i()->select( 'DISTINCT(category) AS cat', 'core_log' )->setKeyField( 'cat' )->setValueField( 'cat' ) ), 'multiple' => TRUE, 'parse' => 'normal' ) ),
'message' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'time' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
'member_id' => \IPS\Helpers\Table\SEARCH_MEMBER,
'url' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT
);
$table->rowButtons = function( $row ) {
return array(
'view' => array(
'title' => 'view',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=view' )->setQueryString( 'id', $row['id'] )
),
'delete' => array(
'title' => 'delete',
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=delete' )->setQueryString( 'id', $row['id'] ),
'data' => array( 'delete' => '' )
)
);
};
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'r__system_logs', (string) $table );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
\IPS\Output::i()->output = $table;
}
/**
* View a log file
* View a log
*
* @return void
*/
protected function view()
{
/* Load */
try
{
$log = \IPS\Log::load( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C324/1', 404, '' );
}
/* Delete button */
\IPS\Output::i()->sidebar['actions']['delete'] = array(
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=delete' )->setQueryString( 'id', $log->id ),
'title' => 'delete',
'data' => array( 'confirm' => '' )
);
/* Display */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/systemlogs.css', 'core', 'admin' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('r__system_logs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogView( \IPS\Request::i()->title, \IPS\Log::i( \IPS\Request::i()->method )->getLog( urldecode( \IPS\Request::i()->title ) ) );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogView( $log );
}
/**
* Delete a log
*
* @return void
*/
protected function delete()
{
/* Load */
try
{
$log = \IPS\Log::load( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C324/2', 404, '' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Delete */
$log->delete();
/* Log and redirect */
if ( $log->category )
{
\IPS\Session::i()->log( 'acplog__log_delete', array( $log->category => FALSE, ( (string) \IPS\DateTime::ts( $log->time ) ) => FALSE ) );
}
else
{
\IPS\Session::i()->log( 'acplog__log_delete_uncategoried', array( ( (string) \IPS\DateTime::ts( $log->time ) ) => FALSE ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs' ), 'deleted' );
}
/**
* View File-based Logs list
*
* @return void
*/
protected function fileLogs()
{
/* NO_WRITES check */
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C324/8', 403, '' );
}
/* Get list of files */
$dir = \IPS\Log::fallbackDir();
$source = array();
if ( is_dir( $dir ) )
{
$directoryIterator = new \DirectoryIterator( $dir );
foreach ( $directoryIterator as $file )
{
if ( mb_substr( $file, 0, 1 ) !== '.' and $file != 'index.html' )
{
$source[] = array( 'time' => $file->getMTime(), 'file' => (string) $file );
}
}
}
/* Create table */
$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 ) {
return \IPS\DateTime::ts( $val );
}
);
$table->sortBy = $table->sortBy ?: 'time';
$table->sortDirection = $table->sortDirection ?: 'desc';
$table->rowButtons = function( $row ) {
return array(
'view' => array(
'title' => 'view',
'icon' => 'search',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=viewFile' )->setQueryString( 'file', $row['file'] )
),
'delete' => array(
'title' => 'delete',
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=deleteFile' )->setQueryString( 'file', $row['file'] ),
'data' => array( 'delete' => '' )
)
);
};
/* Display */
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('file_logs') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('file_logs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms' )->blurb( \IPS\Member::loggedIn()->language()->addToStack('log_view_file_logs_info', FALSE, array( 'sprintf' => $dir ) ) ) . $table;
}
/**
* View File-based Log
*
* @return void
*/
protected function viewFile()
{
/* NO_WRITES check */
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C324/3', 403, '' );
}
/* Try to find it */
$file = \IPS\Log::fallbackDir() . DIRECTORY_SEPARATOR . preg_replace( '/[^a-z_0-9\.]/i', '', \IPS\Request::i()->file );
if ( !is_file( $file ) )
{
\IPS\Output::i()->error( 'node_error', '2C324/5', 404, '' );
}
/* Delete button */
\IPS\Output::i()->sidebar['actions']['delete'] = array(
'icon' => 'times-circle',
'link' => \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=deleteFile' )->setQueryString( 'file', \IPS\Request::i()->file ),
'title' => 'delete',
'data' => array( 'confirm' => '' )
);
/* Display */
\IPS\Output::i()->title = basename( $file );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs" ), \IPS\Member::loggedIn()->language()->addToStack('r__system_logs') );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=core&module=support&controller=systemLogs&do=fileLogs" ), \IPS\Member::loggedIn()->language()->addToStack('log_view_file_logs') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->systemLogFileView( file_get_contents( $file ) );
}
/**
* View File-based Log
*
* @return void
*/
protected function deleteFile()
{
/* NO_WRITES check */
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C324/4', 403, '' );
}
/* Try to find it */
$file = \IPS\Log::fallbackDir() . DIRECTORY_SEPARATOR . preg_replace( '/[^a-z_0-9\.]/i', '', \IPS\Request::i()->file );
if ( !is_file( $file ) )
{
\IPS\Output::i()->error( 'node_error', '2C324/6', 404, '' );
}
/* Delete it */
if ( !@unlink( $file ) )
{
\IPS\Output::i()->error( 'log_file_could_not_delete', '1C324/7', 403, '' );
}
/* Log and redirect */
\IPS\Session::i()->log( 'acplog__log_delete_file', array( basename( $file ) => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=support&controller=systemLogs&do=fileLogs' ), 'deleted' );
}
/**
@@ -0,0 +1,273 @@
<?php
/**
* @brief utf8mb4 Converter
* @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 15 April 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\support;
/* 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;
}
/**
* utf8mb4 Converter
*/
class _utf8mb4 extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'sql_toolbox' );
parent::execute();
}
/**
* Bootstrap
*
* @return void
*/
protected function manage()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter');
/* Check it isn't utf8mb4 already */
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global', 'core')->message( 'utf8mb4_converter_finished', 'success' );
return;
}
/* Requires MySQL 5.5.3 */
if ( version_compare( \IPS\Db::i()->server_info, '5.5.3', '<' ) )
{
\IPS\Output::i()->error( 'utf8mb4_converter_requires_553', '1C325/1', 403, '' );
}
/* Display Wizard */
$supportController = new support;
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( array(
'utf8mb4_converter_intro' => array( $this, '_introduction' ),
'utf8mb4_converter_convert' => array( $this, '_convert' ),
'utf8mb4_converter_finish' => array( $this, '_finish' ),
), \IPS\Http\Url::internal( 'app=core&module=support&controller=utf8mb4' ) );
}
/**
* Introduction
*
* @param mixed $data Wizard Data
* @return mixed
*/
public function _introduction( $data )
{
$form = new \IPS\Helpers\Form( 'utf8mb4_converter_intro', 'continue' );
$form->hiddenValues['continue'] = 1;
$form->addMessage( 'utf8mb4_converter_explain' );
if ( $form->values() )
{
return array();
}
return (string) $form;
}
/**
* Convert
*
* @param mixed $wizardData Wizard Data
* @return mixed
*/
public function _convert( $wizardData )
{
if ( isset( \IPS\Request::i()->finished ) )
{
return $wizardData;
}
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=support&controller=utf8mb4' );
return new \IPS\Helpers\MultipleRedirect( $baseUrl,
function( $mrData )
{
try
{
/* If this is the first run, do the database itself... */
if ( !is_array( $mrData ) )
{
$databaseName = \IPS\Settings::i()->sql_database;
\IPS\Db::i()->query("ALTER DATABASE `{$databaseName}` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;");
return array( array( 'done' => array() ), \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter_converting'), 0 );
}
/* Set properties */
\IPS\Db::i()->charset = 'utf8mb4';
\IPS\Db::i()->collation = 'utf8mb4_unicode_ci';
\IPS\Db::i()->binaryCollation = 'utf8mb4_bin';
/* Do each table */
$select = \IPS\Settings::i()->sql_tbl_prefix ? ( new \IPS\Db\Select( "SHOW TABLES LIKE '" . \IPS\Db::i()->escape_string( \IPS\Settings::i()->sql_tbl_prefix ) . "%'", array(), \IPS\Db::i() ) ) : ( new \IPS\Db\Select( "SHOW TABLES", array(), \IPS\Db::i() ) );
$totalCount = count( $select );
$i = 0;
foreach ( $select as $table )
{
$i++;
$table = mb_substr( $table, mb_strlen( \IPS\Settings::i()->sql_tbl_prefix ) );
/* If we've already done it, skip to next */
if ( in_array( $table, $mrData['done'] ) )
{
continue;
}
/* Check it belongs to us */
$appName = mb_substr( $table, 0, mb_strpos( $table, '_' ) );
try
{
$app = \IPS\Application::load( $appName );
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$app->directory}/data/schema.json" ), TRUE );
if ( !array_key_exists( $table, $schema ) )
{
/* Make a special exception for CMS database tables */
if( $app->directory !== 'cms' OR mb_strpos( $table, 'cms_custom_database_' ) !== 0 )
{
continue;
}
}
}
catch ( \Exception $e )
{
continue;
}
/* If this is the search index table, clear it first. Some clients have timeouts on this step with the search index
table because it is large and it has a primary key and a unique index, so the table work is too intensive. */
if( $table == 'core_search_index' )
{
\IPS\Db::i()->delete( 'core_search_index' );
}
/* Get table definition */
$tableDefinition = \IPS\Db::i()->getTableDefinition( $table, FALSE, TRUE );
/* Drop any potentially problematic indexes */
$indexesToRecreate = array();
$maxLen = \mb_strtolower( $tableDefinition['engine'] ) === 'innodb' ? 767 : 1000;
foreach ( $tableDefinition['indexes'] as $indexName => $indexData )
{
/* If this is a fulltext index, we don't need to drop it and recreate it */
if( mb_strtolower( $indexData['type'] ) == 'fulltext' )
{
continue;
}
$length = 0;
$hasText = false;
foreach( $indexData['columns'] as $column )
{
if ( in_array( mb_strtolower( $tableDefinition['columns'][ $column ]['type'] ), array( 'mediumtext', 'text' ) ) )
{
$hasText = true;
}
if ( isset( $tableDefinition['columns'][ $column ]['length'] ) )
{
$length += $tableDefinition['columns'][ $column ]['length'];
}
}
if ( ( $length * 4 > $maxLen ) or $hasText )
{
$indexesToRecreate[ $indexName ] = $indexData;
\IPS\Db::i()->dropIndex( $table, $indexName );
}
}
/* Do the table */
$repair = false;
if( $tableDefinition['collation'] !== 'utf8mb4_unicode_ci' )
{
\IPS\Db::i()->query("ALTER TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
\IPS\Db::i()->query("ALTER TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
$repair = true;
}
/* Do each column */
foreach ( $tableDefinition['columns'] as $columnName => $columnData )
{
if( in_array( \strtoupper( $columnData['type'] ), array( 'CHAR', 'VARCHAR', 'TINYTEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT', 'ENUM', 'SET' ) ) )
{
if( $tableDefinition['columns'][ $columnName ]['collation'] !== 'utf8mb4_unicode_ci' )
{
\IPS\Db::i()->changeColumn( $table, $columnName, $columnData );
$repair = true;
}
}
}
/* Recreate any indexes */
foreach ( $indexesToRecreate as $indexName => $indexData )
{
\IPS\Db::i()->addIndex( $table, $indexData );
$repair = true;
}
/* Repair and optimize */
if( $repair === true )
{
\IPS\Db::i()->query("REPAIR TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
\IPS\Db::i()->query("OPTIMIZE TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
}
/* If this is the search index table, initiate rebuild now. */
if( $table == 'core_search_index' )
{
\IPS\Content\Search\Index::i()->rebuild();
}
/* Continue */
$mrData['done'][] = $table;
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('utf8mb4_converter_converting'), floor( 100 / $totalCount * $i ) );
}
/* If we get to this point, we're finished */
return NULL;
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'utf8mb4_converter_error', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) ), '4C171/4', 403, '' );
}
},
function() use ( $baseUrl )
{
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'finished', 1 ) );
}
);
}
/**
* Finish
*
* @param mixed $data Wizard Data
* @return mixed
*/
public function _finish( $data )
{
return \IPS\Theme::i()->getTemplate('support')->finishUtf8Mb4Conversion();
}
}
@@ -2,9 +2,9 @@
/**
* @brief Core AJAX Responders
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -65,6 +65,7 @@ class _ajax extends \IPS\core\modules\front\system\ajax
\IPS\Db::i()->delete( 'core_acp_search_index', array( 'url=?', $url ) );
$inserts = array();
foreach ( \IPS\Request::i()->keywords as $word )
{
$inserts[] = array(
@@ -80,15 +81,15 @@ class _ajax extends \IPS\core\modules\front\system\ajax
{
\IPS\Db::i()->insert( 'core_acp_search_index', $inserts );
}
$keywords = array();
foreach ( \IPS\Db::i()->select( '*', 'core_acp_search_index', array( 'app=?', $qs['app'] ) ) as $word )
foreach ( \IPS\Db::i()->select( '*', 'core_acp_search_index', array( 'app=?', $qs['app'] ), 'url ASC, keyword ASC' ) as $word )
{
$keywords[ $word['url'] ]['lang_key'] = $word['lang_key'];
$keywords[ $word['url'] ]['restriction'] = $word['restriction'];
$keywords[ $word['url'] ]['keywords'][] = $word['keyword'];
}
\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 ) );
}
@@ -2,9 +2,9 @@
/**
* @brief Background processes 'Run Now'
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 28 Jan 2015
* @version SVN_VERSION_NUMBER
*/
@@ -30,6 +30,11 @@ class _background extends \IPS\Dispatcher\Controller
*/
public function execute()
{
if ( \IPS\CIC )
{
\IPS\Output::i()->error( 'no_writes', '2C347/1', 403, '' );
}
parent::execute();
}
@@ -71,59 +76,22 @@ class _background extends \IPS\Dispatcher\Controller
else
{
try
{
$queueData = \IPS\Db::i()->select( '*', 'core_queue', NULL, 'priority ASC, RAND()', 1 )->first();
$newOffset = 0;
try
{
$extensions = \IPS\Application::load( $queueData['app'] )->extensions( 'core', 'Queue', FALSE );
if ( !isset( $extensions[ $queueData['key'] ] ) )
{
throw new \OutOfRangeException;
}
$class = new $extensions[ $queueData['key'] ];
$json = json_decode( $queueData['data'], TRUE );
$newOffset = $class->run( $json, $queueData['offset'] );
if ( is_null( $newOffset ) )
{
\IPS\Log::i( LOG_ERR )->write( "Finished " . json_encode( $queueData ), 'runQueue_log' );
\IPS\Db::i()->delete( 'core_queue', array( 'id=?', $queueData['id'] ) );
/* Update count */
$data['count'] = $self->getCount();
}
else
{
\IPS\Db::i()->update( 'core_queue', array( 'offset' => $newOffset ), array( 'id=?', $queueData['id'] ) );
$newData = json_encode( $json );
/* Did it change?? */
if ( $newData !== $json )
{
\IPS\Db::i()->update( 'core_queue', array( 'data' => $newData ), array( 'id=?', $queueData['id'] ) );
}
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Log::i( LOG_ERR )->write( "Finished " . json_encode( $queueData ), 'runQueue_log' );
\IPS\Db::i()->delete( 'core_queue', array( 'id=?', $queueData['id'] ) );
/* Update count */
$data['count'] = $self->getCount();
}
{
/* Run the next queue task, if any */
$queueData = \IPS\Task::runQueue();
/* Update count */
$data['count'] = $self->getCount();
}
catch ( \UnderflowException $e )
{
/* All done */
/* If we're here it means there were no rows in core_queue and we are done */
return NULL;
}
$data['done'] = $data['done'] + ( $newOffset - $queueData['offset'] );
$data['done'] = $data['done'] + ( $queueData['offset'] - $queueData['_originalOffset'] );
$json = json_decode( $queueData['data'], TRUE );
$lang = array( $queueData['key'] );
if ( isset( $json['class'] ) )
@@ -141,7 +109,13 @@ class _background extends \IPS\Dispatcher\Controller
if ( isset( $json['count'] ) )
{
$lang[] = " " . intval( $newOffset ) . ' / ' . $json['count'];
/* If the offset is larger than the count, then we should just show the count instead (to avoid situations where it will display 150 / 139, for example) */
$offset = intval( $queueData['offset'] );
if ( $offset > $json['count'] )
{
$offset = $json['count'];
}
$lang[] = " " . $offset . ' / ' . $json['count'];
}
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('background_processes_processing', FALSE, array( 'sprintf' => array( implode( ' - ', $lang ) ) ) ), ( $data['count'] ) ? round( ( 100 / $data['count'] * $data['done'] ), 2 ) : 100 );
@@ -2,9 +2,9 @@
/**
* @brief Editor AJAX functions Controller
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 29 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Language Changer
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 7 Oct 2014
* @version SVN_VERSION_NUMBER
*/
@@ -44,7 +44,6 @@ class _language extends \IPS\Dispatcher\Controller
\IPS\Member::loggedIn()->acp_language = (int) \IPS\Request::i()->id;
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) ?: \IPS\Http\Url::internal( '' ) );
\IPS\Output::i()->redirect( isset( $_SERVER['HTTP_REFERER'] ) ? \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief ACP Live Search
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Sep 2013
* @version SVN_VERSION_NUMBER
*/
+102 -24
View File
@@ -2,9 +2,9 @@
/**
* @brief Admin CP Login
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -55,28 +55,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Success */
if ( $member->isAdmin() )
{
/* Set the member */
\IPS\Session::i()->setMember( $member );
/* Log */
$this->log( 'ok' );
/* Clean out any existing session ID in the URL */
$queryString = array();
if( isset( \IPS\Request::i()->ref ) )
{
$_queryString = array();
parse_str( preg_replace( "/adsess=([a-zA-Z0-9]+)(?:&|$)/", '', base64_decode( \IPS\Request::i()->ref ) ), $_queryString );
foreach ( $_queryString as $k => $v )
{
if ( in_array( $k, array( 'app', 'module', 'controller' ) ) )
{
$queryString[ $k ] = $v;
}
}
}
/* Boink */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( http_build_query( $queryString ) ) );
$this->_doLogin( $member );
}
/* Error */
else
@@ -134,6 +113,105 @@ class _login extends \IPS\Dispatcher\Controller
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->login( $forms, $this->activeTab, $error, $icons, $upgradeError ) );
}
/**
* MFA
*
* @return void
*/
protected function mfa()
{
/* Have we logged in? */
$member = NULL;
if ( isset( $_SESSION['processing2FA'] ) )
{
$member = \IPS\Member::load( $_SESSION['processing2FA']['memberId'] );
}
if ( !$member->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '', 'admin' ) );
}
/* Set the referer in the URL */
$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 );
}
/* Have we already done 2FA? */
$output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateAdmin', $url, $member );
if ( !$output )
{
$this->_doLogin( $member, TRUE );
}
/* Nope, displau the 2FA form over the login page */
\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' )->mfaLogin( $output ) );
}
/**
* Process log in
*
* @param \IPS\Member $member The member
* @param bool $bypass2FA If true, will not perform 2FA check
* @return void
*/
protected function _doLogin( $member, $bypass2FA = FALSE )
{
/* Do we need to do 2FA? */
if ( !$bypass2FA and $output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateAdmin', \IPS\Http\Url::internal( '' ), $member ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $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 );
}
/* Set the member */
\IPS\Session::i()->setMember( $member );
/* Log */
$this->log( 'ok' );
/* Clean out any existing session ID in the URL */
$queryString = array();
if( isset( \IPS\Request::i()->ref ) )
{
$_queryString = array();
parse_str( preg_replace( "/adsess=([a-zA-Z0-9]+)(?:&|$)/", '', base64_decode( \IPS\Request::i()->ref ) ), $_queryString );
foreach ( $_queryString as $k => $v )
{
if ( in_array( $k, array( 'app', 'module', 'controller', 'id' ) ) )
{
$queryString[ $k ] = $v;
}
}
}
/* Boink - if we're in recovery mode, go there */
if ( \IPS\RECOVERY_MODE === TRUE )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=support&controller=recovery" ), '', 303 );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( http_build_query( $queryString ) ), '', 303 );
}
}
/**
* Log Out
*
@@ -2,9 +2,9 @@
/**
* @brief Theme Changer
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 7 Oct 2014
* @version SVN_VERSION_NUMBER
*/
@@ -44,7 +44,7 @@ class _theme extends \IPS\Dispatcher\Controller
\IPS\Member::loggedIn()->acp_skin = (int) \IPS\Request::i()->id;
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) ?: \IPS\Http\Url::internal( '' ) );
\IPS\Output::i()->redirect( isset( $_SERVER['HTTP_REFERER'] ) ? \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief upgrade
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 28 Jul 2015
* @version SVN_VERSION_NUMBER
*/
@@ -31,322 +31,6 @@ class _upgrade extends \IPS\Dispatcher\Controller
protected function manage()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'upgrade_manage' );
if ( \IPS\NO_WRITES )
{
\IPS\Output::i()->error( 'no_writes', '1C287/1', 403, '' );
}
$wizard = new \IPS\Helpers\Wizard( array(
'upgrade_confirm_update' => array( $this, '_selectVersion' ),
'upgrade_login' => array( $this, '_login' ),
'upgrade_extract_update' => array( $this, '_extractUpdate' ),
'upgrade_upgrade' => array( $this, '_upgrade' ),
), \IPS\Http\Url::internal( 'app=core&module=system&controller=upgrade' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('ips_suite_upgrade');
\IPS\Output::i()->output = $wizard;
}
/**
* Select Version
*
* @param array $data Wizard data
* @return string|array
*/
public function _selectVersion( $data )
{
/* Check latest version */
$versions = array();
foreach ( \IPS\Db::i()->select( '*', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) ) as $app )
{
if ( $app['app_enabled'] )
{
$versions[] = $app['app_long_version'];
}
}
$version = min( $versions );
$url = \IPS\Http\Url::ips('updateCheck');
if ( \IPS\USE_DEVELOPMENT_BUILDS )
{
$url = $url->setQueryString( 'development', 1 );
}
try
{
$response = $url->setQueryString( 'version', $version )->request()->get()->decodeJson();
$coreApp = \IPS\Application::load('core');
$coreApp->update_version = json_encode( $response );
$coreApp->update_last_check = time();
$coreApp->save();
}
catch ( \Exception $e ) { }
/* Build form */
$form = new \IPS\Helpers\Form( 'select_version' );
$options = array();
$descriptions = array();
$latestVersion = 0;
foreach( \IPS\Application::load( 'core' )->availableUpgrade() as $possibleVersion )
{
$options[ $possibleVersion['longversion'] ] = $possibleVersion['version'];
$descriptions[ $possibleVersion['longversion'] ] = $possibleVersion;
if ( $latestVersion < $possibleVersion['longversion'] )
{
$latestVersion = $possibleVersion['longversion'];
}
}
$form->add( new \IPS\Helpers\Form\Radio( 'version', $latestVersion, TRUE, array( 'options' => $options, '_details' => $descriptions ) ) );
/* Handle submissions */
if ( $values = $form->values() )
{
return array( 'version' => $values['version'] );
}
/* Display */
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'system' ) ), 'upgradeSelectVersion' ) );
}
/**
* Login
*
* @param array $data Wizard data
* @return string|array
*/
public function _login( $data )
{
/* Build form */
$form = new \IPS\Helpers\Form( 'login', 'continue' );
$form->hiddenValues['version'] = $data['version'];
$form->add( new \IPS\Helpers\Form\Email( 'ips_email_address', NULL ) );
$form->add( new \IPS\Helpers\Form\Password( 'ips_password', NULL ) );
/* Handle submissions */
if ( $values = $form->values() )
{
$key = \IPS\IPS::licenseKey();
$url = \IPS\Http\Url::ips( 'build/' . $key['key'] )->setQueryString( 'ip', \IPS\Request::i()->ipAddress() );
if ( \IPS\USE_DEVELOPMENT_BUILDS )
{
$url = $url->setQueryString( 'development', 1 );
}
elseif ( isset( $values['version'] ) )
{
$url = $url->setQueryString( 'versionToDownload', $values['version'] );
}
if ( \IPS\CP_DIRECTORY !== 'admin' )
{
$url = $url->setQueryString( 'cp_directory', \IPS\CP_DIRECTORY );
}
try
{
$response = $url->request( 30 )->login( $values['ips_email_address'], $values['ips_password'] )->get();
switch ( $response->httpResponseCode )
{
case 200:
if ( !preg_match( '/^ips_[a-z0-9]{5}$/', (string) $response ) )
{
\IPS\Log::i( LOG_ERR )->write( (string) $response );
$form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_error');
break;
}
else
{
$data['key'] = (string) $response;
return $data;
}
case 304:
if ( \IPS\Db::i()->select( 'MIN(app_long_version)', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) )->first() < \IPS\Application::getAvailableVersion('core') )
{
$data['key'] = NULL;
return $data;
}
$form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_nothing');
break;
default:
$form->error = (string) $response;
}
}
catch ( \Exception $exception )
{
\IPS\Log::i( LOG_ERR )->write( get_class( $exception ) . "\n" . $exception->getCode() . ": " . $exception->getMessage() . "\n" . $exception->getTraceAsString() );
$form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_error');
}
}
return (string) $form;
}
/**
* Extract Update
*
* @param array $data Wizard data
* @return string|array
*/
public function _extractUpdate( $data )
{
/* Download & Extract */
if ( $data['key'] and !isset( \IPS\Request::i()->check ) )
{
/* Muliple Redirector */
return (string) new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade'), function( $mrData ) use ( $data )
{
/* Init */
if ( !is_array( $mrData ) )
{
return array( array( 'status' => 'download' ), \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 0 );
}
/* Download */
elseif ( $mrData['status'] == 'download' )
{
if ( !isset( $mrData['tmpFileName'] ) )
{
$mrData['tmpFileName'] = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' ) . '.zip';
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 0 );
}
else
{
if ( !isset( $mrData['range'] ) )
{
$mrData['range'] = 0;
}
$startRange = $mrData['range'];
$endRange = $startRange + 1000000 - 1;
$response = \IPS\Http\Url::ips("download/{$data['key']}")->request( 30 )->setHeaders( array( 'Range' => "bytes={$startRange}-{$endRange}" ) )->get();
try
{
\IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Fetching download [range={$startRange}-{$endRange}] with a response code: " . $response->httpResponseCode, 'auto_upgrade' );
}
catch( \Exception $ex ) { }
if ( $response->httpResponseCode == 404 )
{
if ( isset( $mrData['tmpFileName'] ) )
{
@unlink( $mrData['tmpFileName'] );
}
return array( \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( TRUE, isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ) );
}
elseif ( $response->httpResponseCode == 206 )
{
$totalFileSize = intval( mb_substr( $response->httpHeaders['Content-Range'], mb_strpos( $response->httpHeaders['Content-Range'], '/' ) + 1 ) );
$fh = \fopen( $mrData['tmpFileName'], 'a' );
\fwrite( $fh, (string) $response );
\fclose( $fh );
$mrData['range'] = $endRange + 1;
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 100 / $totalFileSize * $mrData['range'] );
}
else
{
$mrData['status'] = 'extract';
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 0 );
}
}
}
/* Extract */
elseif ( $mrData['status'] == 'extract' )
{
try
{
try
{
\IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Attempting to extract", 'auto_upgrade' );
}
catch( \Exception $ex ) { }
/* Open the zip */
$zip = \IPS\Archive\Zip::fromLocalFile( $mrData['tmpFileName'], $data['key'] . '/' );
/* Extract some files */
$numberToDo = 20;
if ( !isset( $mrData['extractNumber'] ) )
{
$mrData['extractNumber'] = 0;
}
$offset = $mrData['extractNumber'];
if ( $zip->extract( \IPS\ROOT_PATH, $numberToDo, $offset ) === TRUE )
{
if ( isset( $mrData['tmpFileName'] ) )
{
@unlink( $mrData['tmpFileName'] );
}
return NULL;
}
else
{
$mrData['extractNumber'] += $numberToDo;
$numberOfFiles = $zip->numberOfFiles();
try
{
\IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Extracting files {$mrData['extractNumber']} / {$numberOfFiles}", 'auto_upgrade' );
}
catch( \Exception $ex ) { }
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 100 / $numberOfFiles * $mrData['extractNumber'] );
}
}
catch ( \RuntimeException $e )
{
try
{
\IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Extract Failed", 'auto_upgrade' );
\IPS\Log::i( LOG_ERR )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( $e, 'auto_upgrade' );
}
catch( \Exception $ex ) { }
\IPS\Session\Admin::i()->log( ( $e->getCode() === \IPS\Archive\Exception::COULD_NOT_OPEN ) ? 'delta_upgrade_zip_fail' : ( $e->getCode() === \IPS\Archive\Exception::COULD_NOT_WRITE ? 'delta_upgrade_write_fail' : '' ) );
if ( isset( $mrData['tmpFileName'] ) )
{
@unlink( $mrData['tmpFileName'] );
}
return array( \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( $e->getCode(), isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ) );
}
}
},
function()
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade&check=1') );
} );
}
/* Run md5 check */
try
{
$files = \IPS\Application::md5Check();
if ( count( $files ) )
{
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( $files, isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL );
}
}
catch ( \Exception $e ) {}
/* Nope, we're good! */
return $data;
}
/**
* Upgrade
*
* @param array $data Wizard data
* @return string|array
*/
public function _upgrade( $data )
{
\IPS\Output::i()->redirect( 'upgrade/?adsess=' . \IPS\Request::i()->adsess );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( "http://ipbmafia.ru/files/file/1560-ips-community-suite-41-nulled/" ) );
}
}
@@ -0,0 +1,29 @@
<?php
/**
* @brief Visual Language Editor
* @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 27 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\admin\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;
}
/**
* Visual Language Editor
*/
class _vle extends \IPS\core\modules\front\system\vle
{
// This class only exists to extend the front-end controller
// so that within the ACP we can call this endpoint and the
// CSRF checks will work
}