Version 4.3.6
This commit is contained in:
1 parent
fe1acf984a
commit
1a0c7fd3c2
609 files changed
+14707
-5726
No files matched your search
@@ -855,7 +855,7 @@ class _applications extends \IPS\Node\Controller
|
||||
\IPS\Application::load( $data['key'] )->installSkins( TRUE );
|
||||
\IPS\Application::load( $data['key'] )->installJavascript();
|
||||
|
||||
$laststep = 'skins';
|
||||
$laststep = NULL;
|
||||
$language = \IPS\Member::loggedIn()->language()->addToStack('appinstall_skins');
|
||||
$progress = 100;
|
||||
break;
|
||||
@@ -1286,6 +1286,11 @@ class _applications extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_dir_not_write', '4C133/L', 403, '' );
|
||||
}
|
||||
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/plugins/hooks.php") AND !is_writable( \IPS\ROOT_PATH . "/plugins/hooks.php" ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_file_not_write', '4C133/U', 403, '' );
|
||||
}
|
||||
|
||||
if ( !extension_loaded('phar') )
|
||||
{
|
||||
|
||||
@@ -1658,7 +1658,7 @@ class _developer extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
/* Changed reporting? */
|
||||
if ( !isset( $definition['reporting'] ) or $values['database_table_reporting'] !== $definition['reporting'] )
|
||||
if ( isset( $values['database_table_reporting'] ) AND ( !isset( $definition['reporting'] ) or $values['database_table_reporting'] !== $definition['reporting'] ) )
|
||||
{
|
||||
$schemaJson[ $definition['name'] ]['reporting'] = $values['database_table_reporting'];
|
||||
}
|
||||
@@ -2543,6 +2543,12 @@ class _developer extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
unset( $schema[ \IPS\Request::i()->_name ]['engine'] );
|
||||
}
|
||||
|
||||
if( isset( $schemaDefinition['reporting'] ) )
|
||||
{
|
||||
$schema[ \IPS\Request::i()->_name ]['reporting'] = $schemaDefinition['reporting'];
|
||||
}
|
||||
|
||||
$this->_writeSchema( $schema );
|
||||
}
|
||||
/* Use schema file */
|
||||
|
||||
@@ -166,11 +166,16 @@ class _plugins extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_writes', '1C145/1', 403, '' );
|
||||
}
|
||||
if( !is_writable( \IPS\ROOT_PATH . "/plugins/" ) )
|
||||
if( !is_writable( \IPS\ROOT_PATH . "/plugins/" ) ) // necessary as we write the hooks.php file here
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_dir_not_write', '4C145/2', 403, '' );
|
||||
}
|
||||
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/plugins/hooks.php") AND !is_writable( \IPS\ROOT_PATH . "/plugins/hooks.php" ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_file_not_write', '4C145/N', 403, '' );
|
||||
}
|
||||
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form( NULL, 'install' );
|
||||
if ( isset( \IPS\Request::i()->id ) )
|
||||
@@ -324,7 +329,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
'storeKeys' => array(),
|
||||
'setUpClasses' => array(),
|
||||
'step' => 0,
|
||||
'upgradeData' => array(),
|
||||
'upgradeData' => NULL,
|
||||
'done' => array(),
|
||||
'isNew' => $new
|
||||
), \IPS\Member::loggedIn()->language()->addToStack('processing') );
|
||||
@@ -819,6 +824,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Log::debug( "Plugin setup: Running " . $key . ", " . $method, 'plugin_setup' );
|
||||
|
||||
\IPS\Request::i()->extra = $data['upgradeData'];
|
||||
$result = $upgrader->$method();
|
||||
|
||||
if ( $result === TRUE )
|
||||
@@ -831,6 +837,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
|
||||
/* Hit it on the next redirect */
|
||||
$data['step']++;
|
||||
$data['upgradeData'] = NULL;
|
||||
$more = TRUE;
|
||||
}
|
||||
}
|
||||
@@ -1121,7 +1128,13 @@ class _plugins extends \IPS\Node\Controller
|
||||
|
||||
/* Strip any raw replacement tags remaining */
|
||||
$code = preg_replace( '/\{{(.+?)}}/', '', $code );
|
||||
|
||||
|
||||
/* Ensure attributes with variable data are encoded before the cheeky DOM parser gets to it */
|
||||
$code = preg_replace_callback( '/=([\'"])(\{.+?\})([\'"])/', function( $matches )
|
||||
{
|
||||
return "=" . $matches[1] . htmlspecialchars( $matches[2], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $matches[3];
|
||||
}, $code );
|
||||
|
||||
/* Now fix <if/foreach/for tags that are embedded into attributes */
|
||||
while( preg_match( '/\<([^>]+?)(\<(\/*?)(if|foreach|for|else).*?\>([^>]*?)(\<\/\4\>))/ms', $code ) )
|
||||
{
|
||||
@@ -1137,12 +1150,6 @@ class _plugins extends \IPS\Node\Controller
|
||||
return "=''";
|
||||
}, $code );
|
||||
|
||||
/* Ensure attributes with variable data are encoded before the cheeky DOM parser gets to it */
|
||||
$code = preg_replace_callback( '/=([\'"])(\{.+?\})([\'"])/', function( $matches )
|
||||
{
|
||||
return "=" . $matches[1] . htmlspecialchars( $matches[2], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $matches[3];
|
||||
}, $code );
|
||||
|
||||
/* Now load the HTML - doctype necessary sometimes */
|
||||
$document->loadHTML( \IPS\Xml\DOMDocument::wrapHtml( '<ipscontent id="ipscontent">' . $code . '</ipscontent>' ) );
|
||||
|
||||
@@ -1505,7 +1512,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C145/B', 404, '' );
|
||||
}
|
||||
|
||||
|
||||
/* Init */
|
||||
$xml = \IPS\Xml\SimpleXML::create('plugin');
|
||||
$xml->addAttribute( 'name', $plugin->name );
|
||||
@@ -1514,6 +1521,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
$xml->addAttribute( 'author', $plugin->author );
|
||||
$xml->addAttribute( 'website', $plugin->website );
|
||||
$xml->addAttribute( 'update_check', $plugin->update_check );
|
||||
/* It's intentional that $plugin->location is skipped for the XML file. The location is being built automatically while the installation to avoid conflicts when another plugin uses the same location */
|
||||
|
||||
/* Get Hooks */
|
||||
$hooks = $xml->addChild( 'hooks' );
|
||||
|
||||
@@ -177,10 +177,13 @@ class _bulkmail extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'couldnt_find_bulkmail', '2C125/7', 404, '' );
|
||||
}
|
||||
|
||||
|
||||
/* Unclaim attachments */
|
||||
\IPS\File::unclaimAttachments( 'core_Admin', $mail->id, NULL, 'bulkmail' );
|
||||
|
||||
/* Delete the bulk mail */
|
||||
$mail->delete();
|
||||
|
||||
|
||||
/* Log and redirect */
|
||||
\IPS\Session::i()->log( 'acplog__bulkmail_deleted', array( $mail->subject => FALSE ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail' ), 'deleted' );
|
||||
@@ -459,13 +462,14 @@ class _bulkmail extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Get tags */
|
||||
$tags = \IPS\core\BulkMail\Bulkmailer::getTags();
|
||||
|
||||
$autoSaveKey = 'bulkmail' . ( $mail->id ? '-' . $mail->id : '' );
|
||||
|
||||
/* Start the form */
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->class = '';
|
||||
$form->addTab( 'bulkmail__main', NULL, NULL, 'ipsForm_vertical' );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'mail_subject', $mail->subject, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'mail_body', $mail->content ?: '', TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => 'bulkmail' . ( $mail->id ? '-' . $mail->id : '' ), 'tags' => $tags, 'attachIds' => array( $mail->id, NULL, 'bulkmail' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'mail_body', $mail->content ?: '', TRUE, array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => $autoSaveKey, 'tags' => $tags, 'attachIds' => $mail->id ? array( $mail->id, NULL, 'bulkmail' ) : NULL ) ) );
|
||||
|
||||
/* Add the filters tab and the "generic filters" header */
|
||||
$form->addTab( 'bulkmail__filters', NULL, NULL, 'ipsForm_horizontal' );
|
||||
@@ -538,6 +542,9 @@ class _bulkmail extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__bulkmail_added', array( $mail->subject => FALSE ) );
|
||||
}
|
||||
|
||||
/* Claim attachments */
|
||||
\IPS\File::claimAttachments( $autoSaveKey, $mail->id, NULL, 'bulkmail' );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=bulkmail&controller=bulkmail&do=preview&id=' . $mail->id ), 'saved' );
|
||||
}
|
||||
|
||||
@@ -269,12 +269,12 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
foreach ( $templates as $template )
|
||||
{
|
||||
$uniqueIds[] = md5( $template['css_set_id'] . ',' . $template['css_app'] . ',' . $template['css_location'] . ',' . $template['css_path'] . ',' . $template['css_name'] );
|
||||
$uniqueIds[] = md5( $template['css_app'] . ',' . $template['css_location'] . ',' . $template['css_path'] . ',' . $template['css_name'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', css_set_id, css_app, css_location, css_path, css_name ) )", $uniqueIds ) );
|
||||
$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', css_app, css_location, css_path, css_name ) )", $uniqueIds ) );
|
||||
}
|
||||
if ( in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
|
||||
{
|
||||
|
||||
@@ -2479,7 +2479,7 @@ class _themes extends \IPS\Node\Controller
|
||||
|
||||
if ( isset( $template['app'] ) )
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplogs__themetemplate_deleted', array( $template['app'] => FALSE, $template['location'] => FALSE, $template['group'] => FALSE, $template['name'] => FALSE ) );
|
||||
\IPS\Session::i()->log( 'acplogs__themetemplate_deleted', array( 'app: ' . $template['app'] => FALSE, 'location: ' . $template['location'] => FALSE, 'group: ' . $template['group'] => FALSE, 'name: ' . $template['name'] => FALSE ) );
|
||||
}
|
||||
|
||||
/* Clear guest page caches */
|
||||
@@ -2564,7 +2564,7 @@ class _themes extends \IPS\Node\Controller
|
||||
if ( in_array( $k, array( 'app', 'location', 'group', 'name' ) ) )
|
||||
{
|
||||
$url[] = 't_' . $k . '=' . $v;
|
||||
$log[ $v ] = FALSE;
|
||||
$log[ $k . ': ' . $v ] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
),
|
||||
'toggles' => array(
|
||||
'mysql' => array( 'search_index_timeframe' ),
|
||||
'elastic' => array( 'search_elastic_server', 'search_elastic_index', 'search_elastic_analyzer', 'search_decay', 'search_elastic_self_boost' )
|
||||
'elastic' => array( 'search_elastic_server', 'search_elastic_index', 'search_elastic_analyzer', 'search_decay', 'search_elastic_self_boost', 'search_index_maxresults' )
|
||||
)
|
||||
) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Url( 'search_elastic_server', \IPS\Settings::i()->search_elastic_server, NULL, array( 'placeholder' => 'http://localhost:9200' ), function( $val )
|
||||
@@ -142,12 +142,14 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
), NULL, NULL, NULL, 'search_decay' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'search_elastic_self_boost', \IPS\Settings::i()->search_elastic_self_boost, FALSE, array( 'unlimited' => floatval( 0 ), 'unlimitedLang' => 'do_not_boost', 'decimals' => 1 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_elastic_self_boost_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_elastic_self_boost_suffix'), 'search_elastic_self_boost' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'search_index_timeframe', \IPS\Settings::i()->search_index_timeframe, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'search_index_timeframe_unlimited' ), NULL, \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_prefix'), \IPS\Member::loggedIn()->language()->addToStack('search_index_timeframe_suffix'), 'search_index_timeframe' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'search_index_maxresults', \IPS\Settings::i()->search_index_maxresults, FALSE, array(), NULL, NULL, NULL, 'search_index_maxresults' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$engine = \IPS\Settings::i()->search_method;
|
||||
$indexPrune = \IPS\Settings::i()->search_index_timeframe;
|
||||
$analyzer = \IPS\Settings::i()->search_elastic_analyzer;
|
||||
$maxResults = \IPS\Settings::i()->search_index_maxresults;
|
||||
|
||||
if ( isset( $values['search_decay'][2] ) )
|
||||
{
|
||||
@@ -178,7 +180,7 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
\IPS\Session::i()->log( 'acplogs__search_settings' );
|
||||
|
||||
/* And re-index if setting updated */
|
||||
if( $engine != $values['search_method'] or ( $values['search_method'] == 'elastic' and $values['search_elastic_analyzer'] != $analyzer ) )
|
||||
if( $engine != $values['search_method'] or ( $values['search_method'] == 'elastic' and ( $values['search_elastic_analyzer'] != $analyzer or $values['search_index_maxresults'] != $maxResults ) ) )
|
||||
{
|
||||
/* We pass TRUE to the i() method to ensure we get a new instance, otherwise the old instance cached from the previous prune call will be used */
|
||||
\IPS\Content\Search\Index::i( TRUE )->init();
|
||||
|
||||
@@ -49,7 +49,7 @@ class _emoticons extends \IPS\Dispatcher\Controller
|
||||
|
||||
if ( $activeTab == 'standard' )
|
||||
{
|
||||
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') )
|
||||
if ( \IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') === TRUE )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'emoji_style', \IPS\Settings::i()->emoji_style, FALSE, array(
|
||||
@@ -59,11 +59,6 @@ class _emoticons extends \IPS\Dispatcher\Controller
|
||||
'emojione' => 'emoji_style_emojione',
|
||||
'disabled' => 'emoji_style_disabled',
|
||||
),
|
||||
'toggles' => array(
|
||||
'native' => array( 'emoji_shortcodes', 'emoji_ascii' ),
|
||||
'twemoji' => array( 'emoji_shortcodes', 'emoji_ascii' ),
|
||||
'emojione' => array( 'emoji_shortcodes', 'emoji_ascii' ),
|
||||
),
|
||||
) ) );
|
||||
\IPS\Member::loggedIn()->language()->get( 'emoji_style_native' ); // We need to preload the word before we can add more text to it.
|
||||
\IPS\Member::loggedIn()->language()->words['emoji_style_native'] .= "<br><div class='ipsType_large ipsSpacer_top ipsSpacer_half'><span class='ipsEmoji'>😀</span><span class='ipsEmoji'>😉</span><span class='ipsEmoji'>😂</span><span class='ipsEmoji'>😍</span><span class='ipsEmoji'>🤘</span><span class='ipsEmoji'>🤦♀️</span><span class='ipsEmoji'>🤷♂️</span><span class='ipsEmoji'>🍿</span><span class='ipsEmoji'>🚀</span><span class='ipsEmoji'>🎉</span><span class='ipsEmoji'>🏳️🌈</span></div>"; // Have to do this here because if we try to put it in the actual language string, that will cause an error if not utf8mb4
|
||||
@@ -318,22 +313,10 @@ class _emoticons extends \IPS\Dispatcher\Controller
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !isset( $data['order'] ) )
|
||||
{
|
||||
if ( !isset( $orders[ $data['set'] ] ) )
|
||||
{
|
||||
$orders[ $data['set'] ] = 0;
|
||||
}
|
||||
$data['order'] = ++$orders[ $data['set'] ];
|
||||
}
|
||||
|
||||
if ( $emoticons[ $id ]['typed'] !== $data['name'] or $data['order'] != $emoticons[ $id ]['emo_position'] )
|
||||
if ( $emoticons[ $id ]['typed'] !== $data['name'] )
|
||||
{
|
||||
$save = array( 'typed' => preg_replace( "#\s#", "", $data['name'] ) );
|
||||
if ( isset( $data['order'] ) )
|
||||
{
|
||||
$save['emo_position'] = $data['order'];
|
||||
}
|
||||
|
||||
if ( $set !== NULL )
|
||||
{
|
||||
$save['emo_set'] = str_replace( 'core_emoticon_group_', '', $data['set'] );
|
||||
|
||||
@@ -91,10 +91,9 @@ class _groups extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
/* Show an extra warning if we are going to delete a group that Commerce intends to move subscribers back to */
|
||||
$warnGroups = array();
|
||||
if( \IPS\Db::i()->checkForColumn( 'core_members', 'cm_return_group' ) )
|
||||
{
|
||||
$warnGroups = array();
|
||||
|
||||
try
|
||||
{
|
||||
$warnGroups = iterator_to_array( \IPS\Db::i()->select( 'DISTINCT(cm_return_group)', 'core_members' ) );
|
||||
@@ -350,6 +349,13 @@ class _groups extends \IPS\Dispatcher\Controller
|
||||
$class::load( $permTypeId )->changePermissions( $group, $perms );
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear out member's cached "Create Menu" contents */
|
||||
\IPS\Member::clearCreateMenu();
|
||||
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Log */
|
||||
\IPS\Session::i()->log( 'permissions_adjusted_node', array( "core_group_". $group->g_id => TRUE ) );
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'name<>? AND email<>?', '', '' ) ), 'joined' );
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'email<>?', '' ) ), 'joined' );
|
||||
$table->langPrefix = 'members_';
|
||||
|
||||
/* Columns we need */
|
||||
@@ -48,7 +48,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$table->sortBy = $table->sortBy ?: 'joined';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
|
||||
/* Groups for advanced filter (need to do it this way because array_merge renumbers the result */
|
||||
/* Groups for advanced filter (need to do it this way because array_merge renumbers the result) */
|
||||
$groups = array( '' => 'any_group' );
|
||||
$joinFields = array( 'core_members.member_id as member_id' );
|
||||
|
||||
@@ -58,7 +58,6 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
$fieldsToAdd = array();
|
||||
$helperClasses = array();
|
||||
|
||||
/* Profile fields */
|
||||
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::STAFF ) as $group => $fields )
|
||||
@@ -108,9 +107,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$helper = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $options ) );
|
||||
break;
|
||||
}
|
||||
|
||||
$helperClasses[ "field_{$id}" ] = $type;
|
||||
|
||||
|
||||
if ( $helper )
|
||||
{
|
||||
$fieldsToAdd[ "field_{$id}" ] = $helper;
|
||||
@@ -172,10 +169,14 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
return array( '( member_group_id=? OR FIND_IN_SET( ?, mgroup_others ) )', $val, $val );
|
||||
} ),
|
||||
'joined' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'joined' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'member_last_post' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'last_visit' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'last_activity' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'member_posts' => \IPS\Helpers\Table\SEARCH_NUMERIC,
|
||||
'allow_admin_emails' => array( \IPS\Helpers\Table\SEARCH_RADIO, array( 'options' => array( 'a' => 'allow_admin_emails_any', 1 => 'yes', 0 => 'no' ) ), function( $val )
|
||||
{
|
||||
return ( $val == 'a' ) ? array( '1=1' ) : array( 'allow_admin_mails=?', intval( $val ) );
|
||||
} )
|
||||
);
|
||||
|
||||
if( count( $fieldsToAdd ) )
|
||||
@@ -192,7 +193,12 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'members_filter_validating' => '( v.lost_pass=0 AND v.forgot_security=0 AND v.vid IS NOT NULL )',
|
||||
'members_filter_administrators' => '( m.row_id IS NOT NULL OR g.row_id IS NOT NULL )'
|
||||
);
|
||||
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( "email <> '' and name=''" ) )->first() )
|
||||
{
|
||||
$table->filters['members_filtered_reserved'] = "(name='')";
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->ipb_bruteforce_attempts )
|
||||
{
|
||||
/* We do this so we can put the locked filter at the 'end' of the buttons - array_unshift does not give us a simple method to retain keys */
|
||||
@@ -249,32 +255,42 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack( 'never' );
|
||||
},
|
||||
'last_visit' => function( $val, $row )
|
||||
'last_activity' => function( $val, $row )
|
||||
{
|
||||
return ( $val ) ? \IPS\DateTime::ts( $val )->localeDate() : \IPS\Member::loggedIn()->language()->addToStack( 'never' );
|
||||
},
|
||||
'name' => function( $val, $row )
|
||||
{
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
if ( $banned = $member->isBanned() )
|
||||
if ( $val )
|
||||
{
|
||||
if ( $banned instanceof \IPS\DateTime )
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
if ( $banned = $member->isBanned() )
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'suspended_until', FALSE, array( 'sprintf' => array( $banned->localeDate() ) ) );
|
||||
if ( $banned instanceof \IPS\DateTime )
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'suspended_until', FALSE, array( 'sprintf' => array( $banned->localeDate() ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'banned' );
|
||||
}
|
||||
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ) . $row['member_id'] . "'>" . htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) . "</a> <span class='ipsBadge ipsBadge_negative'>" . $title ."</span> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'banned' );
|
||||
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ) . $row['member_id'] . "'>" . htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) . "</a>";
|
||||
}
|
||||
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ) . $row['member_id'] . "'>" . htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) . "</a> <span class='ipsBadge ipsBadge_negative'>" . $title ."</span> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "<a href='" . \IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ) . $row['member_id'] . "'>" . htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) . "</a>";
|
||||
return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberReserved( \IPS\Member::constructFromData( $row ) );
|
||||
}
|
||||
|
||||
},
|
||||
'allow_admin_emails' => function( $val, $row )
|
||||
{
|
||||
return $row['allow_admin_mails'] ? '✔' : '✗';
|
||||
}
|
||||
);
|
||||
|
||||
/* Specify the buttons */
|
||||
@@ -398,7 +414,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if( \IPS\Request::i()->advanced_search_submitted OR \IPS\Request::i()->quicksearch )
|
||||
{
|
||||
$link = ' <a href="' . \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ) . '">' . \IPS\Member::loggedIn()->language()->addToStack('member_view_full_list') . '</a>';
|
||||
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) OR \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) )
|
||||
{
|
||||
$query = array(
|
||||
@@ -410,9 +426,10 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'members_member_group_id' => \IPS\Request::i()->members_member_group_id,
|
||||
'members_joined' => \IPS\Request::i()->members_joined,
|
||||
'members_last_post' => \IPS\Request::i()->members_member_last_post,
|
||||
'members_last_visit' => \IPS\Request::i()->members_last_visit,
|
||||
'members_last_activity' => \IPS\Request::i()->members_last_activity,
|
||||
'members_posts' => \IPS\Request::i()->members_member_posts,
|
||||
'filter' => \IPS\Request::i()->filter,
|
||||
'members_allow_admin_emails' => \IPS\Request::i()->members_allow_admin_emails
|
||||
);
|
||||
|
||||
foreach ( \IPS\Request::i() as $k => $v )
|
||||
@@ -423,31 +440,15 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$query[ $k ] = $v;
|
||||
|
||||
/* And also add them as parsers so they display properly */
|
||||
$table->parsers[ str_replace( 'members_', '', $k ) ] = function( $val, $row ) use ( $k, $helperClasses )
|
||||
$table->parsers[ str_replace( 'members_', '', $k ) ] = function( $val, $row ) use ( $k )
|
||||
{
|
||||
if ( isset( $helperClasses[ 'field_' . str_replace( 'members_field_', '', $k ) ] ) )
|
||||
try
|
||||
{
|
||||
$helper = $helperClasses[ 'field_' . str_replace( 'members_field_', '', $k ) ];
|
||||
$options = array();
|
||||
switch( $helper )
|
||||
{
|
||||
case 'IPS\Helpers\Form\Editor':
|
||||
$options = array_merge(
|
||||
\IPS\core\ProfileFields\Field::$editorOptions,
|
||||
array(
|
||||
'autoSaveKey' => md5( $helper . '-' . str_replace( 'members_field_', '', $k ) . '-' . $row['member_id'] ),
|
||||
'attachIds' => array( $row['member_id'], str_replace( 'members_field_', '', $k ) )
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$class = new $helper( 'field_' . str_replace( 'members_field_', '', $k ), $val, FALSE, $options );
|
||||
return $class->formatValue();
|
||||
return \IPS\core\ProfileFields\Field::load( str_replace( 'members_field_', '', $k ) )->displayValue( $val );
|
||||
}
|
||||
else
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
return $val;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -461,6 +462,11 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) )
|
||||
{
|
||||
$link .= ' — <a href="' . \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=massManage&action=move" )->setQueryString( $query ) . '">' . \IPS\Member::loggedIn()->language()->addToStack( 'member_search_move' ) . '</a>';
|
||||
|
||||
if ( \IPS\Request::i()->members_allow_admin_emails !== 'a' )
|
||||
{
|
||||
$link .= ' — <a href="' . \IPS\Http\Url::internal( "app=core&module=members&controller=members&do=massManage&action=unSub" )->setQueryString( $query ) . '">' . \IPS\Member::loggedIn()->language()->addToStack( 'member_search_unsub' ) . '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +598,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( array( 'joined', 'last_post', 'last_visit' ) as $k )
|
||||
foreach ( array( 'joined', 'last_post', 'last_activity' ) as $k )
|
||||
{
|
||||
$requestKey = "members_{$k}";
|
||||
if ( $k === 'last_post' )
|
||||
@@ -608,12 +614,28 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$end = NULL;
|
||||
if ( $request['start'] )
|
||||
{
|
||||
$start = new \IPS\DateTime( \IPS\Helpers\Form\Date::_convertDateFormat( $request['start'] ) );
|
||||
$time = \IPS\Helpers\Form\Date::_convertDateFormat( $request['start'] );
|
||||
if ( is_numeric( $time ) )
|
||||
{
|
||||
$start = \IPS\DateTime::ts( $time );
|
||||
}
|
||||
else
|
||||
{
|
||||
$start = new \IPS\DateTime( $time );
|
||||
}
|
||||
$start = $start->setTime( 0, 0, 0 );
|
||||
}
|
||||
if ( $request['end'] )
|
||||
{
|
||||
$end = new \IPS\DateTime( \IPS\Helpers\Form\Date::_convertDateFormat( $request['end'] ) );
|
||||
$time = \IPS\Helpers\Form\Date::_convertDateFormat( $request['end'] );
|
||||
if ( is_numeric( $time ) )
|
||||
{
|
||||
$end = \IPS\DateTime::ts( $time );
|
||||
}
|
||||
else
|
||||
{
|
||||
$end = new \IPS\DateTime( $time );
|
||||
}
|
||||
$end = $end->setTime( 23, 59, 59 );
|
||||
}
|
||||
|
||||
@@ -730,7 +752,13 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Bulk email */
|
||||
if ( isset( \IPS\Request::i()->members_allow_admin_emails ) and \IPS\Request::i()->members_allow_admin_emails != 'a' )
|
||||
{
|
||||
$where[] = array( 'allow_admin_mails=?', intval( \IPS\Request::i()->members_allow_admin_emails ) );
|
||||
}
|
||||
|
||||
if ( !count( $where ) )
|
||||
{
|
||||
if ( \IPS\Request::i()->action === 'prune' )
|
||||
@@ -746,8 +774,8 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Unset any previous session data */
|
||||
$_SESSION['members_manage_where'] = $where;
|
||||
$_SESSION['members_manage_action'] = \IPS\Request::i()->action;
|
||||
|
||||
if ( \IPS\Request::i()->action === 'prune' )
|
||||
|
||||
if ( \IPS\Request::i()->action === 'prune' or \IPS\Request::i()->action === 'unSub' )
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*) AS count', 'core_members', $where )
|
||||
->join( 'core_pfields_content', 'core_members.member_id=core_pfields_content.member_id' );
|
||||
@@ -763,13 +791,20 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
->join( array( 'core_admin_permission_rows', 'g' ), array( 'g.row_id', \IPS\Db::i()->select( 'row_id', array( 'core_admin_permission_rows', 'sub' ), array( "((sub.row_id=core_members.member_group_id OR FIND_IN_SET( sub.row_id, core_members.mgroup_others ) ) AND sub.row_id_type='group') AND g.row_id_type='group'" ), NULL, array( 0, 1 ) ) ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->confirmMassAction( $count->first(), 'prune' );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->confirmMassAction( $count->first(), \IPS\Request::i()->action );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'member_prune_confirm' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'move_to_group', NULL, TRUE, array( 'options' => \IPS\Member\Group::groups( TRUE, FALSE ), 'parse' => 'normal' ) ) );
|
||||
$groups = \IPS\Member\Group::groups( TRUE, FALSE );
|
||||
|
||||
/* We can remove the group we are moving *from* */
|
||||
if( isset( \IPS\Request::i()->members_member_group_id ) )
|
||||
{
|
||||
unset( $groups[\IPS\Request::i()->members_member_group_id] );
|
||||
}
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'move_to_group', NULL, TRUE, array( 'options' => $groups, 'parse' => 'normal' ) ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
@@ -827,6 +862,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
AND isset( $_SESSION['members_manage_action'] ) AND $_SESSION['members_manage_action'] !== NULL )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'MoveMembers', array( 'where' => $_SESSION['members_manage_where'], 'group' => $_SESSION['members_manage_group'], 'oldGroup' => ( isset( $_SESSION['members_manage_old_group'] ) ) ? $_SESSION['members_manage_old_group'] : NULL, 'by' => \IPS\Member::loggedIn()->member_id ), 2 );
|
||||
\IPS\Session::i()->log( 'acplog__members_mass_move' );
|
||||
|
||||
$_SESSION['members_manage_where'] = NULL;
|
||||
$_SESSION['members_manage_action'] = NULL;
|
||||
@@ -836,6 +872,30 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
\IPS\Output::i()->error( 'members_manage_error', '2C114/K', 404, '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe Members
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function doUnsub()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'member_edit' );
|
||||
|
||||
/* Don't queue the task if the session variables are null (i.e. the page has been reloaded) */
|
||||
if( isset( $_SESSION['members_manage_where'] ) AND $_SESSION['members_manage_where'] !== NULL
|
||||
AND isset( $_SESSION['members_manage_action'] ) AND $_SESSION['members_manage_action'] !== NULL )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'UnsubMembers', array( 'where' => $_SESSION['members_manage_where'] ), 2 );
|
||||
\IPS\Session::i()->log( 'acplog__members_mass_unsub' );
|
||||
|
||||
$_SESSION['members_manage_where'] = NULL;
|
||||
$_SESSION['members_manage_action'] = NULL;
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=members&controller=members" ), 'members_queued_for_unsub' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->error( 'members_manage_error', '2C114/K', 404, '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune members
|
||||
@@ -851,6 +911,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
AND isset( $_SESSION['members_manage_action'] ) AND $_SESSION['members_manage_action'] !== NULL )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'PruneMembers', array( 'where' => $_SESSION['members_manage_where'] ), 2 );
|
||||
\IPS\Session::i()->log( 'acplog__members_mass_delete' );
|
||||
|
||||
$_SESSION['members_manage_where'] = NULL;
|
||||
$_SESSION['members_manage_action'] = NULL;
|
||||
@@ -954,7 +1015,15 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Get the available tabs */
|
||||
$extensions = \IPS\Application::allExtensions( 'core', 'MemberACPProfileTabs', TRUE, 'core', 'Main', FALSE );
|
||||
$extensions = array();
|
||||
foreach( \IPS\Application::allExtensions( 'core', 'MemberACPProfileTabs', TRUE, 'core', 'Main', FALSE ) AS $key => $ext )
|
||||
{
|
||||
$class = new $ext( $member );
|
||||
if ( $class->canView() )
|
||||
{
|
||||
$extensions[ $key ] = $ext;
|
||||
}
|
||||
}
|
||||
|
||||
/* What's our active tab? */
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $extensions ) ) ? \IPS\Request::i()->tab : 'core_Main';
|
||||
@@ -962,7 +1031,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$tab = new $classname( $member );
|
||||
|
||||
/* Output */
|
||||
\IPS\Output::i()->title = $member->name;
|
||||
\IPS\Output::i()->title = $member->name ? $member->name : \IPS\Member::loggedIn()->language()->addToStack('members_name_missing_as_reserved');
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->blockKey ) )
|
||||
@@ -1221,7 +1290,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
$error = \IPS\Member::loggedIn()->language()->addToStack('form_bad_value');
|
||||
}
|
||||
elseif ( $message = \IPS\Login::usernameIsInUse( \IPS\Request::i()->name ) )
|
||||
elseif ( $message = \IPS\Login::usernameIsInUse( \IPS\Request::i()->name, $member ) )
|
||||
{
|
||||
$error = $message;
|
||||
}
|
||||
@@ -1306,7 +1375,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$error = NULL;
|
||||
if ( filter_var( \IPS\Request::i()->email, FILTER_VALIDATE_EMAIL ) === FALSE )
|
||||
{
|
||||
$error = 'form_email_bad';
|
||||
$error = \IPS\Member::loggedIn()->language()->addToStack( 'form_email_bad' );
|
||||
}
|
||||
elseif ( $message = \IPS\Login::emailIsInUse( \IPS\Request::i()->email, $member ) )
|
||||
{
|
||||
@@ -1318,7 +1387,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
if ( preg_match( '/^' . str_replace( '\*', '.*', preg_quote( $bannedEmail, '/' ) ) . '$/i', \IPS\Request::i()->email ) )
|
||||
{
|
||||
$error = 'form_email_banned';
|
||||
$error = \IPS\Member::loggedIn()->language()->addToStack( 'form_email_banned' );
|
||||
}
|
||||
}
|
||||
if ( \IPS\Settings::i()->allowed_reg_email !== '' AND $allowedEmailDomains = explode( ',', \IPS\Settings::i()->allowed_reg_email ) )
|
||||
@@ -1333,7 +1402,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
if ( count( $allowedEmailDomains ) AND !$matched )
|
||||
{
|
||||
$error = 'form_email_banned';
|
||||
$error = \IPS\Member::loggedIn()->language()->addToStack( 'form_email_banned' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1535,7 +1604,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( $option == 'status' and ( !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'status' ) ) or !\IPS\core\Statuses\Status::canCreateFromCreateMenu( $member ) or !\IPS\Settings::i()->profile_comments or $member->group['gbw_no_status_update'] ) )
|
||||
if ( $option == 'status' and ( !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'status', 'front' ) ) or !\IPS\core\Statuses\Status::canCreateFromCreateMenu( $member ) or !\IPS\Settings::i()->profile_comments or $member->group['gbw_no_status_update'] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2693,6 +2762,8 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'member_add' );
|
||||
|
||||
$maxMemberId = 16777215; // This is the maximum value for UNSIGNED MEDIUMINT. Even though nowadays we use BIGINT, older installs might still have MEDIUMINT, plus setting the limit to lower than what the limit actually is ensures there's room for future members.
|
||||
|
||||
$wizard = new \IPS\Helpers\Wizard(
|
||||
array(
|
||||
/* Step 1: Upload .csv file */
|
||||
@@ -2720,7 +2791,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
return (string) $form;
|
||||
},
|
||||
/* Step 2: Select Columns */
|
||||
'import_select_cols' => function( $data )
|
||||
'import_select_cols' => function( $data ) use ( $maxMemberId )
|
||||
{
|
||||
/* Init */
|
||||
$fh = fopen( $data['file'], 'r' );
|
||||
@@ -2822,7 +2893,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
unset( \IPS\Member::loggedIn()->language()->words[ 'core_pfield_' . $fieldId . '_desc' ] );
|
||||
}
|
||||
}
|
||||
return new \IPS\Helpers\Form\Select( $key, $value, FALSE, array( 'options' => $importOptions ) );
|
||||
return new \IPS\Helpers\Form\Select( $key, $value, FALSE, array( 'options' => $importOptions, 'toggles' => array( 'member_id' => array( 'elImportMemberIdWarning' ) ) ) );
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2973,6 +3044,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Add the matrix */
|
||||
$form->addMatrix( 'columns', $matrix );
|
||||
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack( 'import_member_id_warning', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatNumber( $maxMemberId ) ) ) ), 'ipsMessage ipsMessage_warning', FALSE, 'elImportMemberIdWarning' );
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
@@ -3002,9 +3074,9 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
return (string) $form;
|
||||
},
|
||||
/* Step 3: Import */
|
||||
'import_do_import' => function( $wizardData )
|
||||
'import_do_import' => function( $wizardData ) use ( $maxMemberId )
|
||||
{
|
||||
return (string) new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal('app=core&module=members&controller=members&do=import'), function( $mrData ) use ( $wizardData )
|
||||
return (string) new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal('app=core&module=members&controller=members&do=import'), function( $mrData ) use ( $wizardData, $maxMemberId )
|
||||
{
|
||||
/* Get line from the file */
|
||||
$fh = fopen( $wizardData['file'], 'r' );
|
||||
@@ -3092,10 +3164,16 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
switch ( $wizardData['columns'][ $k ] )
|
||||
{
|
||||
case 'member_id':
|
||||
if ( !is_numeric( $v ) or $v < 0 or $v > $maxMemberId )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_member_id_invalid' ), $v, \IPS\Member::loggedIn()->language()->formatNumber( $maxMemberId ) ) );
|
||||
}
|
||||
$v = intval( $v );
|
||||
|
||||
$existingMember = \IPS\Member::load( $v );
|
||||
if ( $existingMember->member_id )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_member_id_exists' ) ) );
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_member_id_exists' ), $v ) );
|
||||
}
|
||||
$member->member_id = $v;
|
||||
break;
|
||||
@@ -3103,7 +3181,11 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
case 'name':
|
||||
if ( !$v )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_no_name' ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->get( 'import_no_name' ) );
|
||||
}
|
||||
if ( \strlen( $v ) > 255 )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_name_too_long' ), $v ) );
|
||||
}
|
||||
if ( \IPS\Login::usernameIsInUse( $v, NULL, TRUE ) )
|
||||
{
|
||||
@@ -3120,6 +3202,10 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_no_email' ) ) );
|
||||
}
|
||||
if ( \strlen( $v ) > 255 )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_email_too_long' ), $v ) );
|
||||
}
|
||||
if ( filter_var( $v, FILTER_VALIDATE_EMAIL ) === FALSE )
|
||||
{
|
||||
throw new \DomainException( sprintf( \IPS\Member::loggedIn()->language()->get( 'import_email_invalid' ), $v ) );
|
||||
@@ -3219,6 +3305,9 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
$member->joined = time();
|
||||
}
|
||||
|
||||
$member->members_bitoptions['created_externally'] = TRUE;
|
||||
|
||||
$member->save();
|
||||
if ( count( $profileFields ) )
|
||||
{
|
||||
@@ -3406,7 +3495,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
return $wizardData;
|
||||
}
|
||||
|
||||
|
||||
return (string) new \IPS\Helpers\MultipleRedirect(
|
||||
$baseUrl,
|
||||
function( $mrData ) use ( $wizardData, $baseUrl )
|
||||
@@ -3428,11 +3517,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
if( $_where = $extension->getQueryWhereClause( $wizardData['filters'][ $key ] ) )
|
||||
{
|
||||
if ( is_string( $_where ) )
|
||||
{
|
||||
$_where = array( $_where );
|
||||
}
|
||||
$where = array_merge( $where, $_where );
|
||||
$where[] = $_where;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3638,6 +3723,53 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('members_export');
|
||||
\IPS\Output::i()->output = $wizard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export Personal Information
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function exportPersonalInfo()
|
||||
{
|
||||
/* Check permission */
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'member_export_pi' );
|
||||
|
||||
/* Member */
|
||||
$member = \IPS\Member::load( \IPS\Request::i()->id );
|
||||
|
||||
if ( !$member->member_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C114/V', 404, '' );
|
||||
}
|
||||
|
||||
if ( ! isset( \IPS\Request::i()->process ) )
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('member_export_pi_title');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('memberprofile')->downloadPersonalInfo( $member );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Init */
|
||||
$xml = \IPS\Xml\SimpleXML::create('member_export');
|
||||
$xml->addAttribute( 'created', \IPS\DateTime::ts( time() )->rfc3339() );
|
||||
|
||||
/* Get the data */
|
||||
foreach( \IPS\Application::allExtensions( 'core', 'MemberExportPersonalInformation', TRUE, 'core' ) AS $key => $ext )
|
||||
{
|
||||
if ( $data = $ext->getData( $member ) and is_array( $data ) and count( $data ) )
|
||||
{
|
||||
$child = $xml->addChild( $key );
|
||||
foreach( $data as $k => $v )
|
||||
{
|
||||
$child->addChild( $k, $v );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build */
|
||||
\IPS\Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( "Content-Disposition" => \IPS\Output::getContentDisposition( 'attachment', $member->name . '_personal_information.xml' ) ), FALSE, FALSE, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Member History
|
||||
|
||||
@@ -26,7 +26,28 @@ class _profilecompletion extends \IPS\Node\Controller
|
||||
* Node Class
|
||||
*/
|
||||
protected $nodeClass = '\IPS\Member\ProfileStep';
|
||||
|
||||
|
||||
/**
|
||||
* Get Root Buttons
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function _getRootButtons()
|
||||
{
|
||||
$return = parent::_getRootButtons();
|
||||
|
||||
if ( isset( \IPS\Output::i()->sidebar['actions']['add'] ) )
|
||||
{
|
||||
$class = new \IPS\Member\ProfileStep;
|
||||
if ( ! $class->canAdd() )
|
||||
{
|
||||
unset( \IPS\Output::i()->sidebar['actions']['add'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
@@ -45,7 +66,8 @@ class _profilecompletion extends \IPS\Node\Controller
|
||||
*/
|
||||
public function manage()
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->profileCompleteBlurb();
|
||||
$class = new \IPS\Member\ProfileStep;
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->profileCompleteBlurb( $class->canAdd() );
|
||||
parent::manage();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class _profiles extends \IPS\Dispatcher\Controller
|
||||
$tabs = array();
|
||||
|
||||
/* Add a tab for fields and completion */
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'profilesfields_manage' ) )
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'membersettings', 'profilefields_manage' ) )
|
||||
{
|
||||
$tabs['profilefields'] = 'profile_fields';
|
||||
$tabs['profilecompletion'] = 'profile_completion';
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief spam
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
|
||||
* @since 18 Apr 2018
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\membersettings;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* spam
|
||||
* @deprecated
|
||||
*/
|
||||
class _spam extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Output::i()->redirect(\IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&tab=' . \IPS\Request::i()->tab ) );
|
||||
}
|
||||
|
||||
|
||||
// Create new methods with the same name as the 'do' parameter which should execute it
|
||||
}
|
||||
@@ -110,15 +110,6 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
/* Warnings */
|
||||
$warnings = array();
|
||||
|
||||
$dir = @dir( '/' );
|
||||
if ( $dir instanceof \Directory )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_title'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('open_basedir_desc'),
|
||||
);
|
||||
}
|
||||
|
||||
$functionsToDisable = array( 'exec', 'system', 'passhtru', 'pcntl_exec', 'popen', 'proc_open', 'shell_exec' );
|
||||
$showingFunctionWarning = FALSE;
|
||||
foreach ( $functionsToDisable as $k => $function )
|
||||
@@ -135,21 +126,23 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( $showingFunctionWarning )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'disable_functions',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_title'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('disable_functions_desc', FALSE, array( 'sprintf' => array( implode( ', ', $functionsToDisable ) ) ) ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( !\IPS\IN_DEV and ini_get( 'display_errors' ) )
|
||||
if ( !\IPS\IN_DEV and ( (bool) ini_get( 'display_errors' ) ) !== FALSE AND ini_get( 'display_errors' ) !== 'Off' )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'display_errors',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_title'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('display_errors_desc'),
|
||||
'risk' => "medium",
|
||||
);
|
||||
}
|
||||
|
||||
$tasks = \IPS\Db::i()->select( '*', 'core_tasks', 'lock_count >= 3' );
|
||||
$tasks = \IPS\Db::i()->select( '*', 'core_tasks', 'lock_count >= 3 AND enabled=1' );
|
||||
$keys = array();
|
||||
foreach( $tasks as $task )
|
||||
{
|
||||
@@ -158,6 +151,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( !empty( $keys ) )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_tasks_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_broken_desc', TRUE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $keys ) ) ) )
|
||||
);
|
||||
@@ -166,6 +160,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if( isset( \IPS\Data\Store::i()->failedMailCount ) AND \IPS\Data\Store::i()->failedMailCount >= 3 )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_email_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_email_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_email_broken_desc', TRUE )
|
||||
);
|
||||
@@ -175,6 +170,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( $supportAccount->member_id )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_support_account',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_support_account' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_support_account_desc', TRUE, array( 'sprintf' => array( $supportAccount->acpUrl() ) ) )
|
||||
);
|
||||
@@ -217,6 +213,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if( !$inProgress )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'block_core_OrigTables',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('block_core_OrigTables'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('orig_cleanup_suggested')
|
||||
);
|
||||
@@ -227,7 +224,10 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
/* Check Tasks */
|
||||
try
|
||||
{
|
||||
$task = \IPS\DateTime::ts( \IPS\Db::i()->select( 'next_run', 'core_tasks', array( 'enabled=?', TRUE ), 'next_run ASC' )->first() );
|
||||
$task = \IPS\DateTime::ts( \IPS\Db::i()->select( 'next_run', 'core_tasks', array( 'core_tasks.enabled=1 AND (core_plugins.plugin_enabled=1 OR core_applications.app_enabled=1)' ), 'next_run ASC' )
|
||||
->join( 'core_applications', array( 'core_applications.app_directory=core_tasks.app' ) )
|
||||
->join( 'core_plugins', array( 'core_plugins.plugin_id=core_tasks.plugin' ) )
|
||||
->first() );
|
||||
$today = new \IPS\DateTime;
|
||||
$difference = $today->diff( $task )->h + ( $today->diff( $task )->days * 24 );
|
||||
|
||||
@@ -236,6 +236,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if( \IPS\Settings::i()->task_use_cron == 'cron' )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_tasksrun_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( \IPS\CIC ? 'dashboard_tasks_cron_broken_desc_cic' : 'dashboard_tasks_cron_broken_desc' )
|
||||
);
|
||||
@@ -243,6 +244,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
elseif( \IPS\Settings::i()->task_use_cron == 'web' )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_tasksrun_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_web_broken_desc' )
|
||||
);
|
||||
@@ -250,6 +252,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
else
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_tasksrun_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasksrun_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_tasks_not_enough_desc' )
|
||||
);
|
||||
@@ -261,12 +264,39 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( !\IPS\Settings::i()->site_online AND \IPS\Settings::i()->task_use_cron == 'normal' AND !\IPS\CIC )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dasbhoard_tasks_site_offline',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('dasbhoard_tasks_site_offline'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('dasbhoard_tasks_site_offline_desc')
|
||||
);
|
||||
}
|
||||
|
||||
/* Check MySQL and PHP min versions */
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$mysqlVersion = \IPS\Db::i()->server_info;
|
||||
$requirements = json_decode( file_get_contents( \IPS\ROOT_PATH . '/applications/core/data/requirements.json' ), TRUE );
|
||||
|
||||
if ( version_compare( $phpVersion, $requirements['php']['recommended'] ) < 0 )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_recommended_php_version',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('dashboard_recommended_php_version'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_advice', FALSE, array( 'sprintf' => array( $phpVersion, $requirements['php']['recommended'] ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( version_compare( $mysqlVersion, $requirements['mysql']['recommended'] ) < 0 AND !mb_strpos( $mysqlVersion, "MariaDB" ) )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dasbhoard_required_mysql_version',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('dasbhoard_required_mysql_version'),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'requirements_mysql_version_advice', FALSE, array( 'sprintf' => array( $mysqlVersion, $requirements['mysql']['recommended'] ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Don't do this for IN_DEV on localhost */
|
||||
//
|
||||
|
||||
/* If there have been more than 10 datastore failures in the last hour, or if an instant test fails, show a message */
|
||||
if( !\IPS\Data\Store::i()->test() OR \IPS\Db::i()->select( 'COUNT(*)', 'core_log', array( '`category`=? AND `time`>?', 'datastore', \IPS\DateTime::create()->sub( new \DateInterval( 'PT1H' ) )->getTimestamp() ) )->first() >= 10 )
|
||||
@@ -275,6 +305,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if( \IPS\Settings::i()->last_data_store_update < \IPS\DateTime::create()->sub( new \DateInterval( 'PT24H' ) )->getTimestamp() )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_datastore_broken',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_datastore_broken' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_datastore_broken_desc' )
|
||||
);
|
||||
@@ -307,6 +338,7 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( isset( $cicEmails['status'] ) AND $cicEmails['status'] == 'BLOCKED' )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_cic_email_quota',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_cic_email_quota' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_cic_email_quota_desc' )
|
||||
);
|
||||
@@ -317,10 +349,21 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if ( \IPS\CACHE_METHOD AND \IPS\CACHE_METHOD != 'None' AND \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'dashboard_invalid_cachesetup',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_invalid_cachesetup' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( 'dashboard_invalid_cachesetup_desc' )
|
||||
);
|
||||
}
|
||||
|
||||
/* Temporary thing for to show a warning if Facebook login is enabled but site doesn't use https */
|
||||
if ( \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\OAuth2\Facebook' ) and mb_substr( \IPS\Settings::i()->base_url, 0, 8 ) !== 'https://' )
|
||||
{
|
||||
$warnings[] = array(
|
||||
'key' => 'facebook_https',
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( time() < mktime( 0, 0, 0, 10, 6, 2018 ) ? 'facebook_https_warning_title' : 'facebook_https_warning_title2' ),
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack( \IPS\CIC ? 'facebook_https_warning_desc_cic' : 'facebook_https_warning_desc' )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Get new core update available data */
|
||||
@@ -351,6 +394,19 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
catch( \RuntimeException $e ){}
|
||||
}
|
||||
|
||||
/* Don't show warnings we've hidden */
|
||||
if ( isset( \IPS\Request::i()->cookie['acpWarnings_mute'] ) )
|
||||
{
|
||||
$keys = explode( ',', \IPS\Request::i()->cookie['acpWarnings_mute'] );
|
||||
foreach( $warnings as $index => $data )
|
||||
{
|
||||
if ( isset( $data['key'] ) and in_array( $data['key'], $keys ) )
|
||||
{
|
||||
unset( $warnings[ $index ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('dashboard');
|
||||
\IPS\Output::i()->customHeader = \IPS\Theme::i()->getTemplate( 'dashboard' )->dashboardHeader( $info, $blocks );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'dashboard' )->dashboard( $update, $features, $toShow, $blocks, $info, $bulletins, $warnings );
|
||||
@@ -390,8 +446,9 @@ class _dashboard extends \IPS\Dispatcher\Controller
|
||||
if( !$toShow OR !isset( $toShow['main'] ) OR !isset( $toShow['side'] ) )
|
||||
{
|
||||
$toShow = array(
|
||||
'main' => array( 'core_AdminNotes', 'core_Registrations', 'core_AwaitingValidation', 'core_BackgroundQueue' ),
|
||||
'side' => array( 'core_OnlineAdmins', 'core_FailedLogins', 'core_OnlineUsers' ),
|
||||
'main' => array( 'core_AdminNotes', 'core_Registrations', 'core_AwaitingValidation', 'core_BackgroundQueue' ),
|
||||
'side' => array( 'core_OnlineAdmins', 'core_FailedLogins', 'core_OnlineUsers' ),
|
||||
'collapsed' => array( 'core_BackgroundQueue' ),
|
||||
);
|
||||
|
||||
$blocks[ \IPS\Member::loggedIn()->member_id ] = $toShow;
|
||||
|
||||
@@ -94,13 +94,13 @@ class _files extends \IPS\Dispatcher\Controller
|
||||
if ( $row['attach_is_image'] and $table->filter === 'images' )
|
||||
{
|
||||
$url = \IPS\Http\Url::external( \IPS\File::get( 'core_Attachment', $row['attach_location'] )->url )->makeSafeForAcp( TRUE );
|
||||
return "<a href='{$url}' target='_blank'><img src='{$url}' style='max-height:200px'></a>";
|
||||
return "<a href='{$url}' target='_blank' rel='noopener'><img src='{$url}' style='max-height:200px'></a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = \IPS\Http\Url::external( \IPS\Settings::i()->base_url . "applications/core/interface/file/attachment.php" )->setQueryString( 'id', $row['attach_id'] )->makeSafeForAcp( FALSE );
|
||||
$val = htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE );
|
||||
return "<a href='{$url}' target='_blank'>{$val}</a>";
|
||||
return "<a href='{$url}' target='_blank' rel='noopener'>{$val}</a>";
|
||||
}
|
||||
},
|
||||
'attach_filesize' => function( $val )
|
||||
@@ -269,13 +269,15 @@ class _files extends \IPS\Dispatcher\Controller
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'image_suite', class_exists( 'Imagick', FALSE ) ? \IPS\Settings::i()->image_suite : 'gd', TRUE, array(
|
||||
'options' => array( 'gd' => 'imagesuite_gd', 'imagemagick' => 'imagesuite_imagemagick' ),
|
||||
'toggles' => array( 'imagemagick' => array( 'image_jpg_quality' ), 'gd' => array( 'image_jpg_quality', 'image_png_quality_gd' ) ),
|
||||
'toggles' => array( 'imagemagick' => array( 'image_jpg_quality', 'imagick_strip_exif' ), 'gd' => array( 'image_jpg_quality', 'image_png_quality_gd' ) ),
|
||||
'disabled'=> class_exists( 'Imagick', FALSE ) ? array() : array( 'imagemagick' )
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'image_jpg_quality', \IPS\Settings::i()->image_jpg_quality, FALSE, array( 'min' => 0, 'max' => 100, 'range' => TRUE, 'step' => 1 ), NULL, NULL, NULL, 'image_jpg_quality' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'image_png_quality_gd', \IPS\Settings::i()->image_png_quality_gd, FALSE, array( 'min' => 0, 'max' => 9, 'range' => TRUE, 'step' => 1 ), NULL, NULL, NULL, 'image_png_quality_gd' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'imagick_strip_exif', \IPS\Settings::i()->imagick_strip_exif, FALSE, array(), NULL, NULL, NULL, 'imagick_strip_exif' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$form->saveAsSettings();
|
||||
|
||||
@@ -386,8 +386,8 @@ class _advertisements extends \IPS\Dispatcher\Controller
|
||||
$locations,
|
||||
TRUE,
|
||||
array(
|
||||
'options' => array_combine( array_keys( $defaultLocations ), array_keys( $defaultLocations ) ),
|
||||
'toggles' => $defaultLocations,
|
||||
'options' => array_combine( array_keys( $defaultLocations ), array_keys( $defaultLocations ) ),
|
||||
'toggles' => $defaultLocations,
|
||||
),
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -463,15 +463,26 @@ class _advertisements extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$images = array( 'large' => (string) $values['ad_image'] );
|
||||
|
||||
if( isset( $values['ad_image_small'] ) AND $values['ad_image_small'] )
|
||||
if( $values['ad_image_more'] and isset( $values['ad_image_small'] ) AND $values['ad_image_small'] )
|
||||
{
|
||||
$images['small'] = (string) $values['ad_image_small'];
|
||||
}
|
||||
|
||||
if( isset( $values['ad_image_medium'] ) AND $values['ad_image_medium'] )
|
||||
if( $values['ad_image_more'] and isset( $values['ad_image_medium'] ) AND $values['ad_image_medium'] )
|
||||
{
|
||||
$images['medium'] = (string) $values['ad_image_medium'];
|
||||
}
|
||||
|
||||
/* If there are images, but we disabled additional images, remove them */
|
||||
if( !$values['ad_image_more'] and isset( $values['ad_image_small'] ) AND $values['ad_image_small'] )
|
||||
{
|
||||
$values['ad_image_small']->delete();
|
||||
}
|
||||
|
||||
if( !$values['ad_image_more'] and isset( $values['ad_image_medium'] ) AND $values['ad_image_medium'] )
|
||||
{
|
||||
$values['ad_image_medium']->delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -349,18 +349,72 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
|
||||
$account = \IPS\core\Promote::getPromoter('Facebook')->setMember( \IPS\Member::loggedIn() );
|
||||
|
||||
/* Have we set up Facebook yet? */
|
||||
if ( !$facebook OR ! $facebook->settings['client_id'] )
|
||||
/* We are using the default app here */
|
||||
if ( \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) )
|
||||
{
|
||||
/* Nope, so lets do that first... */
|
||||
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookApp();
|
||||
/* Have we set up Facebook yet? */
|
||||
if ( !$facebook OR ! $facebook->settings['client_id'] )
|
||||
{
|
||||
/* Nope, so lets do that first... */
|
||||
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookApp();
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* We are using our custom app here */
|
||||
$facebook->settings = json_decode( \IPS\Settings::i()->promote_facebook_auth, TRUE );
|
||||
}
|
||||
|
||||
/* promote_facebook_auth: value 0 means not set up, value 1 means using default, JSON means using custom */
|
||||
if ( ! \IPS\Settings::i()->promote_facebook_auth )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$json = array();
|
||||
|
||||
if ( ! \is_int( \IPS\Settings::i()->promote_facebook_auth ) )
|
||||
{
|
||||
$json = json_decode( \IPS\Settings::i()->promote_facebook_auth, TRUE );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'promote_facebook_auth_choose', ( \IPS\Settings::i()->promote_facebook_auth === 0 or \IPS\Settings::i()->promote_facebook_auth === 1 ) ? 1 : 0, FALSE, array( 'options' => array(
|
||||
0 => 'promote_facebook_auth_choose_default',
|
||||
1 => 'promote_facebook_auth_choose_custom'
|
||||
),
|
||||
'toggles' => array(
|
||||
1 => array( 'promote_facebook_auth_id', 'promote_facebook_auth_secret' )
|
||||
) ), NULL, NULL, NULL, 'promote_facebook_auth_choose' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'promote_facebook_auth_id', ( isset( $json['client_id'] ) ? $json['client_id'] : NULL ), TRUE, array(), NULL, NULL, NULL, 'promote_facebook_auth_id' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'promote_facebook_auth_secret', ( isset( $json['client_secret'] ) ? $json['client_secret'] : NULL ), TRUE, array(), NULL, NULL, NULL, 'promote_facebook_auth_secret' ) );
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['promote_facebook_auth_id_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'login_handler_Facebook_info', FALSE, array( 'sprintf' => array( (string) \IPS\Http\Url::internal( 'oauth/callback/', 'none' ) ) ) );
|
||||
|
||||
/* Are we saving? */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* Default to .. default */
|
||||
$auth = 1;
|
||||
|
||||
if ( $values['promote_facebook_auth_choose'] == 1 )
|
||||
{
|
||||
$auth = array(
|
||||
'client_id' => $values['promote_facebook_auth_id'],
|
||||
'client_secret' => $values['promote_facebook_auth_secret']
|
||||
);
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'promote_facebook_auth' => json_encode( $auth ) ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=promotion&controller=promote&tab=" . \IPS\Request::i()->tab ), 'saved' );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/* Have we synchronized our user account with Facebook? */
|
||||
if ( ! $facebook->canProcess( \IPS\Member::loggedIn() ) )
|
||||
if ( ! $account->isConnected( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
/* Nope, so lets do that now... */
|
||||
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookUser( $facebook );
|
||||
return \IPS\Theme::i()->getTemplate( 'promote' )->warningNoFacebookUser( $facebook, \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) );
|
||||
}
|
||||
|
||||
/* Do we have post to page permissions? */
|
||||
@@ -383,9 +437,13 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
'page_name' => NULL,
|
||||
'enabled' => NULL,
|
||||
'page' => NULL,
|
||||
'group' => NULL
|
||||
'group' => NULL,
|
||||
'member_token' => NULL,
|
||||
'shareable' => NULL
|
||||
) );
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'promote_facebook_auth' => '' ) );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=promotion&controller=promote&tab=facebook" ) );
|
||||
}
|
||||
|
||||
@@ -559,7 +617,7 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$promote = \IPS\core\Promote::load( $val );
|
||||
|
||||
return $promote->objectTitle . ' (' . $val . ')';
|
||||
return htmlspecialchars( $promote->objectTitle, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ) . ' (' . $val . ')';
|
||||
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
@@ -214,7 +214,6 @@ class _seo extends \IPS\Dispatcher\Controller
|
||||
if( !$form->error )
|
||||
{
|
||||
$values['sitemap_url'] = (string) $values['sitemap_url'];
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
foreach( \IPS\Application::allExtensions( 'core', 'Sitemap', FALSE, 'core' ) as $extKey => $extension )
|
||||
{
|
||||
@@ -224,6 +223,8 @@ class _seo extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
|
||||
$form->saveAsSettings( array( 'sitemap_url' => $values['sitemap_url'] ) );
|
||||
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
$options = array(
|
||||
'FileSystem' => 'datastore_method_FileSystem',
|
||||
'Database' => 'datastore_method_Database',
|
||||
'Redis' => 'datastore_method_Redis',
|
||||
);
|
||||
$existingConfiguration = json_decode( \IPS\STORE_CONFIG, TRUE );
|
||||
foreach ( $options as $k => $v )
|
||||
@@ -159,7 +160,12 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
'options' => $options,
|
||||
'toggles' => $toggles,
|
||||
'disabled' => $disabled,
|
||||
) ) );
|
||||
), function( $val ){
|
||||
if( $val === 'Redis' AND \IPS\Request::i()->cache_method !== 'Redis' )
|
||||
{
|
||||
throw new \DomainException( 'datastore_redis_cache' );
|
||||
}
|
||||
} ) );
|
||||
foreach ( $extra as $input )
|
||||
{
|
||||
$form->add( $input );
|
||||
@@ -299,7 +305,7 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$val = constant( 'IPS\\' . $k );
|
||||
|
||||
if ( $val !== $v and !in_array( $k, array( 'STORE_METHOD', 'STORE_CONFIG', 'CACHE_METHOD', 'CACHE_CONFIG', 'CACHE_PAGE_TIMEOUT', 'SUITE_UNIQUE_KEY', 'READ_WRITE_SEPARATION', 'REDIS_ENABLED' ) ) )
|
||||
if ( $val !== $v and !in_array( $k, array( 'STORE_METHOD', 'STORE_CONFIG', 'CACHE_METHOD', 'CACHE_CONFIG', 'CACHE_PAGE_TIMEOUT', 'SUITE_UNIQUE_KEY', 'READ_WRITE_SEPARATION', 'REDIS_ENABLED', 'REPORT_EXCEPTIONS' ) ) )
|
||||
{
|
||||
$output .= "define( '{$k}', " . var_export( $val, TRUE ) . " );\n";
|
||||
}
|
||||
@@ -331,7 +337,7 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
$output .= "define( 'CACHE_PAGE_TIMEOUT', " . var_export( (int) \IPS\Request::i()->cache_guest_page, TRUE ) . " );\n";
|
||||
$output .= "define( 'SUITE_UNIQUE_KEY', " . var_export( mb_substr( md5( mt_rand() ), 10, 10 ), TRUE ) . " );\n"; // Regenerate the unique key so there's no conflicts
|
||||
$output .= "\n\n\n";
|
||||
|
||||
|
||||
\IPS\Output::i()->sendOutput( $output, 200, 'text/x-php', array( 'Content-Disposition' => 'attachment; filename=constants.php' ) );
|
||||
}
|
||||
|
||||
@@ -451,9 +457,10 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'advanced_manage_tasks' );
|
||||
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_tasks', \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=tasks' ), array( array( 'a.app_enabled=1' ) ) );
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_tasks', \IPS\Http\Url::internal( 'app=core&module=settings&controller=advanced&do=tasks' ), array( array( '(p.plugin_enabled=1 OR a.app_enabled=1)' ) ) );
|
||||
$table->joins = array(
|
||||
array( 'select' => 'a.app_enabled', 'from' => array( 'core_applications', 'a' ), 'where' => "a.app_directory=app" )
|
||||
array( 'select' => 'a.app_enabled', 'from' => array( 'core_applications', 'a' ), 'where' => "a.app_directory=app" ),
|
||||
array( 'select' => 'p.plugin_enabled', 'from' => array( 'core_plugins', 'p' ), 'where' => "p.plugin_id=plugin" )
|
||||
);
|
||||
$table->langPrefix = 'task_manager_';
|
||||
$table->include = array( 'app', 'key', 'frequency', 'next_run', 'last_run' );
|
||||
@@ -644,18 +651,19 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'advancedsettings' )->taskResult( TRUE, $output, $task->id );
|
||||
}
|
||||
}
|
||||
catch( \RuntimeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'task_class_not_found', '4C124/6', 404, '' );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C124/1', 404, '' );
|
||||
}
|
||||
catch ( \IPS\Task\Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'advancedsettings' )->taskResult( FALSE, \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage(), FALSE ), $task->id );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'task_class_not_found', '2C124/1', 404, '' );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'uncaught_exception' );
|
||||
\IPS\Output::i()->error( $e->getMessage(), '4C124/6', 404, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -718,7 +726,14 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = \IPS\Member::loggedIn()->language()->addToStack( $val, FALSE );
|
||||
if( $decoded = json_decode( $val ) )
|
||||
{
|
||||
$val = \IPS\Member::loggedIn()->language()->addToStack( array_shift( $decoded ), FALSE, array( 'sprintf' => $decoded ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = \IPS\Member::loggedIn()->language()->addToStack( $val, FALSE );
|
||||
}
|
||||
}
|
||||
return $row['error'] ? \IPS\Theme::i()->getTemplate( 'global' )->message( $val, 'error' ) : $val;
|
||||
}
|
||||
@@ -905,7 +920,7 @@ class _advanced extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
ksort( $furl );
|
||||
ksort( $furl, SORT_NATURAL );
|
||||
$keys = array_keys( $furl );
|
||||
$lastKey = str_replace( 'key', '', end( $keys ) );
|
||||
$key = 'key' . ( $lastKey + 1 );
|
||||
|
||||
@@ -209,6 +209,7 @@ class _email extends \IPS\Dispatcher\Controller
|
||||
/* Columns we need */
|
||||
$table->include = array( 'mlog_to', 'mlog_subject', 'mlog_date', 'mlog_msg' );
|
||||
$table->widths = array( 'mlog_date' => '15', 'mlog_to' => '20', 'mlog_subject' => '20', 'mlog_msg' => '35' );
|
||||
$table->rowClasses = array( 'mlog_subject' => array( 'ipsTable_wrap' ), 'mlog_msg' => array( 'ipsTable_wrap' ) );
|
||||
|
||||
$table->sortBy = $table->sortBy ?: 'mlog_date';
|
||||
$table->sortDirection = $table->sortDirection ?: 'DESC';
|
||||
@@ -236,6 +237,19 @@ class _email extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$val = \IPS\Member::loggedIn()->language()->get('phpmail_not_sent');
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $data = json_decode( $val, true ) )
|
||||
{
|
||||
/* We may not have a 'message' key if this is an older SendGrid log entry */
|
||||
if( isset( $data['message'] ) )
|
||||
{
|
||||
$val = \is_string( $data['message'] ) ?
|
||||
( ( isset( $data['details'] ) AND $data['details'] ) ? \IPS\Member::loggedIn()->language()->addToStack( $data['message'], FALSE, array( 'sprintf' => $data['details'] ) ) : \IPS\Member::loggedIn()->language()->addToStack( $data['message'] ) ) :
|
||||
$val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'logs' )->emailErrorLog( nl2br( htmlspecialchars( $val, ENT_DISALLOWED, 'UTF-8', FALSE ) ), $row );
|
||||
},
|
||||
|
||||
@@ -61,16 +61,20 @@ class _general extends \IPS\Dispatcher\Controller
|
||||
\IPS\Lang::saveCustom( 'core', "copyright_line_value", $values['copyright_line'] );
|
||||
unset( $values['copyright_line'] );
|
||||
|
||||
array_walk( $values['site_social_profiles'], function( &$value ){
|
||||
$value['key'] = (string) $value['key'];
|
||||
});
|
||||
$values['site_social_profiles'] = json_encode( array_filter( $values['site_social_profiles'], function( $value ) {
|
||||
return (bool) $value['key'];
|
||||
} ) );
|
||||
|
||||
$values['site_address'] = json_encode( $values['site_address'] );
|
||||
|
||||
$values['upgrade_email'] = implode( ',', $values['upgrade_email'] );
|
||||
|
||||
$values['usage_reporting'] = in_array( 'usage', $values['diagnostics_reporting'] );
|
||||
$values['diagnostics_reporting'] = in_array( 'diagnostics', $values['diagnostics_reporting'] );
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => intval( $values['usage_reporting'] ) ), array( '`key`=?', 'usagereporting' ) );
|
||||
// $values['usage_reporting'] = in_array( 'usage', $values['diagnostics_reporting'] );
|
||||
// $values['diagnostics_reporting'] = in_array( 'diagnostics', $values['diagnostics_reporting'] );
|
||||
// \IPS\Db::i()->update( 'core_tasks', array( 'enabled' => intval( $values['usage_reporting'] ) ), array( '`key`=?', 'usagereporting' ) );
|
||||
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class _licensekey extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function settings()
|
||||
{
|
||||
$$form = new \IPS\Helpers\Form;
|
||||
$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 ) );
|
||||
|
||||
@@ -170,7 +170,10 @@ class _login extends \IPS\Node\Controller
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'login_handler_1', 'continue' );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'login_handler', TRUE, NULL, array( 'options' => $options ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'login_handler', TRUE, NULL, array( 'options' => $options ), function( $val )
|
||||
{
|
||||
$val::testCompatibility();
|
||||
} ) );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
return array( 'handler' => $values['login_handler'] );
|
||||
@@ -366,11 +369,19 @@ class _login extends \IPS\Node\Controller
|
||||
'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' )
|
||||
) ) );
|
||||
|
||||
/* 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() )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['allow_reg_normal_warning'] = \IPS\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 )
|
||||
{
|
||||
if ( !$val and \IPS\Request::i()->allow_red === 'redirect' )
|
||||
|
||||
@@ -172,6 +172,8 @@ class _posting extends \IPS\Dispatcher\Controller
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'dellog_retention_period', \IPS\Settings::i()->dellog_retention_period, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'immediately', 'max' => PHP_INT_MAX ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('dellog_days_after_deleted') ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'ip_address_prune', \IPS\Settings::i()->ip_address_prune, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'never', 'max' => PHP_INT_MAX ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days') ) );
|
||||
|
||||
/* Save values */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
@@ -361,6 +363,7 @@ class _posting extends \IPS\Dispatcher\Controller
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_acronyms', \IPS\Http\Url::internal( 'app=core&module=settings&controller=posting&tab=acronymExpansion' ) );
|
||||
$table->langPrefix = 'acronym_';
|
||||
$table->mainColumn = 'a_short';
|
||||
$table->rowClasses = array( 'a_long' => array( 'ipsTable_wrap' ) );
|
||||
|
||||
/* Columns we need */
|
||||
$table->include = array( 'a_short', 'a_long', 'a_casesensitive' );
|
||||
|
||||
@@ -63,13 +63,17 @@ class _terms extends \IPS\Dispatcher\Controller
|
||||
'external' => 'privacy_external',
|
||||
'none' => "privacy_none" ),
|
||||
'toggles' => array(
|
||||
'internal' => array( 'privacy_text_id' ),
|
||||
'internal' => array( 'privacy_text_id', 'privacy_show_processors' ),
|
||||
'external' => array( 'privacy_link' ),
|
||||
'none' => array(),
|
||||
)
|
||||
) ) );
|
||||
|
||||
$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 \IPS\Helpers\Form\Url( 'privacy_link', \IPS\Settings::i()->privacy_link, FALSE, array(), NULL, NULL, NULL, 'privacy_link' ) );
|
||||
|
||||
$form->addHeader( 'terms_registration' );
|
||||
|
||||
@@ -144,6 +144,9 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
/* Issue */
|
||||
else
|
||||
{
|
||||
/* Log that the support tool has been run */
|
||||
\IPS\Session::i()->log( 'acplog__support_tool_ran' );
|
||||
|
||||
/* Get requirements and suggestions */
|
||||
$requirementsCheck = \IPS\core\Setup\Upgrade::systemRequirements();
|
||||
|
||||
@@ -173,13 +176,12 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::clearJsFiles();
|
||||
|
||||
/* Reset theme maps to make sure bad data hasn't been cached by visits mid-setup */
|
||||
\IPS\Theme::deleteCompiledCss();
|
||||
|
||||
foreach( \IPS\Theme::themes() as $id => $set )
|
||||
{
|
||||
/* Invalidate template disk cache */
|
||||
$set->cache_key = md5( microtime() . mt_rand( 0, 1000 ) );
|
||||
|
||||
/* Update mappings */
|
||||
$set->css_map = array();
|
||||
$set->save();
|
||||
}
|
||||
|
||||
@@ -346,7 +348,7 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function _connectionChecker()
|
||||
{
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -174,6 +174,9 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If all columns in an index are already utf8mb4 then we don't need to worry about recreating the index */
|
||||
$needToRecreate = FALSE;
|
||||
|
||||
$length = 0;
|
||||
$hasText = false;
|
||||
foreach( $indexData['columns'] as $column )
|
||||
@@ -186,9 +189,14 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$length += $tableDefinition['columns'][ $column ]['length'];
|
||||
}
|
||||
|
||||
if( $tableDefinition['columns'][ $column ]['collation'] !== 'utf8mb4_unicode_ci' )
|
||||
{
|
||||
$needToRecreate = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( $length * 4 > $maxLen ) or $hasText )
|
||||
if ( $needToRecreate AND ( ( $length * 4 > $maxLen ) or $hasText ) )
|
||||
{
|
||||
$indexesToRecreate[ $indexName ] = $indexData;
|
||||
\IPS\Db::i()->dropIndex( $table, $indexName );
|
||||
@@ -205,6 +213,9 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
$repair = true;
|
||||
}
|
||||
|
||||
/* Aggregate all the changes into one query for efficiency */
|
||||
$aggregatedChanges = array();
|
||||
|
||||
/* Do each column */
|
||||
foreach ( $tableDefinition['columns'] as $columnName => $columnData )
|
||||
{
|
||||
@@ -212,7 +223,7 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
if( $tableDefinition['columns'][ $columnName ]['collation'] !== 'utf8mb4_unicode_ci' )
|
||||
{
|
||||
\IPS\Db::i()->changeColumn( $table, $columnName, $columnData );
|
||||
$aggregatedChanges[] = "CHANGE COLUMN `" . \IPS\Db::i()->escape_string( $columnName ) . "` " . \IPS\Db::i()->compileColumnDefinition( $columnData );
|
||||
$repair = true;
|
||||
}
|
||||
}
|
||||
@@ -221,15 +232,21 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
/* Recreate any indexes */
|
||||
foreach ( $indexesToRecreate as $indexName => $indexData )
|
||||
{
|
||||
\IPS\Db::i()->addIndex( $table, $indexData );
|
||||
$aggregatedChanges[] = \IPS\Db::i()->buildIndex( $table, $indexData );
|
||||
$repair = true;
|
||||
}
|
||||
|
||||
/* Now if we have any changes to make....make them */
|
||||
if( count( $aggregatedChanges ) )
|
||||
{
|
||||
\IPS\Db::i()->query( "ALTER TABLE " . \IPS\Db::i()->prefix . \IPS\Db::i()->escape_string( $table ) . " " . implode( ', ', $aggregatedChanges ) );
|
||||
}
|
||||
|
||||
/* Repair and optimize */
|
||||
if( $repair === true )
|
||||
{
|
||||
\IPS\Db::i()->query("REPAIR TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
|
||||
\IPS\Db::i()->query("OPTIMIZE TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
|
||||
//\IPS\Db::i()->query("OPTIMIZE TABLE `" . \IPS\Settings::i()->sql_tbl_prefix . "{$table}`");
|
||||
}
|
||||
|
||||
/* If this is the search index table, initiate rebuild now. */
|
||||
@@ -248,6 +265,7 @@ class _utf8mb4 extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'utf8mb4' );
|
||||
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'utf8mb4_converter_error', FALSE, array( 'sprintf' => array( $e->getMessage() ) ) ), '4C171/4', 403, '' );
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,24 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
{
|
||||
/* Do we have an unfinished upgrade? */
|
||||
if ( !\IPS\IN_DEV and !isset( \IPS\Request::i()->noWarning ) )
|
||||
{
|
||||
if( \IPS\Application::load('core')->long_version < \IPS\Application::getAvailableVersion('core') and \IPS\Application::load('core')->version != \IPS\Application::getAvailableVersion( 'core', TRUE ) )
|
||||
{
|
||||
include( \IPS\ROOT_PATH . '/' . \IPS\CP_DIRECTORY . '/upgrade/upgradeAvailable.html' );
|
||||
session_abort();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init login class */
|
||||
$url = \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'admin' );
|
||||
if ( isset( \IPS\Request::i()->noWarning ) )
|
||||
{
|
||||
$url = $url->setQueryString( 'noWarning', 1 );
|
||||
}
|
||||
if ( isset( \IPS\Request::i()->ref ) )
|
||||
{
|
||||
$url = $url->setQueryString( 'ref', \IPS\Request::i()->ref );
|
||||
@@ -63,7 +78,8 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
|
||||
$success->device->updateAfterAuthentication( FALSE, $success->handler, FALSE, FALSE );
|
||||
/* Otherwise go ahead */
|
||||
$this->_doLogin( $success->member );
|
||||
}
|
||||
@@ -95,21 +111,11 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we need to show a message about an unfinished upgrade? */
|
||||
$upgradeError = FALSE;
|
||||
if ( !\IPS\IN_DEV and !isset( \IPS\Request::i()->noWarning ) )
|
||||
{
|
||||
if( \IPS\Application::load('core')->long_version < \IPS\Application::getAvailableVersion('core') and \IPS\Application::load('core')->version != \IPS\Application::getAvailableVersion( 'core', TRUE ) )
|
||||
{
|
||||
$upgradeError = \IPS\Application::getAvailableVersion( 'core', TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Display Login Form */
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_system.js', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/login.css', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->login( $login, $error, $upgradeError ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'system' )->login( $login, $error, FALSE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +219,7 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( http_build_query( $queryString ) ), '', 303 );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( http_build_query( $queryString, '', '&' ) ), '', 303 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,823 @@ class _upgrade extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'upgrade_manage', 'core', 'overview' );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( "http://ipbmafia.ru/files/file/2134-invision-community-42-nulled/" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('ips_suite_upgrade');
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( "https://ipbmafia.ru/files/file/2279-invision-community-43-nulled/" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Select Version
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @return string|array
|
||||
*/
|
||||
public function _selectVersion( $data )
|
||||
{
|
||||
/* Check latest version */
|
||||
$versions = array();
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) ) as $app )
|
||||
{
|
||||
if ( $app['app_enabled'] )
|
||||
{
|
||||
$versions[] = $app['app_long_version'];
|
||||
}
|
||||
}
|
||||
$version = min( $versions );
|
||||
$url = \IPS\Http\Url::ips('updateCheck')->setQueryString( array( 'type' => 'upgrader', 'key' => \IPS\Settings::i()->ipb_reg_number ) );
|
||||
if ( \IPS\USE_DEVELOPMENT_BUILDS )
|
||||
{
|
||||
$url = $url->setQueryString( 'development', 1 );
|
||||
}
|
||||
try
|
||||
{
|
||||
$response = $url->setQueryString( 'version', $version )->request()->get()->decodeJson();
|
||||
$coreApp = \IPS\Application::load('core');
|
||||
$coreApp->update_version = json_encode( $response );
|
||||
$coreApp->update_last_check = time();
|
||||
$coreApp->save();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form( 'select_version' );
|
||||
$options = array();
|
||||
$descriptions = array();
|
||||
$latestVersion = 0;
|
||||
foreach( \IPS\Application::load( 'core' )->availableUpgrade( FALSE, !isset( $data['patch'] ) ) as $possibleVersion )
|
||||
{
|
||||
$options[ $possibleVersion['longversion'] ] = $possibleVersion['version'];
|
||||
$descriptions[ $possibleVersion['longversion'] ] = $possibleVersion;
|
||||
if ( $latestVersion < $possibleVersion['longversion'] )
|
||||
{
|
||||
$latestVersion = $possibleVersion['longversion'];
|
||||
}
|
||||
}
|
||||
if ( \IPS\TEST_DELTA_ZIP )
|
||||
{
|
||||
$options['test'] = 'x.y.z';
|
||||
$descriptions['test'] = array(
|
||||
'releasenotes' => '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis scelerisque rhoncus leo. In eu ultricies magna. Vivamus nec est vitae felis iaculis mollis non ac ante. In vitae erat quis urna volutpat vulputate. Integer ultrices tellus felis, at posuere nulla faucibus nec. Fusce malesuada nunc purus, luctus accumsan nulla rhoncus ut. Nam ac pharetra magna. Nam semper augue at mi tempus, sed dapibus metus cursus. Suspendisse potenti. Curabitur at pulvinar metus, sed pharetra elit.</p>',
|
||||
'security' => FALSE,
|
||||
'updateurl' => '',
|
||||
);
|
||||
}
|
||||
if ( !$options )
|
||||
{
|
||||
\IPS\Output::i()->error( 'download_upgrade_nothing', '1C287/4', 403, '' );
|
||||
}
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'version', $latestVersion, TRUE, array( 'options' => $options, '_details' => $descriptions ) ) );
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* Check requirements */
|
||||
try
|
||||
{
|
||||
$requirements = \IPS\Http\Url::ips('requirements')->setQueryString( 'version', $values['version'] )->request()->get()->decodeJson();
|
||||
$phpVersion = PHP_VERSION;
|
||||
$mysqlVersion = \IPS\Db::i()->server_info;
|
||||
if ( !( version_compare( $phpVersion, $requirements['php']['required'] ) >= 0 ) )
|
||||
{
|
||||
if ( $requirements['php']['required'] == $requirements['php']['recommended'] )
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_fail_no_recommended', FALSE, array( 'sprintf' => array( $phpVersion, $requirements['php']['required'] ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack( 'requirements_php_version_fail', FALSE, array( 'sprintf' => array( $phpVersion, $requirements['php']['required'], $requirements['php']['recommended'] ) ) );
|
||||
}
|
||||
\IPS\Output::i()->error( $message, '1C287/2' );
|
||||
}
|
||||
if ( !( version_compare( $mysqlVersion, $requirements['mysql']['required'] ) >= 0 ) )
|
||||
{
|
||||
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'requirements_mysql_version_fail', FALSE, array( 'sprintf' => array( $mysqlVersion, $requirements['mysql']['required'], $requirements['mysql']['recommended'] ) ) ), '1C287/3', 403, '' );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
/* Check our files aren't modified */
|
||||
if ( !\IPS\Request::i()->skip_md5_check )
|
||||
{
|
||||
try
|
||||
{
|
||||
$files = \IPS\Application::md5Check();
|
||||
if ( count( $files ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaMd5( $values['version'], $files );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Check theme compatibility */
|
||||
$extra = NULL;
|
||||
if ( \IPS\TEST_DELTA_TEMPLATE_CHANGES )
|
||||
{
|
||||
$themeChanges = json_decode( \IPS\TEST_DELTA_TEMPLATE_CHANGES, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$themeChanges = \IPS\Http\Url::ips( 'themediff/' . intval( \IPS\Application::getAvailableVersion('core') ) . '-' . intval( $values['version'] ) )->setQueryString( 'list', 1 )->request()->get()->decodeJson();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$themeChanges = NULL;
|
||||
$extra = get_class( $e ) . '::' . $e->getCode() . ": " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
if ( !is_array( $themeChanges ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'delta_upgrade_fail_server', '3C287/5', 500, NULL, array(), $extra );
|
||||
}
|
||||
if ( !isset( \IPS\Request::i()->skip_theme_check ) )
|
||||
{
|
||||
$conflicts = array();
|
||||
if ( isset( $themeChanges['html'] ) )
|
||||
{
|
||||
foreach ( $themeChanges['html'] as $_app => $_locations )
|
||||
{
|
||||
foreach ( $_locations as $_location => $_groups )
|
||||
{
|
||||
foreach ( $_groups as $_group => $_changedTemplates )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( array( 'template_id', 'template_set_id', 'template_name' ), 'core_theme_templates', array( array( 'template_set_id>0 AND template_app=? AND template_location=? AND template_group=?', $_app, $_location, $_group ), array( \IPS\Db::i()->in( 'template_name', array_keys( $_changedTemplates ) ) ) ) ) as $modifiedTemplate )
|
||||
{
|
||||
$conflicts[ $modifiedTemplate['template_set_id'] ]['html'][ $_app . '/' . $_location . '/' . $_group . '/' . $modifiedTemplate['template_name'] ] = $modifiedTemplate['template_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( isset( $themeChanges['css'] ) )
|
||||
{
|
||||
foreach ( $themeChanges['css'] as $_app => $_locations )
|
||||
{
|
||||
foreach ( $_locations as $_location => $_paths )
|
||||
{
|
||||
foreach ( $_paths as $_path => $_changedFiles )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( array( 'css_id', 'css_set_id', 'css_name' ), 'core_theme_css', array( array( 'css_set_id>0 AND css_app=? AND css_location=? AND css_path=?', $_app, $_location, $_path ), array( \IPS\Db::i()->in( 'css_name', array_keys( $_changedFiles ) ) ) ) ) as $modifiedCss )
|
||||
{
|
||||
$conflicts[ $modifiedCss['css_set_id'] ]['css'][ $_app . '/' . $_location . '/' . $_path . '/' . $modifiedCss['css_name'] ] = $modifiedCss['css_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( count( $conflicts ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaThemeConflicts( $values['version'], $conflicts );
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return array( 'version' => $values['version'], 'themeChanges' => $themeChanges );
|
||||
}
|
||||
|
||||
/* Display */
|
||||
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'system' ) ), 'upgradeSelectVersion' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @return string|array
|
||||
*/
|
||||
public function _login( $data )
|
||||
{
|
||||
/* If we're just testing, we can skip this step */
|
||||
if ( \IPS\TEST_DELTA_ZIP and $data['version'] == 'test' )
|
||||
{
|
||||
$data['key'] = 'test';
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form( 'login', 'continue' );
|
||||
$form->hiddenValues['version'] = $data['version'];
|
||||
$form->add( new \IPS\Helpers\Form\Email( 'ips_email_address', NULL ) );
|
||||
$form->add( new \IPS\Helpers\Form\Password( 'ips_password', NULL ) );
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->_clientAreaPassword = $values['ips_password'];
|
||||
if ( $downloadKey = $this->_getDownloadKey( $values['ips_email_address'], isset( $values['version'] ) ? $values['version'] : NULL ) )
|
||||
{
|
||||
$data['key'] = $downloadKey;
|
||||
$data['ips_email'] = $values['ips_email_address'];
|
||||
$data['ips_pass'] = $values['ips_password'];
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \IPS\Db::i()->select( 'MIN(app_long_version)', 'core_applications', \IPS\Db::i()->in( 'app_directory', \IPS\Application::$ipsApps ) )->first() < \IPS\Application::getAvailableVersion('core') )
|
||||
{
|
||||
$data['key'] = NULL;
|
||||
return $data;
|
||||
}
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_nothing');
|
||||
}
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'auto_upgrade' );
|
||||
$form->error = $e->getMessage();
|
||||
}
|
||||
catch ( \RuntimeException $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'auto_upgrade' );
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack('download_upgrade_error');
|
||||
}
|
||||
}
|
||||
|
||||
return (string) $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a download key
|
||||
*
|
||||
* @param string $clientAreaEmail IPS client area email address
|
||||
* @param string $version Version to download
|
||||
* @param array $files If desired, specific files to download rather than a delta from current version
|
||||
* @return string|NULL string is a download key. NULL indicates already running the latest version
|
||||
* @throws \LogicException
|
||||
* @throws \IPS\Http\Request\Exception
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function _getDownloadKey( $clientAreaEmail, $version, $files=array() )
|
||||
{
|
||||
$key = \IPS\IPS::licenseKey();
|
||||
$url = \IPS\Http\Url::ips( 'build/' . $key['key'] )->setQueryString( 'ip', \IPS\Request::i()->ipAddress() );
|
||||
|
||||
if ( \IPS\USE_DEVELOPMENT_BUILDS )
|
||||
{
|
||||
$url = $url->setQueryString( 'development', 1 );
|
||||
}
|
||||
elseif ( $version )
|
||||
{
|
||||
$url = $url->setQueryString( 'versionToDownload', $version );
|
||||
}
|
||||
if ( \IPS\CP_DIRECTORY !== 'admin' )
|
||||
{
|
||||
$url = $url->setQueryString( 'cp_directory', \IPS\CP_DIRECTORY );
|
||||
}
|
||||
/* Check whether the converter application is present and installed */
|
||||
if ( array_key_exists( 'convert', \IPS\Application::applications() )
|
||||
AND file_exists( \IPS\ROOT_PATH . '/applications/convert/Application.php' )
|
||||
AND \IPS\Application::load( 'convert' )->version == \IPS\Application::load('core')->version )
|
||||
{
|
||||
$url = $url->setQueryString( 'includeConverters', 1 );
|
||||
}
|
||||
if ( $files )
|
||||
{
|
||||
$url = $url->setQueryString( 'files', implode( ',', $files ) );
|
||||
}
|
||||
|
||||
$response = $url->request( \IPS\LONG_REQUEST_TIMEOUT )->login( $clientAreaEmail, $this->_clientAreaPassword )->get();
|
||||
switch ( $response->httpResponseCode )
|
||||
{
|
||||
case 200:
|
||||
if ( !preg_match( '/^ips_[a-z0-9]{5}$/', (string) $response ) )
|
||||
{
|
||||
throw new \RuntimeException( (string) $response );
|
||||
}
|
||||
else
|
||||
{
|
||||
return (string) $response;
|
||||
}
|
||||
|
||||
case 304:
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
throw new \LogicException( (string) $response );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get FTP Details
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @return string|array
|
||||
*/
|
||||
public function _ftpDetails( $data )
|
||||
{
|
||||
if ( \IPS\DELTA_FORCE_FTP or !is_writable( \IPS\ROOT_PATH . '/init.php' ) or !is_writable( \IPS\ROOT_PATH . '/applications/core/Application.php' ) or !is_writable( \IPS\ROOT_PATH . '/system/Db/Db.php' ) )
|
||||
{
|
||||
/* If the server does not have the Ftp extension, we can't do this and have to prompt the user to downlad manually... */
|
||||
if ( !function_exists( 'ftp_connect' ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( 'ftp', isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL );
|
||||
}
|
||||
/* Otherwise, we can ask for FTP details... */
|
||||
else
|
||||
{
|
||||
/* If they've clicked the button to manually apply patch, let them do that */
|
||||
if ( isset( \IPS\Request::i()->manual ) )
|
||||
{
|
||||
$data['manual'] = TRUE;
|
||||
return $data;
|
||||
}
|
||||
/* Otherwise, carry on */
|
||||
else
|
||||
{
|
||||
/* Define the method we will use to validate the FTP details */
|
||||
$validateCallback = function( $ftp ) {
|
||||
try
|
||||
{
|
||||
if ( file_get_contents( \IPS\ROOT_PATH . '/conf_global.php' ) != $ftp->download( 'conf_global.php' ) )
|
||||
{
|
||||
throw new \DomainException('delta_upgrade_ftp_details_no_match');
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Ftp\Exception $e )
|
||||
{
|
||||
throw new \DomainException('delta_upgrade_ftp_details_err');
|
||||
}
|
||||
};
|
||||
|
||||
/* If we have details stored, retreive them */
|
||||
if ( \IPS\Settings::i()->upgrade_ftp_details and $decoded = @json_decode( \IPS\Text\Encrypt::fromCipher( \IPS\Settings::i()->upgrade_ftp_details )->decrypt(), TRUE ) )
|
||||
{
|
||||
$defaultDetails = $decoded;
|
||||
}
|
||||
/* Otherwise, guess the server/username/password for the user's benefit */
|
||||
else
|
||||
{
|
||||
$defaultDetails = array(
|
||||
'server' => \IPS\Http\Url::internal('')->data['host'],
|
||||
'un' => @get_current_user(),
|
||||
'path' => str_replace( '/home/' . @get_current_user(), '', \IPS\ROOT_PATH )
|
||||
);
|
||||
}
|
||||
|
||||
/* Build the form */
|
||||
$form = new \IPS\Helpers\Form( 'ftp_details', 'continue' );
|
||||
$form->add( new \IPS\Helpers\Form\Ftp( 'delta_upgrade_ftp_details', $defaultDetails, TRUE, array( 'rejectUnsupportedSftp' => TRUE, 'allowBypassValidation' => FALSE ), $validateCallback ) );
|
||||
$form->add( new \IPS\Helpers\Form\Checkbox( 'delta_upgrade_ftp_remember', TRUE ) );
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( $values['delta_upgrade_ftp_remember'] )
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'upgrade_ftp_details' => \IPS\Text\Encrypt::fromPlaintext( json_encode( $values['delta_upgrade_ftp_details'] ) )->cipher ) );
|
||||
}
|
||||
|
||||
$data['ftpDetails'] = $values['delta_upgrade_ftp_details'];
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* Display the form */
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFtp( (string) $form );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download & Extract Update
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @return string|array
|
||||
*/
|
||||
public function _extractUpdate( $data )
|
||||
{
|
||||
/* If extraction failed, show error */
|
||||
if ( isset( \IPS\Request::i()->fail ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( 'exception', isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL );
|
||||
}
|
||||
|
||||
/* Download & Extract */
|
||||
if ( $data['key'] and !isset( \IPS\Request::i()->check ) )
|
||||
{
|
||||
/* If we've asked to do it manually, just show that screen */
|
||||
if ( isset( $data['manual'] ) and $data['manual'] )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( NULL, isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL );;
|
||||
}
|
||||
|
||||
/* Multiple Redirector */
|
||||
$url = \IPS\Http\Url::internal('app=core&module=system&controller=upgrade');
|
||||
return (string) new \IPS\Helpers\MultipleRedirect( $url, function( $mrData ) use ( $data )
|
||||
{
|
||||
/* Init */
|
||||
if ( !is_array( $mrData ) )
|
||||
{
|
||||
return array( array( 'status' => 'download' ), \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_processing') );
|
||||
}
|
||||
/* Download */
|
||||
elseif ( $mrData['status'] == 'download' )
|
||||
{
|
||||
if ( !isset( $mrData['tmpFileName'] ) )
|
||||
{
|
||||
$mrData['tmpFileName'] = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' ) . '.zip';
|
||||
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \IPS\TEST_DELTA_ZIP and $data['version'] == 'test' )
|
||||
{
|
||||
\file_put_contents( $mrData['tmpFileName'], file_get_contents( \IPS\TEST_DELTA_ZIP ) );
|
||||
$mrData['status'] = 'extract';
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !isset( $mrData['range'] ) )
|
||||
{
|
||||
$mrData['range'] = 0;
|
||||
}
|
||||
$startRange = $mrData['range'];
|
||||
$endRange = $startRange + 1000000 - 1;
|
||||
|
||||
$response = \IPS\Http\Url::ips("download/{$data['key']}")->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Range' => "bytes={$startRange}-{$endRange}" ) )->get();
|
||||
|
||||
\IPS\Log::debug( "Fetching download [range={$startRange}-{$endRange}] with a response code: " . $response->httpResponseCode, 'auto_upgrade' );
|
||||
|
||||
if ( $response->httpResponseCode == 404 )
|
||||
{
|
||||
if ( isset( $mrData['tmpFileName'] ) )
|
||||
{
|
||||
@unlink( $mrData['tmpFileName'] );
|
||||
}
|
||||
|
||||
\IPS\Log::log( "Cannot fetch delta download: " . var_export( $response, TRUE ), 'auto_upgrade' );
|
||||
|
||||
return array( \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( 'unexpected_response', isset( $data['key'] ) ? \IPS\Http\Url::ips("download/{$data['key']}") : NULL ) );
|
||||
}
|
||||
elseif ( $response->httpResponseCode == 206 )
|
||||
{
|
||||
$totalFileSize = intval( mb_substr( $response->httpHeaders['Content-Range'], mb_strpos( $response->httpHeaders['Content-Range'], '/' ) + 1 ) );
|
||||
$fh = \fopen( $mrData['tmpFileName'], 'a' );
|
||||
\fwrite( $fh, (string) $response );
|
||||
\fclose( $fh );
|
||||
|
||||
$mrData['range'] = $endRange + 1;
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_downloading'), 100 / $totalFileSize * $mrData['range'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$mrData['status'] = 'extract';
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_extracting'), 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Extract */
|
||||
elseif ( $mrData['status'] == 'extract' )
|
||||
{
|
||||
\IPS\core\Setup\Upgrade::setUpgradingFlag( TRUE );
|
||||
|
||||
$extractUrl = new \IPS\Http\Url( \IPS\Settings::i()->base_url . \IPS\CP_DIRECTORY . '/upgrade/extract.php' );
|
||||
$extractUrl = $extractUrl
|
||||
->setScheme( NULL ) // Use protocol-relative in case the AdminCP is being loaded over https but rest of site is not
|
||||
->setQueryString( array(
|
||||
'file' => $mrData['tmpFileName'],
|
||||
'container' => $data['key'],
|
||||
'key' => md5( \IPS\Settings::i()->board_start . $mrData['tmpFileName'] . \IPS\Settings::i()->sql_pass ),
|
||||
'ftp' => ( isset( $data['ftpDetails'] ) ) ? $data['ftpDetails'] : ''
|
||||
)
|
||||
);
|
||||
|
||||
return array( \IPS\Theme::i()->getTemplate('system')->upgradeExtract( $extractUrl ) );
|
||||
}
|
||||
},
|
||||
function()
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade&check=1') );
|
||||
} );
|
||||
}
|
||||
|
||||
/* Run md5 check */
|
||||
try
|
||||
{
|
||||
$files = \IPS\Application::md5Check();
|
||||
if ( count( $files ) )
|
||||
{
|
||||
/* Log */
|
||||
\IPS\Log::debug( "MD5 check of delta download failed with " . count( $files ) . " reported as modified", 'auto_upgrade' );
|
||||
|
||||
/* If we'rve already tried to fix them and failed, show an error */
|
||||
if ( isset( $data['md5Fix'] ) and $data['md5Fix'] )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('system')->upgradeDeltaFailed( 'exception', NULL );
|
||||
}
|
||||
|
||||
/* Otherwise try to just fix them - first get a new download key */
|
||||
$files = array_map( function( $file ) {
|
||||
return str_replace( \IPS\ROOT_PATH, '', $file );
|
||||
}, $files );
|
||||
$this->_clientAreaPassword = $data['ips_pass'];
|
||||
$newDownloadKey = $this->_getDownloadKey( $data['ips_email'], $data['version'], $files );
|
||||
|
||||
/* Manipulate the wizard data */
|
||||
$data = $_SESSION[ 'wizard-' . md5( \IPS\Http\Url::internal( 'app=core&module=system&controller=upgrade' ) ) . '-data' ];
|
||||
$data['key'] = $newDownloadKey;
|
||||
$data['md5Fix'] = TRUE;
|
||||
$_SESSION[ 'wizard-' . md5( \IPS\Http\Url::internal( 'app=core&module=system&controller=upgrade' ) ) . '-data' ] = $data;
|
||||
|
||||
/* Redirect back in */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=system&controller=upgrade') );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
/* Nope, we're good! */
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @return string|array
|
||||
*/
|
||||
public function _upgrade( $data )
|
||||
{
|
||||
/* Resync */
|
||||
\IPS\IPS::resyncIPSCloud('Uploaded new version');
|
||||
|
||||
/* If this is NOT a patch, redirect them to the upgrader */
|
||||
if ( !isset( $data['patch'] ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( 'upgrade/?adsess=' . \IPS\Request::i()->adsess );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise let's do the upgrade! */
|
||||
$url = \IPS\Http\Url::internal('app=core&module=system&controller=upgrade');
|
||||
return (string) new \IPS\Helpers\MultipleRedirect( $url, function( $mrData ) use ( $data )
|
||||
{
|
||||
if ( !is_array( $mrData ) )
|
||||
{
|
||||
return array( array( 'step' => 0 ), \IPS\Member::loggedIn()->language()->addToStack('delta_upgrade_processing'), 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$steps = array(
|
||||
'_upgradeTemplates',
|
||||
);
|
||||
$perStepPercentage = ( 100 / count( $steps ) );
|
||||
|
||||
if ( array_key_exists( $mrData['step'], $steps ) )
|
||||
{
|
||||
$step = $steps[ $mrData['step'] ];
|
||||
$percentage = $perStepPercentage * intval( $mrData['step'] );
|
||||
$stepData = isset( $mrData[ $step ] ) ? $mrData[ $step ] : array();
|
||||
|
||||
$return = $this->$step( $data, $stepData );
|
||||
if ( $return === NULL )
|
||||
{
|
||||
unset( $mrData[ $step ] );
|
||||
$mrData['step']++;
|
||||
$percentage += $perStepPercentage;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mrData[ $step ] = $return[1];
|
||||
$percentage += ( $return[0] / ( 100 / $perStepPercentage ) );
|
||||
}
|
||||
|
||||
return array( $mrData, \IPS\Member::loggedIn()->language()->addToStack( 'delta_upgrade' . $step ), round( $percentage, 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\core\Setup\Upgrade::setUpgradingFlag( FALSE );
|
||||
return array( \IPS\Theme::i()->getTemplate('system')->upgradeFinished() );
|
||||
}
|
||||
}
|
||||
},
|
||||
function()
|
||||
{
|
||||
\IPS\Output::i()->redirect( 'upgrade/?adsess=' . \IPS\Request::i()->adsess );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade: HTML and CSS
|
||||
*
|
||||
* @param array $data Wizard data
|
||||
* @param array $stepData Data for this step
|
||||
* @return array|null array( percentage of this step complete, $stepData ) OR NULL if this step is complete
|
||||
*/
|
||||
public function _upgradeTemplates( $data, $stepData )
|
||||
{
|
||||
return $this->_appLoop( $stepData, function( $app, $stepData ) use ( $data )
|
||||
{
|
||||
/* Get counts or delete old stuff (we need to do it this way to ensure removed stuff gets removed) */
|
||||
$numberOfChangesInThisApp = 0;
|
||||
if ( isset( $data['themeChanges']['html'] ) and isset( $data['themeChanges']['html'][ $app ] ) )
|
||||
{
|
||||
foreach ( $data['themeChanges']['html'][ $app ] as $_location => $_groups )
|
||||
{
|
||||
foreach ( $_groups as $_group => $_changedTemplates )
|
||||
{
|
||||
if ( !isset( $stepData['offset'] ) )
|
||||
{
|
||||
\IPS\Theme::deleteCompiledTemplate( $app, $_location, $_group );
|
||||
|
||||
foreach ( $_changedTemplates as $_template => $_type )
|
||||
{
|
||||
if ( $_type != 'added' )
|
||||
{
|
||||
\IPS\Theme::removeTemplates( $app, $_location, $_group, NULL, FALSE, $_template );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberOfChangesInThisApp += count( $_changedTemplates );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( isset( $data['themeChanges']['css'] ) and isset( $data['themeChanges']['css'][ $app ] ) )
|
||||
{
|
||||
foreach ( $data['themeChanges']['css'][ $app ] as $_location => $_paths )
|
||||
{
|
||||
foreach ( $_paths as $_path => $_changedFiles )
|
||||
{
|
||||
if ( !isset( $stepData['offset'] ) )
|
||||
{
|
||||
foreach ( $_changedFiles as $_file => $_type )
|
||||
{
|
||||
if ( $_type != 'added' )
|
||||
{
|
||||
\IPS\Theme::deleteCompiledCss( $app, $_location, $_path, $_file );
|
||||
\IPS\Theme::removeCss( $app, $_location, $_path, NULL, FALSE, $_file );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$numberOfChangesInThisApp += count( $_changedFiles );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !isset( $stepData['offset'] ) )
|
||||
{
|
||||
if ( $numberOfChangesInThisApp )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$stepData['offset'] = 0;
|
||||
return array( 0, $stepData );
|
||||
}
|
||||
}
|
||||
|
||||
/* Import new stuff */
|
||||
$perLoop = 150;
|
||||
$i = 0;
|
||||
$done = 0;
|
||||
$xml = new \IPS\Xml\XMLReader;
|
||||
$xml->open( \IPS\ROOT_PATH . "/applications/{$app}/data/theme.xml" );
|
||||
$xml->read();
|
||||
while ( $xml->read() )
|
||||
{
|
||||
/* Skip to where we need to be */
|
||||
if( $xml->nodeType != \XMLReader::ELEMENT )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$i++;
|
||||
if ( $stepData['offset'] )
|
||||
{
|
||||
if ( $i - 1 < $stepData['offset'] )
|
||||
{
|
||||
$xml->next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Templates */
|
||||
if( $xml->name == 'template' )
|
||||
{
|
||||
if ( $location = $xml->getAttribute('template_location') and isset( $data['themeChanges']['html'][ $app ][ $location ] ) )
|
||||
{
|
||||
if ( $group = $xml->getAttribute('template_group') and isset( $data['themeChanges']['html'][ $app ][ $location ][ $group ] ) )
|
||||
{
|
||||
if ( $template = $xml->getAttribute('template_name') and isset( $data['themeChanges']['html'][ $app ][ $location ][ $group ][ $template ] ) )
|
||||
{
|
||||
\IPS\Theme::addTemplate( array(
|
||||
'app' => $app,
|
||||
'group' => $group,
|
||||
'name' => $template,
|
||||
'variables' => $xml->getAttribute('template_data'),
|
||||
'content' => $xml->readString(),
|
||||
'location' => $location,
|
||||
'_default_template' => true
|
||||
) );
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* CSS Files */
|
||||
elseif( $xml->name == 'css' )
|
||||
{
|
||||
if ( $location = $xml->getAttribute('css_location') and isset( $data['themeChanges']['css'][ $app ][ $location ] ) )
|
||||
{
|
||||
if ( $path = $xml->getAttribute('css_path') and isset( $data['themeChanges']['css'][ $app ][ $location ][ $path ] ) )
|
||||
{
|
||||
if ( $name = $xml->getAttribute('css_name') and isset( $data['themeChanges']['css'][ $app ][ $location ][ $path ][ $name ] ) )
|
||||
{
|
||||
\IPS\Theme::addCss( array(
|
||||
'app' => $app,
|
||||
'location' => $location,
|
||||
'path' => $path,
|
||||
'name' => $name,
|
||||
'content' => $xml->readString(),
|
||||
'_default_template' => true
|
||||
) );
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Have we done the most we're allowed per loop? */
|
||||
if( $done >= $perLoop )
|
||||
{
|
||||
$stepData['offset'] = $i;
|
||||
$stepData['done'] = isset( $stepData['done'] ) ? ( $stepData['done'] + $done ) : $done;
|
||||
return array( 100 / $numberOfChangesInThisApp * $stepData['done'], $stepData );
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're still here, this app is complete */
|
||||
return NULL;
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* App Looper
|
||||
*
|
||||
* @param array $stepData Data for this step
|
||||
* @param callback $code Code to execute for each app
|
||||
* @return array|null array( percentage of this step complete, $stepData ) OR NULL if this step is complete
|
||||
*/
|
||||
protected function _appLoop( $stepData, $code )
|
||||
{
|
||||
$returnNext = FALSE;
|
||||
$apps = array_keys( \IPS\Application::applications() );
|
||||
$percentage = 0;
|
||||
$perAppPercentage = ( 100 / count( $apps ) );
|
||||
|
||||
foreach ( $apps as $app )
|
||||
{
|
||||
if( !in_array( $app, \IPS\Application::$ipsApps ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !isset( $stepData['app'] ) )
|
||||
{
|
||||
$stepData['app'] = $app;
|
||||
}
|
||||
|
||||
if ( $stepData['app'] == $app )
|
||||
{
|
||||
$val = call_user_func( $code, $app, $stepData );
|
||||
|
||||
if ( $val !== NULL )
|
||||
{
|
||||
$percentage += ( $val[0] / ( 100 / $perAppPercentage ) );
|
||||
return array( $percentage, $val[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$returnNext = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$percentage += $perAppPercentage;
|
||||
|
||||
if ( $returnNext )
|
||||
{
|
||||
$stepData = array( 'app' => $app );
|
||||
return array( $percentage, $stepData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user