Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -28,7 +28,6 @@ class _Application extends \IPS\Node\Model
|
||||
public static $ipsApps = array(
|
||||
'blog',
|
||||
'calendar',
|
||||
'chat',
|
||||
'cms',
|
||||
'core',
|
||||
'downloads',
|
||||
@@ -114,7 +113,7 @@ class _Application extends \IPS\Node\Model
|
||||
}
|
||||
|
||||
/* Save the new FURL customisation */
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $furlCustomizations ) ), array( 'conf_key=?', 'furl_configuration' ) );
|
||||
\IPS\Settings::i()->changeValues( array( 'furl_configuration' => json_encode( $furlCustomizations ) ) );
|
||||
}
|
||||
|
||||
/* Actually update the database */
|
||||
@@ -123,7 +122,6 @@ class _Application extends \IPS\Node\Model
|
||||
|
||||
/* Clear cached data */
|
||||
unset( \IPS\Data\Store::i()->applications );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
unset( \IPS\Data\Store::i()->furl_configuration );
|
||||
\IPS\Member::clearCreateMenu();
|
||||
|
||||
@@ -468,6 +466,37 @@ class _Application extends \IPS\Node\Model
|
||||
return $update;
|
||||
}
|
||||
|
||||
/**
|
||||
* The latest new feature ID
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function newFeature()
|
||||
{
|
||||
if( $this->update_version )
|
||||
{
|
||||
$versions = json_decode( $this->update_version, TRUE );
|
||||
if ( is_array( $versions ) and !isset( $versions[0] ) and isset( $versions['longversion'] ) )
|
||||
{
|
||||
$versions = array( $versions );
|
||||
}
|
||||
|
||||
$latestVersion = NULL;
|
||||
|
||||
foreach ( $versions as $data )
|
||||
{
|
||||
if( isset( $data['latestNewFeature'] ) AND $data['latestNewFeature'] AND $data['latestNewFeature'] > $latestVersion )
|
||||
{
|
||||
$latestVersion = $data['latestNewFeature'];
|
||||
}
|
||||
}
|
||||
|
||||
return $latestVersion;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the application up to date with security patches?
|
||||
*
|
||||
@@ -493,10 +522,11 @@ class _Application extends \IPS\Node\Model
|
||||
/**
|
||||
* MD5 check (returns path to files which do not match)
|
||||
*
|
||||
* @retrun array
|
||||
* @param int|NULL $version Version to check against
|
||||
* @return array
|
||||
* @throws \IPS\Http\Request\Exception
|
||||
*/
|
||||
public static function md5Check()
|
||||
public static function md5Check( $version = NULL )
|
||||
{
|
||||
/* For Community in the Cloud customers we cannot do this because they have encoded files
|
||||
and the encoder produces different output each time it runs, so every Cloud customer
|
||||
@@ -508,7 +538,12 @@ class _Application extends \IPS\Node\Model
|
||||
}
|
||||
|
||||
/* For everyone else, get the correct md5 sums for each file... */
|
||||
$correctMd5s = \IPS\Http\Url::ips( 'md5' )->request()->get()->decodeJson();
|
||||
$url = \IPS\Http\Url::ips( 'md5' );
|
||||
if ( $version !== NULL )
|
||||
{
|
||||
$url = $url->setQueryString( 'version', $version );
|
||||
}
|
||||
$correctMd5s = $url->request()->get()->decodeJson();
|
||||
|
||||
/* And return whichever ones don't match */
|
||||
$return = array();
|
||||
@@ -533,11 +568,40 @@ class _Application extends \IPS\Node\Model
|
||||
continue;
|
||||
}
|
||||
|
||||
/* MD5 check */
|
||||
if ( !file_exists( \IPS\ROOT_PATH . $file ) or !\IPS\Login::compareHashes( md5( preg_replace( '#\s#', '', utf8_decode( file_get_contents( \IPS\ROOT_PATH . $file ) ) ) ), $md5Hash ) ) // We strip whitespace since FTP in ASCII mode will change the whitespace characters
|
||||
/* If the file doesn't exist at all, flag it */
|
||||
if ( !file_exists( \IPS\ROOT_PATH . $file ) )
|
||||
{
|
||||
$return[] = \IPS\ROOT_PATH . $file;
|
||||
}
|
||||
/* Otherwise, compare the md5 hashes... */
|
||||
else
|
||||
{
|
||||
/* Get the contents. If you can't get the contents, it may be that the file permissions are set wrong. Try to fix. */
|
||||
$fileContents = @file_get_contents( \IPS\ROOT_PATH . $file );
|
||||
if ( !$fileContents )
|
||||
{
|
||||
@chmod( \IPS\ROOT_PATH . $file, \IPS\FILE_PERMISSION_NO_WRITE );
|
||||
}
|
||||
|
||||
/* If we got the file contents... */
|
||||
if ( $fileContents )
|
||||
{
|
||||
/* Strip whitespace since FTP in ASCII mode will change the whitespace characters */
|
||||
$fileContents = preg_replace( '#\s#', '', utf8_decode( file_get_contents( \IPS\ROOT_PATH . $file ) ) );
|
||||
|
||||
/* Compare */
|
||||
if ( md5( $fileContents ) != $md5Hash )
|
||||
{
|
||||
$return[] = \IPS\ROOT_PATH . $file;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, flag it */
|
||||
else
|
||||
{
|
||||
$return[] = \IPS\ROOT_PATH . $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -989,7 +1053,7 @@ EOF;
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return $this->enabled and ( !in_array( $this->directory, static::$ipsApps ) or $this->long_version == \IPS\Application::load('core')->long_version );
|
||||
return $this->enabled and ( !in_array( $this->directory, static::$ipsApps ) or $this->version == \IPS\Application::load('core')->version );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1008,6 +1072,23 @@ EOF;
|
||||
$this->enabled = $enabled;
|
||||
$this->save();
|
||||
\IPS\Plugin\Hook::writeDataFile();
|
||||
|
||||
/* Clear templates to rebuild automatically */
|
||||
\IPS\Theme::deleteCompiledTemplate();
|
||||
|
||||
/* Invalidate disk templates */
|
||||
\IPS\Theme::resetAllCacheKeys();
|
||||
|
||||
/* Enable queue task in case there are pending items */
|
||||
if( $this->enabled )
|
||||
{
|
||||
$queueTask = \IPS\Task::load( 'queue', 'key' );
|
||||
$queueTask->enabled = TRUE;
|
||||
$queueTask->save();
|
||||
}
|
||||
|
||||
/* Update other app specific task statuses */
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => (int) $this->enabled ), array( 'app=?', $this->directory ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1022,7 +1103,7 @@ EOF;
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if ( !$this->_enabled and in_array( $this->directory, static::$ipsApps ) and $this->long_version != \IPS\Application::load('core')->long_version )
|
||||
if ( !$this->_enabled and in_array( $this->directory, static::$ipsApps ) and $this->version != \IPS\Application::load('core')->version )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1249,7 +1330,7 @@ EOF;
|
||||
/* Clear out member's cached "Create Menu" contents */
|
||||
\IPS\Member::clearCreateMenu();
|
||||
unset( \IPS\Data\Store::i()->applications );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
\IPS\Settings::i()->clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1682,7 +1763,7 @@ EOF;
|
||||
$module->position = ++$position;
|
||||
$module->area = $area;
|
||||
$module->default_controller = $data['default_controller'];
|
||||
$module->default = isset( $data['default'] ) and $data['default'];
|
||||
$module->default = ( isset( $data['default'] ) and $data['default'] );
|
||||
$module->save( TRUE );
|
||||
}
|
||||
}
|
||||
@@ -1723,7 +1804,15 @@ EOF;
|
||||
|
||||
try
|
||||
{
|
||||
$fileSystem = \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', 'FileSystem' ), 'id ASC' )->first();
|
||||
/* Only check for Amazon when installing an app via the Admin CP on Community in the Cloud. The CiC Installer will handle brand new installs. */
|
||||
if ( \IPS\CIC AND !$newInstall )
|
||||
{
|
||||
$fileSystem = \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', 'Amazon' ), 'id ASC' )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$fileSystem = \IPS\Db::i()->select( '*', 'core_file_storage', array( 'method=?', 'FileSystem' ), 'id ASC' )->first();
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $ex )
|
||||
{
|
||||
@@ -1735,9 +1824,7 @@ EOF;
|
||||
$settings[ 'filestorage__' . $this->directory . '_' . $key ] = $fileSystem['id'];
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => json_encode( $settings ) ), array( 'conf_key=?', 'upload_settings' ) );
|
||||
\IPS\Settings::i()->upload_settings = json_encode( $settings );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
\IPS\Settings::i()->changeValues( array( 'upload_settings' => json_encode( $settings ) ) );
|
||||
|
||||
$inserts = array();
|
||||
foreach( $this->extensions( 'core', 'Notifications' ) as $key => $class )
|
||||
@@ -1792,23 +1879,24 @@ EOF;
|
||||
{
|
||||
if( file_exists( \IPS\ROOT_PATH . "/applications/{$this->directory}/data/settings.json" ) )
|
||||
{
|
||||
$currentDefaults = iterator_to_array( \IPS\Db::i()->select( '*', 'core_sys_conf_settings' )->setKeyField('conf_key')->setValueField('conf_default') );
|
||||
$currentData = iterator_to_array( \IPS\Db::i()->select( array( 'conf_key', 'conf_default', 'conf_report' ), 'core_sys_conf_settings' )->setKeyField('conf_key') );
|
||||
|
||||
$insert = array();
|
||||
$update = array();
|
||||
|
||||
foreach ( json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$this->directory}/data/settings.json" ), TRUE ) as $setting )
|
||||
{
|
||||
if ( ! array_key_exists( $setting['key'], $currentDefaults ) )
|
||||
$report = ( isset( $setting['report'] ) and $setting['report'] != 'none' ) ? $setting['report'] : NULL;
|
||||
if ( ! array_key_exists( $setting['key'], $currentData ) )
|
||||
{
|
||||
$insert[] = array( 'conf_key' => $setting['key'], 'conf_value' => $setting['default'], 'conf_default' => $setting['default'], 'conf_app' => $this->directory );
|
||||
$insert[] = array( 'conf_key' => $setting['key'], 'conf_value' => $setting['default'], 'conf_default' => $setting['default'], 'conf_app' => $this->directory, 'conf_report' => $report );
|
||||
}
|
||||
elseif ( $currentDefaults[ $setting['key'] ] != $setting['default'] )
|
||||
elseif ( $currentData[ $setting['key'] ]['conf_default'] != $setting['default'] or $currentData[ $setting['key'] ]['conf_report'] != $report )
|
||||
{
|
||||
$update[] = array( array( 'conf_default' => $setting['default'] ), array( 'conf_key=?', $setting['key'] ) );
|
||||
$update[] = array( array( 'conf_default' => $setting['default'], 'conf_report' => $report ), array( 'conf_key=?', $setting['key'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !empty( $insert ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_sys_conf_settings', $insert, TRUE );
|
||||
@@ -1819,7 +1907,7 @@ EOF;
|
||||
\IPS\Db::i()->update( 'core_sys_conf_settings', $data[0], $data[1] );
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
\IPS\Settings::i()->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2008,6 +2096,7 @@ EOF;
|
||||
'template_parent' => 0,
|
||||
'template_app' => $this->directory,
|
||||
'template_edited' => 0,
|
||||
'template_pinned' => 0
|
||||
);
|
||||
|
||||
while ( $xml->read() and $xml->name != 'template' )
|
||||
@@ -2035,6 +2124,10 @@ EOF;
|
||||
case 'template_content_plaintext':
|
||||
$insert['template_content_plaintext'] = $xml->readString();
|
||||
break;
|
||||
|
||||
case 'template_pinned':
|
||||
$insert['template_pinned'] = $xml->readString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2675,7 +2768,10 @@ EOF;
|
||||
|
||||
/* If there were other differences, carry on... */
|
||||
if ( $differences )
|
||||
{
|
||||
{
|
||||
/* We re-add indexes after changing columns */
|
||||
$indexesToAdd = array();
|
||||
|
||||
/* First check indexes to see if any need to be adjusted */
|
||||
foreach( $localDefinition['indexes'] as $indexName => $indexData )
|
||||
{
|
||||
@@ -2703,7 +2799,7 @@ EOF;
|
||||
elseif( $thisIndex['indexes'][ $indexName ] !== $localDefinition['indexes'][ $indexName ] )
|
||||
{
|
||||
$tableChanges[] = "DROP INDEX `{$db->escape_string( $indexName )}`";
|
||||
$tableChanges[] = $db->buildIndex( $tableName, $thisIndex['indexes'][ $indexName ] );
|
||||
$indexesToAdd[] = $db->buildIndex( $tableName, $thisIndex['indexes'][ $indexName ], $tableDefinition );
|
||||
$dropped[] = $indexName;
|
||||
|
||||
if( $tableDefinition['indexes'][ $indexName ]['type'] == 'unique' OR $tableDefinition['indexes'][ $indexName ]['type'] == 'primary' )
|
||||
@@ -2714,7 +2810,6 @@ EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If we are about to adjust the column to not allow NULL values then adjust those values first... */
|
||||
if( isset( $columnData['allow_null'] ) and $columnData['allow_null'] === FALSE )
|
||||
@@ -2738,6 +2833,11 @@ EOF;
|
||||
}
|
||||
|
||||
$tableChanges[] = "CHANGE COLUMN `{$db->escape_string( $columnName )}` {$db->compileColumnDefinition( $columnData )}";
|
||||
|
||||
if( count( $indexesToAdd ) )
|
||||
{
|
||||
$tableChanges = array_merge( $tableChanges, $indexesToAdd );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3458,7 +3558,7 @@ EOF;
|
||||
$forXml = array();
|
||||
foreach( $template as $k => $v )
|
||||
{
|
||||
if ( in_array( \substr( $k, 9 ), array('app', 'name', 'content_html', 'data', 'content_plaintext' ) ) )
|
||||
if ( in_array( \substr( $k, 9 ), array('app', 'name', 'content_html', 'data', 'content_plaintext', 'pinned' ) ) )
|
||||
{
|
||||
$forXml[ $k ] = $v;
|
||||
}
|
||||
@@ -3657,7 +3757,7 @@ EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
$member = ( $memberGroups === NULL ) ? \IPS\Member::loggedIn() : $memberGroups;
|
||||
$member = ( $memberOrGroup === NULL ) ? \IPS\Member::loggedIn() : $memberOrGroup;
|
||||
$memberGroups = array_merge( array( $member->member_group_id ), array_filter( explode( ',', $member->mgroup_others ) ) );
|
||||
}
|
||||
$accessGroups = explode( ',', $this->disabled_groups );
|
||||
@@ -3783,6 +3883,7 @@ EOF;
|
||||
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=?', $this->directory ) );
|
||||
\IPS\Db::i()->delete( 'core_view_updates', array( "classname LIKE CONCAT( ?, '%' )", "IPS\\\\{$this->directory}" ) );
|
||||
\IPS\Db::i()->delete( 'core_moderator_logs', array( 'appcomponent=?', $this->directory ) );
|
||||
\IPS\Db::i()->delete( 'core_member_history', array( 'log_app=?', $this->directory ) );
|
||||
|
||||
$classes = array();
|
||||
foreach( $this->extensions( 'core', 'ContentRouter' ) AS $contentRouter )
|
||||
@@ -3822,9 +3923,29 @@ EOF;
|
||||
|
||||
/* Delete Deletion Log Records */
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', \IPS\Db::i()->in( 'dellog_content_class', $classes ) );
|
||||
|
||||
/* Delete Promoted Content from this app */
|
||||
\IPS\Db::i()->delete( 'core_social_promote', \IPS\Db::i()->in( 'promote_class', $classes ) );
|
||||
|
||||
|
||||
/* Delete Soft Deletion Log data */
|
||||
$softDeleteKeys = array();
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
if ( $class::$hideLogKey )
|
||||
{
|
||||
$softDeleteKeys[] = $class::$hideLogKey;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $softDeleteKeys ) )
|
||||
{
|
||||
|
||||
\IPS\Db::i()->delete( 'core_soft_delete_log', \IPS\Db::i()->in( 'sdl_obj_key', $softDeleteKeys ) );
|
||||
}
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
\IPS\Settings::i()->clearCache();
|
||||
|
||||
/* Delete tasks and task logs */
|
||||
\IPS\Db::i()->delete( 'core_tasks_log', array( 'task IN(?)', \IPS\Db::i()->select( 'id', 'core_tasks', array( 'app=?', $this->directory ) ) ) );
|
||||
@@ -3865,6 +3986,9 @@ EOF;
|
||||
\IPS\Theme::removeTemplates( $this->directory, NULL, NULL, NULL, TRUE );
|
||||
\IPS\Theme::removeCss( $this->directory, NULL, NULL, NULL, TRUE );
|
||||
\IPS\Theme::removeResources( $this->directory, NULL, NULL, NULL, TRUE );
|
||||
|
||||
/* Invalidate disk templates */
|
||||
\IPS\Theme::resetAllCacheKeys();
|
||||
|
||||
/* Delete theme settings */
|
||||
$valueIds = iterator_to_array( \IPS\Db::i()->select( 'sc_id', 'core_theme_settings_fields', array( array( 'sc_app=?', $this->directory ) ) ) );
|
||||
@@ -4059,9 +4183,10 @@ EOF;
|
||||
/* Clear out data store for updated values */
|
||||
unset( \IPS\Data\Store::i()->modules );
|
||||
unset( \IPS\Data\Store::i()->applications );
|
||||
unset( \IPS\Data\Store::i()->settings );
|
||||
unset( \IPS\Data\Store::i()->widgets );
|
||||
unset( \IPS\Data\Store::i()->furl_configuration );
|
||||
|
||||
\IPS\Settings::i()->clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user