Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -11,30 +11,47 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\CheckboxSet;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\YesNo;
use IPS\Http\Url;
use IPS\Member;
use IPS\Member\Group;
use IPS\Output;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* contactus
*/
class _contactus extends \IPS\Dispatcher\Controller
class contactus extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'contactus_manage' );
Dispatcher::i()->checkAcpPermission( 'contactus_manage' );
parent::execute();
}
@@ -43,11 +60,11 @@ class _contactus extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = $this->_getConfigForm();
if ( $values = $form->values( true ) )
if ( $values = $form->values(true) )
{
/* If we unselect 'everyone' and save, an empty string is passed through, so the default value is picked up in Settings::changeValues(),
which is the 'everyone' preference...the end result is that everyone gets rechecked when you uncheck it. To counter that, we'll store an invalid
@@ -59,33 +76,30 @@ class _contactus extends \IPS\Dispatcher\Controller
$form->saveAsSettings( $values );
/* 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' );
Session::i()->log( 'acplogs__contactus_settings' );
Output::i()->redirect( 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 );
Output::i()->title = Member::loggedIn()->language()->addToStack( 'r__contactus' );
Output::i()->output .= Theme::i()->getTemplate( 'global' )->block( '', $form );
}
/**
* Build the configuration form
*
* @return \IPS\Helpers\Form
* @return Form
*/
protected function _getConfigForm()
protected function _getConfigForm() : Form
{
$form = new \IPS\Helpers\Form;
$form = new Form;
$options = array();
$toggles = array();
$disabled = array();
$formFields = array();
$form->add( new \IPS\Helpers\Form\CheckboxSet( '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() ) ),
$form->add( new CheckboxSet( 'contact_access', ( Settings::i()->contact_access == '*' ) ? '*' : explode( ',', Settings::i()->contact_access ), FALSE, array(
'options' => array_combine( array_keys( Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, Group::groups() ) ),
'multiple' => true,
'unlimited' => '*',
'unlimitedLang' => 'everyone',
@@ -93,14 +107,14 @@ class _contactus extends \IPS\Dispatcher\Controller
), NULL, NULL, NULL, 'contact_access' ) );
/* Get extensions */
$extensions = \IPS\Application::allExtensions( 'core', 'ContactUs', FALSE, 'core', 'InternalEmail', TRUE );
$extensions = 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(
$form->add( new Radio( 'contact_type', Settings::i()->contact_type, FALSE, array(
'options' => $options,
'toggles' => $toggles,
'disabled' => $disabled
@@ -111,7 +125,7 @@ class _contactus extends \IPS\Dispatcher\Controller
$form->add( $field );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'contact_email_verify', \IPS\Settings::i()->contact_email_verify, TRUE ) );
$form->add( new YesNo( 'contact_email_verify', Settings::i()->contact_email_verify, TRUE ) );
return $form;
}
@@ -12,21 +12,55 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use InvalidArgumentException;
use IPS\Application;
use IPS\core\DataLayer as DataLayerClass;
use IPS\core\DataLayer\Handler;
use IPS\Data\Store;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\CheckboxSet;
use IPS\Helpers\Form\Node;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\TextArea;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\Table\Custom;
use IPS\Http\Url;
use IPS\Login\Handler as HandlerClass;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfRangeException;
use function call_user_func_array;
use function count;
use function defined;
use function mb_substr;
use function strlen;
use function strtolower;
use function substr;
use function trim;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* dataLayer
*/
class _dataLayer extends \IPS\Dispatcher\Controller
class dataLayer extends Controller
{
/**
* @breif the tabs
*/
protected static $tabs = array(
protected static array $tabs = array(
'main' => 'datalayer_main',
'pageContext' => 'datalayer_pageContext',
'properties' => 'datalayer_properties',
@@ -36,22 +70,35 @@ class _dataLayer extends \IPS\Dispatcher\Controller
/**
* @breif Makes this controller work
*/
public static $csrfProtected = true;
public static bool $csrfProtected = true;
/**
* @brief used to actually handle events and properties in the browser
*/
public static $handlerClass = '\IPS\core\DataLayer\Handler';
public static string $handlerClass = '\IPS\core\DataLayer\Handler';
/**
* Constructor
*/
public function __construct()
{
if ( Application::appIsEnabled('cloud') and DataLayerClass::i() instanceof \IPS\cloud\DataLayer\Handler )
{
static::$handlerClass = 'IPS\cloud\DataLayer\Handler';
}
return parent::__construct();
}
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'dataLayer_manage' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'menu__core_settings_dataLayer' );
Dispatcher::i()->checkAcpPermission( 'dataLayer_manage' );
Output::i()->title = Member::loggedIn()->language()->addToStack( 'menu__core_settings_dataLayer' );
/* Can we use custom handlers? Only show the tab on sites that have full analytics */
$class = static::$handlerClass;
@@ -60,7 +107,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
class_exists( 'IPS\cloud\Application' ) AND
method_exists( $class, 'handlerForm' ) AND
method_exists( $class, 'loadWhere' ) AND
\IPS\Member::loggedIn()->hasAcpRestriction( 'dataLayer_handlers_view' ) AND
Member::loggedIn()->hasAcpRestriction( 'dataLayer_handlers_view' ) AND
\IPS\cloud\Application::featureIsEnabled('analytics_full')
)
{
@@ -73,7 +120,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
);
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'settings/general.css', 'core', 'admin' ) );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'settings/general.css', 'core', 'admin' ) );
parent::execute();
}
@@ -86,12 +133,12 @@ class _dataLayer extends \IPS\Dispatcher\Controller
{
if ( method_exists( $this, $name ) )
{
return \call_user_func_array( $this->$name, $arguments );
return call_user_func_array( $this->$name, $arguments );
}
elseif ( method_exists( \IPS\core\DataLayer::i(), $name ) )
elseif ( method_exists( DataLayerClass::i(), $name ) )
{
$method = array( \IPS\core\DataLayer::i(), $name );
return \call_user_func_array( $method, $arguments );
$method = array( DataLayerClass::i(), $name );
return call_user_func_array( $method, $arguments );
}
return "You should Upgrade!";
@@ -102,49 +149,49 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$tab = \IPS\Request::i()->tab;
$tab = Request::i()->tab;
$tab = empty( static::$tabs[ $tab ] ) ? 'main' : $tab;
$output = $this->$tab();
$output = "<div id='dataLayerContent'>$output</div>" ;
if ( isset( static::$tabs['handlers'] ) AND \IPS\Member::loggedIn()->hasAcpRestriction( 'dataLayer_handlers_edit' ) )
if ( isset( static::$tabs['handlers'] ) AND Member::loggedIn()->hasAcpRestriction( 'dataLayer_handlers_edit' ) )
{
\IPS\Output::i()->sidebar['actions']['addHandler'] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'datalayer_handler_form' ),
Output::i()->sidebar['actions']['addHandler'] = array(
'title' => Member::loggedIn()->language()->addToStack( 'datalayer_handler_form' ),
'icon' => 'plus',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&do=addHandler' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'datalayer_handler_form' ) )
'link' => Url::internal( 'app=core&module=settings&controller=dataLayer&do=addHandler' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'datalayer_handler_form' ) )
);
}
$addPropertyUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&do=addProperty' );
\IPS\Output::i()->sidebar['actions']['addProperty'] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'datalayer_add_property' ),
$addPropertyUrl = Url::internal( 'app=core&module=settings&controller=dataLayer&do=addProperty' );
Output::i()->sidebar['actions']['addProperty'] = array(
'title' => Member::loggedIn()->language()->addToStack( 'datalayer_add_property' ),
'icon' => 'plus',
'link' => $addPropertyUrl,
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'datalayer_add_property' ) )
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'datalayer_add_property' ) )
);
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->output = $output;
Output::i()->output = $output;
}
else
{
if ( isset( $_SESSION['deleted_datalayer_property'] ) )
{
\IPS\Output::i()->inlineMessage = 'Deleted Property';
Output::i()->inlineMessage = 'Deleted Property';
unset( $_SESSION['deleted_datalayer_property'] );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->tabs(
Output::i()->output = Theme::i()->getTemplate( 'global', 'core', 'admin' )->tabs(
static::$tabs,
$tab,
$output,
\IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer', 'admin' )
Url::internal( 'app=core&module=settings&controller=dataLayer', 'admin' )
);
}
}
@@ -155,25 +202,25 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function main()
protected function main() : string
{
$form = new \IPS\Helpers\Form( 'datalayer_general' );
$form = new Form( 'datalayer_general' );
$form->addHeader('Settings');
$form->add( new \IPS\Helpers\Form\YesNo( 'core_datalayer_enabled', \IPS\Settings::i()->core_datalayer_enabled, false ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'core_datalayer_include_pii', \IPS\Settings::i()->core_datalayer_include_pii, false, array( 'togglesOn' => [ 'datalayer_general_core_datalayer_member_pii_choice' ] ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'core_datalayer_member_pii_choice', \IPS\Settings::i()->core_datalayer_member_pii_choice, false ) );
$form->add( new YesNo( 'core_datalayer_enabled', Settings::i()->core_datalayer_enabled, false ) );
$form->add( new YesNo( 'core_datalayer_include_pii', Settings::i()->core_datalayer_include_pii, false, array( 'togglesOn' => [ 'datalayer_general_core_datalayer_member_pii_choice' ] ) ) );
$form->add( new YesNo( 'core_datalayer_member_pii_choice', Settings::i()->core_datalayer_member_pii_choice, false ) );
try
{
$default = \IPS\Login\Handler::load( \IPS\Settings::i()->core_datalayer_replace_with_sso );
$default = HandlerClass::load( Settings::i()->core_datalayer_replace_with_sso );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
$default = 0;
}
$form->add( new \IPS\Helpers\Form\Node( 'core_datalayer_replace_with_sso', $default, false, array(
$form->add( new Node( 'core_datalayer_replace_with_sso', $default, false, array(
'class' => '\IPS\Login\Handler',
'zeroVal' => 'Use internal Member ID (default)',
'where' => array(
@@ -185,47 +232,47 @@ class _dataLayer extends \IPS\Dispatcher\Controller
) ) );
$form->addHeader('enhancements__core_GoogleTagManager');
$form->addMessage( 'use_gtm_for_installation', 'ipsMessage ipsMessage_info ipsMargin' );
$form->add( new \IPS\Helpers\Form\YesNo( 'core_datalayer_use_gtm', \IPS\Settings::i()->core_datalayer_use_gtm, false ) );
$gtmkey = explode( '.', \IPS\Settings::i()->core_datalayer_gtmkey );
$form->add( new \IPS\Helpers\Form\Text(
$form->addMessage( 'use_gtm_for_installation', 'ipsMessage ipsMessage--info i-margin_3' );
$form->add( new YesNo( 'core_datalayer_use_gtm', Settings::i()->core_datalayer_use_gtm, false ) );
$gtmkey = explode( '.', Settings::i()->core_datalayer_gtmkey );
$form->add( new Text(
'core_datalayer_gtmkey',
array_pop( $gtmkey ),
false,
array(),
function( $_value ) {
/* Check for invalid characters */
if ( preg_match( '/[^a-z,A-Z,0-9,\_]/', $_value ) )
if ( preg_match( '/[^a-zA-Z0-9_]/', $_value ) )
{
throw new \InvalidArgumentException( 'The variable name can only contain alphanumeric characters and underscores.' );
throw new InvalidArgumentException( 'The variable name can only contain alphanumeric characters and underscores.' );
}
elseif ( preg_match( '/[0-9]/', \mb_substr( $_value, 0, 1 ) ) )
elseif ( preg_match( '/[0-9]/', mb_substr( $_value, 0, 1 ) ) )
{
throw new \InvalidArgumentException( 'The variable name cannot start with a number.' );
throw new InvalidArgumentException( 'The variable name cannot start with a number.' );
}
/* Is a custom handler using this? Note that, in JS, window.variable and variable are nearly always the same */
$where = [
[ 'enabled=?', 1 ],
[ 'use_js=?', 1 ],
\IPS\Db::i()->in( 'datalayer_key', [ $_value, "window.$_value" ] ),
Db::i()->in( 'datalayer_key', [ $_value, "window.$_value" ] ),
];
if (
class_exists( 'IPS\cloud\DataLayer' ) AND
\IPS\core\DataLayer::i() instanceof \IPS\cloud\DataLayer AND
\count( \IPS\Db::i()->select( 'datalayer_key', \IPS\cloud\DataLayer\Handler::$databaseTable, $where, null, 1 ) )
DataLayerClass::i() instanceof \IPS\cloud\DataLayer AND
count( Db::i()->select( 'datalayer_key', \IPS\cloud\DataLayer\Handler::$databaseTable, $where, null, 1 ) )
)
{
throw new \InvalidArgumentException( "$_value or window.$_value is in use by a custom handler." );
throw new InvalidArgumentException( "$_value or window.$_value is in use by a custom handler." );
}
},
'<span class="ipsType_monospace">window.</span>'
'<span class="i-font-family_monospace">window.</span>'
));
if ( $values = $form->values() )
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if ( isset( $values['core_datalayer_replace_with_sso'] ) )
{
@@ -243,21 +290,21 @@ class _dataLayer extends \IPS\Dispatcher\Controller
{
if ( isset( $values[$input] ) )
{
$key = \IPS\core\DataLayer\Handler::$handlerCacheKey;
unset( \IPS\Data\Store::i()->$key );
$key = Handler::$handlerCacheKey;
unset( Store::i()->$key );
break;
}
}
/* Clear the cached configuration since we're changing it */
\IPS\core\DataLayer::i()->clearCachedConfiguration([ '_jsConfig', '_eventProperties', '_propertyEvents' ]);
DataLayerClass::i()->clearCachedConfiguration([ '_jsConfig', '_eventProperties', '_propertyEvents' ]);
\IPS\Settings::i()->changeValues( $values );
Settings::i()->changeValues( $values );
\IPS\Session::i()->log( 'acplog__datalayer_settings_edited' );
Session::i()->log( 'acplog__datalayer_settings_edited' );
/* Redirect to avoid csrfKey errors */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=main' ) );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=dataLayer&tab=main' ) );
}
return "<br>$form";
@@ -268,10 +315,10 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function pageContext()
protected function pageContext() : string
{
/* Get the page level properties */
$_properties = \IPS\core\DataLayer::i()->propertiesConfiguration;
$_properties = DataLayerClass::i()->propertiesConfiguration;
foreach ( $_properties as $k => $property )
{
if ( $property['page_level'] AND $property['enabled'] )
@@ -286,20 +333,20 @@ class _dataLayer extends \IPS\Dispatcher\Controller
}
}
$propertyBlock = new \IPS\Helpers\Table\Custom(
$propertyBlock = new Custom(
$properties,
\IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=pageContext' )
Url::internal( 'app=core&module=settings&controller=dataLayer&tab=pageContext' )
);
$propertyBlock->classes[] = 'ipsPadding:none ipsMargin:none';
$propertyBlock->classes[] = 'ipsPadding:none';
$propertyBlock->exclude = array('custom', 'description');
$propertyBlock->langPrefix = 'datalayer_';
if ( !\IPS\Request::i()->sortby )
if ( !Request::i()->sortby )
{
$propertyBlock->sortBy = 'name';
}
if ( !\IPS\Request::i()->sortdirection )
if ( !Request::i()->sortdirection )
{
$propertyBlock->sortDirection = 'asc';
}
@@ -307,13 +354,13 @@ class _dataLayer extends \IPS\Dispatcher\Controller
$propertyBlock->parsers = array(
'pii' => array( $this, '_yesNo' ),
'name' => function ( $val, $row ) {
$url = \IPS\Http\Url::internal('app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $val);
$url = Url::internal('app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $val);
$title = $row['short'];
return "<span class='ipsType_monospace ipsMargin:none'><a href='$url' data-ipstooltip title='$title'>$val</a></span>";
return "<span class='i-font-family_monospace'><a href='$url' data-ipstooltip title='$title'>$val</a></span>";
},
);
return \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerContext( $propertyBlock );
return Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerContext( $propertyBlock );
}
/**
@@ -321,21 +368,21 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function properties()
protected function properties() : string
{
/* Load our properties */
$properties = \IPS\core\DataLayer::i()->propertiesConfiguration;
$property_key = \IPS\Request::i()->property_key ?: array_keys( $properties )[0];
$properties = DataLayerClass::i()->propertiesConfiguration;
$property_key = Request::i()->property_key ?: array_keys( $properties )[0];
/* Do we know the requested property? */
if ( !isset( $properties[$property_key] ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->stripQueryString([ 'property_key' ]) );
Output::i()->redirect( Request::i()->url()->stripQueryString([ 'property_key' ]) );
}
$property = $properties[$property_key];
/* Sidebar */
$propertySelector = \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerSelector(
$propertySelector = Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerSelector(
$properties,
'properties',
'property_key',
@@ -346,46 +393,30 @@ class _dataLayer extends \IPS\Dispatcher\Controller
);
/* Form */
$form = new \IPS\Helpers\Form( 'datalayer_properties_' . $property_key, 'save', \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key ) );
$form->class = 'ipsForm_vertical';
$form = new Form( 'datalayer_properties_' . $property_key, 'save', Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key ) );
$form->class = 'ipsForm--vertical ipsForm--datalayer-properties';
$form->add( new \IPS\Helpers\Form\YesNo( 'datalayer_property_enabled', $property['enabled'], false ) );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_formatted_name', $property['formatted_name'], false, array(), $this->formattedNameValid('properties', $property_key) ) );
$form->add( new YesNo( 'datalayer_property_enabled', $property['enabled'], false ) );
$form->add( new Text( 'datalayer_property_formatted_name', $property['formatted_name'], false, array(), $this->formattedNameValid('properties', $property_key) ) );
if ( $property['custom'] ?? 0 )
{
$defaults = [
'pii' => false,
'value' => null,
'page_level' => true,
'short' => "",
'description' => "",
'event_keys' => []
];
$form->add( new Text( 'datalayer_property_value', $property['value'], true ) );
$form->add( new YesNo( 'datalayer_property_page_level', $property['page_level'], true ) );
$form->add( new Text( 'datalayer_property_short', $property['short'], false, array( 'maxLength' => 50 ) ) );
foreach ( $defaults as $key => $value )
{
if ( !array_key_exists( $key, $property ) )
{
$property[$key] = $value;
}
}
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_value', $property['value'], true ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'datalayer_property_page_level', $property['page_level'], true ) );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_short', $property['short'], false, array( 'maxLength' => 50 ) ) );
$events = \IPS\core\DataLayer::i()->eventConfiguration;
$events = DataLayerClass::i()->eventConfiguration;
$options = array();
foreach ( $events as $key => $data )
{
$options[$key] = $data['formatted_name'];
}
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'datalayer_property_event_keys', $property['event_keys'], false, array('options' => $options, 'multiple' => 1) ) );
$form->add( new CheckboxSet( 'datalayer_property_event_keys', $property['event_keys'], false, array('options' => $options, 'multiple' => 1) ) );
}
/* Update the values as long as the property_key was specified in the request */
if ( ( $values = $form->values() ) AND \IPS\Request::i()->property_key === $property_key )
if ( ( $values = $form->values() ) AND Request::i()->property_key === $property_key )
{
/* Get our submitted values */
$_values = array();
@@ -418,18 +449,18 @@ class _dataLayer extends \IPS\Dispatcher\Controller
{
try
{
\IPS\core\DataLayer::i()->savePropertyConfiguration( $property_key, $_values );
DataLayerClass::i()->savePropertyConfiguration( $property_key, $_values );
}
catch ( \InvalidArgumentException $e ) {}
catch ( InvalidArgumentException $e ) {}
\IPS\Session::i()->log( 'acplog__data_layer_property_edited', array( $property_key => FALSE ) );
Session::i()->log( 'acplog__data_layer_property_edited', array( $property_key => FALSE ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key ) );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key ) );
}
/* Load our events */
$_events = \IPS\core\DataLayer::i()->getPropertyEvents( $property_key );
$_events = DataLayerClass::i()->getPropertyEvents( $property_key );
$events = array();
foreach( $_events as $key => $event )
{
@@ -448,18 +479,18 @@ class _dataLayer extends \IPS\Dispatcher\Controller
}
else
{
$eventTable = new \IPS\Helpers\Table\Custom(
$eventTable = new Custom(
$events,
\IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key )
Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $property_key )
);
if ( !\IPS\Request::i()->sortby )
if ( !Request::i()->sortby )
{
$eventTable->sortBy = 'name';
}
if ( !\IPS\Request::i()->sortdirection )
if ( !Request::i()->sortdirection )
{
$eventTable->sortDirection = 'asc';
}
@@ -469,16 +500,16 @@ class _dataLayer extends \IPS\Dispatcher\Controller
$eventTable->parsers = array(
'name' => function ( $val, $row )
{
$url = \IPS\Http\Url::internal('app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $row['key']);
$url = Url::internal('app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $row['key']);
$title = $row['short'];
return "<span class='ipsMargin:none ipsType_monospace'><a href='$url' data-ipstooltip title='$title'>$val</a></span>";
return "<span class='i-font-family_monospace'><a href='$url' data-ipstooltip title='$title'>$val</a></span>";
},
'enabled' => array( $this, '_enabledDisabled' ),
);
}
/* Render Content */
$content = \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTitleContent(
$content = Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTitleContent(
$property,
$property_key,
'property',
@@ -486,36 +517,36 @@ class _dataLayer extends \IPS\Dispatcher\Controller
(string) $eventTable
);
return \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTab( $propertySelector, $content );
return Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTab( $propertySelector, $content );
}
/**
* Property settings and configuration
*
* @return string
* @return void
*/
protected function addProperty()
protected function addProperty() : void
{
\IPS\Output::i()->title = 'Add property';
$form = new \IPS\Helpers\Form( 'datalayer_add_property' );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_formatted_name', null, true, array(), $this->formattedNameValid() ) );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_value', null, true ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'datalayer_property_description', null, true ) );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_property_short', null, false, array( 'maxLength' => 50 ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'datalayer_property_page_level', 1, true ) );
Output::i()->title = 'Add property';
$form = new Form( 'datalayer_add_property' );
$form->add( new Text( 'datalayer_property_formatted_name', null, true, array(), $this->formattedNameValid() ) );
$form->add( new Text( 'datalayer_property_value', null, true ) );
$form->add( new TextArea( 'datalayer_property_description', null, true ) );
$form->add( new Text( 'datalayer_property_short', null, false, array( 'maxLength' => 50 ) ) );
$form->add( new YesNo( 'datalayer_property_page_level', 1, true ) );
$events = \IPS\core\DataLayer::i()->eventConfiguration;
$events = DataLayerClass::i()->eventConfiguration;
$options = array();
foreach ( $events as $key => $data )
{
$options[$key] = $data['formatted_name'];
}
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'datalayer_property_event_keys', array(), false, array('options' => $options, 'multiple' => 1) ) );
$form->add( new CheckboxSet( 'datalayer_property_event_keys', array(), false, array('options' => $options, 'multiple' => 1) ) );
if ( $values = $form->values() )
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$_values = array();
foreach ( $values as $field => $value )
{
@@ -527,40 +558,40 @@ class _dataLayer extends \IPS\Dispatcher\Controller
$values['enabled'] = true;
$key = $values['formatted_name'];
\IPS\core\DataLayer::i()->savePropertyConfiguration( $key, $values, true );
DataLayerClass::i()->savePropertyConfiguration( $key, $values, true );
\IPS\Session::i()->log( 'acplog__data_layer_property_added', array( $key => FALSE ) );
Session::i()->log( 'acplog__data_layer_property_added', array( $key => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $key ) );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $key ) );
}
\IPS\Output::i()->output = (string) $form;
Output::i()->output = (string) $form;
}
/**
* Delete a property
*/
protected function deleteProperty()
protected function deleteProperty() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$key = \IPS\Request::i()->property_key;
$propertiesUrl = \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties' );
$key = Request::i()->property_key;
$propertiesUrl = Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties' );
if ( empty( $key ) )
{
\IPS\Output::i()->redirect( $propertiesUrl );
Output::i()->redirect( $propertiesUrl );
}
$properties = \IPS\core\DataLayer::i()->propertiesConfiguration;
$properties = DataLayerClass::i()->propertiesConfiguration;
if ( isset( $properties[$key] ) )
{
if ( $properties[$key]['custom'] ?? 0 )
{
$setting = json_decode( \IPS\Settings::i()->core_datalayer_properties, true ) ?: array();
$setting = json_decode( Settings::i()->core_datalayer_properties, true ) ?: array();
unset( $setting[$key] );
\IPS\Settings::i()->changeValues([ 'core_datalayer_properties' => json_encode( $setting ) ]);
\IPS\core\DataLayer::i()->clearCachedConfiguration();
\IPS\Session::i()->log( 'acplog__data_layer_property_deleted', array( $key => FALSE ) );
Settings::i()->changeValues([ 'core_datalayer_properties' => json_encode( $setting ) ]);
DataLayerClass::i()->clearCachedConfiguration();
Session::i()->log( 'acplog__data_layer_property_deleted', array( $key => FALSE ) );
$_SESSION['deleted_datalayer_property'] = 1;
}
else
@@ -568,7 +599,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
$propertiesUrl = $propertiesUrl->setQueryString([ 'property_key' => $key ]);
}
}
\IPS\Output::i()->redirect( $propertiesUrl );
Output::i()->redirect( $propertiesUrl );
}
/**
@@ -576,16 +607,16 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function events()
protected function events() : string
{
/* Load our events */
$events = \IPS\core\DataLayer::i()->eventConfiguration;
$event_key = \IPS\Request::i()->event_key ?: 'content_create';
$events = DataLayerClass::i()->eventConfiguration;
$event_key = Request::i()->event_key ?: 'content_create';
/* Do we know the recognized one? */
if ( !isset( $events[$event_key] ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->stripQueryString([ 'event_key' ]) );
Output::i()->redirect( Request::i()->url()->stripQueryString([ 'event_key' ]) );
}
$event = $events[$event_key];
@@ -595,7 +626,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
}
/* Create our sidebar */
$eventSelector = \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerSelector(
$eventSelector = Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerSelector(
$events,
'events',
'event_key',
@@ -606,14 +637,14 @@ class _dataLayer extends \IPS\Dispatcher\Controller
);
/* Form */
$form = new \IPS\Helpers\Form( 'datalayer_events_' . $event_key, 'save', \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key ) );
$form->class = 'ipsForm_vertical';
$form = new Form( 'datalayer_events_' . $event_key, 'save', Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key ) );
$form->class = 'ipsForm--vertical ipsForm--datalayer-events';
$form->add( new \IPS\Helpers\Form\YesNo( 'datalayer_event_enabled', $event['enabled'], false ) );
$form->add( new \IPS\Helpers\Form\Text( 'datalayer_event_formatted_name', $event['formatted_name'], false, array(), $this->formattedNameValid( 'events', $event_key ) ) );
$form->add( new YesNo( 'datalayer_event_enabled', $event['enabled'], false ) );
$form->add( new Text( 'datalayer_event_formatted_name', $event['formatted_name'], false, array(), $this->formattedNameValid( 'events', $event_key ) ) );
/* We only want to change values when a real event is specified in the request */
if ( ( $values = $form->values() ) AND \IPS\Request::i()->event_key === $event_key )
if ( ( $values = $form->values() ) AND Request::i()->event_key === $event_key )
{
/* Pull out the values to use */
$_values = array();
@@ -632,19 +663,19 @@ class _dataLayer extends \IPS\Dispatcher\Controller
{
try
{
\IPS\core\DataLayer::i()->saveEventConfiguration( $event_key, $_values );
DataLayerClass::i()->saveEventConfiguration( $event_key, $_values );
}
catch ( \InvalidArgumentException $e ) {}
catch ( InvalidArgumentException $e ) {}
}
\IPS\Session::i()->log( 'acplog__data_layer_event_edited', array( $event_key => FALSE ) );
Session::i()->log( 'acplog__data_layer_event_edited', array( $event_key => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key ) );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key ) );
}
/* Load our properties */
$_properties = \IPS\core\DataLayer::i()->getEventProperties( $event_key );
$_properties = DataLayerClass::i()->getEventProperties( $event_key );
$properties = array();
foreach( $_properties as $key => $property )
{
@@ -666,17 +697,17 @@ class _dataLayer extends \IPS\Dispatcher\Controller
}
else
{
$propertyTable = new \IPS\Helpers\Table\Custom(
$propertyTable = new Custom(
$properties,
\IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key )
Url::internal( 'app=core&module=settings&controller=dataLayer&tab=events&event_key=' . $event_key )
);
if ( !\IPS\Request::i()->sortby )
if ( !Request::i()->sortby )
{
$propertyTable->sortBy = 'name';
}
if ( !\IPS\Request::i()->sortdirection )
if ( !Request::i()->sortdirection )
{
$propertyTable->sortDirection = 'asc';
}
@@ -688,16 +719,16 @@ class _dataLayer extends \IPS\Dispatcher\Controller
'pii' => array( $this, '_yesNo' ),
'name' => function ( $val, $row )
{
$url = \IPS\Http\Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $row['key'] );
$url = Url::internal( 'app=core&module=settings&controller=dataLayer&tab=properties&property_key=' . $row['key'] );
$title = $row['short'];
return "<pre class='ipsMargin:none'><a href='$url' data-ipstooltip title='$title' >$val</a></pre>";
return "<pre><a href='$url' data-ipstooltip title='$title' >$val</a></pre>";
},
);
}
/* Render Content */
$event['description'] = "Fires when {$event['description']}";
$content = \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTitleContent(
$content = Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTitleContent(
$event,
$event_key,
'event',
@@ -705,7 +736,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
(string) $propertyTable
);
return \IPS\Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTab( $eventSelector, $content );
return Theme::i()->getTemplate( 'settings', 'core', 'admin' )->dataLayerTab( $eventSelector, $content );
}
/**
@@ -714,23 +745,23 @@ class _dataLayer extends \IPS\Dispatcher\Controller
* @param string $group Either properties or events; the datalayer collection to test the key against
* @param ?string $current The key of the property/event that currently has this value set as its formatted name
*
* @return callback
* @return callable
*/
public function formattedNameValid( string $group='properties', ?string $current=null )
public function formattedNameValid( string $group='properties', ?string $current=null ) : callable
{
return function( $value ) use ( $group, $current )
{
if ( $group === 'properties' AND \strtolower( $value ) === 'event' )
if ( $group === 'properties' AND strtolower( $value ) === 'event' )
{
throw new \InvalidArgumentException( "You cannot name a property '$value' because that key is reserved" );
throw new InvalidArgumentException( "You cannot name a property '$value' because that key is reserved" );
}
if ( preg_match( '/[^a-z,A-Z,\_]/', $value ) )
if ( preg_match( '/[^a-zA-Z_]/', $value ) )
{
throw new \InvalidArgumentException( 'The name can only contain letters and underscores.' );
throw new InvalidArgumentException( 'The name can only contain letters and underscores.' );
}
$collection = ( $group === 'events' ) ? \IPS\core\DataLayer::i()->eventConfiguration : \IPS\core\DataLayer::i()->propertiesConfiguration;
$collection = ( $group === 'events' ) ? DataLayerClass::i()->eventConfiguration : DataLayerClass::i()->propertiesConfiguration;
foreach ( $collection as $key => $data )
{
if ( $key === $current )
@@ -740,7 +771,7 @@ class _dataLayer extends \IPS\Dispatcher\Controller
if ( isset( $data['formatted_name'] ) AND $data['formatted_name'] === $value )
{
throw new \InvalidArgumentException( 'This Data Layer name is already in use' );
throw new InvalidArgumentException( 'This Data Layer name is already in use' );
}
}
};
@@ -749,11 +780,11 @@ class _dataLayer extends \IPS\Dispatcher\Controller
/**
* Formatter method to make code cleaner
*
* @param mixed $val
*
* @param mixed $val
* @param array|null $row *
* @return string
*/
public function _enabledDisabled( $val, $row=null )
public function _enabledDisabled( mixed $val, ?array $row=null ) : string
{
return $val ? 'Enabled' : 'Disabled';
}
@@ -762,10 +793,10 @@ class _dataLayer extends \IPS\Dispatcher\Controller
* Formatter method to make code cleaner
*
* @param mixed $val
*
* @param array|null $row
* @return string
*/
public function _yesNo( $val, $row=null )
public function _yesNo( mixed $val, ?array $row=null ) : string
{
return $val ? 'Yes' : 'No';
}
@@ -778,15 +809,15 @@ class _dataLayer extends \IPS\Dispatcher\Controller
*
* @return string
*/
public function _truncate( $_string, $length=100 )
public function _truncate( string $_string, int $length=100 ) : string
{
$_string = strip_tags( $_string );
$string = \substr( $_string, 0, $length );
$changedLength = ( \strlen( $_string ) !== \strlen( $string ) );
$string = substr( $_string, 0, $length );
$changedLength = ( strlen( $_string ) !== strlen( $string ) );
$string = trim( $string, ". \n\r\t\v\x00" );
if ( $changedLength )
{
$string = \trim( \substr( $string, 0, $length - 3 ), ". \n\r\t\v\x00" ) . '...';
$string = trim( substr( $string, 0, $length - 3 ), ". \n\r\t\v\x00" ) . '...';
}
return $string;
}
@@ -10,21 +10,30 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
use DateInterval;
use Exception;
use IPS\core\AdminNotification;
use IPS\DateTime;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Email;
use IPS\Dispatcher\Controller;
use IPS\Email as EmailClass;
use IPS\File;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Color;
use IPS\Helpers\Form\Email as FormEmail;
use IPS\Helpers\Form\Interval;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\Password;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Select;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\TextArea;
use IPS\Helpers\Form\Upload;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\Table\Db as TableDb;
use IPS\Http\Url;
use IPS\Member;
use IPS\Output;
@@ -32,31 +41,35 @@ use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
use function get_class;
use function is_string;
use const IPS\CIC;
use const IPS\DEMO_MODE;
use const IPS\Helpers\Table\SEARCH_CONTAINS_TEXT;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* email
*/
class _email extends \IPS\Dispatcher\Controller
class email extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
Dispatcher::i()->checkAcpPermission( 'email_manage' );
parent::execute();
@@ -67,33 +80,30 @@ class _email extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Build the settings form */
$messageHtml = '';
$settingsForm = new Form( 'settings_form' );
$settingsForm->addHeader( 'basic_settings' );
$settingsForm->add( new FormEmail( 'email_out', Settings::i()->email_out, TRUE, [], NULL, NULL, NULL, 'email_out' ) );
$settingsForm->add( new FormEmail( 'email_out', Settings::i()->email_out, TRUE, array(), NULL, NULL, NULL, 'email_out' ) );
$settingsForm->add( new FormEmail( 'email_in', Settings::i()->email_in, TRUE ) );
$settingsForm->add( new Color( 'email_color', Settings::i()->email_color, TRUE ) );
$settingsForm->add( new Upload( 'email_logo', Settings::i()->email_logo ? File::get( 'core_Theme', Settings::i()->email_logo ) : NULL, FALSE, [ 'image' => TRUE, 'storageExtension' => 'core_Theme' ] ) );
$settingsForm->add( new YesNo( 'social_links_in_email', Settings::i()->social_links_in_email, FALSE, [], NULL, NULL, NULL, 'social_links_in_email' ) );
$settingsForm->add( new Upload( 'email_logo', Settings::i()->email_logo ? File::get( 'core_Theme', Settings::i()->email_logo ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'core_Theme' ) ) );
$settingsForm->add( new YesNo( 'social_links_in_email', Settings::i()->social_links_in_email, FALSE, array(), NULL, NULL, NULL, 'social_links_in_email' ) );
$settingsForm->add( new YesNo( 'our_picks_in_email', Settings::i()->our_picks_in_email, FALSE, array(), NULL, NULL, NULL, 'our_picks_in_email' ) );
if ( Settings::i()->promote_community_enabled )
{
$settingsForm->add( new YesNo( 'our_picks_in_email', Settings::i()->our_picks_in_email, FALSE, [], NULL, NULL, NULL, 'our_picks_in_email' ) );
}
$settingsForm->add( new YesNo( 'email_truncate', ( Settings::i()->email_truncate ), FALSE, [], NULL, NULL, NULL, 'email_truncate' ) );
$settingsForm->add( new YesNo( 'email_log_do', ( Settings::i()->prune_log_emailstats != 0 ), FALSE, [ 'togglesOn' => [ 'prune_log_emailstats' ] ], NULL, NULL, NULL, 'email_log_do' ) );
$settingsForm->add( new Interval( 'prune_log_emailstats', Settings::i()->prune_log_emailstats ?: 60, FALSE, [ 'valueAs' => 'd', 'unlimited' => '-1', 'unlimitedLang' => 'never' ], NULL, NULL, NULL, 'prune_log_emailstats' ) );
$settingsForm->add( new YesNo( 'email_truncate', ( Settings::i()->email_truncate ), FALSE, array(), NULL, NULL, NULL, 'email_truncate' ) );
$settingsForm->add( new YesNo( 'email_log_do', ( Settings::i()->prune_log_emailstats != 0 ), FALSE, array( 'togglesOn' => array( 'prune_log_emailstats' ) ), NULL, NULL, NULL, 'email_log_do' ) );
$settingsForm->add( new Interval( 'prune_log_emailstats', Settings::i()->prune_log_emailstats ?: 60, FALSE, array( 'valueAs' => 'd', 'unlimited' => '-1', 'unlimitedLang' => 'never' ), NULL, NULL, NULL, 'prune_log_emailstats' ) );
if ( !DEMO_MODE )
{
$settingsForm->addHeader( 'advanced_settings' );
$method = Settings::i()->mail_method;
$disabled = [];
$disabled = array();
if ( Settings::i()->sendgrid_api_key AND Settings::i()->sendgrid_use_for > 0 )
{
@@ -113,49 +123,23 @@ class _email extends \IPS\Dispatcher\Controller
$method = 'php';
}
$debug = FALSE;
if( Email::classToUse( Email::TYPE_TRANSACTIONAL ) == 'IPS\\Email\\Outgoing\\Debug' )
$settingsForm->add( new Radio( 'mail_method', $method, TRUE, array(
'options' => array( 'php' => ( CIC ? 'mail_method_cic' : 'mail_method_php' ), 'smtp' => 'mail_method_smtp', 'sendgrid' => 'mail_method_sendgrid' ),
'disabled' => $disabled,
'toggles' => array(
'php' => 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' );
$settingsForm->add( new Text( 'smtp_host', Settings::i()->smtp_host, FALSE, array(), NULL, NULL, NULL, 'smtp_host' ) );
$settingsForm->add( new Select( 'smtp_protocol', Settings::i()->smtp_protocol, FALSE, array( 'options' => $options ), NULL, NULL, NULL, 'smtp_protocol' ) );
$settingsForm->add( new Number( 'smtp_port', Settings::i()->smtp_port, FALSE, array(), NULL, NULL, NULL, 'smtp_port' ) );
$settingsForm->add( new Text( 'smtp_user', Settings::i()->smtp_user, FALSE, array(), NULL, NULL, NULL, 'smtp_user' ) );
$settingsForm->add( new Password( 'smtp_pass', Settings::i()->smtp_pass, FALSE, array( 'enforceMaxLimit' => FALSE ), NULL, NULL, NULL, 'smtp_pass' ) );
if ( !CIC )
{
$debug = true;
$method = 'debug';
}
$mailOptions = $toggles = $fields = [];
foreach( Email::outgoingHandlers() as $key => $handler )
{
if( ! $handler::isUsable( Email::TYPE_TRANSACTIONAL ) )
{
continue;
}
$mailOptions[ $key ] = 'mail_method_' . $key;
$formFields = $handler::form();
$toggles[ $key ] = array_keys( $formFields );
$fields = $fields + $formFields;
}
/* Change value back to default for platform */
if( !\in_array( $method, array_keys( $mailOptions ) ) )
{
$method = \IPS\CIC ? 'cloud' : 'php';
}
if( !$debug )
{
$settingsForm->add( new Radio( 'mail_method', $method, TRUE, [
'options' => $mailOptions,
'disabled' => $disabled,
'toggles' => $toggles
] ) );
foreach( $fields as $f )
{
$settingsForm->add( $f );
}
}
else
{
$settingsForm->addDummy( 'mail_method', Member::loggedIn()->language()->addToStack('mail_method_debug', false, [ 'sprintf' => [ \IPS\EMAIL_DEBUG_PATH ] ] ) );
$settingsForm->add( new Text( 'php_mail_extra', Settings::i()->php_mail_extra, FALSE, array(), NULL, NULL, NULL, 'php_mail_extra' ) );
}
}
if ( $values = $settingsForm->values() )
@@ -176,11 +160,14 @@ class _email extends \IPS\Dispatcher\Controller
}
unset( $values['email_log_do'] );
/* Allow individual handlers to save settings */
foreach( Email::outgoingHandlers() as $key => $handler )
if ( $values['mail_method'] != 'sendgrid' and Settings::i()->sendgrid_use_for == 2 )
{
$values = $handler::processSettings( $values );
$values['sendgrid_use_for'] = 1;
}
elseif ( $values['mail_method'] == 'sendgrid' )
{
$values['sendgrid_use_for'] = 2;
}
if ( $values['email_logo'] )
@@ -193,27 +180,31 @@ class _email extends \IPS\Dispatcher\Controller
if( $sendTestEmail )
{
$email = Email::buildFromContent( Member::loggedIn()->language()->get('email_test_subject'), Member::loggedIn()->language()->addToStack('email_test_message'), Member::loggedIn()->language()->addToStack('email_test_message'), Email::TYPE_BULK );
$email = EmailClass::buildFromContent( Member::loggedIn()->language()->get('email_test_subject'), Member::loggedIn()->language()->addToStack('email_test_message'), Member::loggedIn()->language()->addToStack('email_test_message'), EmailClass::TYPE_BULK );
try
{
$email->_send( Member::loggedIn(), fromEmail: Settings::i()->email_out );
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay_auto', 'success' );
$result = $email->send( to: Member::loggedIn(), fromEmail: Settings::i()->email_out, returnException: TRUE );
if( $result )
{
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay_auto', 'success' );
}
/* Sent successfully, remove notification */
AdminNotification::remove( 'core', 'ConfigurationError', 'failedMail' );
Db::i()->update( 'core_mail_error_logs', [ 'mlog_notification_sent' => TRUE ] );
Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ) );
}
catch ( \Exception $e )
catch ( Exception $e )
{
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_error_auto', 'error', $e->getMessage() );
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( $e->getMessage() ?: 'email_test_error_auto', 'error', $e->getMessage() );
}
}
}
/* Build the test form */
$testFormHtml = '';
if ( !DEMO_MODE AND Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'email_test' ) )
if ( !DEMO_MODE AND Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'email_test' ) )
{
Output::i()->sidebar['actions']['test'] = array(
'title' => 'email_test',
@@ -231,23 +222,26 @@ class _email extends \IPS\Dispatcher\Controller
{
try
{
$email = Email::buildFromContent( $values['subject'], $values['message'], $values['message'], Email::TYPE_BULK );
$email->_send( $values['to'], fromEmail: $values['from'] );
$email = EmailClass::buildFromContent( $values['subject'], $values['message'], $values['message'], EmailClass::TYPE_BULK );
$result = $email->send( to: $values['to'], fromEmail: $values['from'], returnException: TRUE );
/* Sent successfully, remove notification */
AdminNotification::remove( 'core', 'ConfigurationError', 'failedMail' );
Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ) );
if( $result )
{
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay', 'success' );
}
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( 'email_test_okay', 'success' );
}
catch ( \Exception $exception )
catch ( Exception $exception )
{
$content = $exception->getMessage();
if ( !( $exception instanceof \IPS\Email\Outgoing\Exception ) )
{
$content = \get_class( $exception ) . ": " . $exception->getMessage() . " (" . $exception->getCode() . ")";
$content = get_class( $exception ) . ": " . $exception->getMessage() . " (" . $exception->getCode() . ")";
}
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( $content ?: 'email_test_error_auto', 'error' );
$messageHtml = Theme::i()->getTemplate( 'global', 'core', 'global' )->message( $content, 'error' );
}
}
@@ -265,7 +259,7 @@ class _email extends \IPS\Dispatcher\Controller
}
/* Display */
Output::i()->title = Member::loggedIn()->language()->addToStack('email_settings');
Output::i()->title = Member::loggedIn()->language()->addToStack('email_settings');
Output::i()->output = $messageHtml;
Output::i()->output .= Theme::i()->getTemplate( 'global' )->block( 'email_settings', $settingsForm );
Output::i()->output .= $testFormHtml;
@@ -276,7 +270,7 @@ class _email extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function errorLog()
protected function errorLog() : void
{
Dispatcher::i()->checkAcpPermission( 'email_errorlog' );
@@ -303,12 +297,12 @@ class _email extends \IPS\Dispatcher\Controller
*
* @param Url $url Base URL for table
* @param array $where Where Array
* @return \IPS\Helpers\Table\Db
* @return TableDb
*/
public static function emailErrorLogTable( Url $url, array $where=array() ): \IPS\Helpers\Table\Db
public static function emailErrorLogTable( Url $url, array $where=array() ): TableDb
{
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_mail_error_logs', $url, $where );
$table = new TableDb( 'core_mail_error_logs', $url, $where );
$table->langPrefix = 'emailerrorlogs_';
/* Columns we need */
@@ -322,16 +316,16 @@ class _email extends \IPS\Dispatcher\Controller
/* Search */
$table->quickSearch = 'mlog_to';
$table->advancedSearch = array(
'mlog_to' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'mlog_from' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'mlog_subject' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'mlog_msg' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'mlog_content' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
'mlog_to' => SEARCH_CONTAINS_TEXT,
'mlog_from' => SEARCH_CONTAINS_TEXT,
'mlog_subject' => SEARCH_CONTAINS_TEXT,
'mlog_msg' => SEARCH_CONTAINS_TEXT,
'mlog_content' => SEARCH_CONTAINS_TEXT,
);
/* Custom parsers */
$table->parsers = array(
'mlog_date' => function( $val, $row )
'mlog_date' => function( $val )
{
return DateTime::ts( $val );
},
@@ -348,7 +342,7 @@ class _email extends \IPS\Dispatcher\Controller
/* We may not have a 'message' key if this is an older SendGrid log entry */
if( isset( $data['message'] ) )
{
$val = \is_string( $data['message'] ) ?
$val = is_string( $data['message'] ) ?
( ( isset( $data['details'] ) AND $data['details'] ) ? Member::loggedIn()->language()->addToStack( $data['message'], FALSE, array( 'sprintf' => $data['details'] ) ) : Member::loggedIn()->language()->addToStack( $data['message'] ) ) :
$val;
}
@@ -394,7 +388,7 @@ class _email extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function errorLogResend()
public function errorLogResend() : void
{
Dispatcher::i()->checkAcpPermission( 'email_errorlog' );
Session::i()->csrfCheck();
@@ -416,7 +410,7 @@ class _email extends \IPS\Dispatcher\Controller
unset( $emailData['headers']['Content-Type'] );
unset( $emailData['headers']['Content-Transfer-Encoding'] );
$email = Email::buildFromContent( $log['mlog_subject'], $emailData['body']['html'], $emailData['body']['plain'], isset( $emailData['type'] ) ? $emailData['type'] : Email::TYPE_TRANSACTIONAL );
$email = EmailClass::buildFromContent( $log['mlog_subject'], $emailData['body']['html'], $emailData['body']['plain'], $emailData['type'] ?? EmailClass::TYPE_TRANSACTIONAL );
$email->_send(
array_map( 'trim', explode( ',', $log['mlog_to'] ) ),
isset( $emailData['headers']['Cc'] ) ? array_map( 'trim', explode( ',', $emailData['headers']['Cc'] ) ) : array(),
@@ -426,7 +420,7 @@ class _email extends \IPS\Dispatcher\Controller
$emailData['headers']
);
}
catch( \Exception $e )
catch( Exception $e )
{
Output::i()->error( $e->getMessage(), '4C143/1', 500, '' );
}
@@ -434,7 +428,7 @@ class _email extends \IPS\Dispatcher\Controller
Db::i()->delete( 'core_mail_error_logs', array( 'mlog_id=?', $id ) );
/* Remove notification since this was re-sent with success and it is below the recent threshold */
if( Email::countFailedMail( DateTime::create()->sub( new \DateInterval( 'P3D' ) ), FALSE, TRUE ) <= 3 )
if( EmailClass::countFailedMail( DateTime::create()->sub( new DateInterval( 'P3D' ) ), FALSE, TRUE ) <= 3 )
{
AdminNotification::remove( 'core', 'ConfigurationError', 'failedMail' );
Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ), array( 'mlog_id=?', $id ) );
@@ -448,7 +442,7 @@ class _email extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function errorLogView()
public function errorLogView() : void
{
Dispatcher::i()->checkAcpPermission( 'email_errorlog' );
@@ -463,7 +457,7 @@ class _email extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function errorLogSettings()
protected function errorLogSettings() : void
{
Dispatcher::i()->checkAcpPermission( 'email_errorlog_prune' );
@@ -11,30 +11,57 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\core\AdminNotification;
use IPS\Data\Store;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\GeoLocation;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Address;
use IPS\Helpers\Form\CheckboxSet;
use IPS\Helpers\Form\Editor;
use IPS\Helpers\Form\Stack;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\Translatable;
use IPS\Helpers\Form\Url as FormUrl;
use IPS\Helpers\Form\YesNo;
use IPS\Http\Url;
use IPS\Lang;
use IPS\Member;
use IPS\Output;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
use function in_array;
use function intval;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* general
*/
class _general extends \IPS\Dispatcher\Controller
class general extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'general_manage' );
Dispatcher::i()->checkAcpPermission( 'general_manage' );
parent::execute();
}
@@ -43,27 +70,31 @@ class _general extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Text( 'board_name', \IPS\Settings::i()->board_name, TRUE ) );
$form = new Form;
$form->add( new Text( 'board_name', Settings::i()->board_name, TRUE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'site_online', \IPS\Settings::i()->site_online, FALSE, array(
$form->add( new YesNo( 'site_online', Settings::i()->site_online, FALSE, array(
'togglesOff' => array( 'site_offline_message_id' ),
) ) );
$form->add( new \IPS\Helpers\Form\Editor( 'site_offline_message', \IPS\Settings::i()->site_offline_message, FALSE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'onlineoffline', 'attachIds' => array( NULL, NULL, 'site_offline_message' ) ), NULL, NULL, NULL, 'site_offline_message_id' ) );
$form->add( new \IPS\Helpers\Form\Address( 'site_address', \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->site_address ), FALSE ) );
$form->add( new \IPS\Helpers\Form\Stack( 'site_social_profiles', \IPS\Settings::i()->site_social_profiles ? json_decode( \IPS\Settings::i()->site_social_profiles, true ) : array(), FALSE, array( 'stackFieldType' => '\IPS\core\Form\SocialProfiles', 'maxItems' => 50, 'key' => array( 'placeholder' => 'http://example.com', 'size' => 20 ) ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'site_twitter_id', \IPS\Settings::i()->site_twitter_id, FALSE, array( 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('site_twitter_id_placeholder'), 'size' => 20 ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'copyright_line', NULL, FALSE, array( 'app' => 'core', 'key' => 'copyright_line_value', 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('copyright_line_placeholder') ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'relative_dates_enable', \IPS\Settings::i()->relative_dates_enable, FALSE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'site_site_elsewhere', \IPS\Settings::i()->site_site_elsewhere, FALSE, [ 'togglesOn' => [ 'site_main_url', 'site_main_title' ] ] ) );
$form->add( new \IPS\Helpers\Form\Url( 'site_main_url', \IPS\Settings::i()->site_main_url, FALSE, [], NULL, NULL, NULL, 'site_main_url' ) );
$form->add( new \IPS\Helpers\Form\Text( 'site_main_title', \IPS\Settings::i()->site_main_title, FALSE, [], NULL, NULL, NULL, 'site_main_title' ) );
$form->add( new Editor( 'site_offline_message', 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 Address( 'site_address', GeoLocation::buildFromJson( Settings::i()->site_address ), FALSE ) );
$form->add( new Stack( 'site_social_profiles', Settings::i()->site_social_profiles ? json_decode( Settings::i()->site_social_profiles, true ) : array(), FALSE, array( 'stackFieldType' => '\IPS\core\Form\SocialProfiles', 'maxItems' => 50, 'key' => array( 'placeholder' => 'https://example.com', 'size' => 20 ) ) ) );
$form->add( new Text( 'site_twitter_id', Settings::i()->site_twitter_id, FALSE, array( 'placeholder' => Member::loggedIn()->language()->addToStack('site_twitter_id_placeholder'), 'size' => 20 ) ) );
$form->add( new Translatable( 'copyright_line', NULL, FALSE, array( 'app' => 'core', 'key' => 'copyright_line_value', 'placeholder' => Member::loggedIn()->language()->addToStack('copyright_line_placeholder') ) ) );
$form->add( new YesNo( 'relative_dates_enable', Settings::i()->relative_dates_enable, FALSE ) );
$form->add( new YesNo( 'site_site_elsewhere', Settings::i()->site_site_elsewhere, FALSE, [ 'togglesOn' => [ 'site_main_url', 'site_main_title' ] ] ) );
$form->add( new FormUrl( 'site_main_url', Settings::i()->site_main_url, FALSE, [], NULL, NULL, NULL, 'site_main_url' ) );
$form->add( new Text( 'site_main_title', Settings::i()->site_main_title, FALSE, [], NULL, NULL, NULL, 'site_main_title' ) );
$form->add( new CheckboxSet( 'diagnostics_reporting', array( 'usage' => ( (bool) Settings::i()->usage_reporting ), 'diagnostics' => ( (bool) Settings::i()->diagnostics_reporting ) ), FALSE, array( 'options' => array(
'usage' => 'diagnostics_reporting_usage',
'diagnostics' => 'diagnostics_reporting_diagnostics',
) ) ) );
if ( $values = $form->values() )
{
\IPS\Lang::saveCustom( 'core', "copyright_line_value", $values['copyright_line'] );
Lang::saveCustom( 'core', "copyright_line_value", $values['copyright_line'] );
unset( $values['copyright_line'] );
array_walk( $values['site_social_profiles'], function( &$value ){
@@ -74,30 +105,31 @@ class _general extends \IPS\Dispatcher\Controller
} ) );
$values['site_address'] = json_encode( $values['site_address'] );
$values['usage_reporting'] = in_array( 'usage', $values['diagnostics_reporting'] );
$values['diagnostics_reporting'] = in_array( 'diagnostics', $values['diagnostics_reporting'] );
Db::i()->update( 'core_tasks', array( 'enabled' => intval( $values['usage_reporting'] ) ), array( '`key`=?', 'usagereporting' ) );
$form->saveAsSettings( $values );
if ( $values['site_online'] )
{
\IPS\core\AdminNotification::remove( 'core', 'ConfigurationError', 'siteOffline' );
AdminNotification::remove( 'core', 'ConfigurationError', 'siteOffline' );
}
else
{
\IPS\core\AdminNotification::send( 'core', 'ConfigurationError', 'siteOffline', FALSE, NULL, \IPS\Member::loggedIn() );
AdminNotification::send( 'core', 'ConfigurationError', 'siteOffline', FALSE, NULL, Member::loggedIn() );
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Clear manifest and ie browser data stores */
unset( \IPS\Data\Store::i()->manifest, \IPS\Data\Store::i()->iebrowserconfig );
unset( Store::i()->manifest, Store::i()->iebrowserconfig );
\IPS\Session::i()->log( 'acplogs__general_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=general' ), 'saved' );
Session::i()->log( 'acplogs__general_settings' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=general' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_general');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_general', $form );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'settings/general.css', 'core', 'admin' ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_general');
Output::i()->output .= Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_general', $form );
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'settings/general.css', 'core', 'admin' ) );
}
}
@@ -11,35 +11,53 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application;
use IPS\core\AdminNotification;
use IPS\Data\Store;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Text;
use IPS\Http\Url;
use IPS\IPS;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* licensekey
*/
class _licensekey extends \IPS\Dispatcher\Controller
class licensekey extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* @brief Data about the license key from the store
*/
protected $licenseData = array();
protected array $licenseData = array();
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'licensekey_manage' );
Dispatcher::i()->checkAcpPermission( 'licensekey_manage' );
parent::execute();
}
@@ -48,42 +66,43 @@ class _licensekey extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Get license info. If license info is empty, refresh it. */
$licenseData = \IPS\IPS::licenseKey();
$licenseData = IPS::licenseKey();
/* If no license key has been supplied yet just show the form */
if( !\IPS\Settings::i()->ipb_reg_number )
if( !Settings::i()->ipb_reg_number )
{
return $this->settings();
$this->settings();
return;
}
/* Init */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('license_settings');
\IPS\Output::i()->sidebar['actions'] = array(
Output::i()->title = Member::loggedIn()->language()->addToStack('license_settings');
Output::i()->sidebar['actions'] = array(
'refresh' => array(
'icon' => 'refresh',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=licensekey&do=refresh' )->csrf(),
'link' => Url::internal( 'app=core&module=settings&controller=licensekey&do=refresh' )->csrf(),
'title' => 'license_refresh',
),
'remove' => array(
'icon' => 'pencil',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=licensekey&do=settings' ),
'link' => Url::internal( 'app=core&module=settings&controller=licensekey&do=settings' ),
'title' => 'license_change',
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('license_change') )
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => 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' );
Output::i()->output = 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 );
Output::i()->output = Theme::i()->getTemplate( 'licensekey', 'core' )->overview( $licenseData );
}
}
@@ -92,22 +111,22 @@ class _licensekey extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function refresh()
protected function refresh() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Fetch the license key data and update our local storage */
\IPS\IPS::licenseKey( TRUE );
IPS::licenseKey( TRUE );
/* Return the overview screen afterwards */
if ( isset( \IPS\Request::i()->return ) and \IPS\Request::i()->return === 'cloud' and \IPS\Application::appIsEnabled('cloud') )
if ( isset( Request::i()->return ) and Request::i()->return === 'cloud' and Application::appIsEnabled('cloud') )
{
\IPS\cloud\Application::toggleDisabledApps();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cloud&module=smartcommunity&controller=smartcommunity' ), 'cloud_license_refreshed' );
Output::i()->redirect( Url::internal( 'app=cloud&module=smartcommunity&controller=smartcommunity' ), 'cloud_license_refreshed' );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=licensekey' ), 'license_key_refreshed' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=licensekey' ), 'license_key_refreshed' );
}
}
@@ -116,32 +135,12 @@ class _licensekey extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function settings()
protected function settings() : void
{
$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 ) );
$form = new Form;
$form->add( new Text( 'ipb_reg_number', NULL, TRUE, array(), function( $val ){
IPS::checkLicenseKey( $val, Settings::i()->base_url );
} ) );
if ( $values = $form->values() )
{
@@ -153,17 +152,17 @@ class _licensekey extends \IPS\Dispatcher\Controller
}
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__license_settings' );
Session::i()->log( 'acplogs__license_settings' );
/* Refresh the locally stored license info */
unset( \IPS\Data\Store::i()->license_data );
unset( Store::i()->license_data );
\IPS\core\AdminNotification::remove( 'core', 'License', 'missing' );
AdminNotification::remove( 'core', 'License', 'missing' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=licensekey' ), 'saved' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=licensekey' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('license_settings');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_licensekey', $form );
Output::i()->title = Member::loggedIn()->language()->addToStack('license_settings');
Output::i()->output = Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_licensekey', $form );
}
}
+250 -170
View File
@@ -11,41 +11,76 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use IPS\Application;
use IPS\Data\Cache;
use IPS\Data\Store;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Extensions\SSOAbstract;
use IPS\GeoLocation;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Address;
use IPS\Helpers\Form\Interval;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Stack;
use IPS\Helpers\Form\Tel;
use IPS\Helpers\Form\Url as FormUrl;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\Wizard;
use IPS\Http\Request\Exception;
use IPS\Http\Url;
use IPS\Login as LoginClass;
use IPS\Login\Handler;
use IPS\Member;
use IPS\Member\Group;
use IPS\Node\Controller;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use LogicException;
use function defined;
use function is_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Login Methods
*/
class _login extends \IPS\Node\Controller
class login extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Node Class
*/
protected $nodeClass = 'IPS\Login\Handler';
protected string $nodeClass = 'IPS\Login\Handler';
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
protected bool $_addButtonInRoot = FALSE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_access' );
return parent::execute();
Dispatcher::i()->checkAcpPermission( 'login_access' );
parent::execute();
}
/**
@@ -53,7 +88,7 @@ class _login extends \IPS\Node\Controller
*
* @return array
*/
public function _getRootButtons()
public function _getRootButtons(): array
{
$buttons = parent::_getRootButtons();
@@ -70,31 +105,31 @@ class _login extends \IPS\Node\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Work out tabs */
$tabs = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_manage' ) )
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_manage' ) )
{
$tabs['handlers'] = 'login_handlers';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_settings' ) )
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_settings' ) )
{
$tabs['settings'] = 'login_settings';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'registration_settings' ) )
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'registration_settings' ) )
{
$tabs['registration'] = 'registration_settings';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_account_management' ) )
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'settings', 'login_account_management' ) )
{
$tabs['accountsettings'] = 'account_management_settings';
}
/* Get active tab */
if ( isset( \IPS\Request::i()->tab ) and isset( $tabs[ \IPS\Request::i()->tab ] ) )
if ( isset( Request::i()->tab ) and isset( $tabs[ Request::i()->tab ] ) )
{
$activeTab = \IPS\Request::i()->tab;
$activeTab = Request::i()->tab;
}
else
{
@@ -107,9 +142,9 @@ class _login extends \IPS\Node\Controller
switch ( $activeTab )
{
case 'handlers':
\IPS\Dispatcher::i()->checkAcpPermission( 'login_manage' );
Dispatcher::i()->checkAcpPermission( 'login_manage' );
parent::manage();
$output = \IPS\Output::i()->output;
$output = Output::i()->output;
break;
case 'settings':
$output = $this->_settings();
@@ -123,22 +158,22 @@ class _login extends \IPS\Node\Controller
}
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_login');
if ( \IPS\Request::i()->isAjax() )
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_login');
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->output = $output;
Output::i()->output = $output;
}
else
{
\IPS\Output::i()->sidebar['actions'] = array(
Output::i()->sidebar['actions'] = array(
'forcelogout' => array(
'title' => 'force_all_logout',
'icon' => 'lock',
'link' => \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&do=forceLogout' )->csrf(),
'link' => Url::internal( 'app=core&module=settings&controller=login&do=forceLogout' )->csrf(),
'data' => array( 'confirm' => '' ),
),
);
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $output, \IPS\Http\Url::internal( "app=core&module=settings&controller=login" ) );
Output::i()->output = Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $output, Url::internal( "app=core&module=settings&controller=login" ) );
}
}
@@ -147,23 +182,24 @@ class _login extends \IPS\Node\Controller
*
* @return void
*/
protected function form()
protected function form() : void
{
if ( \IPS\Request::i()->id )
if ( Request::i()->id )
{
return parent::form();
parent::form();
}
else
{
\IPS\Output::i()->output = (string) new \IPS\Helpers\Wizard( array(
Output::i()->output = (string) new Wizard( array(
'login_handler' => function( $data )
{
$options = array();
foreach ( \IPS\Login\Handler::handlerClasses() as $class )
foreach ( Handler::handlerClasses() as $class )
{
/* @var Handler $class */
if ( !$class::$allowMultiple )
{
foreach ( \IPS\Login\Handler::roots() as $handler )
foreach ( Handler::roots() as $handler )
{
if ( $handler instanceof $class )
{
@@ -174,8 +210,8 @@ class _login extends \IPS\Node\Controller
$options[ $class ] = $class::getTitle();
}
$form = new \IPS\Helpers\Form( 'login_handler_1', 'continue' );
$form->add( new \IPS\Helpers\Form\Radio( 'login_handler', TRUE, NULL, array( 'options' => $options ), function( $val )
$form = new Form( 'login_handler_1', 'continue' );
$form->add( new Radio( 'login_handler', TRUE, NULL, array( 'options' => $options ), function( $val )
{
$val::testCompatibility();
} ) );
@@ -195,21 +231,21 @@ class _login extends \IPS\Node\Controller
try
{
$node->settings = array();
$node->order = \IPS\Db::i()->select( 'MAX(login_order)', $node::$databaseTable )->first() + 1;
$node->order = Db::i()->select( 'MAX(login_order)', $node::$databaseTable )->first() + 1;
$node->saveForm( $node->formatFormValues( $values ) );
\IPS\Session::i()->log( 'acplog__node_created', array( $this->title => TRUE, $node->titleForLog() => FALSE ) );
Session::i()->log( 'acplog__node_created', array( $this->title => TRUE, $node->titleForLog() => FALSE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=login') );
Output::i()->redirect( Url::internal('app=core&module=settings&controller=login') );
}
catch ( \LogicException $e )
catch ( LogicException $e )
{
$form->error = $e->getMessage();
}
}
return $form;
}
), \IPS\Http\Url::internal('app=core&module=settings&controller=login&do=form') );
), Url::internal('app=core&module=settings&controller=login&do=form') );
}
}
@@ -219,13 +255,13 @@ class _login extends \IPS\Node\Controller
*
* @return void
*/
protected function enableToggle()
protected function enableToggle() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$loginMethod = \IPS\Login\Handler::load( \IPS\Request::i()->id );
$loginMethod = Handler::load( Request::i()->id );
if ( \IPS\Request::i()->status )
if ( Request::i()->status )
{
try
{
@@ -233,7 +269,7 @@ class _login extends \IPS\Node\Controller
}
catch ( \Exception $e )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=login&do=form&id={$loginMethod->id}" ) );
Output::i()->redirect( Url::internal( "app=core&module=settings&controller=login&do=form&id={$loginMethod->id}" ) );
}
}
else
@@ -242,11 +278,11 @@ class _login extends \IPS\Node\Controller
}
/* Clear caches */
unset( \IPS\Data\Store::i()->loginMethods, \IPS\Data\Store::i()->essentialCookieNames );
\IPS\Data\Cache::i()->clearAll();
unset( Store::i()->loginMethods, Store::i()->essentialCookieNames );
Cache::i()->clearAll();
/* Toggle */
return parent::enableToggle();
parent::enableToggle();
}
/**
@@ -254,36 +290,36 @@ class _login extends \IPS\Node\Controller
*
* @return void
*/
protected function delete()
protected function delete() : void
{
/* Check it's okay */
$loginMethod = \IPS\Login\Handler::load( \IPS\Request::i()->id );
$loginMethod = Handler::load( Request::i()->id );
$this->_disableCheck( $loginMethod );
/* Do it */
parent::delete();
/* Clear caches */
unset( \IPS\Data\Store::i()->loginMethods );
\IPS\Data\Cache::i()->clearAll();
unset( Store::i()->loginMethods, Store::i()->essentialCookieNames );
Cache::i()->clearAll();
}
/**
* If a particular method is disabled/deleted - will we still be able to log in?
*
* @param \IPS\Login\Handler $methodToRemove Handler to be disabled/deleted
* @return void
* @param Handler $methodToRemove Handler to be disabled/deleted
* @return bool
*/
protected function _disableCheck( \IPS\Login\Handler $methodToRemove )
protected function _disableCheck( Handler $methodToRemove ) : bool
{
foreach ( \IPS\Login::methods() as $method )
foreach ( LoginClass::methods() as $method )
{
if ( $method != $methodToRemove and $method->canProcess( \IPS\Member::loggedIn() ) and $method->acp )
if ( $method != $methodToRemove and $method->canProcess( Member::loggedIn() ) and $method->acp )
{
return true;
}
}
\IPS\Output::i()->error( 'login_handler_cannot_disable', '1C166/5', 403, '' );
Output::i()->error( 'login_handler_cannot_disable', '1C166/5', 403, '' );
}
/**
@@ -291,50 +327,47 @@ class _login extends \IPS\Node\Controller
*
* @return string
*/
protected function _settings()
protected function _settings() : string
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_settings' );
Dispatcher::i()->checkAcpPermission( 'login_settings' );
/* Build Form */
$form = new \IPS\Helpers\Form();
$form = new Form();
$form->addHeader( 'ipb_bruteforce_attempts_title' );
$form->addMessage( 'ipb_bruteforce_attempts_block_desc', 'ipsMessage ipsMessage_info' );
$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\Interval( 'ipb_bruteforce_period', \IPS\Settings::i()->ipb_bruteforce_period, FALSE, array( 'valueAs' => \IPS\Helpers\Form\Interval::MINUTES, 'min' => 0, 'max' => 10000, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), NULL, '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->addHtml( Theme::i()->getTemplate( 'forms' )->blurb( 'ipb_bruteforce_attempts_block_desc', true, true ) );
$form->add( new Number( 'ipb_bruteforce_attempts', Settings::i()->ipb_bruteforce_attempts, FALSE, array( 'min' => 0, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, Member::loggedIn()->language()->addToStack('after'), Member::loggedIn()->language()->addToStack('failed_logins'), 'ipb_bruteforce_attempts' ) );
$form->add( new Interval( 'ipb_bruteforce_period', Settings::i()->ipb_bruteforce_period, FALSE, array( 'valueAs' => Interval::MINUTES, 'min' => 0, 'max' => 10000, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, Member::loggedIn()->language()->addToStack('after'), NULL, 'ipb_bruteforce_period' ) );
$form->add( new YesNo( 'ipb_bruteforce_unlock', Settings::i()->ipb_bruteforce_unlock, FALSE, array(), NULL, NULL, NULL, 'ipb_bruteforce_unlock' ) );
$form->addHeader( 'bruteforce_global_attempts_title' );
$form->addMessage( 'bruteforce_global_attempts_block_desc', 'ipsMessage ipsMessage_info' );
$form->add( new \IPS\Helpers\Form\Number( 'bruteforce_global_attempts', \IPS\Settings::i()->bruteforce_global_attempts, FALSE, array( 'min' => 5 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), \IPS\Member::loggedIn()->language()->addToStack('failed_logins'), 'bruteforce_global_attempts' ) );
$form->add( new \IPS\Helpers\Form\Interval( 'bruteforce_global_period', \IPS\Settings::i()->bruteforce_global_period, FALSE, array( 'valueAs' => \IPS\Helpers\Form\Interval::MINUTES, 'min' => 0, 'max' => 10000 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), NULL, 'bruteforce_global_period' ) );
$form->addHtml( Theme::i()->getTemplate( 'forms' )->blurb( 'bruteforce_global_attempts_block_desc', true, true ) );
$form->add( new Number( 'bruteforce_global_attempts', Settings::i()->bruteforce_global_attempts, FALSE, array( 'min' => 5 ), NULL, Member::loggedIn()->language()->addToStack('after'), Member::loggedIn()->language()->addToStack('failed_logins'), 'bruteforce_global_attempts' ) );
$form->add( new Interval( 'bruteforce_global_period', Settings::i()->bruteforce_global_period, FALSE, array( 'valueAs' => Interval::MINUTES, 'min' => 0, 'max' => 10000 ), NULL, Member::loggedIn()->language()->addToStack('after'), NULL, 'bruteforce_global_period' ) );
$form->addHeader( 'login_settings' );
$form->add( new \IPS\Helpers\Form\YesNo( 'new_device_email', \IPS\Settings::i()->new_device_email, FALSE ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'login_after_inactivity_notification', \IPS\Settings::i()->login_after_inactivity_notification, FALSE ) );
$form->add( new YesNo( 'new_device_email', Settings::i()->new_device_email, FALSE ) );
/* Save */
if ( $values = $form->values() )
{
/* unlock all locked members if we have disabled the locking */
if ( \IPS\Settings::i()->ipb_bruteforce_attempts > 0 AND $values['ipb_bruteforce_attempts'] == 0 )
if ( Settings::i()->ipb_bruteforce_attempts > 0 AND $values['ipb_bruteforce_attempts'] == 0 )
{
\IPS\Member::updateAllMembers( array( 'failed_login_count' => 0 ) );
\IPS\Db::i()->delete( 'core_login_failures', [ 'login_member_id IS NOT NULL' ] );
Member::updateAllMembers( array( 'failed_login_count' => 0 ) );
Db::i()->delete( 'core_login_failures', [ 'login_member_id IS NOT NULL' ] );
/* disable task */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), "`key`='unlockmembers'" );
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'" );
Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='unlockmembers'" );
}
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__login_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=settings' ), 'saved' );
Session::i()->log( 'acplogs__login_settings' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=login&tab=settings' ), 'saved' );
}
/* Display */
@@ -344,18 +377,18 @@ class _login extends \IPS\Node\Controller
/**
* HTTPS check
*
* @return null
* @return void
*/
protected function httpsCheck()
protected function httpsCheck() : void
{
try
{
$response = \IPS\Http\Url::external( 'https://' . mb_substr( \IPS\Settings::i()->base_url, 7 ) )->request()->get();
\IPS\Output::i()->output = $response;
$response = Url::external( 'https://' . mb_substr( Settings::i()->base_url, 7 ) )->request()->get();
Output::i()->output = $response;
}
catch ( \IPS\Http\Request\Exception $e )
catch ( Exception $e )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->message( $e->getMessage() ?: '500_error_title', 'error' );
Output::i()->output = Theme::i()->getTemplate( 'global' )->message( $e->getMessage() ?: '500_error_title', 'error' );
}
}
@@ -364,60 +397,81 @@ class _login extends \IPS\Node\Controller
*
* @return string
*/
protected function _registration()
protected function _registration() : string
{
\IPS\Dispatcher::i()->checkAcpPermission( 'registration_settings' );
Dispatcher::i()->checkAcpPermission( 'registration_settings' );
/* Check SSO Extensions for overloads */
$disabledSettings = $appBlocks = [];
$ssoSettings = [ 'allow_reg', 'allow_reg_target' ];
foreach( Application::allExtensions( 'core', 'SSO', FALSE ) as $app => $ext )
{
/* @var SSOAbstract $ext */
if( $ext->isEnabled() )
{
foreach( array_keys( $ext->overrideSettings() ) as $settingKey )
{
if( !in_array( $settingKey, $ssoSettings ) )
{
continue;
}
$appBlocks[ $app ] = Member::loggedIn()->language()->addToStack( '__app_' . explode( '_', $app )[0], FALSE );
$disabledSettings[ $settingKey ] = $settingKey;
Member::loggedIn()->language()->words[ $settingKey . '_desc'] = Member::loggedIn()->language()->addToStack( 'sso_setting_override', FALSE, [ 'pluralize' => [ count( $appBlocks ) ],'htmlsprintf' => [ Member::loggedIn()->language()->formatList( $appBlocks ) ] ] );
}
}
}
/* Build Form */
$form = new \IPS\Helpers\Form();
$form = new Form();
$form->addHeader('registration_standard_settings');
$form->addMessage('registration_standard_settings_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'allow_reg', \IPS\Login::registrationType(), FALSE, array(
'options' => array(
$form->addHtml( Theme::i()->getTemplate( 'forms' )->blurb( 'registration_standard_settings_blurb', true, true ) );
$form->add( new Radio( 'allow_reg', LoginClass::registrationType(), FALSE, [
'options' => [
'normal' => 'allow_reg_normal',
'full' => 'allow_reg_full',
'redirect' => 'allow_reg_redirect',
'disabled' => 'allow_reg_disabled'
),
'toggles' => array(
'normal' => array( 'allow_reg_normal_warning' ),
'full' => array( 'minimum_age', 'use_coppa' ),
'redirect' => array( 'allow_reg_target' )
),
'disabled' => \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\Standard' ) ? array() : array( 'normal', 'full' )
) ) );
],
'toggles' => [
'normal' => [ 'allow_reg_normal_warning' ],
'full' => [ 'minimum_age', 'use_coppa' ],
'redirect' => [ 'allow_reg_target' ]
],
'disabled' => isset( $disabledSettings['allow_reg'] ) ? TRUE : ( Handler::findMethod( 'IPS\Login\Handler\Standard' ) ? [] : [ 'normal', 'full' ] )
] ) );
/* Do we have required custom fields? */
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_pfields_data', array( 'pf_not_null != 0 and pf_show_on_reg=1' ) )->first() )
if ( Db::i()->select( 'COUNT(*)', 'core_pfields_data', array( 'pf_not_null != 0 and pf_show_on_reg=1' ) )->first() )
{
\IPS\Member::loggedIn()->language()->words['allow_reg_normal_warning'] = \IPS\Member::loggedIn()->language()->addToStack( 'allow_reg_normal_desc_required_warning' );
Member::loggedIn()->language()->words['allow_reg_normal_warning'] = Member::loggedIn()->language()->addToStack( 'allow_reg_normal_desc_required_warning' );
}
$form->add( new \IPS\Helpers\Form\Url( 'allow_reg_target', \IPS\Settings::i()->allow_reg_target, NULL, array(), function( $val )
$form->add( new FormUrl( 'allow_reg_target', Settings::i()->allow_reg_target, NULL, [ 'disabled' => isset( $disabledSettings['allow_reg_target'] ) ], function( $val )
{
if ( !$val and \IPS\Request::i()->allow_red === 'redirect' )
if ( !$val and Request::i()->allow_red === 'redirect' )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, NULL, 'allow_reg_target' ) );
$form->add( new \IPS\Helpers\Form\Number( 'minimum_age', \IPS\Settings::i()->minimum_age, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'any_age' ), NULL, NULL, NULL, 'minimum_age' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'use_coppa', \IPS\Settings::i()->use_coppa, FALSE, array( 'togglesOn' => array( 'coppa_fax', 'coppa_address' ) ), NULL, NULL, NULL, 'use_coppa' ) );
$form->add( new \IPS\Helpers\Form\Tel( 'coppa_fax', \IPS\Settings::i()->coppa_fax, FALSE, array(), NULL, NULL, NULL, 'coppa_fax' ) );
$form->add( new \IPS\Helpers\Form\Address( 'coppa_address', \IPS\GeoLocation::buildFromJson( \IPS\Settings::i()->coppa_address ), FALSE, array(), NULL, NULL, NULL, 'coppa_address' ) );
$form->add( new Number( 'minimum_age', Settings::i()->minimum_age, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'any_age' ), NULL, NULL, NULL, 'minimum_age' ) );
$form->add( new YesNo( 'use_coppa', Settings::i()->use_coppa, FALSE, array( 'togglesOn' => array( 'coppa_fax', 'coppa_address' ) ), NULL, NULL, NULL, 'use_coppa' ) );
$form->add( new Tel( 'coppa_fax', Settings::i()->coppa_fax, FALSE, array(), NULL, NULL, NULL, 'coppa_fax' ) );
$form->add( new Address( 'coppa_address', Settings::i()->coppa_address ? GeoLocation::buildFromJson( Settings::i()->coppa_address ) : null, FALSE, array(), NULL, NULL, NULL, 'coppa_address' ) );
$form->addHeader('registration_global_settings');
$form->addMessage('registration_global_settings_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'reg_auth_type', \IPS\Settings::i()->reg_auth_type, FALSE, array(
$form->addHtml( Theme::i()->getTemplate( 'forms' )->blurb( 'registration_global_settings_blurb', true, true ) );
$form->add( new Radio( 'reg_auth_type', Settings::i()->reg_auth_type, FALSE, array(
'options' => array( 'user' => 'reg_auth_type_user', 'admin' => 'reg_auth_type_admin', 'admin_user' => 'reg_auth_type_admin_user', 'none' => 'reg_auth_type_none' ),
'toggles' => array( 'user' => array( 'validate_day_prune' ), 'admin_user' => array( 'validate_day_prune' ) )
), NULL, NULL, NULL, 'reg_auth_type' ) );
$form->add( new \IPS\Helpers\Form\Interval( 'validate_day_prune', \IPS\Settings::i()->validate_day_prune, FALSE, array( 'valueAs' => \IPS\Helpers\Form\Interval::DAYS, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), NULL, 'validate_day_prune' ) );
$form->add( new \IPS\Helpers\Form\Stack( 'allowed_reg_email', explode( ',', \IPS\Settings::i()->allowed_reg_email ), FALSE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
$form->add( new Interval( 'validate_day_prune', Settings::i()->validate_day_prune, FALSE, array( 'valueAs' => Interval::DAYS, 'unlimited' => 0, 'unlimitedLang' => 'never' ), NULL, Member::loggedIn()->language()->addToStack('after'), NULL, 'validate_day_prune' ) );
$form->add( new Stack( 'allowed_reg_email', explode( ',', Settings::i()->allowed_reg_email ), FALSE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
if( isset( $value[0] ) AND mb_stripos( $value[0], '@' ) )
{
throw new \DomainException( 'allowed_reg_email_email_detected' );
throw new DomainException( 'allowed_reg_email_email_detected' );
}
}, NULL, NULL ) );
$form->add( new \IPS\Helpers\Form\Radio( 'force_reg_terms', \IPS\Settings::i()->force_reg_terms, FALSE, array( 'options' => array(
$form->add( new Radio( 'force_reg_terms', Settings::i()->force_reg_terms, FALSE, array( 'options' => array(
'0' => 'force_reg_terms_0',
'1' => 'force_reg_terms_1',
) ) ) );
@@ -426,29 +480,26 @@ class _login extends \IPS\Node\Controller
if ( $values = $form->values() )
{
/* Save */
if ( isset( $values['allowed_reg_email'] ) and \is_array( $values['allowed_reg_email'] ) )
if ( isset( $values['allowed_reg_email'] ) and is_array( $values['allowed_reg_email'] ) )
{
$values['allowed_reg_email'] = implode( ',', $values['allowed_reg_email'] );
}
if ( isset( $values['coppa_address'] ) AND ( $values['coppa_address'] instanceof \IPS\GeoLocation ) )
if ( isset( $values['coppa_address'] ) AND ( $values['coppa_address'] instanceof GeoLocation ) )
{
$values['coppa_address'] = json_encode( $values['coppa_address'] );
}
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__registration_settings' );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
Session::i()->log( 'acplogs__registration_settings' );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=registration' ), 'saved' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=login&tab=registration' ), 'saved' );
}
$desc = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('registration_default_group_info', NULL, [ 'sprintf' => [\IPS\Member\Group::load( \IPS\Settings::i()->member_group )->formattedName ] ] ), 'info' );
$desc = Theme::i()->getTemplate( 'global', 'core' )->message( Member::loggedIn()->language()->addToStack('registration_default_group_info', NULL, [ 'sprintf' => [Group::load( Settings::i()->member_group )->formattedName ] ] ), 'none i-border-radius_0' );
/* Display */
return (string) $desc . $form;
return $desc . $form;
}
/**
@@ -456,74 +507,103 @@ class _login extends \IPS\Node\Controller
*
* @return string
*/
protected function _accountsettings()
protected function _accountsettings() : string
{
\IPS\Dispatcher::i()->checkAcpPermission( 'login_account_management' );
Dispatcher::i()->checkAcpPermission( 'login_account_management' );
/* Check SSO Extensions for overloads */
$disabledSettings = $appBlocks = [];
$ssoSettings = [ 'allow_email_changes', 'allow_email_changes_target', 'allow_password_changes', 'allow_password_changes_target', 'allow_forgot_password', 'allow_forgot_password_target' ];
foreach( Application::allExtensions( 'core', 'SSO', FALSE ) as $app => $ext )
{
/* @var SSOAbstract $ext */
if( $ext->isEnabled() )
{
foreach( array_keys( $ext->overrideSettings() ) as $settingKey )
{
if( !in_array( $settingKey, $ssoSettings ) )
{
continue;
}
$appBlocks[ $settingKey ][] = Member::loggedIn()->language()->addToStack( '__app_' . explode( '_', $app )[0], FALSE );
$disabledSettings[ $settingKey ] = true;
}
}
}
foreach( $appBlocks as $sKey => $apps )
{
Member::loggedIn()->language()->words[ $sKey . '_desc'] = Member::loggedIn()->language()->addToStack( 'sso_setting_override', FALSE, [ 'pluralize' => [ count( $apps ) ],'htmlsprintf' => [ Member::loggedIn()->language()->formatList( $apps ) ] ] );
}
/* Build Form */
$form = new \IPS\Helpers\Form();
$form = new Form();
$form->addHeader( 'security_header_accounts' );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter', \IPS\Settings::i()->password_strength_meter, FALSE, array( 'togglesOn' => array( 'password_strength_meter_enforce' ) ), NULL, NULL, NULL, 'password_strength_meter' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'password_strength_meter_enforce', \IPS\Settings::i()->password_strength_meter_enforce, FALSE, array( 'togglesOn' => array( 'password_strength_option' ) ), NULL, NULL, NULL, 'password_strength_meter_enforce' ) );
$form->add( new YesNo( 'password_strength_meter', Settings::i()->password_strength_meter, FALSE, array( 'togglesOn' => array( 'password_strength_meter_enforce' ) ), NULL, NULL, NULL, 'password_strength_meter' ) );
$form->add( new YesNo( 'password_strength_meter_enforce', Settings::i()->password_strength_meter_enforce, FALSE, array( 'togglesOn' => array( 'password_strength_option' ) ), NULL, NULL, NULL, 'password_strength_meter_enforce' ) );
$strengthOptions = array(
'3' => 'strength_3',
'4' => 'strength_4',
'5' => 'strength_5',
);
$form->add( new \IPS\Helpers\Form\Radio( 'password_strength_option', \IPS\Settings::i()->password_strength_option, FALSE, array( 'options' => $strengthOptions ), NULL, NULL, NULL, 'password_strength_option' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'device_management', \IPS\Settings::i()->device_management, FALSE ) );
$form->add( new Radio( 'password_strength_option', Settings::i()->password_strength_option, FALSE, array( 'options' => $strengthOptions ), NULL, NULL, NULL, 'password_strength_option' ) );
$form->add( new YesNo( 'device_management', Settings::i()->device_management, FALSE ) );
$form->addHeader('account_management_email_pass');
$form->addMessage('account_management_email_pass_blurb');
$form->add( new \IPS\Helpers\Form\Radio( 'allow_email_changes', \IPS\Settings::i()->allow_email_changes, FALSE, array(
'options' => array(
$form->addHtml( Theme::i()->getTemplate( 'forms' )->blurb( 'account_management_email_pass_blurb', true, true ) );
$form->add( new Radio( 'allow_email_changes', Settings::i()->allow_email_changes, FALSE, [
'options' => [
'normal' => 'allow_email_changes_normal',
'redirect' => 'allow_email_changes_redirect',
'disabled' => 'allow_email_changes_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_email_changes_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_email_changes_target', \IPS\Settings::i()->allow_email_changes_target, NULL, array(), function( $val )
],
'toggles' => [
'redirect' => [ 'allow_email_changes_target' ]
],
'disabled' => isset( $disabledSettings['allow_email_changes'] )
] ) );
$form->add( new FormUrl( 'allow_email_changes_target', Settings::i()->allow_email_changes_target, NULL, [ 'disabled' => isset( $disabledSettings['allow_email_changes_target'] ) ], function( $val )
{
if ( !$val and \IPS\Request::i()->allow_email_changes === 'redirect' )
if ( !$val and Request::i()->allow_email_changes === 'redirect' )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, NULL, 'allow_email_changes_target' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'allow_password_changes', \IPS\Settings::i()->allow_password_changes, FALSE, array(
'options' => array(
$form->add( new Radio( 'allow_password_changes', Settings::i()->allow_password_changes, FALSE, [
'options' => [
'normal' => 'allow_password_changes_normal',
'redirect' => 'allow_password_changes_redirect',
'disabled' => 'allow_password_changes_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_password_changes_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_password_changes_target', \IPS\Settings::i()->allow_password_changes_target, NULL, array(), function( $val )
],
'toggles' => [
'redirect' => [ 'allow_password_changes_target' ]
],
'disabled' => isset( $disabledSettings['allow_password_changes'] )
] ) );
$form->add( new FormUrl( 'allow_password_changes_target', Settings::i()->allow_password_changes_target, NULL, [ 'disabled' => isset( $disabledSettings['allow_password_changes_target'] ) ], function( $val )
{
if ( !$val and \IPS\Request::i()->allow_password_changes === 'redirect' )
if ( !$val and Request::i()->allow_password_changes === 'redirect' )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, NULL, 'allow_password_changes_target' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'allow_forgot_password', \IPS\Settings::i()->allow_forgot_password, FALSE, array(
'options' => array(
$form->add( new Radio( 'allow_forgot_password', Settings::i()->allow_forgot_password, FALSE, [
'options' => [
'normal' => 'allow_forgot_password_normal',
'handler' => 'allow_forgot_password_handler',
'redirect' => 'allow_forgot_password_redirect',
'disabled' => 'allow_forgot_password_disabled',
),
'toggles' => array(
'redirect' => array( 'allow_forgot_password_target' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Url( 'allow_forgot_password_target', \IPS\Settings::i()->allow_forgot_password_target, NULL, array(), function( $val )
],
'toggles' => [
'redirect' => [ 'allow_forgot_password_target' ]
],
'disabled' => isset( $disabledSettings['allow_forgot_password'] )
] ) );
$form->add( new FormUrl( 'allow_forgot_password_target', Settings::i()->allow_forgot_password_target, FALSE, [ 'disabled' => isset( $disabledSettings['allow_forgot_password_target'] ) ], function( $val )
{
if ( !$val and \IPS\Request::i()->allow_forgot_password === 'redirect' )
if ( !$val and Request::i()->allow_forgot_password === 'redirect' )
{
throw new \DomainException('form_required');
throw new DomainException('form_required');
}
}, NULL, NULL, 'allow_forgot_password_target' ) );
@@ -534,8 +614,8 @@ class _login extends \IPS\Node\Controller
$form->saveAsSettings( $values );
\IPS\Session::i()->log( 'acplogs__account_management_settings' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login&tab=accountsettings' ), 'saved' );
Session::i()->log( 'acplogs__account_management_settings' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=login&tab=accountsettings' ), 'saved' );
}
/* Display */
@@ -547,14 +627,14 @@ class _login extends \IPS\Node\Controller
*
* @return void
*/
protected function forceLogout()
protected function forceLogout() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
\IPS\Db::i()->update( 'core_members_known_devices', array( 'login_key' => NULL ) );
\IPS\Db::i()->delete( 'core_sessions' );
Db::i()->update( 'core_members_known_devices', array( 'login_key' => NULL ) );
Db::i()->delete( 'core_sessions' );
\IPS\Session::i()->log( 'acplogs__logout_force' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=settings&controller=login' ), 'logged_out_force' );
Session::i()->log( 'acplogs__logout_force' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=login' ), 'logged_out_force' );
}
}
@@ -11,30 +11,54 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\CheckboxSet;
use IPS\Helpers\Form\Interval;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Translatable;
use IPS\Helpers\Tree\Tree;
use IPS\Http\Url;
use IPS\Lang;
use IPS\Member;
use IPS\Member\Group;
use IPS\MFA\MFAHandler;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Multi-Factor Authentication
*/
class _mfa extends \IPS\Dispatcher\Controller
class mfa extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'mfa_manage' );
Dispatcher::i()->checkAcpPermission( 'mfa_manage' );
parent::execute();
}
@@ -43,14 +67,14 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$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';
$activeTab = ( isset( Request::i()->tab ) and array_key_exists( Request::i()->tab, $tabs ) ) ? Request::i()->tab : 'handlers';
if ( $activeTab === 'handlers' )
{
@@ -61,14 +85,14 @@ class _mfa extends \IPS\Dispatcher\Controller
$activeTabContents = $this->_manageSettings();
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_mfa');
if( \IPS\Request::i()->isAjax() )
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_mfa');
if( Request::i()->isAjax() )
{
\IPS\Output::i()->output = $activeTabContents;
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" ) );
Output::i()->output = Theme::i()->getTemplate( 'forms' )->blurb( 'mfa_blurb' ) . Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, Url::internal( "app=core&module=settings&controller=mfa" ) );
}
}
@@ -77,22 +101,22 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function _manageHandlers()
protected function _manageHandlers() : string
{
/* Create the tree */
$url = \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa&tab=handlers" );
$tree = new \IPS\Helpers\Tree\Tree(
$url = Url::internal( "app=core&module=settings&controller=mfa&tab=handlers" );
$tree = new Tree(
$url,
NULL,
function() use( $url ) {
$return = array();
foreach ( \IPS\MFA\MFAHandler::handlers() as $key => $handler )
foreach ( MFAHandler::handlers() as $key => $handler )
{
$return[] = \IPS\Theme::i()->getTemplate( 'trees', 'core' )->row(
$return[] = Theme::i()->getTemplate( 'trees', 'core' )->row(
$url,
$key,
\IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_title"),
Member::loggedIn()->language()->addToStack("mfa_{$key}_title"),
FALSE,
array(
'settings' => array(
@@ -101,7 +125,7 @@ class _mfa extends \IPS\Dispatcher\Controller
'link' => $url->setQueryString( array( 'do' => 'settings', 'key' => $key ) ),
)
),
\IPS\Member::loggedIn()->language()->addToStack("mfa_{$key}_desc"),
Member::loggedIn()->language()->addToStack("mfa_{$key}_desc"),
NULL,
NULL,
FALSE,
@@ -117,7 +141,7 @@ class _mfa extends \IPS\Dispatcher\Controller
);
/* Return */
return \IPS\Theme::i()->getTemplate( 'forms' )->blurb( 'mfa_blurb', TRUE, TRUE ) . $tree;
return $tree;
}
/**
@@ -125,42 +149,42 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function enableToggle()
protected function enableToggle() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
$key = \IPS\Request::i()->id;
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = Request::i()->id;
$handlers = MFAHandler::handlers();
if ( !isset( $handlers[ $key ] ) )
{
\IPS\Output::i()->error( 'node_error', '2C345/1', 404, '' );
Output::i()->error( 'node_error', '2C345/1', 404, '' );
}
try
{
$handlers[ $key ]->toggle( \IPS\Request::i()->status );
$handlers[ $key ]->toggle( Request::i()->status );
if ( \IPS\Request::i()->status )
if ( Request::i()->status )
{
\IPS\Session::i()->log( 'acplogs__mfa_handler_enabled', array( "mfa_{$key}_title" => TRUE ) );
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 ) );
Session::i()->log( 'acplogs__mfa_handler_disabled', array( "mfa_{$key}_title" => TRUE ) );
}
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json('OK');
Output::i()->json('OK');
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa" ) );
Output::i()->redirect( Url::internal( "app=core&module=settings&controller=mfa" ) );
}
}
catch ( \Exception $e )
catch ( Exception $e )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=" . $key ) );
Output::i()->redirect( Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=" . $key ) );
}
}
@@ -169,21 +193,21 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function settings()
protected function settings() : void
{
$key = \IPS\Request::i()->key;
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = Request::i()->key;
$handlers = MFAHandler::handlers();
if ( !isset( $handlers[ $key ] ) )
{
\IPS\Output::i()->error( 'node_error', '2C345/2', 404, '' );
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") );
Output::i()->title = Member::loggedIn()->language()->addToStack("mfa_{$key}_title");
Output::i()->output = $output;
Output::i()->breadcrumb[] = array( Url::internal('app=core&module=settings&controller=mfa&tab=handlers'), Member::loggedIn()->language()->addToStack('menu__core_settings_mfa') );
Output::i()->breadcrumb[] = array( NULL, Member::loggedIn()->language()->addToStack("mfa_{$key}_title") );
}
/**
@@ -191,26 +215,26 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return string
*/
protected function _manageSettings()
protected function _manageSettings() : string
{
$form = new \IPS\Helpers\Form;
$form = new 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\CheckboxSet( 'mfa_required_groups', \IPS\Settings::i()->mfa_required_groups == '*' ? '*' : explode( ',', \IPS\Settings::i()->mfa_required_groups ), FALSE, array(
$groups = array_combine( array_keys( Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, Group::groups() ) );
$form->add( new CheckboxSet( 'mfa_required_groups', Settings::i()->mfa_required_groups == '*' ? '*' : explode( ',', Settings::i()->mfa_required_groups ), FALSE, array(
'multiple' => TRUE,
'options' => $groups,
'unlimited' => '*',
'unlimitedLang' => 'everyone',
'impliedUnlimited' => TRUE
) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'mfa_required_prompt', \IPS\Settings::i()->mfa_required_prompt, FALSE, array(
$form->add( new Radio( 'mfa_required_prompt', 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(
$form->add( new Radio( 'mfa_optional_prompt', Settings::i()->mfa_optional_prompt, FALSE, array(
'options' => array(
'immediate' => 'mfa_prompt_immediate',
'access' => 'mfa_prompt_access',
@@ -221,15 +245,15 @@ class _mfa extends \IPS\Dispatcher\Controller
'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->add( new 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\Interval( 'security_questions_timer', \IPS\Settings::i()->security_questions_timer, FALSE, array( 'valueAs' => \IPS\Helpers\Form\Interval::MINUTES, 'unlimited' => 0, 'unlimitedLang' => 'security_questions_timer_session' ) ) );
$form->add( new CheckboxSet( 'security_questions_areas', Settings::i()->security_questions_areas ? explode( ',', Settings::i()->security_questions_areas ) : array_keys( MFAHandler::areas() ), FALSE, array( 'options' => MFAHandler::areas() ), NULL, NULL, NULL, 'security_questions_areas' ) );
$form->add( new Interval( 'security_questions_timer', Settings::i()->security_questions_timer, FALSE, array( 'valueAs' => Interval::MINUTES, 'unlimited' => 0, 'unlimitedLang' => 'security_questions_timer_session' ) ) );
$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(
$form->add( new Number( 'security_questions_tries', Settings::i()->security_questions_tries, FALSE, array( 'min' => 1 ) ) );
$form->add( new Radio( 'mfa_lockout_behaviour', Settings::i()->mfa_lockout_behaviour, FALSE, array(
'options' => array(
'lock' => 'mfa_lockout_behaviour_lock',
'email' => 'mfa_lockout_behaviour_email',
@@ -239,8 +263,8 @@ class _mfa extends \IPS\Dispatcher\Controller
'lock' => array( 'mfa_lockout_time' )
)
) ) );
$form->add( new \IPS\Helpers\Form\Interval( 'mfa_lockout_time', \IPS\Settings::i()->mfa_lockout_time, FALSE, array( 'valueAs' => \IPS\Helpers\Form\Interval::MINUTES, 'min' => 1 ), NULL, NULL, NULL, 'mfa_lockout_time' ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'mfa_forgot_behaviour', explode( ',', \IPS\Settings::i()->mfa_forgot_behaviour ), FALSE, array(
$form->add( new Interval( 'mfa_lockout_time', Settings::i()->mfa_lockout_time, FALSE, array( 'valueAs' => Interval::MINUTES, 'min' => 1 ), NULL, NULL, NULL, 'mfa_lockout_time' ) );
$form->add( new CheckboxSet( 'mfa_forgot_behaviour', explode( ',', Settings::i()->mfa_forgot_behaviour ), FALSE, array(
'options' => array(
'email' => 'mfa_forgot_behaviour_email',
'contact' => 'mfa_forgot_behaviour_contact',
@@ -250,7 +274,7 @@ class _mfa extends \IPS\Dispatcher\Controller
if ( $values = $form->values() )
{
\IPS\Lang::saveCustom( 'core', 'security_questions_opt_out_warning_value', $values['security_questions_opt_out_warning'] );
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'] );
@@ -259,8 +283,8 @@ class _mfa extends \IPS\Dispatcher\Controller
$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' );
Session::i()->log( 'acplogs__mfa_settings_updated' );
Output::i()->redirect( Url::internal( 'app=core&module=settings&controller=mfa&tab=settings' ), 'saved' );
}
return (string) $form;
@@ -271,16 +295,16 @@ class _mfa extends \IPS\Dispatcher\Controller
*
* @return void
*/
public function resetSecurityAnswers()
public function resetSecurityAnswers() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
\IPS\Db::i()->delete( 'core_security_answers' );
\IPS\Db::i()->update( 'core_members', "members_bitoptions2=members_bitoptions2 &~ 512" );
Db::i()->delete( 'core_security_answers' );
Db::i()->update( 'core_members', "members_bitoptions2=members_bitoptions2 &~ 512" );
/* Log MFA reset */
\IPS\Session::i()->log( 'acplogs__mfa_questions_reset' );
Session::i()->log( 'acplogs__mfa_questions_reset' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions" ), 'acplogs__mfa_questions_reset' );
Output::i()->redirect( Url::internal( "app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions" ), 'acplogs__mfa_questions_reset' );
}
}
File diff suppressed because it is too large. Load diff
@@ -11,41 +11,50 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Controller;
use IPS\Node\Model;
use IPS\Output;
use IPS\Request;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Security Questions
*/
class _securityquestions extends \IPS\Node\Controller
class securityquestions extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Node Class
*/
protected $nodeClass = '\IPS\MFA\SecurityQuestions\Question';
protected string $nodeClass = '\IPS\MFA\SecurityQuestions\Question';
/**
* Show the "add" button in the page root rather than the table root
*/
protected $_addButtonInRoot = FALSE;
protected bool $_addButtonInRoot = FALSE;
/**
* Form
*
* @return void
*/
public function form()
public function form() : void
{
\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") );
Output::i()->breadcrumb[] = array( Url::internal('app=core&module=settings&controller=mfa&tab=handlers'), Member::loggedIn()->language()->addToStack('menu__core_settings_mfa') );
Output::i()->breadcrumb[] = array( Url::internal('app=core&module=settings&controller=mfa&tab=questions&do=settings&key=questions'), Member::loggedIn()->language()->addToStack("mfa_questions_title") );
parent::form();
}
@@ -54,28 +63,28 @@ class _securityquestions extends \IPS\Node\Controller
*
* @return void
*/
protected function settings()
protected function settings() : void
{
return $this->manage();
$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
* @param Model|null $old A clone of the node as it was before or NULL if this is a creation
* @param Model $new The node now
* @param string $lastUsedTab The tab last used in the form
* @return void
*/
protected function _afterSave( ?\IPS\Node\Model $old, \IPS\Node\Model $new, $lastUsedTab = FALSE )
protected function _afterSave( ?Model $old, Model $new, mixed $lastUsedTab = FALSE ): void
{
if( \IPS\Request::i()->isAjax() )
if( Request::i()->isAjax() )
{
\IPS\Output::i()->json( array() );
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' );
Output::i()->redirect( Url::internal('app=core&module=settings&controller=mfa&tab=handlers&do=settings&key=questions&tab=questions'), 'saved' );
}
}
}
@@ -11,30 +11,51 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Data\Store;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Translatable;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\Form\Url as FormUrl;
use IPS\Http\Url;
use IPS\Lang;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use function defined;
use function intval;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* terms
*/
class _terms extends \IPS\Dispatcher\Controller
class terms extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'terms_manage' );
Dispatcher::i()->checkAcpPermission( 'terms_manage' );
parent::execute();
}
@@ -43,43 +64,40 @@ class _terms extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = new \IPS\Helpers\Form;
$form = new Form;
static::buildForm( $form );
if ( $values = $form->values() )
{
/* What were our previous values? */
$existingPrivacyPolicy = iterator_to_array( \IPS\Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'privacy_text_value' ) ) );
$existingRegistrationTerms = iterator_to_array( \IPS\Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'reg_rules_value' ) ) );
$existingPrivacyPolicy = iterator_to_array( Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'privacy_text_value' ) ) );
$existingRegistrationTerms = iterator_to_array( Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'reg_rules_value' ) ) );
/* Save */
$values = static::processForm( $values );
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Log */
\IPS\Session::i()->log( 'acplogs__terms_edited' );
Session::i()->log( 'acplogs__terms_edited' );
/* Do we need to ask the admin if they want to ask members to reconfirm? */
$changedPrivacyPolicy = $existingPrivacyPolicy != iterator_to_array( \IPS\Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'privacy_text_value' ) ) );
$changedRegistrationTerms = $existingRegistrationTerms != iterator_to_array( \IPS\Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'reg_rules_value' ) ) );
$changedPrivacyPolicy = $existingPrivacyPolicy != iterator_to_array( Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'privacy_text_value' ) ) );
$changedRegistrationTerms = $existingRegistrationTerms != iterator_to_array( Db::i()->select( 'word_custom', 'core_sys_lang_words', array( 'word_key=?', 'reg_rules_value' ) ) );
if ( $changedPrivacyPolicy or $changedRegistrationTerms )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=terms&do=reconfirm')->setQueryString( array(
'privacy' => \intval( $changedPrivacyPolicy ),
'reg' => \intval( $changedRegistrationTerms )
Output::i()->redirect( Url::internal('app=core&module=settings&controller=terms&do=reconfirm')->setQueryString( array(
'privacy' => intval( $changedPrivacyPolicy ),
'reg' => intval( $changedRegistrationTerms )
) ) );
}
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_terms');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_terms', $form );
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_terms');
Output::i()->output .= Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_terms', $form );
}
/**
@@ -88,7 +106,7 @@ class _terms extends \IPS\Dispatcher\Controller
* @param array $values Values from form
* @return array
*/
public static function processForm( $values )
public static function processForm( array $values ) : array
{
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', 'cookie_3rdpartynotice' => 'cookie_3rdpartynotice_value' ) as $k => $v )
{
@@ -101,12 +119,12 @@ class _terms extends \IPS\Dispatcher\Controller
}
}
\IPS\Lang::saveCustom( 'core', $v, $values[ $k ] );
Lang::saveCustom( 'core', $v, $values[ $k ] );
unset( $values[ $k ] );
}
/* Update the essential cookie name list */
unset( \IPS\Data\Store::i()->essentialCookieNames );
unset( Store::i()->essentialCookieNames );
return $values;
}
@@ -114,13 +132,13 @@ class _terms extends \IPS\Dispatcher\Controller
/**
* Build the form
*
* @param \IPS\Form $form Form to add settings to
* @param Form $form Form to add settings to
* @return void
*/
public static function buildForm( $form )
public static function buildForm( Form $form ) : void
{
$form->addHeader( 'terms_guidelines' );
$form->add( new \IPS\Helpers\Form\Radio( 'gl_type', \IPS\Settings::i()->gl_type, FALSE, array(
$form->add( new Radio( 'gl_type', Settings::i()->gl_type, FALSE, array(
'options' => array(
'internal' => 'gl_internal',
'external' => 'gl_external',
@@ -132,10 +150,10 @@ class _terms extends \IPS\Dispatcher\Controller
)
) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'gl_guidelines', NULL, FALSE, array( 'app' => 'core', 'key' => 'guidelines_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'Guidelines', 'attachIds' => array( NULL, NULL, 'gl_guidelines' ) ) ), NULL, NULL, NULL, 'gl_guidelines_id' ) );
$form->add( new \IPS\Helpers\Form\Url( 'gl_link', \IPS\Settings::i()->gl_link, FALSE, array(), NULL, NULL, NULL, 'gl_link' ) );
$form->add( new Translatable( 'gl_guidelines', NULL, FALSE, array( 'app' => 'core', 'key' => 'guidelines_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'Guidelines', 'attachIds' => array( NULL, NULL, 'gl_guidelines' ) ) ), NULL, NULL, NULL, 'gl_guidelines_id' ) );
$form->add( new FormUrl( 'gl_link', Settings::i()->gl_link, FALSE, array(), NULL, NULL, NULL, 'gl_link' ) );
$form->addHeader( 'terms_privacy');
$form->add( new \IPS\Helpers\Form\Radio( 'privacy_type', \IPS\Settings::i()->privacy_type, FALSE, array(
$form->add( new Radio( 'privacy_type', Settings::i()->privacy_type, FALSE, array(
'options' => array(
'internal' => 'privacy_internal',
'external' => 'privacy_external',
@@ -147,22 +165,20 @@ class _terms extends \IPS\Dispatcher\Controller
)
) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'privacy_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'privacy_text_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'Privacy', 'attachIds' => array( NULL, NULL, 'privacy_text' ) ) ), NULL, NULL, NULL, 'privacy_text_id' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'privacy_show_processors', \IPS\Settings::i()->privacy_show_processors, FALSE, array(), NULL, NULL, NULL, 'privacy_show_processors' ) );
$form->add( new Translatable( 'privacy_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'privacy_text_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'Privacy', 'attachIds' => array( NULL, NULL, 'privacy_text' ) ) ), NULL, NULL, NULL, 'privacy_text_id' ) );
$form->add( new YesNo( 'privacy_show_processors', Settings::i()->privacy_show_processors, FALSE, array(), NULL, NULL, NULL, 'privacy_show_processors' ) );
$form->add( new \IPS\Helpers\Form\Url( 'privacy_link', \IPS\Settings::i()->privacy_link, FALSE, array(), NULL, NULL, NULL, 'privacy_link' ) );
$form->add( new FormUrl( 'privacy_link', Settings::i()->privacy_link, FALSE, array(), NULL, NULL, NULL, 'privacy_link' ) );
$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->add( new 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}', '{cookies}' ) ), NULL, NULL, NULL, 'guest_terms_bar_text' ) );
$form->add( new YesNo( 'guest_terms_bar', Settings::i()->guest_terms_bar, FALSE, array( 'togglesOn' => array( 'guest_terms_bar_text' ) ) ) );
$form->add( new Translatable( 'guest_terms_bar_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'guest_terms_bar_text_value', 'sprintf' => array( '{terms}', '{privacy}', '{guidelines}', '{cookies}' ) ), NULL, NULL, NULL, 'guest_terms_bar_text' ) );
$form->addHeader( 'terms_cookies' );
$form->add( new \IPS\Helpers\Form\Translatable( 'cookie_3rdpartynotice', NULL, FALSE, array( 'app' => 'core', 'key' => 'cookie_3rdpartynotice_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => '3rdPartyCookies', 'attachIds' => array( NULL, NULL, 'privacy_text' ) ) ) ));
$form->add( new Translatable( 'cookie_3rdpartynotice', NULL, FALSE, array( 'app' => 'core', 'key' => 'cookie_3rdpartynotice_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => '3rdPartyCookies', 'attachIds' => array( NULL, NULL, 'privacy_text' ) ) ) ));
}
/**
@@ -170,37 +186,37 @@ class _terms extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function reconfirm()
protected function reconfirm() : void
{
$form = new \IPS\Helpers\Form;
$form = new Form;
$form->addMessage( 'admin_reconfirm_blurb' );
if ( \IPS\Request::i()->reg )
if ( Request::i()->reg )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'admin_reconfirm_reg_terms', FALSE ) );
$form->add( new YesNo( 'admin_reconfirm_reg_terms', FALSE ) );
}
if ( \IPS\Request::i()->privacy )
if ( Request::i()->privacy )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'admin_reconfirm_privacy', FALSE ) );
$form->add( new YesNo( 'admin_reconfirm_privacy', FALSE ) );
}
if ( $values = $form->values() )
{
if ( isset( $values['admin_reconfirm_reg_terms'] ) and $values['admin_reconfirm_reg_terms'] )
{
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_terms'] ) );
Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_terms'] ) );
}
if ( isset( $values['admin_reconfirm_privacy'] ) and $values['admin_reconfirm_privacy'] )
{
\IPS\Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . \IPS\Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_privacy'] ) );
Member::updateAllMembers( array( "members_bitoptions2 = members_bitoptions2 | " . Member::$bitOptions['members_bitoptions']['members_bitoptions2']['must_reaccept_privacy'] ) );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=settings&controller=terms') );
Output::i()->redirect( Url::internal('app=core&module=settings&controller=terms') );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_terms');
\IPS\Output::i()->output = $form;
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_terms');
Output::i()->output = $form;
}
}
@@ -12,30 +12,61 @@
namespace IPS\core\modules\admin\settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Data\Store;
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\File;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Color;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\TextArea;
use IPS\Helpers\Form\Upload;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\MultipleRedirect;
use IPS\Http\Url;
use IPS\Http\Url\Friendly;
use IPS\Image;
use IPS\Log;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use LogicException;
use function count;
use function defined;
use function mb_strstr;
use function strlen;
use function substr;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* webapp
*/
class _webapp extends \IPS\Dispatcher\Controller
class webapp extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'webapp_manage' );
Dispatcher::i()->checkAcpPermission( 'webapp_manage' );
parent::execute();
}
@@ -44,74 +75,78 @@ class _webapp extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = new \IPS\Helpers\Form;
$form = new Form;
$form->addTab( 'webapp_tab_icons' );
/* Homescreen icons - we accept one upload and create the images we need */
$homeScreen = json_decode( \IPS\Settings::i()->icons_homescreen, TRUE ) ?? array();
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen', ( isset( $homeScreen['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreen['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
$homeScreen = json_decode( Settings::i()->icons_homescreen, TRUE ) ?? array();
$form->add( new Upload( 'icons_homescreen', ( isset( $homeScreen['original'] ) ) ? File::get( 'core_Icons', $homeScreen['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
$homeScreenMaskable = json_decode( \IPS\Settings::i()->icons_homescreen_maskable, TRUE ) ?? array();
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen_maskable', ( isset( $homeScreenMaskable['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreenMaskable['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons', 'allowedFileTypes' => ['png', 'webp' ] ) ) );
$homeScreenMaskable = json_decode( Settings::i()->icons_homescreen_maskable, TRUE ) ?? array();
$form->add( new Upload( 'icons_homescreen_maskable', ( isset( $homeScreenMaskable['original'] ) ) ? File::get( 'core_Icons', $homeScreenMaskable['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons', 'allowedFileTypes' => ['png', 'webp' ] ) ) );
/* Apple startup screen logo - we accept one upload and create the images we need */
$apple = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
$form->add( new \IPS\Helpers\Form\Upload( 'icons_apple_startup', ( isset( $apple['original'] ) ) ? \IPS\File::get( 'core_Icons', $apple['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
$apple = json_decode( Settings::i()->icons_apple_startup, TRUE ) ?? array();
$form->add( new Upload( 'icons_apple_startup', ( isset( $apple['original'] ) ) ? File::get( 'core_Icons', $apple['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
/* Safari pinned tabs icon and highlight color */
$form->add( new \IPS\Helpers\Form\Upload( 'icons_mask_icon', \IPS\Settings::i()->icons_mask_icon ? \IPS\File::get( 'core_Icons', \IPS\Settings::i()->icons_mask_icon ) : NULL, FALSE, array( 'allowedFileTypes' => array( 'svg' ), 'storageExtension' => 'core_Icons', 'obscure' => FALSE ) ) );
$form->add( new \IPS\Helpers\Form\Color( 'icons_mask_color', \IPS\Settings::i()->icons_mask_color, FALSE ) );
$form->add( new Upload( 'icons_mask_icon', Settings::i()->icons_mask_icon ? File::get( 'core_Icons', Settings::i()->icons_mask_icon ) : NULL, FALSE, array( 'allowedFileTypes' => array( 'svg' ), 'storageExtension' => 'core_Icons', 'obscure' => FALSE ) ) );
$form->add( new Color( 'icons_mask_color', Settings::i()->icons_mask_color, FALSE ) );
$form->addTab( 'webapp_tab_manifest' );
/* And finally, additional manifest and livetile details */
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
$manifestDetails = json_decode( Settings::i()->manifest_details, TRUE );
if ( isset( $manifestDetails['cache_key'] ) )
{
unset( $manifestDetails['cache_key'] );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'configure_manifest', \count( $manifestDetails ) > 0, FALSE, array(
$form->add( new YesNo( 'configure_manifest', count( $manifestDetails ) > 0, FALSE, array(
'togglesOn' => array( 'manifest_shortname', 'manifest_fullname', 'manifest_description', 'manifest_defaultapp', 'manifest_themecolor', 'manifest_bgcolor', 'manifest_display', 'manifest_custom_url_toggle' ),
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'manifest_shortname', ( isset( $manifestDetails['short_name'] ) ) ? $manifestDetails['short_name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_shortname' ) );
$form->add( new \IPS\Helpers\Form\Text( 'manifest_fullname', ( isset( $manifestDetails['name'] ) ) ? $manifestDetails['name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_fullname' ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'manifest_description', ( isset( $manifestDetails['description'] ) ) ? $manifestDetails['description'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_description' ) );
$form->add( new Text( 'manifest_shortname', ( isset( $manifestDetails['short_name'] ) ) ? $manifestDetails['short_name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_shortname' ) );
$form->add( new Text( 'manifest_fullname', ( isset( $manifestDetails['name'] ) ) ? $manifestDetails['name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_fullname' ) );
$form->add( new TextArea( 'manifest_description', ( isset( $manifestDetails['description'] ) ) ? $manifestDetails['description'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_description' ) );
$formStartUrl = '';
if( isset( $manifestDetails['start_url'] ) )
{
$formStartUrl = str_replace( 'index.php?/', '', \IPS\Http\Url\Friendly::fixComponentPath( $manifestDetails['start_url'] ) );
$formStartUrl = str_replace( 'index.php?/', '', Friendly::fixComponentPath( $manifestDetails['start_url'] ) );
}
$form->add( new \IPS\Helpers\Form\YesNo( 'manifest_custom_url_toggle', ( isset( $manifestDetails['start_url'] ) and empty( $formStartUrl ) ? FALSE : TRUE ), FALSE, array(
$form->add( new YesNo( 'manifest_custom_url_toggle', ( isset( $manifestDetails['start_url'] ) and !empty( $formStartUrl ) ), FALSE, array(
'togglesOn' => array( 'manifest_short_url' ),
), NULL, NULL, NULL, 'manifest_custom_url_toggle' ) );
$form->add( new \IPS\Helpers\Form\Text( 'manifest_short_url', $formStartUrl, FALSE, array(), function( $val )
$form->add( new Text( 'manifest_short_url', $formStartUrl, FALSE, array(), function( $val )
{
if ( $val and \IPS\Request::i()->manifest_custom_url_toggle_checkbox )
if ( $val and Request::i()->manifest_custom_url_toggle_checkbox )
{
if ( mb_substr( $val, -1 ) !== '/' )
{
$val .= '/';
}
$response = \IPS\Http\Url::external( \IPS\Http\Url::baseUrl() . ( \IPS\Settings::i()->htaccess_mod_rewrite ? $val : 'index.php?/' . $val ) )->request( NULL, NULL, FALSE )->get();
if ( $response->httpResponseCode != 200 and $response->httpResponseCode != 303 and ( \IPS\Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
$response = Url::external( Url::baseUrl() . ( Settings::i()->htaccess_mod_rewrite ? $val : 'index.php?/' . $val ) )->request( NULL, NULL, FALSE )->get();
if ( $response->httpResponseCode != 200 and $response->httpResponseCode != 303 and ( Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
{
throw new \LogicException( 'pwa_start_url_incorrect' );
throw new LogicException( 'pwa_start_url_incorrect' );
}
}
}, \IPS\Http\Url::baseUrl() . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ), NULL, 'manifest_short_url' ) );
}, Url::baseUrl() . ( !Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ), NULL, 'manifest_short_url' ) );
$form->add( new \IPS\Helpers\Form\Color( 'manifest_themecolor', ( isset( $manifestDetails['theme_color'] ) ) ? $manifestDetails['theme_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_themecolor' ) );
$form->add( new \IPS\Helpers\Form\Color( 'manifest_bgcolor', ( isset( $manifestDetails['background_color'] ) ) ? $manifestDetails['background_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_bgcolor' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'manifest_display', ( isset( $manifestDetails['display'] ) ) ? $manifestDetails['display'] : 'standalone', FALSE, array( 'options' => array( 'fullscreen' => 'manifest_fullscreen', 'standalone' => 'manifest_standalone', 'minimal-ui' => 'manifest_minimalui', 'browser' => 'manifest_browser' ) ), NULL, NULL, NULL, 'manifest_display' ) );
$form->add( new Color( 'manifest_themecolor', ( isset( $manifestDetails['theme_color'] ) ) ? $manifestDetails['theme_color'] : NULL, FALSE, array( 'allowNoneLanguage' => 'manifest_themecolor_none', 'allowNone' => true ), NULL, NULL, NULL, 'manifest_themecolor' ) );
$form->add( new Color( 'manifest_bgcolor', ( isset( $manifestDetails['background_color'] ) ) ? $manifestDetails['background_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_bgcolor' ) );
$form->add( new Radio( 'manifest_display', ( isset( $manifestDetails['display'] ) ) ? $manifestDetails['display'] : 'standalone', FALSE, array( 'options' => array( 'fullscreen' => 'manifest_fullscreen', 'standalone' => 'manifest_standalone', 'minimal-ui' => 'manifest_minimalui', 'browser' => 'manifest_browser' ) ), NULL, NULL, NULL, 'manifest_display' ) );
if( $values = $form->values() )
{
$path = \IPS\Http\Url::createFromString( \IPS\Http\Url::baseUrl() )->data[ \IPS\Http\Url::COMPONENT_PATH ];
$path = Url::createFromString( Url::baseUrl() )->data[ Url::COMPONENT_PATH ];
$startUrl = $path ?? '';
if ( $values['manifest_custom_url_toggle'] !== FALSE and ! empty( $values['manifest_short_url'] ) )
@@ -120,7 +155,7 @@ class _webapp extends \IPS\Dispatcher\Controller
if( !empty( $path ) )
{
$startUrl = '/' . trim( $path . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ) . ltrim( $values['manifest_short_url'], '/' ), '/' ) . '/';
$startUrl = '/' . trim( $path . ( !Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ) . ltrim( $values['manifest_short_url'], '/' ), '/' ) . '/';
}
}
@@ -169,28 +204,25 @@ class _webapp extends \IPS\Dispatcher\Controller
/* Save the settings */
$form->saveAsSettings( $values );
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Clear manifest and ie browser data stores */
unset( \IPS\Data\Store::i()->manifest, \IPS\Data\Store::i()->iebrowserconfig );
unset( Store::i()->manifest, Store::i()->iebrowserconfig );
/* And log */
\IPS\Session::i()->log( 'acplogs__webapp' );
Session::i()->log( 'acplogs__webapp' );
/* And Redirect */
if( $rebuildStartScreen === TRUE )
{
\IPS\Output::i()->redirect( $this->url->setQueryString( 'do', 'buildStartupScreenImages' ), 'saved' );
Output::i()->redirect( $this->url->setQueryString( 'do', 'buildStartupScreenImages' ), 'saved' );
}
else
{
\IPS\Output::i()->redirect( $this->url, 'saved' );
Output::i()->redirect( $this->url, 'saved' );
}
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_webapp');
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_webapp', $form );
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_settings_webapp');
Output::i()->output .= Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_webapp', $form );
}
/**
@@ -201,7 +233,7 @@ class _webapp extends \IPS\Dispatcher\Controller
* @param array $homeScreenMaskable Existing values, if any
* @return array
*/
public static function processApplicationIcon( $values, $homeScreen = array(), $homeScreenMaskable = array() )
public static function processApplicationIcon( array $values, array $homeScreen = array(), array $homeScreenMaskable = array() ) : array
{
if( ( isset( $values['icons_homescreen'] ) AND $values['icons_homescreen'] ) or ( isset( $values['icons_homescreen_maskable' ] ) AND $values['icons_homescreen_maskable'] ) )
{
@@ -244,14 +276,14 @@ class _webapp extends \IPS\Dispatcher\Controller
{
$filename .= "-masked";
if ( ! \mb_strstr( $filename, 'android-chrome' ) )
if ( ! mb_strstr( $filename, 'android-chrome' ) )
{
continue;
}
}
try
{
$image = \IPS\Image::create( $values[ $type ]->contents() );
$image = Image::create( $values[ $type ]->contents() );
if ( $image::exifSupported() )
{
@@ -261,12 +293,12 @@ class _webapp extends \IPS\Dispatcher\Controller
$image->crop( $_sizes[0], $_sizes[1] );
$setting[$filename] = array(
'url' => (string)\IPS\File::create( 'core_Icons', $filename . '.png', (string)$image, NULL, TRUE, NULL, FALSE ),
'url' => (string)File::create( 'core_Icons', $filename . '.png', (string)$image, NULL, TRUE, NULL, FALSE ),
'width' => $image->width,
'height' => $image->height
);
}
catch ( \Exception $e )
catch ( Exception $e )
{
}
}
@@ -283,18 +315,18 @@ class _webapp extends \IPS\Dispatcher\Controller
{
try
{
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
}
catch( \Exception $e ){}
catch( Exception $e ){}
}
foreach( $homeScreenMaskable as $key => $image )
{
try
{
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
}
catch( \Exception $e ){}
catch( Exception $e ){}
}
$values['icons_homescreen'] = '';
@@ -315,7 +347,7 @@ class _webapp extends \IPS\Dispatcher\Controller
* @param array $apple Existing values, if any
* @return array
*/
public static function processAppleStartupScreen( $values, $apple = array() )
public static function processAppleStartupScreen( array $values, array $apple = array() ) : array
{
if( $values['icons_apple_startup'] )
{
@@ -328,9 +360,9 @@ class _webapp extends \IPS\Dispatcher\Controller
{
try
{
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
}
catch( \Exception $e ){}
catch( Exception $e ){}
}
$values['icons_apple_startup'] = '';
@@ -342,21 +374,19 @@ class _webapp extends \IPS\Dispatcher\Controller
/**
* Process Apple startup screen images
*
* @param array $values Values from form submission
* @param array $apple Existing values, if any
* @return array
* @return array|null
*/
public function buildStartupScreenImages()
public function buildStartupScreenImages() : ?array
{
$self = $this;
$multiRedirect = new \IPS\Helpers\MultipleRedirect(
$multiRedirect = new MultipleRedirect(
$this->url->setQueryString('do', 'buildStartupScreenImages'),
function( $data )
{
/* Get the necessary data */
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
$setting = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
$manifestDetails = json_decode( Settings::i()->manifest_details, TRUE );
$setting = json_decode( Settings::i()->icons_apple_startup, TRUE ) ?? array();
if( isset( $setting['original'] ) )
{
@@ -393,24 +423,24 @@ class _webapp extends \IPS\Dispatcher\Controller
'apple-startup-1080x2340' => array( 360, 780, 3, 'portrait' ),
);
$file = \IPS\File::get( 'core_Icons', $setting['original'] );
$file = File::get( 'core_Icons', $setting['original'] );
$originalContents = $file->contents();
$backgroundColor = ( isset( $manifestDetails['background_color'] ) ) ? str_replace( '#', '', $manifestDetails['background_color'] ) : 'FFFFFF';
$rgb = array();
if ( \strlen( $backgroundColor ) == 3 )
if ( strlen( $backgroundColor ) == 3 )
{
$rgb[] = hexdec( \substr( $backgroundColor, 0, 1 ) . \substr( $backgroundColor, 0, 1 ) ); // R
$rgb[] = hexdec( \substr( $backgroundColor, 1, 1 ) . \substr( $backgroundColor, 1, 1 ) ); // G
$rgb[] = hexdec( \substr( $backgroundColor, 2, 1 ) . \substr( $backgroundColor, 2, 1 ) ); // B
$rgb[] = hexdec( substr( $backgroundColor, 0, 1 ) . substr( $backgroundColor, 0, 1 ) ); // R
$rgb[] = hexdec( substr( $backgroundColor, 1, 1 ) . substr( $backgroundColor, 1, 1 ) ); // G
$rgb[] = hexdec( substr( $backgroundColor, 2, 1 ) . substr( $backgroundColor, 2, 1 ) ); // B
}
else
{
$rgb[] = hexdec( \substr( $backgroundColor, 0, 2 ) ); // R
$rgb[] = hexdec( \substr( $backgroundColor, 2, 2 ) ); // G
$rgb[] = hexdec( \substr( $backgroundColor, 4, 2 ) ); // B
$rgb[] = hexdec( substr( $backgroundColor, 0, 2 ) ); // R
$rgb[] = hexdec( substr( $backgroundColor, 2, 2 ) ); // G
$rgb[] = hexdec( substr( $backgroundColor, 4, 2 ) ); // B
}
$did = 0;
@@ -429,8 +459,8 @@ class _webapp extends \IPS\Dispatcher\Controller
$width = ( $_sizes[3] == 'landscape' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
$height = ( $_sizes[3] == 'portrait' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
$logoImage = \IPS\Image::create( $originalContents );
$canvas = \IPS\Image::newImageCanvas( $width, $height, $rgb );
$logoImage = Image::create( $originalContents );
$canvas = Image::newImageCanvas( $width, $height, $rgb );
$logoImage->resizeToMax( $width - static::MINIMUM_STARTUP_IMAGE_PADDING, $height - static::MINIMUM_STARTUP_IMAGE_PADDING );
@@ -445,43 +475,44 @@ class _webapp extends \IPS\Dispatcher\Controller
}
$setting[ $filename ] = array(
'url' => (string) \IPS\File::create( 'core_Icons', $filename . '.png', (string) $canvas, NULL, TRUE, NULL, FALSE ),
'url' => (string) File::create( 'core_Icons', $filename . '.png', (string) $canvas, NULL, TRUE, NULL, FALSE ),
'width' => $canvas->width,
'height' => $canvas->height,
'density' => $_sizes[2],
'orientation' => $_sizes[3],
);
}
catch ( \Exception $e )
catch ( Exception $e )
{
\IPS\Log::log( $e, 'apple-startup-image' );
Log::log( $e, 'apple-startup-image' );
}
break;
}
/* Are we done? */
if( $did == \count( $sizes ) )
if( $did == count( $sizes ) )
{
return NULL;
}
\IPS\Settings::i()->changeValues( array( 'icons_apple_startup' => json_encode( $setting ) ) );
Settings::i()->changeValues( array( 'icons_apple_startup' => json_encode( $setting ) ) );
}
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title'), ( $did ) ? round( ( 100 / \count( $sizes ) * $did ), 2 ) : 0 );
return array( $data, Member::loggedIn()->language()->addToStack('build_start_images_title'), ( $did ) ? round( ( 100 / count( $sizes ) * $did ), 2 ) : 0 );
},
function() use( $self )
{
$manifest = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
$manifest = json_decode( Settings::i()->manifest_details, TRUE );
$manifest['cache_key'] = time();
\IPS\Settings::i()->changeValues( [ 'manifest_details' => json_encode( $manifest ) ] );
\IPS\Output::i()->redirect( $self->url, 'completed' );
Settings::i()->changeValues( [ 'manifest_details' => json_encode( $manifest ) ] );
Output::i()->redirect( $self->url, 'completed' );
}
);
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title');
\IPS\Output::i()->output = $multiRedirect;
Output::i()->title = Member::loggedIn()->language()->addToStack('build_start_images_title');
Output::i()->output = $multiRedirect;
return null;
}
}