Version 4.1.19
This commit is contained in:
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( '<?php', '', highlight_string( "<?php " . var_export(\IPS\DB::i()->getTableDefinition( \IPS\Request::i()->_name ), TRUE ), TRUE ) ),
|
||||
str_replace( '<?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> </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 ) );
|
||||
|
||||
@@ -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') );
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user