Version 4.1.2
This commit is contained in:
1 parent
3ba79295ee
commit
28bd025b35
1131 files changed
+63658
-20579
No files matched your search
@@ -276,7 +276,7 @@ class _Application extends \IPS\Node\Model
|
||||
}
|
||||
|
||||
$_extensions = array();
|
||||
|
||||
|
||||
foreach ( $application->extensions( $app, $extension, $construct, $checkAccess ) as $key => $class )
|
||||
{
|
||||
$_extensions[ $application->directory . '_' . $key ] = $class;
|
||||
@@ -404,6 +404,106 @@ class _Application extends \IPS\Node\Model
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The available version we can upgrade to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function availableUpgrade( $latestOnly=FALSE )
|
||||
{
|
||||
$update = array();
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
$update = array();
|
||||
foreach ( $versions as $data )
|
||||
{
|
||||
if( !empty($data['longversion']) AND $data['longversion'] > $this->long_version )
|
||||
{
|
||||
if( $data['released'] AND intval($data['released']) == $data['released'] AND \strlen($data['released']) == 10 )
|
||||
{
|
||||
$data['released'] = (string) \IPS\DateTime::ts( $data['released'] )->localeDate();
|
||||
}
|
||||
|
||||
$update[] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !empty( $update ) and $latestOnly )
|
||||
{
|
||||
$update = array_pop( $update );
|
||||
}
|
||||
|
||||
return $update;
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 check (returns path to files which do not match)
|
||||
*
|
||||
* @retrun array
|
||||
* @throws \IPS\Http\Request\Exception
|
||||
*/
|
||||
public static function md5Check()
|
||||
{
|
||||
$key = \IPS\IPS::licenseKey();
|
||||
$correctMd5s = \IPS\Http\Url::ips( 'md5/' . $key['key'] )->request()->get()->decodeJson();
|
||||
|
||||
return static::_md5sumCheckerIterator( \IPS\ROOT_PATH, $correctMd5s );
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 check directory
|
||||
*
|
||||
* @param string $directory Directory to look through
|
||||
* @return array
|
||||
*/
|
||||
public static function _md5sumCheckerIterator( $directory, $correctMd5s )
|
||||
{
|
||||
$return = array();
|
||||
foreach( new \DirectoryIterator( $directory ) as $file )
|
||||
{
|
||||
if ( mb_substr( $file, 0, 1 ) === '.' or mb_substr( $file, 0, 1 ) === '_' or $file == 'index.html' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $file->isDir() )
|
||||
{
|
||||
/* If this is an application directory but the application has been disabled then we shouldn't check it */
|
||||
if( mb_strpos( $file->getPathname(), \IPS\ROOT_PATH . DIRECTORY_SEPARATOR . 'applications' ) !== FALSE AND $file->getFilename() != 'applications' )
|
||||
{
|
||||
$applications = static::applications();
|
||||
|
||||
/* If the directory name is a valid application key and the application is not enabled, don't check it */
|
||||
if( isset( $applications[ $file->getFilename() ] ) AND !static::appIsEnabled( $file->getFilename() ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$return = array_merge( $return, static::_md5sumCheckerIterator( $file->getPathname(), $correctMd5s ) );
|
||||
}
|
||||
elseif ( mb_substr( $file, -4 ) === '.php' )
|
||||
{
|
||||
$fullPath = $file->getPathname();
|
||||
$shortPath = mb_substr( $fullPath, mb_strlen( \IPS\ROOT_PATH ) );
|
||||
|
||||
if ( $shortPath != '/init.php' and isset( $correctMd5s[ $shortPath ] ) and md5( preg_replace( '#\s#', '', utf8_decode( file_get_contents( $fullPath ) ) ) ) != $correctMd5s[ $shortPath ] ) // We strip whitespace since FTP in ASCII mode will change the whitespace characters
|
||||
{
|
||||
$return[] = $fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
@@ -518,7 +618,7 @@ EOF;
|
||||
if( $this->modules === NULL )
|
||||
{
|
||||
$modules = \IPS\Application\Module::modules();
|
||||
$this->modules = $modules[ $this->directory ];
|
||||
$this->modules = array_key_exists( $this->directory, $modules ) ? $modules[ $this->directory ] : array();
|
||||
}
|
||||
|
||||
/* Return */
|
||||
@@ -584,8 +684,8 @@ EOF;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$classes[ mb_substr( $file, 0, -4 ) ] = new $classname;
|
||||
{
|
||||
$classes[ mb_substr( $file, 0, -4 ) ] = new $classname( $checkAccess === TRUE ? \IPS\Member::loggedIn() : ( $checkAccess === FALSE ? NULL : $checkAccess ) );
|
||||
}
|
||||
catch( \RuntimeException $e ){}
|
||||
}
|
||||
@@ -717,7 +817,7 @@ EOF;
|
||||
}
|
||||
|
||||
/* Default */
|
||||
if( $this->directory != 'core' and $this->enabled )
|
||||
if( $this->enabled )
|
||||
{
|
||||
$buttons['default'] = array(
|
||||
'icon' => $this->default ? 'star' : 'star-o',
|
||||
@@ -1523,6 +1623,7 @@ EOF;
|
||||
$module->position = ++$position;
|
||||
$module->area = $area;
|
||||
$module->default_controller = $data['default_controller'];
|
||||
$module->default = isset( $data['default'] ) and $data['default'];
|
||||
$module->save( TRUE );
|
||||
}
|
||||
}
|
||||
@@ -1601,6 +1702,32 @@ EOF;
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_notification_defaults', $inserts );
|
||||
}
|
||||
|
||||
/* Install Menu items @note IPS applications are handled by FrontNavigation::buildDefaultNavigation */
|
||||
if ( ! in_array( $this->directory, static::$ipsApps ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$topLevelPosition = \IPS\Db::i()->select( 'MAX(position) + 1', 'core_menu', 'parent IS NULL' )->first();
|
||||
}
|
||||
catch( \IPS\Db\Exception $ex )
|
||||
{
|
||||
$topLevelPosition = 0;
|
||||
}
|
||||
|
||||
foreach( $this->extensions( 'core', 'FrontNavigation', FALSE ) as $key => $class )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_menu', array(
|
||||
'app' => $this->directory,
|
||||
'extension' => $key,
|
||||
'config' => json_encode( array() ),
|
||||
'position' => $topLevelPosition++,
|
||||
'parent' => NULL,
|
||||
'permissions' => '',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1915,6 +2042,8 @@ EOF;
|
||||
'sc_title' => $data['sc_title'],
|
||||
'sc_order' => $data['sc_order']
|
||||
) );
|
||||
|
||||
$currentSettings[ $data['sc_key'] ] = $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1943,9 +2072,18 @@ EOF;
|
||||
|
||||
if ( $update )
|
||||
{
|
||||
$defaultCurrentSettings = $currentSettings;
|
||||
foreach( \IPS\Theme::themes() as $theme )
|
||||
{
|
||||
$currentSettings = iterator_to_array( \IPS\Db::i()->select( '*', 'core_theme_settings_fields', array( 'sc_set_id=?', $theme->id ) )->setKeyField('sc_key') );
|
||||
if ( $theme->id == \IPS\Theme::defaultTheme() )
|
||||
{
|
||||
$currentSettings = $defaultCurrentSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentSettings = iterator_to_array( \IPS\Db::i()->select( '*', 'core_theme_settings_fields', array( 'sc_set_id=?', $theme->id ) )->setKeyField('sc_key') );
|
||||
}
|
||||
|
||||
$added = FALSE;
|
||||
$save = json_decode( $theme->template_settings, TRUE );
|
||||
|
||||
@@ -1972,6 +2110,41 @@ EOF;
|
||||
'sc_order' => $data['sc_order'],
|
||||
) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update */
|
||||
\IPS\Db::i()->update( 'core_theme_settings_fields', array(
|
||||
'sc_tab_key' => $data['sc_tab_key'],
|
||||
'sc_type' => $data['sc_type'],
|
||||
'sc_multiple' => $data['sc_multiple'],
|
||||
'sc_default' => $data['sc_default'],
|
||||
'sc_show_in_vse' => ( isset( $data['sc_show_in_vse'] ) ) ? $data['sc_show_in_vse'] : 0,
|
||||
'sc_content' => $data['sc_content'],
|
||||
'sc_title' => $data['sc_title'],
|
||||
'sc_order' => $data['sc_order']
|
||||
), array( 'sc_set_id=? AND sc_key=?', $theme->id, $data['sc_key'] ) );
|
||||
|
||||
$currentId = $currentSettings[ $data['sc_key'] ]['sc_id'];
|
||||
|
||||
try
|
||||
{
|
||||
$currentValue = \IPS\Db::i()->select( 'sv_value', 'core_theme_settings_values', array( array( 'sv_id=?', $currentId ) ) )->first();
|
||||
}
|
||||
catch( \UnderFlowException $ex )
|
||||
{
|
||||
$currentValue = $currentSettings[ $data['sc_key'] ]['sc_default'];
|
||||
}
|
||||
|
||||
/* Are we using the existing default? If so, update it */
|
||||
if ( ( $data['sc_default'] != $currentSettings[ $data['sc_key'] ]['sc_default'] ) and ( $currentValue == $currentSettings[ $data['sc_key'] ]['sc_default'] ) )
|
||||
{
|
||||
$added = TRUE;
|
||||
$save[ $data['sc_key'] ] = $data['sc_default'];
|
||||
|
||||
\IPS\Db::i()->delete('core_theme_settings_values', array('sv_id=?', $currentId ) );
|
||||
\IPS\Db::i()->insert('core_theme_settings_values', array( 'sv_id' => $currentId, 'sv_value' => (string)$data['sc_default'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $added )
|
||||
@@ -2013,7 +2186,16 @@ EOF;
|
||||
{
|
||||
$i = 0;
|
||||
$inserted = 0;
|
||||
|
||||
|
||||
if ( \IPS\Dispatcher::hasInstance() AND class_exists( '\IPS\Dispatcher', FALSE ) and \IPS\Dispatcher::i()->controllerLocation === 'setup' )
|
||||
{
|
||||
$class = '\IPS\Theme';
|
||||
}
|
||||
else
|
||||
{
|
||||
$class = ( \IPS\Theme::designersModeEnabled() ) ? '\IPS\Theme\Advanced\Theme' : '\IPS\Theme';
|
||||
}
|
||||
|
||||
if( file_exists( \IPS\ROOT_PATH . "/applications/{$this->directory}/data/theme.xml" ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->themes );
|
||||
@@ -2070,7 +2252,7 @@ EOF;
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\Theme::addTemplate( $template );
|
||||
$class::addTemplate( $template );
|
||||
}
|
||||
catch( \OverflowException $e )
|
||||
{
|
||||
@@ -2093,7 +2275,7 @@ EOF;
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\Theme::addCss( $css );
|
||||
$class::addCss( $css );
|
||||
}
|
||||
catch( \OverflowException $e )
|
||||
{
|
||||
@@ -2113,7 +2295,7 @@ EOF;
|
||||
'content' => base64_decode( $xml->readString() ),
|
||||
);
|
||||
|
||||
\IPS\Theme::addResource( $resource, TRUE );
|
||||
$class::addResource( $resource, TRUE );
|
||||
}
|
||||
|
||||
if( $limit !== null AND $i === ( $limit + $offset ) )
|
||||
@@ -2371,6 +2553,27 @@ 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 )
|
||||
{
|
||||
$defaultValue = "''";
|
||||
|
||||
/* Default value */
|
||||
if( isset( $columnData['default'] ) and !in_array( \strtoupper( $columnData['type'] ), array( 'TINYTEXT', 'TEXT', 'MEDIUMTEXT', 'LONGTEXT', 'BLOB', 'MEDIUMBLOB', 'BIGBLOB', 'LONGBLOB' ) ) )
|
||||
{
|
||||
if( $columnData['type'] == 'BIT' )
|
||||
{
|
||||
$defaultValue = "{$columnData['default']}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultValue = in_array( $columnData['type'], array( 'TINYINT', 'SMALLINT', 'MEDIUMINT', 'INT', 'INTEGER', 'BIGINT', 'REAL', 'DOUBLE', 'FLOAT', 'DECIMAL', 'NUMERIC' ) ) ? floatval( $columnData['default'] ) : ( ! in_array( $columnData['default'], array( 'CURRENT_TIMESTAMP', 'BIT' ) ) ? '\'' . $db->escape_string( $columnData['default'] ) . '\'' : $columnData['default'] );
|
||||
}
|
||||
}
|
||||
|
||||
$changesToMake[] = array( 'table' => $tableName, 'query' => "UPDATE `{$db->prefix}{$db->escape_string( $tableName )}` SET `{$db->escape_string( $columnName )}`={$defaultValue} WHERE `{$db->escape_string( $columnName )}` IS NULL;" );
|
||||
}
|
||||
|
||||
$tableChanges[] = "CHANGE COLUMN `{$db->escape_string( $columnName )}` {$db->compileColumnDefinition( $columnData )}";
|
||||
}
|
||||
}
|
||||
@@ -2427,6 +2630,34 @@ EOF;
|
||||
}
|
||||
}
|
||||
|
||||
/* And loop any install routine for columns added to other tables */
|
||||
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$this->directory}/setup/install/queries.json" ) )
|
||||
{
|
||||
foreach( json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$this->directory}/setup/install/queries.json" ), TRUE ) as $query )
|
||||
{
|
||||
switch ( $query['method'] )
|
||||
{
|
||||
/* Add column */
|
||||
case 'addColumn':
|
||||
$localDefinition = \IPS\Db::i()->getTableDefinition( $query['params'][0] );
|
||||
if ( !isset( $localDefinition['columns'][ $query['params'][1]['name'] ] ) )
|
||||
{
|
||||
$changesToMake[] = array( 'table' => $query['params'][0], 'query' => "ALTER TABLE `{$db->prefix}{$query['params'][0]}` ADD COLUMN {$db->compileColumnDefinition( $query['params'][1] )}" );
|
||||
}
|
||||
else
|
||||
{
|
||||
$correctDefinition = $db->compileColumnDefinition( $query['params'][1] );
|
||||
if ( $correctDefinition != $db->compileColumnDefinition( $localDefinition['columns'][ $query['params'][1]['name'] ] ) )
|
||||
{
|
||||
$tableChanges[] = array( 'table' => $query['params'][0], 'query' => "ALTER TABLE `{$db->prefix}{$query['params'][0]}` CHANGE COLUMN `{$db->escape_string( $columnName )}` {$db->compileColumnDefinition( $columnData )}" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $changesToMake;
|
||||
}
|
||||
|
||||
@@ -3220,7 +3451,10 @@ EOF;
|
||||
{
|
||||
$templatesToRecompile[ $class ] = $class;
|
||||
}
|
||||
|
||||
|
||||
/* Delete menu items */
|
||||
\IPS\core\FrontNavigation::deleteByApplication( $this );
|
||||
|
||||
/* Delete data from shared tables */
|
||||
\IPS\Content\Search\Index::i()->removeApplicationContent( $this );
|
||||
\IPS\DB::i()->delete( 'core_permission_index', array( 'app=? AND perm_type=? AND perm_type_id IN(?)', 'core', 'module', \IPS\Db::i()->select( 'sys_module_id', 'core_modules', array( 'sys_module_application=?', $this->directory ) ) ) );
|
||||
@@ -3304,7 +3538,19 @@ 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 );
|
||||
|
||||
|
||||
/* Delete theme settings */
|
||||
$valueIds = iterator_to_array( \IPS\Db::i()->select( 'sc_id', 'core_theme_settings_fields', array( array( 'sc_app=?', $this->directory ) ) ) );
|
||||
|
||||
\IPS\Db::i()->delete( 'core_theme_settings_fields', array( 'sc_app=?', $this->directory ) );
|
||||
|
||||
if ( count( $valueIds ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_theme_settings_values', array( 'sv_id IN(?)', implode( ',', $valueIds ) ) );
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->themes );
|
||||
|
||||
/* Delete any stored files */
|
||||
foreach( $this->extensions( 'core', 'FileStorage', TRUE ) as $extension )
|
||||
{
|
||||
@@ -3344,6 +3590,24 @@ EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Revert other database changes performed by installation */
|
||||
if( file_exists( \IPS\ROOT_PATH . "/applications/{$this->directory}/setup/install/queries.json" ) )
|
||||
{
|
||||
$schema = json_decode( file_get_contents( \IPS\ROOT_PATH . "/applications/{$this->directory}/setup/install/queries.json" ), TRUE );
|
||||
|
||||
ksort($schema);
|
||||
|
||||
foreach( $schema as $instruction )
|
||||
{
|
||||
switch ( $instruction['method'] )
|
||||
{
|
||||
case 'addColumn':
|
||||
\IPS\Db::i()->dropColumn( $instruction['params'][0], $instruction['params'][1]['name'] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* delete widgets */
|
||||
\IPS\Db::i()->delete( 'core_widgets', array( 'app = ?', $this->directory ) );
|
||||
@@ -3433,4 +3697,17 @@ EOF;
|
||||
|
||||
return $versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can view page even when user is a guest when guests cannot access the site
|
||||
*
|
||||
* @param \IPS\Application\Module $module The module
|
||||
* @param string $controller The controller
|
||||
* @param string|NULL $do To "do" parameter
|
||||
* @return bool
|
||||
*/
|
||||
public function allowGuestAccess( \IPS\Application\Module $module, $controller, $do )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,12 @@ class _BuilderIterator extends \RecursiveIteratorIterator
|
||||
* @brief The application
|
||||
*/
|
||||
protected $application;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
* @param \IPS\Application $application
|
||||
*/
|
||||
public function __construct( \IPS\Application $application )
|
||||
{
|
||||
|
||||
@@ -231,7 +231,7 @@ class _Module extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$buttons['permissions'] = array(
|
||||
'icon' => 'lock',
|
||||
'title' => 'permissions',
|
||||
'link' => \IPS\Http\Url::internal( "{$url}&do=permissions&id={$this->_id}" ) . ( $subnode ? '&subnode=1' : '' ),
|
||||
'link' => "{$url}&do=permissions&id={$this->_id}" . ( $subnode ? '&subnode=1' : '' ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('permissions') )
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user