Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Block Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 19 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -47,6 +48,11 @@ class _Block extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array('block_key');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
@@ -239,7 +245,7 @@ class _Block extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
|
||||
/* Still here */
|
||||
if ( ! in_array( $functionName, array_keys( self::$calledTemplates ) ) )
|
||||
if ( ! in_array( $functionName, array_keys( static::$calledTemplates ) ) )
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
@@ -252,8 +258,10 @@ class _Block extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
try
|
||||
{
|
||||
$template = \IPS\cms\Templates::load( $this->template );
|
||||
return call_user_func_array( array( \IPS\cms\Theme::i()->getTemplate( $template->group, 'cms', $template->location ), $template->title ), $args );
|
||||
$template = \IPS\cms\Templates::load( $this->template );
|
||||
$object = \IPS\cms\Theme::i()->getTemplate( $template->group, 'cms', $template->location );
|
||||
$title = $template->title;
|
||||
return $object->$title( ...$args );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
@@ -280,10 +288,10 @@ EOF;
|
||||
$class = "\IPS\Theme\\class_{$functionName}";
|
||||
|
||||
/* Init */
|
||||
self::$calledTemplates[ $functionName ] = new $class();
|
||||
static::$calledTemplates[ $functionName ] = new $class();
|
||||
}
|
||||
|
||||
return call_user_func_array( array( self::$calledTemplates[ $functionName ], 'run' ), $args );
|
||||
|
||||
return static::$calledTemplates[ $functionName ]->run( ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -623,7 +631,12 @@ EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Codemirror( 'block_content', $this->content, FALSE, array(), NULL, NULL, NULL, 'block_content' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Codemirror( 'block_content', htmlentities( $this->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ), FALSE, array(), function( $val ) {
|
||||
if ( mb_strpos( $val, '{block="' . \IPS\Request::i()->block_key . '"}' ) !== FALSE )
|
||||
{
|
||||
throw new \DomainException('block_content_recursive_error');
|
||||
}
|
||||
}, NULL, NULL, 'block_content' ) );
|
||||
}
|
||||
|
||||
if ( $block_type === 'plugin' and ! $this->id )
|
||||
@@ -653,6 +666,12 @@ EOF;
|
||||
}
|
||||
$form->hiddenValues['template_params'] = ( $this->id ) ? $this->template_params : '';
|
||||
|
||||
/* If we are editing, we can save and reload */
|
||||
if( $this->id )
|
||||
{
|
||||
$form->canSaveAndReload = true;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'templates/view.css', 'cms', 'admin' ) );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'blocks/form.css', 'cms', 'admin' ) );
|
||||
|
||||
@@ -682,6 +701,10 @@ EOF;
|
||||
}
|
||||
|
||||
$config = array();
|
||||
if( isset( $values['language_key'] ) )
|
||||
{
|
||||
$config['language_key'] = $values['language_key'];
|
||||
}
|
||||
|
||||
if( isset( $values['block_name'] ) )
|
||||
{
|
||||
@@ -704,11 +727,12 @@ EOF;
|
||||
{
|
||||
if ( is_array( $values['block_name'] ) )
|
||||
{
|
||||
$values['block_key'] = \IPS\Http\Url::seoTitle( $values['block_name'][ key( $values['block_name'] ) ] );
|
||||
reset( $values['block_name'] );
|
||||
$values['block_key'] = \IPS\Http\Url\Friendly::seoTitle( $values['block_name'][ key( $values['block_name'] ) ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$values['block_key'] = \IPS\Http\Url::seoTitle( $values['block_name'] );
|
||||
$values['block_key'] = \IPS\Http\Url\Friendly::seoTitle( $values['block_name'] );
|
||||
}
|
||||
|
||||
/* Now test it */
|
||||
@@ -758,6 +782,11 @@ EOF;
|
||||
{
|
||||
$theValue[ $eachKey ] = $eachValue;
|
||||
}
|
||||
elseif ( $eachKey === 'start' or $eachKey === 'end' )
|
||||
{
|
||||
/* date ranges */
|
||||
$theValue[ $eachKey ] = $eachValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$theValue[] = $eachValue;
|
||||
@@ -816,7 +845,7 @@ EOF;
|
||||
|
||||
$templateArray = array(
|
||||
'key' => 'template_' . $templateBit['template_name'] . '.' . uniqid(),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $templateBit['template_name'] . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url\Friendly::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $templateBit['template_name'] . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'desc' => null,
|
||||
'content' => $values['block_content'],
|
||||
'location' => 'block',
|
||||
@@ -836,7 +865,7 @@ EOF;
|
||||
|
||||
$templateArray = array(
|
||||
'key' => 'template_' . $template->name . '.' . uniqid(),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $template->name . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url\Friendly::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $template->name . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'desc' => null,
|
||||
'content' => $values['block_content'],
|
||||
'location' => 'block',
|
||||
@@ -950,4 +979,43 @@ EOF;
|
||||
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Duplicate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
parent::__clone();
|
||||
|
||||
if( $this->skipCloneDuplication === TRUE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy language bits to make them unique */
|
||||
$config = $this->_plugin_config;
|
||||
$wordKey = 'widget_title_' . md5( uniqid() );
|
||||
|
||||
if ( isset( $config['language_key'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( 'word_key=?', $config['language_key'] ) ) as $row )
|
||||
{
|
||||
unset( $row['word_id'] );
|
||||
$row['word_key'] = $wordKey;
|
||||
\IPS\Db::i()->insert( 'core_sys_lang_words', $row );
|
||||
}
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
|
||||
$config['language_key'] = $wordKey;
|
||||
$this->plugin_config = json_encode( $config );
|
||||
}
|
||||
|
||||
$this->key .= '_' . uniqid();
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Block Container Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 19 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Container extends \IPS\Node\Model
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array('container_key');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Categories Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 8 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -58,6 +59,11 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected static $databaseIdFields = array('category_furl_name', 'category_full_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
@@ -146,7 +152,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/**
|
||||
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
|
||||
*/
|
||||
public static $permissionLangPrefix = 'perm_content_';
|
||||
public static $permissionLangPrefix = 'perm_content_category_';
|
||||
|
||||
/**
|
||||
* @brief [Page] Loaded pages from paths
|
||||
@@ -187,7 +193,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* May contain a record name */
|
||||
$where = ( $databaseId === NULL ) ? array( '? LIKE CONCAT( category_full_path, \'%\')', $path ) : array( 'category_database_id=? AND ? LIKE CONCAT( category_full_path, \'%\')', $databaseId, $path );
|
||||
$where = ( $databaseId === NULL ) ? array( '? LIKE CONCAT( TRIM(TRAILING \'/\' FROM category_full_path), \'/\', \'%\')', rtrim( $path, '/' ) . '/' ) : array( 'category_database_id=? AND ? LIKE CONCAT( TRIM(TRAILING \'/\' FROM category_full_path), \'/\', \'%\')', $databaseId, rtrim( $path, '/' ) . '/' );
|
||||
|
||||
foreach(
|
||||
\IPS\Db::i()->select(
|
||||
@@ -253,6 +259,8 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public static function roots( $permissionCheck='view', $member=NULL, $where=array(), $databaseId=null )
|
||||
{
|
||||
$permissionCheck = ( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation === 'admin' ) ? NULL : $permissionCheck;
|
||||
|
||||
if ( $databaseId === NULL and static::$customDatabaseId !== NULL )
|
||||
{
|
||||
$databaseId = static::$customDatabaseId;
|
||||
@@ -266,6 +274,23 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
return parent::roots( $permissionCheck, $member, $where );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Fetch Child Nodes
|
||||
*
|
||||
* @param string|NULL $permissionCheck The permission key to check for or NULL to not check permissions
|
||||
* @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member
|
||||
* @param bool $subnodes Include subnodes? NULL to *only* check subnodes
|
||||
* @param array|NULL $skip Children IDs to skip
|
||||
* @param mixed $_where Additional WHERE clause
|
||||
* @return array
|
||||
*/
|
||||
public function children( $permissionCheck='view', $member=NULL, $subnodes=TRUE, $skip=null, $_where=array() )
|
||||
{
|
||||
$permissionCheck = ( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation === 'admin' ) ? NULL : $permissionCheck;
|
||||
|
||||
return parent::children( $permissionCheck, $member, $subnodes, $skip, $_where );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a category path
|
||||
*
|
||||
@@ -335,9 +360,16 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
public function __clone()
|
||||
{
|
||||
parent::__clone();
|
||||
|
||||
|
||||
if( $this->skipCloneDuplication === TRUE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->furl_name .= '_' . $this->id;
|
||||
$this->save();
|
||||
|
||||
$this->setFullPath();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,37 +433,31 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->category_parent_id == 0 and \IPS\cms\Categories::isFurlCollision( $val ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_cat_furl_collision');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( \IPS\Request::i()->category_parent_id == 0 and \IPS\cms\Categories::isFurlCollision( $val ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_cat_furl_collision');
|
||||
}
|
||||
|
||||
$cat = \IPS\cms\Categories::load( $val, 'category_furl_name' );
|
||||
|
||||
/* We have a cat, is it in a different database? */
|
||||
if ( $cat->database_id != \IPS\Request::i()->database_id )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->id ) )
|
||||
{
|
||||
if ( $cat->id != \IPS\Request::i()->id )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_cat_furl_not_unique');
|
||||
}
|
||||
}
|
||||
else
|
||||
$cat = \IPS\Db::i()->select( '*', 'cms_database_categories', array( 'category_database_id=? and category_parent_id=? and category_furl_name=?', \IPS\Request::i()->database_id, \IPS\Request::i()->category_parent_id, $val ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $ex )
|
||||
{
|
||||
/* Nuffink matches */
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->id ) )
|
||||
{
|
||||
if ( $cat['category_id'] != \IPS\Request::i()->id )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_cat_furl_not_unique');
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
else
|
||||
{
|
||||
/* Key is OK as select failed */
|
||||
return true;
|
||||
throw new \InvalidArgumentException('content_cat_furl_not_unique');
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -462,6 +488,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'category_show_records', $this->id ? $this->show_records : TRUE, FALSE, array(), NULL, NULL, NULL, 'category_show_records' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'category_allow_rating', $this->allow_rating, FALSE, array(), NULL, NULL, NULL, 'category_allow_rating' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'category_has_perms', $this->has_perms, FALSE, array(), NULL, NULL, NULL, 'category_has_perms' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'category_can_view_others', $this->id ? $this->can_view_others : TRUE, FALSE, array(), NULL, NULL, NULL, 'category_can_view_others' ) );
|
||||
|
||||
$form->addHeader('cms_categories_header_display');
|
||||
$templatesList = array( 0 => \IPS\Member::loggedIn()->language()->addToStack('cms_categories_use_database') );
|
||||
@@ -525,7 +552,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
), function( $val )
|
||||
{
|
||||
if ( ! $val and \IPS\Request::i()->database_forum_record_checkbox )
|
||||
if ( ! $val and \IPS\Request::i()->category_forum_override and \IPS\Request::i()->database_forum_record_checkbox )
|
||||
{
|
||||
throw new \InvalidArgumentException('cms_database_no_forum_selected');
|
||||
}
|
||||
@@ -586,13 +613,13 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
if ( ! $this->id )
|
||||
{
|
||||
$this->_updatePaths = TRUE;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
if ( isset( $values['category_name'] ) AND is_array( $values['category_name'] ) )
|
||||
{
|
||||
$name = current( $values['category_name'] );
|
||||
reset( $values['category_name'] );
|
||||
$name = $values['category_name'][ \IPS\Lang::defaultLanguage() ];
|
||||
}
|
||||
else if( isset( $values['category_name'] ) )
|
||||
{
|
||||
@@ -617,7 +644,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
try
|
||||
{
|
||||
$cat = \IPS\cms\Categories::load( \IPS\Http\Url::seoTitle( $name ), 'category_furl_name' );
|
||||
$cat = \IPS\cms\Categories::load( \IPS\Http\Url\Friendly::seoTitle( $name ), 'category_furl_name' );
|
||||
|
||||
/* We have a cat, is it in a different database? */
|
||||
if ( $cat->database_id != \IPS\Request::i()->database_id )
|
||||
@@ -638,23 +665,23 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$ok = TRUE;
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->category_parent_id == 0 and \IPS\cms\Categories::isFurlCollision( \IPS\Http\Url::seoTitle( $name ) ) )
|
||||
if ( \IPS\Request::i()->category_parent_id == 0 and \IPS\cms\Categories::isFurlCollision( \IPS\Http\Url\Friendly::seoTitle( $name ) ) )
|
||||
{
|
||||
$ok = FALSE;
|
||||
}
|
||||
|
||||
if ( $ok === TRUE )
|
||||
{
|
||||
$values['furl_name'] = \IPS\Http\Url::seoTitle( $name );
|
||||
$values['furl_name'] = \IPS\Http\Url\Friendly::seoTitle( $name );
|
||||
}
|
||||
else
|
||||
{
|
||||
$values['furl_name'] = $this->id . '_' . \IPS\Http\Url::seoTitle( $name );
|
||||
$values['furl_name'] = $this->id . '_' . \IPS\Http\Url\Friendly::seoTitle( $name );
|
||||
}
|
||||
}
|
||||
else if( isset( $values['category_furl_name'] ) )
|
||||
{
|
||||
$values['furl_name'] = \IPS\Http\Url::seoTitle( $values['category_furl_name'] );
|
||||
$values['furl_name'] = \IPS\Http\Url\Friendly::seoTitle( $values['category_furl_name'] );
|
||||
}
|
||||
|
||||
if( array_key_exists( 'category_furl_name_choice', $values ) )
|
||||
@@ -782,6 +809,17 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
\IPS\Db::i()->delete( 'core_tags', array( 'tag_aap_lookup=?', $aap ) );
|
||||
\IPS\Db::i()->delete( 'core_tags_perms', array( 'tag_perm_aap_lookup=?', $aap ) );
|
||||
|
||||
/* Delete category follows */
|
||||
\IPS\Db::i()->delete( 'core_follow', array( "follow_app=? AND follow_area=? AND follow_rel_id=?", static::$permApp, static::$permType . $this->database()->id, $this->_id ) );
|
||||
|
||||
if( $this->hasChildren() )
|
||||
{
|
||||
foreach ( $this->children( NULL, NULL, TRUE ) as $child )
|
||||
{
|
||||
$child->delete();
|
||||
}
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
@@ -794,7 +832,17 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
* @brief Cached title
|
||||
*/
|
||||
protected $_catTitle = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cached title for strip tags version
|
||||
*/
|
||||
protected $_stripTagsCatTitle = NULL;
|
||||
|
||||
/**
|
||||
* @brief Cached title for strip tags version
|
||||
*/
|
||||
protected $_catTitleLangKey = NULL;
|
||||
|
||||
/**
|
||||
* @brief Last comment time
|
||||
*/
|
||||
@@ -954,7 +1002,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if( $this->_url === NULL )
|
||||
{
|
||||
if ( \IPS\cms\Pages\Page::$currentPage )
|
||||
if ( \IPS\cms\Pages\Page::$currentPage and static::database()->page_id == \IPS\cms\Pages\Page::$currentPage->id )
|
||||
{
|
||||
$pagePath = \IPS\cms\Pages\Page::$currentPage->full_path;
|
||||
}
|
||||
@@ -990,7 +1038,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public static function urlFromIndexData( $indexData, $itemData, $containerData )
|
||||
@@ -1014,6 +1062,47 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
return \IPS\Http\Url::internal( "app=cms&module=pages&controller=page&path=" . $recordClass::$pagePath, 'front', 'content_page_path', '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title from index data
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public static function titleFromIndexData( $indexData, $itemData, $containerData )
|
||||
{
|
||||
$recordClass = $indexData['index_class'];
|
||||
if ( in_array( 'IPS\Content\Comment', class_parents( $recordClass ) ) )
|
||||
{
|
||||
$recordClass = $recordClass::$itemClass;
|
||||
}
|
||||
|
||||
if ( $recordClass::database()->use_categories )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $indexData['index_container_id'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
return $recordClass::database()->_title;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Page Title for use in <title> tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function pageTitle()
|
||||
{
|
||||
if ( $this->page_title )
|
||||
{
|
||||
return $this->page_title;
|
||||
}
|
||||
|
||||
return $this->database()->pageTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title of category
|
||||
@@ -1045,6 +1134,68 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
return parent::get__title();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Title language key, not added to a language stack
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get__titleLanguageKey()
|
||||
{
|
||||
/* If the DB is in a page, and we're not using categories, then return the page title, not the category title for continuity */
|
||||
if ( ! \IPS\cms\Databases::load( $this->database_id )->use_categories )
|
||||
{
|
||||
if ( ! $this->_catTitleLangKey )
|
||||
{
|
||||
try
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::loadByDatabaseId( $this->database_id );
|
||||
$this->_catTitleLangKey = $page->_titleLanguageKey;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$this->_catTitleLangKey = parent::get__titleLanguageKey();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_catTitleLangKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::get__titleLanguageKey();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node titles can contain HTML. Apparently.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get__stripTagsTitle()
|
||||
{
|
||||
/* If the DB is in a page, and we're not using categories, then return the page title, not the category title for continuity */
|
||||
if ( ! \IPS\cms\Databases::load( $this->database_id )->use_categories )
|
||||
{
|
||||
if ( ! $this->_stripTagsCatTitle )
|
||||
{
|
||||
try
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::loadByDatabaseId( $this->database_id );
|
||||
$this->_stripTagsCatTitle = $page->_stripTagsTitle;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$this->_stripTagsCatTitle = parent::get__stripTagsTitle();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_stripTagsCatTitle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::get__stripTagsTitle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Description
|
||||
@@ -1068,6 +1219,11 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected function get__items()
|
||||
{
|
||||
if ( ! $this->can_view_others and !\IPS\Member::loggedIn()->modPermission( 'can_content_view_others_records' ) )
|
||||
{
|
||||
return \IPS\Db::i()->select('count(*)', 'cms_custom_database_' . $this->database_id, array("record_future_date=0 AND category_id=? AND record_approved=1 AND member_id=?", $this->id, \IPS\Member::loggedIn()->member_id) )->first();
|
||||
}
|
||||
|
||||
return (int) $this->records;
|
||||
}
|
||||
|
||||
@@ -1282,11 +1438,24 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if ( static::$latestRecordAdded->record_comments AND ( $database->_comment_bump & \IPS\cms\Databases::BUMP_ON_COMMENT ) )
|
||||
{
|
||||
try
|
||||
if ( static::$latestRecordAdded->useForumComments() )
|
||||
{
|
||||
$comment = $commentClass::constructFromData( \IPS\Db::i()->select( '*', 'cms_database_comments', array( 'comment_record_id=? AND comment_approved=1', \IPS\Db::i()->select( 'primary_id_field', 'cms_custom_database_' . $this->database_id, array( 'category_id=? AND record_approved=1', $this->id ), 'record_last_comment DESC', 1 )->first() ), 'comment_date DESC', 1 )->first() );
|
||||
$syncRecord = static::$latestRecordAdded;
|
||||
|
||||
try
|
||||
{
|
||||
$comment = $syncRecord->comments( 1, 0, 'date', 'desc', NULL, FALSE );
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$comment = $commentClass::constructFromData( \IPS\Db::i()->select( '*', 'cms_database_comments', array( 'comment_record_id=? AND comment_approved=1', \IPS\Db::i()->select( 'primary_id_field', 'cms_custom_database_' . $this->database_id, array( 'category_id=? AND record_approved=1', $this->id ), 'record_last_comment DESC', 1 )->first() ), 'comment_date DESC', 1 )->first() );
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
if ( $comment and ( static::$latestRecordAdded->record_last_comment > $comment->mapped('date') ) )
|
||||
@@ -1312,9 +1481,9 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$this->last_record_date = $comment->mapped('date');
|
||||
$this->last_record_member = intval( $comment->author()->member_id );
|
||||
$this->last_record_name = $comment->author()->member_id ? $comment->author()->name : NULL;
|
||||
$this->last_record_seo_name = \IPS\Http\Url::seoTitle( $this->last_poster_name );
|
||||
$this->last_title = $comment->item()->mapped('title');
|
||||
$this->last_seo_title = \IPS\Http\Url::seoTitle( $this->last_title );
|
||||
$this->last_record_seo_name = \IPS\Http\Url\Friendly::seoTitle( $this->last_poster_name );
|
||||
$this->last_title = mb_substr( $comment->item()->mapped('title'), 0, 255 );
|
||||
$this->last_seo_title = \IPS\Http\Url\Friendly::seoTitle( $this->last_title );
|
||||
$this->last_record_id = $comment->item()->_id;
|
||||
}
|
||||
else if ( static::$latestRecordAdded !== NULL )
|
||||
@@ -1322,9 +1491,8 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$this->last_record_date = static::$latestRecordAdded->record_saved;
|
||||
$this->last_record_member = static::$latestRecordAdded->member_id;
|
||||
$this->last_record_name = static::$latestRecordAdded->member_id ? static::$latestRecordAdded->record_last_comment_name : NULL;
|
||||
$this->last_record_seo_name = static::$latestRecordAdded->member_id ? static::$latestRecordAdded->record_last_comment_seo : NULL;
|
||||
$this->last_title = static::$latestRecordAdded->_title;
|
||||
$this->last_seo_title = \IPS\Http\Url::seoTitle( static::$latestRecordAdded->_title );
|
||||
$this->last_title = mb_substr( static::$latestRecordAdded->_title, 0, 255 );
|
||||
$this->last_seo_title = \IPS\Http\Url\Friendly::seoTitle( mb_substr( static::$latestRecordAdded->_title, 0, 255 ) );
|
||||
$this->last_record_id = static::$latestRecordAdded->_id;
|
||||
}
|
||||
|
||||
@@ -1343,6 +1511,20 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public function getLastCommentTime()
|
||||
{
|
||||
if( !$this->can_view_others and !\IPS\Member::loggedIn()->modPermission( 'can_content_view_others_records' ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$select = \IPS\Db::i()->select('record_last_comment', 'cms_custom_database_' . $this->database_id, array("record_future_date=0 AND category_id=? AND record_approved=1 AND member_id=?", $this->id, \IPS\Member::loggedIn()->member_id), 'record_last_comment DESC', 1 )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $select ? \IPS\DateTime::ts( $select ) : NULL;
|
||||
}
|
||||
|
||||
return $this->last_record_date ? \IPS\DateTime::ts( $this->last_record_date ) : NULL;
|
||||
}
|
||||
|
||||
@@ -1354,27 +1536,37 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
public function lastPost()
|
||||
{
|
||||
$result = NULL;
|
||||
$RecordsClass = static::$contentItemClass;
|
||||
|
||||
if( $this->last_record_date )
|
||||
/* This category does not allow you to see records from other users... */
|
||||
if( $this->can_view_others or \IPS\Member::loggedIn()->modPermission( 'can_content_view_others_records' ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$RecordsClass = static::$contentItemClass;
|
||||
|
||||
$result = array(
|
||||
'author' => \IPS\Member::load( $this->last_record_member ),
|
||||
'record_url' => $RecordsClass::load( $this->last_record_id )->url(),
|
||||
'record_title' => $this->last_title,
|
||||
'date' => $this->last_record_date
|
||||
|
||||
);
|
||||
if ( $this->last_record_date )
|
||||
{
|
||||
try
|
||||
{
|
||||
$result = array( 'author' => \IPS\Member::load( $this->last_record_member ), 'record_url' => $RecordsClass::load( $this->last_record_id )->url(), 'record_title' => $this->last_title, 'date' => $this->last_record_date );
|
||||
|
||||
if( !$this->last_record_member AND $this->last_record_name )
|
||||
if ( !$this->last_record_member AND $this->last_record_name )
|
||||
{
|
||||
$result[ 'author' ]->name = $this->last_record_name;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$result['author']->name = $this->last_record_name;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e ){}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$record = $RecordsClass::constructFromData( \IPS\Db::i()->select('*', 'cms_custom_database_' . $this->database_id, array("record_future_date=0 AND category_id=? AND record_approved=1 AND member_id=?", $this->id, \IPS\Member::loggedIn()->member_id), 'record_last_comment DESC', 1 )->first() );
|
||||
$result = array( 'author' => $record->author(), 'record_url' => $record->url(), 'record_title' => $record->_title, 'date' => $record->record_last_comment );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
foreach( $this->children() as $child )
|
||||
@@ -1418,7 +1610,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
if ( ! $parent->furl_name )
|
||||
{
|
||||
$parent->furl_name = \IPS\Http\Url::seoTitle( $parent->name );
|
||||
$parent->furl_name = \IPS\Http\Url\Friendly::seoTitle( $parent->name );
|
||||
}
|
||||
|
||||
$parentId = $parent->parent_id;
|
||||
@@ -1457,7 +1649,63 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
return ( $can === FALSE ) ? FALSE : (boolean) $this->has_perms;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get which permission keys can access all records in a category which
|
||||
* can normally only show records to the author
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function permissionsThatCanAccessAllRecords()
|
||||
{
|
||||
$normal = $this->searchIndexPermissions();
|
||||
$return = array();
|
||||
$members = array();
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $moderator )
|
||||
{
|
||||
if ( $moderator['perms'] === '*' or in_array( 'can_content_view_others_records', explode( ',', $moderator['perms'] ) ) )
|
||||
{
|
||||
if( $moderator['type'] === 'g' )
|
||||
{
|
||||
$return[] = $moderator['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$members[] = "m{$moderator['id']}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$return = ( $normal == '*' ) ? array_unique( $return ) : array_intersect( explode( ',', $normal ), array_unique( $return ) );
|
||||
|
||||
if( count( $members ) )
|
||||
{
|
||||
$return = array_merge( $return, $members );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update search index permissions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function updateSearchIndexPermissions()
|
||||
{
|
||||
if ( $this->can_view_others )
|
||||
{
|
||||
return parent::updateSearchIndexPermissions();
|
||||
}
|
||||
else
|
||||
{
|
||||
$permissions = implode( ',', $this->permissionsThatCanAccessAllRecords() );
|
||||
\IPS\Content\Search\Index::i()->massUpdate( 'IPS\cms\Records' . static::database()->_id, $this->_id, NULL, $permissions, NULL, NULL, NULL, NULL, NULL, TRUE );
|
||||
\IPS\Content\Search\Index::i()->massUpdate( 'IPS\cms\Records\Comment' . static::database()->_id, $this->_id, NULL, $permissions, NULL, NULL, NULL, NULL, NULL, TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter cookie for this category
|
||||
*
|
||||
@@ -1497,7 +1745,17 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
else
|
||||
{
|
||||
$cookie[ $this->id ] = $values;
|
||||
/* We only want to include ones where we have actually specified values to filter on */
|
||||
$toSave = array();
|
||||
foreach( $values AS $key => $data )
|
||||
{
|
||||
if ( count( $data ) )
|
||||
{
|
||||
$toSave[$key] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
$cookie[ $this->id ] = $toSave;
|
||||
}
|
||||
|
||||
\IPS\Request::i()->setCookie( 'cms_filters', json_encode( $cookie ), \IPS\DateTime::create()->add( new \DateInterval( 'P7D' ) ) );
|
||||
@@ -1512,4 +1770,14 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
return $this->meta_description ?: parent::metaDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get meta title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function metaTitle()
|
||||
{
|
||||
return $this->page_title ?: parent::metaTitle();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Abstract class that Controllers should extend
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 16 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Databases Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 31 March 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'database_key', 'database_page_id' );
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
@@ -147,6 +153,11 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Page title
|
||||
*/
|
||||
protected static $pageTitle = NULL;
|
||||
|
||||
/**
|
||||
* Return all databases
|
||||
*
|
||||
@@ -156,15 +167,10 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if ( ! static::$gotAll )
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->cms_databases ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->cms_databases = iterator_to_array( \IPS\Db::i()->select( '*', static::$databaseTable )->setKeyField('database_id') );
|
||||
}
|
||||
|
||||
/* Avoid using SHOW TABLES LIKE / checkForTable() */
|
||||
try
|
||||
{
|
||||
foreach( \IPS\Data\Store::i()->cms_databases as $db )
|
||||
foreach( static::getDatabaseDataFromStore() as $db )
|
||||
{
|
||||
$id = $db[ static::$databasePrefix . static::$databaseColumnId ];
|
||||
static::$multitons[ $id ] = static::constructFromData( $db );
|
||||
@@ -177,7 +183,31 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
return static::$multitons;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns database data from the store
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDatabaseDataFromStore()
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->cms_databases ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->cms_databases = iterator_to_array(
|
||||
\IPS\Db::i()->select(
|
||||
static::$databaseTable . '.*, core_permission_index.perm_id, core_permission_index.perm_view, core_permission_index.perm_2, core_permission_index.perm_3, core_permission_index.perm_4, core_permission_index.perm_5, core_permission_index.perm_6, core_permission_index.perm_7',
|
||||
static::$databaseTable
|
||||
)->join(
|
||||
'core_permission_index',
|
||||
array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=" . static::$databaseTable . "." . static::$databasePrefix . static::$databaseColumnId, static::$permApp, static::$permType )
|
||||
)
|
||||
->setKeyField('database_id')
|
||||
);
|
||||
}
|
||||
|
||||
return \IPS\Data\Store::i()->cms_databases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we promote stuff to Pages?
|
||||
*
|
||||
@@ -652,7 +682,33 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
$this->_data['featured_settings'] = ( is_array( $value ) ? json_encode( $value ) : $value );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the title of the page when using a database
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function pageTitle()
|
||||
{
|
||||
if ( static::$pageTitle === NULL )
|
||||
{
|
||||
if ( $this->use_as_page_title )
|
||||
{
|
||||
static::$pageTitle = $this->_title;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
static::$pageTitle = \IPS\cms\Pages\Page::load( $this->page_id )->getHtmlTitle();
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
return static::$pageTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check permissions
|
||||
*
|
||||
@@ -692,39 +748,22 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$this->langLoaded = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( ! $this->langLoaded )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_comments_title' );
|
||||
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_reviews_title' );
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comment_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_review_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comments_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_reviews_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['content_db_lang_su_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_db_lang_pu_' . $this->id );
|
||||
\IPS\Member::loggedIn()->language()->words['content_db_lang_sl_' . $this->id . '_pl_lc' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_db_lang_pl_' . $this->id );
|
||||
|
||||
$fieldsClass = '\IPS\cms\Fields' . $this->id;
|
||||
$customFields = $fieldsClass::databaseFieldIds();
|
||||
|
||||
foreach ( $customFields AS $id )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['sort_field_' . $id] = \IPS\Member::loggedIn()->language()->addToStack( 'content_field_' . $id );
|
||||
}
|
||||
|
||||
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
|
||||
{
|
||||
/* Moderator tools */
|
||||
\IPS\Member::loggedIn()->language()->words['modperms__core_Content_cms_Records' . $this->id ] = $this->_title;
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['cms' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack('categories');
|
||||
|
||||
/* Editor Areas */
|
||||
\IPS\Member::loggedIn()->language()->words['editor__cms_Records' . $this->id ] = $this->_title;
|
||||
|
||||
foreach( array( 'pin', 'unpin', 'feature', 'unfeature', 'edit', 'hide', 'unhide', 'view_hidden', 'future_publish', 'view_future', 'move', 'lock', 'unlock', 'reply_to_locked', 'delete' ) as $lang )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_db_lang_sl_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_record', FALSE, array( 'sprintf' => array( $this->recordWord( 1 ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_db_lang_su_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_record', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
|
||||
if ( in_array( $lang, array( 'edit', 'hide', 'unhide', 'view_hidden', 'delete' ) ) )
|
||||
{
|
||||
@@ -748,8 +787,16 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public function recordWord( $number = 2, $upper = FALSE )
|
||||
{
|
||||
$case = $upper ? 'u' : 'l';
|
||||
return $number == 1 ? \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_s{$case}_{$this->id}") : \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_p{$case}_{$this->id}");
|
||||
if ( \IPS\Application::appIsEnabled('cms') )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->recordWord( $number, $upper, $this->id );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the Pages app is disabled, just load a generic phrase */
|
||||
$key = "content_database_noun_" . ( $number > 1 ? "p" : "s" ) . ( $upper ? "u" : "l" );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( $key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -759,12 +806,39 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
/* If we are enabling search, we will need to index that content */
|
||||
$rebuildSearchIndex = ( !$this->_new AND isset( $this->changed['search'] ) AND $this->changed['search'] );
|
||||
|
||||
parent::save();
|
||||
|
||||
/* Clear cache */
|
||||
if ( isset( \IPS\Data\Store::i()->cms_databases ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_databases );
|
||||
}
|
||||
|
||||
parent::save();
|
||||
|
||||
/* If this database isn't searchable, make sure its content is not in the search index */
|
||||
if( !$this->search AND !$this->_new )
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $this->id );
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Comment' . $this->id );
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Review' . $this->id );
|
||||
|
||||
/* If there are any bg tasks to rebuild index, clear them */
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( '`key`=?', 'RebuildSearchIndex' ) ) as $queue )
|
||||
{
|
||||
$details = json_decode( $queue['data'], true );
|
||||
|
||||
if( isset( $details['class'] ) AND $details['class'] == 'IPS\cms\Records' . $this->id )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_queue', array( 'id=?', $queue['id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif( $rebuildSearchIndex )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'RebuildSearchIndex', array( 'class' => 'IPS\cms\Records' . $this->id ), 5, TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,20 +869,22 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/* Delete comments */
|
||||
\IPS\Db::i()->delete( 'cms_database_comments', array( 'comment_database_id=?', $this->id ) );
|
||||
|
||||
/* Delete from search index */
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=?', "IPS\cms\Records\Comment" . $this->id ) );
|
||||
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=?', "IPS\cms\Records\Review" . $this->id ) );
|
||||
/* Delete from view counter */
|
||||
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=? ', 'IPS\cms\Records' . $this->id ) );
|
||||
|
||||
/* Delete records */
|
||||
\IPS\Db::i()->dropTable( 'cms_custom_database_' . $this->id, TRUE );
|
||||
|
||||
/* Delete revisions */
|
||||
\IPS\Db::i()->delete( 'cms_database_revisions', array( 'revision_database_id=?', $this->id ) );
|
||||
|
||||
|
||||
/* Remove any reciprocal linking */
|
||||
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map', array( 'map_foreign_database_id=? or map_origin_database_id=?', $this->id, $this->id ) );
|
||||
|
||||
/* Delete notifications */
|
||||
$memberIds = array();
|
||||
|
||||
foreach( \IPS\DB::i()->select( 'member', 'core_notifications', array( 'item_class=? ', 'IPS\cms\Records' . $this->id ) ) as $member )
|
||||
foreach( \IPS\Db::i()->select( 'member', 'core_notifications', array( 'item_class=? ', 'IPS\cms\Records' . $this->id ) ) as $member )
|
||||
{
|
||||
$memberIds[ $member ] = $member;
|
||||
}
|
||||
@@ -823,6 +899,8 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
|
||||
/* Remove from search */
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $this->id );
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Comment' . $this->id );
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Review' . $this->id );
|
||||
|
||||
/* Delete custom languages */
|
||||
\IPS\Lang::deleteCustom( 'cms', "content_db_" . $this->id );
|
||||
@@ -834,16 +912,20 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_ia_" . $this->id );
|
||||
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_sl_" . $this->id . '_pl' );
|
||||
\IPS\Lang::deleteCustom( 'cms', "__indefart_content_db_lang_sl_" . $this->id );
|
||||
\IPS\Lang::deleteCustom( 'cms', "__defart_content_db_lang_sl_" . $this->id );
|
||||
\IPS\Lang::deleteCustom( 'cms', "cms_create_menu_records_" . $this->id );
|
||||
\IPS\Lang::deleteCustom( 'cms', "cms_records" . $this->id . '_pl' );
|
||||
\IPS\Lang::deleteCustom( 'cms', "module__cms_records" . $this->id );
|
||||
|
||||
/* Unclaim attachments */
|
||||
\IPS\File::unclaimAttachments( 'content_Records_' . $this->id );
|
||||
\IPS\File::unclaimAttachments( 'cms_Records_' . $this->id );
|
||||
|
||||
/* Remove widgets */
|
||||
$this->removeWidgets();
|
||||
|
||||
|
||||
/* Best remove the stored data */
|
||||
unset( \IPS\Data\Store::i()->database_reciprocal_links );
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
@@ -890,6 +972,12 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
parent::setPermissions( $insert, $matrix );
|
||||
|
||||
/* Clear cache */
|
||||
if ( isset( \IPS\Data\Store::i()->cms_databases ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_databases );
|
||||
}
|
||||
|
||||
/* Clone these permissions to all categories that do not have permissions */
|
||||
$class = '\IPS\cms\Categories' . $this->id;
|
||||
foreach( $class::roots( NULL, NULL, array(), $this->id ) as $category )
|
||||
@@ -936,5 +1024,79 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
return $this->_numberOfCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if any fields from other databases are linking to items in this database via the Relational field
|
||||
*
|
||||
* @param int $databaseId The ID of the database
|
||||
* @return boolean
|
||||
*/
|
||||
public static function hasReciprocalLinking( $databaseId )
|
||||
{
|
||||
if ( isset( \IPS\Data\Store::i()->database_reciprocal_links ) )
|
||||
{
|
||||
$values = \IPS\Data\Store::i()->database_reciprocal_links;
|
||||
}
|
||||
else
|
||||
{
|
||||
$values = array();
|
||||
foreach( static::databases() as $database )
|
||||
{
|
||||
$fieldsClass = 'IPS\cms\Fields' . $database->_id;
|
||||
|
||||
foreach( $fieldsClass::data() as $field )
|
||||
{
|
||||
if ( $field->type === 'Item' )
|
||||
{
|
||||
$extra = $field->extra;
|
||||
if ( ! empty( $extra['database'] ) )
|
||||
{
|
||||
$values[ $database->_id ] = $extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->database_reciprocal_links = $values;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array( $values ) )
|
||||
{
|
||||
foreach( $values as $id => $data )
|
||||
{
|
||||
if ( $data['database'] == $databaseId and $data['crosslink'] )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the reciprocal linking maps across all databases
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildReciprocalLinkMaps()
|
||||
{
|
||||
/* Ensure the SPL are loaded from /cms/Application.php as this may be called by a task or upgrade module */
|
||||
\IPS\Application::load('cms');
|
||||
|
||||
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map' );
|
||||
|
||||
foreach( static::databases() as $database )
|
||||
{
|
||||
$fieldsClass = 'IPS\cms\Fields' . $database->_id;
|
||||
|
||||
foreach( $fieldsClass::data() as $field )
|
||||
{
|
||||
if ( $field->type === 'Item' )
|
||||
{
|
||||
\IPS\Task::queue( 'cms', 'RebuildReciprocalMaps', array( 'database' => $database->_id, 'field' => $field->id ), 2, array( 'field' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Database Dispatcher
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 16 April 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -61,7 +62,7 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
/**
|
||||
* @brief Output to return
|
||||
*/
|
||||
public $output = NULL;
|
||||
public $output = "";
|
||||
|
||||
/**
|
||||
* Set Database ID
|
||||
@@ -206,7 +207,6 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlug( $slug );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
}
|
||||
catch ( \OutOfRangeException $ex )
|
||||
@@ -216,7 +216,7 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
{
|
||||
$record = $recordClass::loadFromSlugHistory( $slug );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
$this->_redirectToCorrectUrl( $record->url() );
|
||||
}
|
||||
catch ( \OutOfRangeException $ex )
|
||||
{
|
||||
@@ -239,7 +239,7 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
/* Find the record */
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlug( $whatsLeft );
|
||||
$record = $recordClass::loadFromSlug( $whatsLeft, TRUE, $this->categoryId );
|
||||
|
||||
/* Make the Content controller all kinds of happy */
|
||||
\IPS\Request::i()->id = $this->recordId = $record->primary_id_field;
|
||||
@@ -251,7 +251,7 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
{
|
||||
$record = $recordClass::loadFromSlugHistory( $whatsLeft );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
$this->_redirectToCorrectUrl( $record->url() );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
@@ -259,6 +259,12 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure the URL is correct, for instance, it could have moved categories */
|
||||
if ( $database->use_categories AND $this->categoryId != $record->category_id )
|
||||
{
|
||||
$this->_redirectToCorrectUrl( $record->url() );
|
||||
}
|
||||
|
||||
$this->module = 'record';
|
||||
}
|
||||
else
|
||||
@@ -295,6 +301,34 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
return $this->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the "correct" URL (for example if the category slug is incorrect)
|
||||
* while retaining any query string parameters in the request URL
|
||||
* For example, an embed to a record might be example.com/records/cat-1/record/?do=embed
|
||||
* If the record is moved so the URL is cat-2, the embed needs to redirect while retaining
|
||||
* the /?do=embed
|
||||
*
|
||||
* @param \IPS\Http\Url $correctUrl The URL for the record
|
||||
* @return void
|
||||
*/
|
||||
protected function _redirectToCorrectUrl( $correctUrl )
|
||||
{
|
||||
$paramsToSet = array();
|
||||
foreach ( \IPS\Request::i()->url()->queryString as $k => $v )
|
||||
{
|
||||
if ( !array_key_exists( $k, $correctUrl->queryString ) and !array_key_exists( $k, $correctUrl->hiddenQueryString ) )
|
||||
{
|
||||
$paramsToSet[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
if ( count( $paramsToSet ) )
|
||||
{
|
||||
$correctUrl = $correctUrl->setQueryString( $paramsToSet );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $correctUrl, NULL, 301 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish
|
||||
*
|
||||
@@ -302,6 +336,6 @@ class _Dispatcher extends \IPS\Dispatcher
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
return $this->output;
|
||||
return (string) $this->output;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Soundcloud input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -56,6 +57,11 @@ class _Soundcloud extends \IPS\Helpers\Form\Text
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
if( !$value )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = $customField->extra;
|
||||
|
||||
if ( ! isset( $params['width'] ) )
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Spotify input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -56,6 +57,11 @@ class _Spotify extends \IPS\Helpers\Form\Text
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
if( !$value )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = $customField->extra;
|
||||
|
||||
if ( ! isset( $params['width'] ) )
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Youtube input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -56,6 +57,11 @@ class _Youtube extends \IPS\Helpers\Form\Text
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
if( !$value )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = new \IPS\Http\Url( $value );
|
||||
|
||||
if ( isset( $url->queryString['v'] ) )
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Folder Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 07 July 2015
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -72,6 +73,11 @@ class _Folder extends \IPS\Node\Model
|
||||
*/
|
||||
protected static $databaseIdFields = array('media_folder_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
@@ -200,7 +206,7 @@ class _Folder extends \IPS\Node\Model
|
||||
{
|
||||
try
|
||||
{
|
||||
$test = \IPS\cms\Media\Folder::load( \IPS\Http\Url::seoTitle( $val ), 'media_folder_name' );
|
||||
$test = \IPS\cms\Media\Folder::load( \IPS\Http\Url\Friendly::seoTitle( $val ), 'media_folder_name' );
|
||||
|
||||
if ( ! empty( \IPS\Request::i()->id ) and $test->id != \IPS\Request::i()->id )
|
||||
{
|
||||
@@ -264,7 +270,7 @@ class _Folder extends \IPS\Node\Model
|
||||
|
||||
if( isset( $values['media_folder_name'] ) )
|
||||
{
|
||||
$values['name'] = \IPS\Http\Url::seoTitle( $values['media_folder_name'] );
|
||||
$values['name'] = \IPS\Http\Url\Friendly::seoTitle( $values['media_folder_name'] );
|
||||
unset( $values['media_folder_name'] );
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Media Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 15 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Media extends \IPS\Node\Model
|
||||
*/
|
||||
protected static $databaseIdFields = array('media_full_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node ID Database Column
|
||||
*/
|
||||
@@ -387,9 +393,13 @@ class _Media extends \IPS\Node\Model
|
||||
chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ), \IPS\IPS_FOLDER_PERMISSION );
|
||||
}
|
||||
}
|
||||
|
||||
\file_put_contents( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\File::get( 'cms_Media', $media['media_file_object'] )->contents() );
|
||||
@chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\IPS_FILE_PERMISSION );
|
||||
|
||||
try
|
||||
{
|
||||
\file_put_contents( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\File::get( 'cms_Media', $media['media_file_object'] )->contents() );
|
||||
@chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\IPS_FILE_PERMISSION );
|
||||
}
|
||||
catch( \RuntimeException $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +484,7 @@ class _Media extends \IPS\Node\Model
|
||||
$contents = \file_get_contents( $dir->getRealPath() );
|
||||
|
||||
/* Create */
|
||||
$seen[] = static::createMedia( trim( str_replace( \IPS\ROOT_PATH . '/themes/cms/media', '', $dir->getRealPath() ), '/' ), $contents );
|
||||
$seen[] = static::createMedia( trim( str_replace( str_replace( '\\', '/', \IPS\ROOT_PATH ) . '/themes/cms/media', '', str_replace( '\\', '/', $dir->getRealPath() ) ), '/' ), $contents );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Folder Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 15 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -72,6 +73,11 @@ class _Folder extends \IPS\Node\Model
|
||||
*/
|
||||
protected static $databaseIdFields = array('folder_name', 'folder_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
@@ -120,6 +126,16 @@ class _Folder extends \IPS\Node\Model
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node titles can contain HTML. Apparently.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get__stripTagsTitle()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sortable name
|
||||
*
|
||||
@@ -181,7 +197,20 @@ class _Folder extends \IPS\Node\Model
|
||||
|
||||
if ( isset( $buttons['delete'] ) )
|
||||
{
|
||||
$return['delete'] = $buttons['delete'];
|
||||
if ( $this->getItemCount() )
|
||||
{
|
||||
$return['delete'] = array(
|
||||
'icon' => 'trash-o',
|
||||
'title' => 'empty',
|
||||
'link' => $url->setQueryString( array( 'do' => 'delete', 'id' => $this->_id, 'deleteNode' => 0 ) ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('empty') ),
|
||||
'hotkey'=> 'd'
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['delete'] = $buttons['delete'];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -200,7 +229,23 @@ class _Folder extends \IPS\Node\Model
|
||||
{
|
||||
try
|
||||
{
|
||||
$test = \IPS\cms\Pages\Folder::load( \IPS\Http\Url::seoTitle( $val ), 'folder_name' );
|
||||
$testPage = \IPS\cms\Pages\Page::load( $val, 'page_seo_name' );
|
||||
|
||||
/* Ok, we have a folder, but is it on the same tree as us ?*/
|
||||
if ( intval( \IPS\Request::i()->folder_parent_id ) == $testPage->folder_id )
|
||||
{
|
||||
/* Yep, this will break designers' mode and may confuse the FURL engine so we cannot allow this */
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision_folder');
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* Nothing with the same name, so that's proper good that is */
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$test = \IPS\cms\Pages\Folder::load( \IPS\Http\Url\Friendly::seoTitle( $val ), 'folder_name' );
|
||||
|
||||
if ( ! empty( \IPS\Request::i()->id ) and $test->id != \IPS\Request::i()->id )
|
||||
{
|
||||
@@ -210,7 +255,7 @@ class _Folder extends \IPS\Node\Model
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* If we hit here, we don't have an existing folder by that name so check for a collision */
|
||||
if ( \IPS\Request::i()->folder_parent_id == 0 AND \IPS\cms\Pages\Page::isFurlCollision( \IPS\Http\Url::seoTitle( $val ) ) )
|
||||
if ( \IPS\Request::i()->folder_parent_id == 0 AND \IPS\cms\Pages\Page::isFurlCollision( \IPS\Http\Url\Friendly::seoTitle( $val ) ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision');
|
||||
}
|
||||
@@ -260,7 +305,7 @@ class _Folder extends \IPS\Node\Model
|
||||
|
||||
if( isset( $values['folder_name'] ) )
|
||||
{
|
||||
$values['name'] = \IPS\Http\Url::seoTitle( $values['folder_name'] );
|
||||
$values['name'] = \IPS\Http\Url\Friendly::seoTitle( $values['folder_name'] );
|
||||
unset( $values['folder_name'] );
|
||||
}
|
||||
|
||||
@@ -322,6 +367,65 @@ class _Folder extends \IPS\Node\Model
|
||||
parent::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve item count (if applicable) for a node.
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
public function getItemCount()
|
||||
{
|
||||
return (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_pages', array( 'page_folder_id=?', $this->id ) )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to delete or move content
|
||||
*
|
||||
* @param bool $showMoveToChildren If TRUE, will show "move to children" even if there are no children
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
public function deleteOrMoveForm( $showMoveToChildren=FALSE )
|
||||
{
|
||||
$hasContent = $this->getItemCount();
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'form', 'delete' );
|
||||
|
||||
if ( $hasContent )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'cms_move_pages', 0, TRUE, array( 'class' => get_class( $this ), 'disabled' => array( $this->_id ), 'disabledLang' => 'node_move_delete', 'zeroVal' => 'cms_move_to_root', 'subnodes' => FALSE, 'permissionCheck' => function( $node )
|
||||
{
|
||||
return \IPS\Request::i()->id != $node->id;
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle submissions of form to delete or move content
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @param bool $deleteWhenDone Delete the node when done?
|
||||
* @return void
|
||||
*/
|
||||
public function deleteOrMoveFormSubmit( $values, $deleteWhenDone=TRUE )
|
||||
{
|
||||
if ( $values['cms_move_pages'] )
|
||||
{
|
||||
$folderId = $values['cms_move_pages']->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$folderId = 0;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'cms_pages', array( 'page_folder_id' => $folderId ), array( 'page_folder_id=?', $this->id ) );
|
||||
\IPS\Db::i()->update( 'cms_folders', array( 'folder_parent_id' => $folderId ), array( 'folder_id=?', $this->id ) );
|
||||
|
||||
/* Delete it */
|
||||
\IPS\Session::i()->log( 'acplog__node_deleted', array( $this->title => TRUE, $this->titleForLog() => FALSE ) );
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stored path
|
||||
*
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Page Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 15 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected static $databaseIdFields = array('page_seo_name', 'page_full_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
@@ -181,7 +187,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public static function loadFromUrl( \IPS\Http\Url $url )
|
||||
{
|
||||
$qs = array_merge( $url->queryString, $url->getFriendlyUrlData() );
|
||||
$qs = array_merge( $url->queryString, $url->hiddenQueryString );
|
||||
|
||||
if ( isset( $qs['id'] ) )
|
||||
{
|
||||
@@ -196,14 +202,15 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
else if ( isset( $qs['path'] ) )
|
||||
{
|
||||
if ( method_exists( get_called_class(), 'loadAndCheckPerms' ) )
|
||||
$return = static::load( $qs['path'], 'page_full_path' );
|
||||
if ( method_exists( $return, 'can' ) )
|
||||
{
|
||||
return static::loadAndCheckPerms( $qs['path'], 'page_full_path' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return static::load( $qs['path'], 'page_full_path' );
|
||||
if ( !$return->can( 'view' ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException;
|
||||
@@ -288,10 +295,17 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/* Nope - try a folder */
|
||||
try
|
||||
{
|
||||
$class = static::$parentNodeClass;
|
||||
$folder = $class::load( $path, 'folder_path' );
|
||||
|
||||
static::$loadedPagesFromPath[ $path ] = static::getDefaultPage( $folder->id );
|
||||
if ( $path )
|
||||
{
|
||||
$class = static::$parentNodeClass;
|
||||
$folder = $class::load( $path, 'folder_path' );
|
||||
|
||||
static::$loadedPagesFromPath[ $path ] = static::getDefaultPage( $folder->id );
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$loadedPagesFromPath[ $path ] = static::getDefaultPage( 0 );
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
@@ -323,12 +337,25 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Still here? It's possible this is a legacy URL that starts with "page" - last ditch effort */
|
||||
if ( static::$loadedPagesFromPath[ $path ] === NULL AND mb_substr( $path, 0, 5 ) === 'page/' )
|
||||
{
|
||||
$pathWithoutPage = str_replace( 'page/', '', $path );
|
||||
|
||||
try
|
||||
{
|
||||
/* Pass back recursively so we don't have to duplicate all of the checks again */
|
||||
static::$loadedPagesFromPath[ $path ] = static::loadFromPath( $pathWithoutPage );
|
||||
}
|
||||
catch( \OutOfRangeException $e ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( static::$loadedPagesFromPath[ $path ] === NULL )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
@@ -360,14 +387,12 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_url_store', array( 'store_type=? and ? LIKE CONCAT( store_path, \'%\') OR store_path=?', 'page', $slug, $slug ) ) as $item )
|
||||
{
|
||||
$url = static::load( $item['store_current_id'] )->url();
|
||||
|
||||
$url->data['path'] = '/' . trim( str_replace( $item['store_path'], trim( $url->data['path'], '/' ), $slug ), '/' );
|
||||
|
||||
$url = $url->setPath( '/' . trim( str_replace( $item['store_path'], trim( $url->data['path'], '/' ), $slug ), '/' ) );
|
||||
if ( $queryString !== NULL )
|
||||
{
|
||||
$url->data['query'] = $queryString;
|
||||
$url = $url->setQueryString( $queryString );
|
||||
}
|
||||
return \IPS\Http\Url::createFromArray( $url->data );
|
||||
return $url;
|
||||
}
|
||||
|
||||
/* Still here? Ok, now we may have changed the folder name at some point, so lets look for that */
|
||||
@@ -515,13 +540,20 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$page = static::load( \IPS\Settings::i()->cms_error_page );
|
||||
$page->content = str_replace( '{error_message}', $message, $page->content );
|
||||
$page->content = str_replace( '{error_code}', $code, $page->content );
|
||||
|
||||
|
||||
/* Pages are compiled and cached, which we do not want for the error page as the {error_*} tags are saved with their text content */
|
||||
$functionName = 'content_pages_' . $page->id;
|
||||
if ( isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
}
|
||||
|
||||
$page->output( $title, $httpStatusCode, $httpHeaders );
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['enabled'] = FALSE;
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( $title, \IPS\Theme::i()->getTemplate( 'global', 'core' )->error( $title, $message, $code, NULL ), array( 'app' => \IPS\Dispatcher::i()->application ? \IPS\Dispatcher::i()->application->directory : NULL, 'module' => \IPS\Dispatcher::i()->module ? \IPS\Dispatcher::i()->module->key : NULL, 'controller' => \IPS\Dispatcher::i()->controller ) ), $httpStatusCode, 'text/html', $httpHeaders, FALSE, FALSE );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( $title, \IPS\Theme::i()->getTemplate( 'global', 'core' )->error( $title, $message, $code, NULL, \IPS\Member::loggedIn() ), array( 'app' => \IPS\Dispatcher::i()->application ? \IPS\Dispatcher::i()->application->directory : NULL, 'module' => \IPS\Dispatcher::i()->module ? \IPS\Dispatcher::i()->module->key : NULL, 'controller' => \IPS\Dispatcher::i()->controller ) ), $httpStatusCode, 'text/html', $httpHeaders, FALSE, FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,9 +581,32 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if ( empty( $val ) )
|
||||
{
|
||||
$val = \IPS\Http\Url::seoTitle( $val );
|
||||
$val = \IPS\Http\Url\Friendly::seoTitle( $val );
|
||||
}
|
||||
|
||||
|
||||
/* We cannot have a page name the same as a folder name in this folder */
|
||||
try
|
||||
{
|
||||
$testFolder = \IPS\cms\Pages\Folder::load( $val, 'folder_name' );
|
||||
|
||||
/* Ok, we have a folder, but is it on the same tree as us ?*/
|
||||
if ( intval( \IPS\Request::i()->page_folder_id ) == $testFolder->parent_id )
|
||||
{
|
||||
/* Yep, this will break designers' mode and may confuse the FURL engine so we cannot allow this */
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision_pages');
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* Nothing with the same name, so that's proper good that is */
|
||||
}
|
||||
|
||||
/* If we hit here, we don't have an existing name so that's good */
|
||||
if ( ! \IPS\Request::i()->page_folder_id and \IPS\cms\Pages\Page::isFurlCollision( $val ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision_pages_app');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$test = \IPS\cms\Pages\Page::load( $val, 'page_seo_name' );
|
||||
@@ -572,18 +627,14 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* If we hit here, we don't have an existing name so that's good */
|
||||
if ( ! \IPS\Request::i()->page_folder_id and \IPS\cms\Pages\Page::isFurlCollision( $val ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision');
|
||||
}
|
||||
/* An exception means we don't have a match, so that is good */
|
||||
}
|
||||
}, NULL, NULL, 'page_seo_name' );
|
||||
|
||||
$return['page_folder_id'] = new \IPS\Helpers\Form\Node( 'page_folder_id', ( $item ? intval( $item->folder_id ) : ( ( isset( \IPS\Request::i()->parent ) and \IPS\Request::i()->parent ) ? \IPS\Request::i()->parent : 0 ) ), FALSE, array(
|
||||
'class' => '\IPS\cms\Pages\Folder',
|
||||
'class' => 'IPS\cms\Pages\Folder',
|
||||
'zeroVal' => 'node_no_parent',
|
||||
'subnodes' => false
|
||||
), NULL, NULL, NULL, 'page_folder_id' );
|
||||
@@ -705,6 +756,35 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
throw new \LogicException('cms_page_error_bad_syntax');
|
||||
}
|
||||
|
||||
/* New page? quick check to see if we added a DB tag, and if so, make sure it's not being used on another page. */
|
||||
if ( ! isset( \IPS\Request::i()->id ) )
|
||||
{
|
||||
preg_match( '#{database="([^"]+?)"#', $val, $matches );
|
||||
if ( isset( $matches[1] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( is_numeric( $matches[1] ) )
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( intval( $matches[1] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $matches[1], 'database_key' );
|
||||
}
|
||||
|
||||
if ( $database->page_id )
|
||||
{
|
||||
throw new \LogicException('cms_err_db_in_use_other_page');
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
throw new \LogicException('cms_err_db_does_not_exist');
|
||||
}
|
||||
}
|
||||
}
|
||||
}, NULL, NULL, 'page_content' );
|
||||
}
|
||||
|
||||
@@ -752,7 +832,13 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$path = trim( $path , '/');
|
||||
$bits = explode( '/', $path );
|
||||
$folder = $bits[0];
|
||||
|
||||
|
||||
/* Ensure we cannot have a structure that starts with core/interface as we have this partial URL blacklisted in \IPS\Text\Parser::safeIframeRegexp() */
|
||||
if ( mb_substr( $path, 0, 15 ) == 'core/interface/' )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
$defaultApplication = \IPS\Db::i()->select( 'app_directory', 'core_applications', 'app_default=1' )->first();
|
||||
|
||||
foreach( \IPS\Application::applications() as $key => $app )
|
||||
@@ -792,6 +878,21 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still here? Some apps use very loose matching, like calendar looks for {id}-{?} which may conflict with a page with a filename of 123-foo */
|
||||
try
|
||||
{
|
||||
$url = \IPS\Http\Url::createFromString( \IPS\Http\Url::baseUrl() . $path );
|
||||
|
||||
if ( $url and $url instanceof \IPS\Http\Url\Friendly and $url->seoTemplate !== 'content_page_path' )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
/* If we get an error, then it cannot be a legitimate link */
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -814,6 +915,18 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public static function buildPageUrlStore()
|
||||
{
|
||||
/* This fails because hooks are not installed when this is attempted to build via admin/install */
|
||||
if ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'setup' )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* This also fails if we're installing via ACP */
|
||||
if ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'admin' and isset( \IPS\Request::i()->do ) and \IPS\Request::i()->do == 'install' )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$store = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_pages' ), 'IPS\cms\Pages\Page' ) as $page )
|
||||
{
|
||||
@@ -839,7 +952,6 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
return \IPS\Data\Store::i()->pages_page_urls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set JS/CSS include keys
|
||||
*
|
||||
@@ -1031,16 +1143,30 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
$functionName = 'content_pages_' . $this->id;
|
||||
|
||||
if ( ! isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->$functionName = \IPS\Theme::compileTemplate( $this->content, $functionName, null, true );
|
||||
if ( \IPS\Theme::i()->designersModeEnabled() and file_exists( \IPS\ROOT_PATH . '/themes/cms/pages/' . $this->full_path ) )
|
||||
{
|
||||
$contents = @file_get_contents( \IPS\ROOT_PATH . '/themes/cms/pages/' . $this->full_path );
|
||||
$contents = preg_replace( '#^<ips:pages.+?/>(\r\n?|\n)#', '', $contents );
|
||||
\IPS\Theme::runProcessFunction( \IPS\Theme::compileTemplate( $contents, $functionName, null, true ), $functionName );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->$functionName = \IPS\Theme::compileTemplate( $this->content, $functionName, null, true );
|
||||
}
|
||||
|
||||
\IPS\Theme::runProcessFunction( \IPS\Data\Store::i()->$functionName, $functionName );
|
||||
}
|
||||
|
||||
\IPS\Theme::runProcessFunction( \IPS\Data\Store::i()->$functionName, $functionName );
|
||||
|
||||
return call_user_func( 'IPS\\Theme\\'. $functionName );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cached widgets
|
||||
*/
|
||||
protected $cachedWidgets = NULL;
|
||||
|
||||
/**
|
||||
* Return the blocks for this page
|
||||
*
|
||||
@@ -1048,10 +1174,16 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public function getWidgets()
|
||||
{
|
||||
$widgets = array();
|
||||
$return = array();
|
||||
$dbWidgets = array();
|
||||
$areas = array();
|
||||
if( $this->cachedWidgets !== NULL )
|
||||
{
|
||||
return $this->cachedWidgets;
|
||||
}
|
||||
|
||||
$this->cachedWidgets = array();
|
||||
|
||||
$widgets = array();
|
||||
$dbWidgets = array();
|
||||
$areas = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas', array( 'area_page_id=?', $this->id ) ) as $k => $widgetMain )
|
||||
{
|
||||
@@ -1104,17 +1236,17 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
\IPS\Output::i()->sidebar['widgets'][ $areaKey ][] = $_widget;
|
||||
}
|
||||
|
||||
$return[ $areaKey ][] = $_widget;
|
||||
$this->cachedWidgets[ $areaKey ][] = $_widget;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Log::i( LOG_ERR )->write( $e->getMessage() );
|
||||
\IPS\Log::debug( $e, 'pages_widgets' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $this->cachedWidgets;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1212,7 +1344,6 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
if ( ! $this->id )
|
||||
{
|
||||
$form->hiddenValues['page_type'] = $pageType = \IPS\Request::i()->page_type;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1301,7 +1432,10 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
}
|
||||
|
||||
$form->addButton( 'save_and_reload', 'submit', null, 'ipsButton ipsButton_primary', array( 'name' => 'save_and_reload', 'value' => 1 ) );
|
||||
if( $this->id )
|
||||
{
|
||||
$form->canSaveAndReload = true;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = $this->id ? \IPS\Member::loggedIn()->language()->addToStack('content_editing_page', NULL, array( 'sprintf' => array( $this->_title ) ) ) : \IPS\Member::loggedIn()->language()->addToStack('content_add_page');
|
||||
}
|
||||
@@ -1335,7 +1469,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$bits = explode( '.', $values['page_seo_name'] );
|
||||
foreach( $bits as $i => $v )
|
||||
{
|
||||
$bits[ $i ] = \IPS\Http\Url::seoTitle( $v );
|
||||
$bits[ $i ] = \IPS\Http\Url\Friendly::seoTitle( $v );
|
||||
}
|
||||
|
||||
$values['page_seo_name'] = implode( '.', $bits );
|
||||
@@ -1390,23 +1524,19 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if( $values['page_add_to_menu'] )
|
||||
{
|
||||
$values = \IPS\cms\extensions\core\FrontNavigation\Pages::parseConfiguration( $values, $this->id );
|
||||
$config = array( 'menu_content_page' => $this->id );
|
||||
$permission = $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] );
|
||||
|
||||
foreach( array( 'menu_title_page_type', 'menu_title_page' ) as $field )
|
||||
if ( $values['menu_manager_access_type'] === 0 )
|
||||
{
|
||||
if ( isset( $values[ $field ] ) )
|
||||
{
|
||||
$config[ $field ] = $values[ $field ];
|
||||
}
|
||||
$permission = '';
|
||||
}
|
||||
|
||||
|
||||
$save = array(
|
||||
'app' => 'cms',
|
||||
'extension' => 'Pages',
|
||||
'config' => json_encode( $config ),
|
||||
'config' => '',
|
||||
'parent' => $values['menu_parent'],
|
||||
'permissions' => $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] )
|
||||
'permissions' => $permission
|
||||
);
|
||||
|
||||
try
|
||||
@@ -1418,7 +1548,21 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
$save['position'] = 1;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'core_menu', $save );
|
||||
$id = \IPS\Db::i()->insert( 'core_menu', $save );
|
||||
|
||||
$values = \IPS\cms\extensions\core\FrontNavigation\Pages::parseConfiguration( $values, $id );
|
||||
$config = array( 'menu_content_page' => $this->id );
|
||||
|
||||
foreach( array( 'menu_title_page_type', 'menu_title_page' ) as $field )
|
||||
{
|
||||
if ( isset( $values[ $field ] ) )
|
||||
{
|
||||
$config[ $field ] = $values[ $field ];
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_menu', array( 'config' => json_encode( $config ) ), array( 'id=?', $id ) );
|
||||
|
||||
unset( \IPS\Data\Store::i()->frontNavigation );
|
||||
}
|
||||
|
||||
@@ -1530,9 +1674,19 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if( $this->_url === NULL )
|
||||
{
|
||||
if ( \IPS\Application::load('cms')->default AND $this->default AND ! $this->folder_id )
|
||||
if ( ( \IPS\Application::load('cms')->default OR \IPS\Settings::i()->cms_use_different_gateway ) AND $this->default AND ! $this->folder_id )
|
||||
{
|
||||
$this->_url = \IPS\Http\Url::internal( '', 'front' );
|
||||
/* Are we using the gateway file? */
|
||||
if ( \IPS\Settings::i()->cms_use_different_gateway )
|
||||
{
|
||||
/* Yes, work out the proper URL. */
|
||||
$this->_url = \IPS\Http\Url::createFromString( \IPS\Settings::i()->cms_root_page_url, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No - that's easy */
|
||||
$this->_url = \IPS\Http\Url::internal( '', 'front' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1611,7 +1765,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
if ( isset( $seen['database'] ) )
|
||||
{
|
||||
/* Yep, is it the same ID? */
|
||||
if ( $seen['database']['value'] != $database->id )
|
||||
if ( $seen['database']['value'] != $database->id AND $seen['database']['value'] != $database->key )
|
||||
{
|
||||
/* There's been a change.. */
|
||||
try
|
||||
@@ -1805,8 +1959,13 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}
|
||||
|
||||
unset( \IPS\Data\Store::i()->frontNavigation );
|
||||
|
||||
return parent::delete();
|
||||
|
||||
parent::delete();
|
||||
|
||||
if ( $this->full_path and \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
static::cleanUpDesignersModeFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1878,6 +2037,11 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
parent::save();
|
||||
|
||||
static::buildPageUrlStore();
|
||||
|
||||
if ( $this->full_path and \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
static::exportDesignersMode( $this->id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1897,8 +2061,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
public function setAsDefault()
|
||||
{
|
||||
\IPS\DB::i()->update( 'cms_pages', array( 'page_default' => 0 ), array( 'page_folder_id=?', $this->folder_id ) );
|
||||
\IPS\DB::i()->update( 'cms_pages', array( 'page_default' => 1 ), array( 'page_id=?', $this->id ) );
|
||||
\IPS\Db::i()->update( 'cms_pages', array( 'page_default' => 0 ), array( 'page_folder_id=?', $this->folder_id ) );
|
||||
\IPS\Db::i()->update( 'cms_pages', array( 'page_default' => 1 ), array( 'page_id=?', $this->id ) );
|
||||
|
||||
static::buildPageUrlStore();
|
||||
}
|
||||
@@ -1918,8 +2082,9 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/**
|
||||
* Displays a page
|
||||
*
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @param string|NULL $title The Page title
|
||||
* @param int $httpStatusCode HTTP Status Code
|
||||
* @param array $httpHeaders Additional HTTP Headers
|
||||
* @throws \ErrorException
|
||||
* @return void
|
||||
*/
|
||||
@@ -1956,7 +2121,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/* Populate \IPS\Output::i()->sidebar['widgets'] sidebar/header/footer widgets */
|
||||
$this->getWidgets();
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('pages')->globalWrap( $nav, $this->getHtmlContent(), $this );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'pages', 'cms' )->globalWrap( $nav, $this->getHtmlContent(), $this );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sidebar['enabled'] = true;
|
||||
@@ -1972,6 +2137,12 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
\IPS\Output::i()->metaTags['description'] = $this->meta_description;
|
||||
}
|
||||
|
||||
/* If this is a default page, we may be accessing this from the folder only */
|
||||
if ( $this->default )
|
||||
{
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) $this->url();
|
||||
}
|
||||
|
||||
/* Can only disable sidebar if HTML page */
|
||||
if ( ! $this->show_sidebar and $this->type === 'html' )
|
||||
@@ -2050,4 +2221,224 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
\IPS\Output::i()->sendOutput( $this->getHtmlContent(), ( $httpStatusCode ? $httpStatusCode : 200 ), $this->getContentType(), ( $httpHeaders ? $httpHeaders : \IPS\Output::i()->httpHeaders ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write HTML pages to disk for designer's mode
|
||||
*
|
||||
* @param NULL|int $pageId Single page to export
|
||||
* @return void
|
||||
*/
|
||||
public static function exportDesignersMode( $pageId=NULL)
|
||||
{
|
||||
$where = array( array( 'page_type=?', 'html' ) );
|
||||
$seen = array();
|
||||
|
||||
if ( $pageId )
|
||||
{
|
||||
$where[] = array( 'page_id=?', $pageId );
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_pages', $where ) as $page )
|
||||
{
|
||||
/* We could use recursive mode but it wouldn't correctly chmod the intermediate dirs */
|
||||
$bits = explode( '/', "/themes/cms/pages/" . $page['page_full_path'] );
|
||||
$dir = '';
|
||||
|
||||
$filename = array_pop( $bits );
|
||||
|
||||
foreach( $bits as $part )
|
||||
{
|
||||
$dir .= $part . '/';
|
||||
|
||||
if ( ! is_dir( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) ) )
|
||||
{
|
||||
mkdir( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ), \IPS\IPS_FOLDER_PERMISSION );
|
||||
chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ), \IPS\IPS_FOLDER_PERMISSION );
|
||||
}
|
||||
}
|
||||
|
||||
$headers = array();
|
||||
|
||||
foreach( array( 'page_seo_name', 'page_ipb_wrapper', 'page_title') as $field )
|
||||
{
|
||||
$headers[ $field ] = $field . '="' . str_replace( '"', '\\"', $page[ $field ] ) . '"';
|
||||
}
|
||||
|
||||
$header = "<ips:pages " . implode( " ", $headers ) . " />";
|
||||
try
|
||||
{
|
||||
\file_put_contents( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, $header . "\n" . $page['page_content'] );
|
||||
@chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\IPS_FILE_PERMISSION );
|
||||
}
|
||||
catch( \RuntimeException $e ) { }
|
||||
}
|
||||
|
||||
/* Clear out any older designer mode files */
|
||||
if ( ! $pageId )
|
||||
{
|
||||
static::cleanUpDesignersModeFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any old designer mode files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function cleanUpDesignersModeFiles()
|
||||
{
|
||||
$diskPaths = array();
|
||||
static::getCurrentDesignersModeFilePaths( $diskPaths, \IPS\ROOT_PATH . "/themes/cms/pages/" );
|
||||
|
||||
$databasePaths = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_pages', array( 'page_type=?', 'html' ) ) as $page )
|
||||
{
|
||||
$databasePaths[] = $page['page_full_path'];
|
||||
}
|
||||
|
||||
if ( count( $diskPaths ) )
|
||||
{
|
||||
foreach( $diskPaths as $path )
|
||||
{
|
||||
if ( ! in_array( $path, $databasePaths ) )
|
||||
{
|
||||
@unlink( \IPS\ROOT_PATH . "/themes/cms/pages/" . $path );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing designer's mode page paths
|
||||
*
|
||||
* @param array $paths Array of processed page paths
|
||||
* @param string $path Path to look into
|
||||
* @return void
|
||||
*/
|
||||
public static function getCurrentDesignersModeFilePaths( &$paths, $path )
|
||||
{
|
||||
if ( is_dir( $path ) )
|
||||
{
|
||||
foreach ( new \DirectoryIterator( $path ) as $dir )
|
||||
{
|
||||
if ( $dir->isDot() || mb_substr( $dir->getFilename(), 0, 1 ) === '.' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $dir->isDir() )
|
||||
{
|
||||
static::getCurrentDesignersModeFilePaths( $paths, $dir->getRealPath() );
|
||||
}
|
||||
else
|
||||
{
|
||||
$paths[] = trim( str_replace( \IPS\ROOT_PATH . '/themes/cms/pages/', '', $dir->getRealPath() ), '/' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import media from disk for designer's mode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function importDesignersMode()
|
||||
{
|
||||
$path = \IPS\ROOT_PATH . '/themes/cms/pages';
|
||||
$seen = array();
|
||||
|
||||
/* Grab folder data */
|
||||
if ( is_dir( $path ) )
|
||||
{
|
||||
static::importDesignersModeRecurse( $seen, $path );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'cms_pages', array( 'page_type=? and ' . \IPS\Db::i()->in( 'page_id', $seen, TRUE ), 'html' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Import media from disk for designer's mode recursive method
|
||||
*
|
||||
* @param array $seen Array of processed page IDs
|
||||
* @param string $path Path to look into
|
||||
* @return void
|
||||
*/
|
||||
public static function importDesignersModeRecurse( &$seen, $path )
|
||||
{
|
||||
if ( is_dir( $path ) )
|
||||
{
|
||||
foreach ( new \DirectoryIterator( $path ) as $dir )
|
||||
{
|
||||
if ( $dir->isDot() || mb_substr( $dir->getFilename(), 0, 1 ) === '.' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $dir->isDir() )
|
||||
{
|
||||
static::importDesignersModeRecurse( $seen, $dir->getRealPath() );
|
||||
}
|
||||
else
|
||||
{
|
||||
$folders = \IPS\cms\Pages\Folder::roots();
|
||||
$contents = \file_get_contents( $dir->getRealPath() );
|
||||
$params = array();
|
||||
|
||||
/* Parse the header tag */
|
||||
preg_match( '#^<ips:pages(.+?)/>(\r\n?|\n)#', $contents, $params );
|
||||
|
||||
/* Strip it */
|
||||
$contents = ( isset($params[0]) ) ? str_replace( $params[0], '', $contents ) : $contents;
|
||||
|
||||
/* Get fields */
|
||||
preg_match_all( '#([a-z\-_]+?)="(.+?)"#', $params[1], $data, PREG_SET_ORDER );
|
||||
|
||||
$fields = array();
|
||||
foreach( $data as $id => $matches )
|
||||
{
|
||||
$fields[ $data[ $id ][1] ] = $data[ $id ][2];
|
||||
}
|
||||
|
||||
/* Existing page, or a new one? */
|
||||
$fullPath = trim( str_replace( str_replace( '\\', '/', \IPS\ROOT_PATH ) . '/themes/cms/pages', '', str_replace( '\\', '/', $dir->getRealPath() ) ), '/' );
|
||||
$bits = explode( '/', $fullPath );
|
||||
$fileName = array_pop( $bits );
|
||||
$path = implode( '/', $bits );
|
||||
|
||||
try
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::load( $fullPath, 'page_full_path' );
|
||||
$page->content = $contents;
|
||||
$page->save();
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$folderId = 0;
|
||||
foreach( $folders as $folder )
|
||||
{
|
||||
if ( $folder->path == $path )
|
||||
{
|
||||
$folderId = $folder->id;
|
||||
}
|
||||
}
|
||||
/* Doesn't exist, so this is new */
|
||||
$page = new \IPS\cms\Pages\Page;
|
||||
$page->content = $contents;
|
||||
$page->full_path = $fullPath;
|
||||
$page->seo_name = $fileName;
|
||||
$page->type = 'html';
|
||||
$page->title = ( isset( $fields['page_title'] ) ) ? $fields['page_title'] : $fileName;
|
||||
$page->ipb_wrapper = ( isset( $fields['page_ipb_wrapper'] ) ) ? $fields['page_ipb_wrapper'] : 1;
|
||||
$page->folder_id = $folderId;
|
||||
$page->save();
|
||||
|
||||
\IPS\Lang::saveCustom( 'cms', "cms_page_" . $page->id, $page->title );
|
||||
}
|
||||
|
||||
$seen[] = $page->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
/**
|
||||
* @brief Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Board
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 8 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -103,6 +103,11 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
|
||||
*/
|
||||
public static $hideLogKey = 'ccs-records';
|
||||
|
||||
/**
|
||||
* @brief Store generated search index titles for efficiency
|
||||
*/
|
||||
protected static $searchIndexTitles = array();
|
||||
|
||||
/**
|
||||
* Return custom where for SQL delete
|
||||
*
|
||||
@@ -113,7 +118,45 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
|
||||
{
|
||||
return array( array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=?', $id ), array( static::$databasePrefix . 'database_id=?', static::$customDatabaseId ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML for search result display
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param bool $iPostedIn If the user has posted in the item
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
* @param bool $asItem Displaying results as items?
|
||||
* @param bool $canIgnoreComments Can ignore comments in the result stream? Activity stream can, but search results cannot.
|
||||
* @param array $template Optional custom template
|
||||
* @return string
|
||||
*/
|
||||
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments=FALSE, $template=NULL )
|
||||
{
|
||||
/* Ensure that the comment title is formatted correctly */
|
||||
try
|
||||
{
|
||||
$databases = \IPS\cms\Databases::databases();
|
||||
|
||||
if ( ! isset( static::$searchIndexTitles[ $itemData['primary_id_field'] ] ) )
|
||||
{
|
||||
$fields = '\IPS\cms\Fields' . static::$customDatabaseId;
|
||||
$titleField = $databases[ static::$customDatabaseId ]->field_title;
|
||||
|
||||
static::$searchIndexTitles[ $itemData['primary_id_field'] ] = $fields::load( $databases[ static::$customDatabaseId ]->field_title )->displayValue( $itemData['field_' . $databases[ static::$customDatabaseId ]->field_title ] );
|
||||
}
|
||||
|
||||
$itemData['field_' . $databases[ static::$customDatabaseId ]->field_title ] = static::$searchIndexTitles[ $itemData['primary_id_field'] ];
|
||||
}
|
||||
catch ( \Exception $ex ) { }
|
||||
|
||||
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments, $template );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do stuff after creating (abstracted as comments and reviews need to do different things)
|
||||
*
|
||||
@@ -164,7 +207,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
public function url( $action='find' )
|
||||
{
|
||||
$url = parent::url( $action );
|
||||
|
||||
@@ -172,6 +215,8 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
|
||||
{
|
||||
$url = $url->setQueryString( 'd', static::$customDatabaseId );
|
||||
}
|
||||
|
||||
$url = $url->setQueryString( 'tab', 'comments' );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Forum Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 8 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -126,7 +127,7 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
|
||||
$comment->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Edit Comment Contents - Note: does not add edit log
|
||||
*
|
||||
* @param string $newContent New content
|
||||
@@ -138,6 +139,18 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
|
||||
$comment->editContents( $newContent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Report
|
||||
*
|
||||
* @param string $reportContent Report content message from member
|
||||
* @return \\IPS\core\Reports\Report
|
||||
* @throws \UnexpectedValueException If there is a permission error - you should only call this method after checking canReport
|
||||
*/
|
||||
public function report( $reportContent )
|
||||
{
|
||||
$comment = \IPS\forums\Topic\Post::load( $this->pid );
|
||||
return $comment->report( $reportContent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition where needed for fetching comments
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,10 +2,10 @@
|
||||
/**
|
||||
* @brief Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Board
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 8 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -107,17 +107,19 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\ReportCenter,
|
||||
/**
|
||||
* Create first comment (created with content item)
|
||||
*
|
||||
* @param \IPS\Content\Item $item The content item just created
|
||||
* @param string $comment The comment
|
||||
* @param bool $first Is the first comment?
|
||||
* @param int $rating The rating (1-5)
|
||||
* @param string $guestName If author is a guest, the name to use
|
||||
* @param \IPS\Member|NULL $member The author of this comment. If NULL, uses currently logged in member.
|
||||
* @param \IPS\DateTime|NULL $time The time
|
||||
* @param \IPS\Content\Item $item The content item just created
|
||||
* @param string $comment The comment
|
||||
* @param bool $first Is the first comment?
|
||||
* @param int $rating The rating (1-5)
|
||||
* @param string $guestName If author is a guest, the name to use
|
||||
* @param \IPS\Member|NULL $member The author of this comment. If NULL, uses currently logged in member.
|
||||
* @param \IPS\DateTime|NULL $time The time
|
||||
* @param string|NULL $ipAddress The IP address or NULL to detect automatically
|
||||
* @param int|NULL $hiddenStatus NULL to set automatically or override: 0 = unhidden; 1 = hidden, pending moderator approval; -1 = hidden (as if hidden by a moderator)
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function create( $item, $comment, $first=FALSE, $rating=NULL, $guestName=NULL, $member=NULL, \IPS\DateTime $time=NULL )
|
||||
public static function create( $item, $comment, $first=FALSE, $rating=NULL, $guestName=NULL, $member=NULL, \IPS\DateTime $time=NULL, $ipAddress=NULL, $hiddenStatus=NULL )
|
||||
{
|
||||
$review = call_user_func_array( 'parent::create', func_get_args() );
|
||||
|
||||
@@ -179,4 +181,14 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\ReportCenter,
|
||||
$commentIdColumn = static::$databaseColumnId;
|
||||
return array( $this->item()->$idColumn, $this->$commentIdColumn, static::$customDatabaseId . '-review' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition where needed for fetching comments
|
||||
*
|
||||
* @return array|NULL
|
||||
*/
|
||||
public static function commentWhere()
|
||||
{
|
||||
return array( 'review_database_id=?', static::$customDatabaseId );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Revisions Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 29 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -99,25 +100,14 @@ class _Revisions extends \IPS\Patterns\ActiveRecord
|
||||
$customFields = $fieldsClass::data( 'view' );
|
||||
$conflicts = array();
|
||||
|
||||
require_once \IPS\ROOT_PATH . "/system/3rd_party/Diff/class.Diff.php";
|
||||
|
||||
/* Build up our data set */
|
||||
foreach( $customFields as $id => $field )
|
||||
{
|
||||
$key = 'field_' . $field->id;
|
||||
|
||||
$conflicts[ $key ] = array( 'revision' => $this->get( $key ), 'record' => $record->$key, 'field' => $field, 'diff' => NULL );
|
||||
|
||||
if ( $record->$key AND $this->get( $key ) )
|
||||
if( $justChanged === FALSE OR !\IPS\Login::compareHashes( md5( $record->$key ), md5( $this->get( $key ) ) ) )
|
||||
{
|
||||
if ( md5( $record->$key ) != md5( $this->get( $key ) ) )
|
||||
{
|
||||
$conflicts[ $key ]['diff'] = \Diff::toTable( \Diff::compare( $this->get( $key ), $record->$key ) );
|
||||
}
|
||||
else if ( $justChanged !== FALSE )
|
||||
{
|
||||
unset( $conflicts[ $key ] );
|
||||
}
|
||||
$conflicts[ md5( uniqid() ) ] = array( 'original' => $this->get( $key ), 'current' => $record->$key, 'field' => $field );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Categories Selector Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 20 July 2015
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -58,6 +59,11 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected static $databaseIdFields = array('category_furl_name', 'category_full_path');
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Databases Selector Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 20 July 2015
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'database_key', 'database_page_id' );
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Templates Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 25 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,6 +49,11 @@ class _Container extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'container_key' );
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief Have fetched all?
|
||||
*/
|
||||
@@ -115,7 +121,7 @@ class _Container extends \IPS\Patterns\ActiveRecord
|
||||
/* Create a unique key */
|
||||
if ( empty( $newContainer->key ) )
|
||||
{
|
||||
$newContainer->key = 'template__' . \IPS\Http\Url::seoTitle( $newContainer->name ) . '.' . $newContainer->id;
|
||||
$newContainer->key = 'template__' . \IPS\Http\Url\Friendly::seoTitle( $newContainer->name ) . '.' . $newContainer->id;
|
||||
$newContainer->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Templates Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 25 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -47,6 +48,11 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'template_key', 'template_id' );
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Map
|
||||
*/
|
||||
protected static $multitonMap = array();
|
||||
|
||||
/**
|
||||
* @brief Retusn all types
|
||||
@@ -92,7 +98,74 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
* @brief Return both IN_DEV and database templates
|
||||
*/
|
||||
const RETURN_DATABASE_AND_IN_DEV = 256;
|
||||
|
||||
/**
|
||||
* @brief Default database template group names
|
||||
*/
|
||||
public static $databaseDefaults = array(
|
||||
'featured' => 'category_articles',
|
||||
'form' => 'form',
|
||||
'display' => 'display',
|
||||
'listing' => 'listing',
|
||||
'categories' => 'category_index'
|
||||
);
|
||||
|
||||
/**
|
||||
* Ensure that the template is calling the correct groups
|
||||
*
|
||||
* @param string $group Group to load templates from
|
||||
* @return void
|
||||
*/
|
||||
public static function fixTemplateTags( $group )
|
||||
{
|
||||
$templates = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_templates', array( array( 'template_group=?', $group ) ) )->setKeyField('template_title') );
|
||||
|
||||
foreach( $templates as $template )
|
||||
{
|
||||
$save = array();
|
||||
|
||||
/* Make sure template tags call the correct group */
|
||||
if ( mb_stristr( $template['template_content'], '{template' ) )
|
||||
{
|
||||
preg_match_all( '/\{([a-z]+?=([\'"]).+?\\2 ?+)}/', $template['template_content'], $matches, PREG_SET_ORDER );
|
||||
|
||||
/* Work out the plugin and the values to pass */
|
||||
foreach( $matches as $index => $array )
|
||||
{
|
||||
preg_match_all( '/(.+?)=' . $array[ 2 ] . '(.+?)' . $array[ 2 ] . '\s?/', $array[ 1 ], $submatches );
|
||||
|
||||
$plugin = array_shift( $submatches[ 1 ] );
|
||||
if ( $plugin == 'template' )
|
||||
{
|
||||
$value = array_shift( $submatches[ 2 ] );
|
||||
$options = array();
|
||||
|
||||
foreach ( $submatches[ 1 ] as $k => $v )
|
||||
{
|
||||
$options[ $v ] = $submatches[ 2 ][ $k ];
|
||||
}
|
||||
|
||||
if ( isset( $options['app'] ) and $options['app'] == 'cms' and isset( $options['location'] ) and $options['location'] == 'database' and isset( $options['group'] ) and $options['group'] != $template['template_original_group'] )
|
||||
{
|
||||
if ( in_array( $value, array_keys( $templates ) ) )
|
||||
{
|
||||
$options['group'] = $group;
|
||||
|
||||
$replace = '{template="' . $value . '" app="' . $options['app'] . '" location="' . $options['location'] . '" group="' . $options['group'] . '" params="' . ( isset($options['params']) ? $options['params'] : NULL ) . '"}';
|
||||
$save['template_content'] = str_replace( $matches[$index][0], $replace, $template['template_content'] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $save ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_templates', $save, array( 'template_id=?', $template['template_id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Record
|
||||
* Overloaded so we can force loading by key by default but still retain the template_id field as the primary key so
|
||||
@@ -395,7 +468,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
$newTemplate->save();
|
||||
|
||||
/* Create a unique key */
|
||||
$newTemplate->key = $newTemplate->location . '_' . \IPS\Http\Url::seoTitle( $newTemplate->title ) . '_' . $newTemplate->id;
|
||||
$newTemplate->key = $newTemplate->location . '_' . \IPS\Http\Url\Friendly::seoTitle( $newTemplate->title ) . '_' . $newTemplate->id;
|
||||
|
||||
/* Make sure there's no double __ in there */
|
||||
foreach( array( 'group', 'title', 'key' ) as $field )
|
||||
@@ -490,7 +563,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Open XML file */
|
||||
$xml = new \XMLReader;
|
||||
$xml = new \IPS\Xml\XMLReader;
|
||||
$xml->open( $file );
|
||||
$xml->read();
|
||||
|
||||
@@ -548,13 +621,15 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if ( $this->user_added )
|
||||
\IPS\cms\Theme::deleteCompiledTemplate( 'cms', $this->location, $this->group );
|
||||
|
||||
if ( $this->user_created )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_added=?', $this->key, 1 ) );
|
||||
|
||||
if ( isset( static::$multitons[ $this->key ] ) )
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_created=?', $this->key, 1 ) );
|
||||
|
||||
if ( isset( static::$multitons[ $this->id ] ) )
|
||||
{
|
||||
unset( static::$multitons[ $this->key ] );
|
||||
unset( static::$multitons[ $this->id ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -562,10 +637,10 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
if ( $this->user_edited )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_edited=?', $this->key, 1 ) );
|
||||
|
||||
if ( isset( static::$multitons[ $this->key ] ) )
|
||||
|
||||
if ( isset( static::$multitons[ $this->id ] ) )
|
||||
{
|
||||
unset( static::$multitons[ $this->key ] );
|
||||
unset( static::$multitons[ $this->id ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -606,7 +681,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
$content = $this->content;
|
||||
|
||||
/* Build on demand */
|
||||
if ( mb_stristr( $this->content, "{block=" ) )
|
||||
if ( $this->type != 'js' and ( mb_stristr( $this->content, "{block=" ) or mb_stristr( $this->content, "{{if" ) ) )
|
||||
{
|
||||
$functionName = 'css_' . uniqid();
|
||||
\IPS\Theme::makeProcessFunction( str_replace( '\\', '\\\\', $content ), $functionName );
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Designer's Mode Theme
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 28 Nov 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -133,22 +134,21 @@ class _Theme extends \IPS\cms\Theme
|
||||
|
||||
if ( isset( $templates[ $key ] ) )
|
||||
{
|
||||
if ( md5( trim( $templates[ $key ]['template_content'] ) ) == md5( trim( $html ) ) and 1==2 )
|
||||
if( \IPS\Login::compareHashes( md5( trim( $html ) ), md5( trim( $templates[ $key ]['template_content'] ) ) ) )
|
||||
{
|
||||
/* No change */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
/* Update */
|
||||
if ( ! $templates[ $key ]['template_master'] )
|
||||
{
|
||||
/* Update */
|
||||
if ( ! $templates[ $key ]['template_master'] )
|
||||
{
|
||||
$added = TRUE;
|
||||
\IPS\Db::i()->update( 'cms_templates', array(
|
||||
'template_content' => $html,
|
||||
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
|
||||
'template_file_object' => NULL
|
||||
), array( 'template_id=?', $templates[ $key ]['template_id'] ) );
|
||||
}
|
||||
$added = TRUE;
|
||||
\IPS\Db::i()->update( 'cms_templates', array(
|
||||
'template_content' => $html,
|
||||
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
|
||||
'template_file_object' => NULL
|
||||
), array( 'template_id=?', $templates[ $key ]['template_id'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief Magic Template Class for IN_DEV mode
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief IN_DEV Skin Set
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 16 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -175,7 +176,7 @@ class _Theme extends \IPS\Theme
|
||||
|
||||
if ( isset( $master[ $key ] ) )
|
||||
{
|
||||
if ( md5( trim( $master[ $key ]['template_content'] ) ) == md5( trim( $html ) ) )
|
||||
if( \IPS\Login::compareHashes( md5( trim( $master[ $key ]['template_content'] ) ), md5( trim( $html ) ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -342,7 +343,7 @@ class _Theme extends \IPS\Theme
|
||||
|
||||
$contents = file_get_contents( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() );
|
||||
$key = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'key' );
|
||||
$key = $key ? $key : \IPS\Http\Url::seoTitle( $file->getFilename() . '_' . $title );
|
||||
$key = $key ? $key : \IPS\Http\Url\Friendly::seoTitle( $file->getFilename() . '_' . $title );
|
||||
$ogroup = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'original_group' );
|
||||
$params = \IPS\cms\Theme\Template::extractParamsFromTag( $contents );
|
||||
$container = NULL;
|
||||
@@ -429,16 +430,52 @@ class _Theme extends \IPS\Theme
|
||||
{
|
||||
$where[] = "template_type='js'";
|
||||
}
|
||||
|
||||
foreach(
|
||||
\IPS\Db::i()->select(
|
||||
'*',
|
||||
'cms_templates',
|
||||
implode( " AND ", $where ),
|
||||
'template_location, template_group, template_key, template_user_edited ASC'
|
||||
)
|
||||
as $row
|
||||
) {
|
||||
|
||||
$templateNames = array();
|
||||
$rawTemplates = array();
|
||||
$originalGroups = array();
|
||||
$originalTemplates = array();
|
||||
$originalTemplateNames = array();
|
||||
$groupMap = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_templates', implode( " AND ", $where ), 'template_location, template_group, template_key, template_user_edited ASC' ) as $row )
|
||||
{
|
||||
$rawTemplates[] = $row;
|
||||
$templateNames[ $row['template_original_group'] ][] = $row['template_title'];
|
||||
$groupMap[ $row['template_original_group'] ] = $row['template_group'];
|
||||
|
||||
if ( $row['template_original_group'] )
|
||||
{
|
||||
$originalGroups[ $row['template_original_group'] ] = $row['template_original_group'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $originalGroups ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( array( 'template_original_group = template_group '), array( \IPS\Db::i()->in( 'template_original_group', $originalGroups ) ) ) ) as $row )
|
||||
{
|
||||
$originalTemplates[ $row['template_group'] . '_' . $row['template_title'] ] = $row;
|
||||
$originalTemplateNames[ $row['template_group'] ][] = $row['template_title'];
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try and see if we can merge in missing templates */
|
||||
foreach( $originalTemplateNames as $group => $names )
|
||||
{
|
||||
if ( isset( $templateNames[ $group ] ) )
|
||||
{
|
||||
foreach( $names as $name )
|
||||
{
|
||||
if ( ! in_array( $name, $templateNames[ $group ] ) )
|
||||
{
|
||||
$rawTemplates[] = array_merge( $originalTemplates[ $group . '_' . $name ], array( 'template_group' => $groupMap[ $group ]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach( $rawTemplates as $row )
|
||||
{
|
||||
$row['TemplateKey'] = $row['template_app'] . '_' . $row['template_location'] . '_' . $row['template_group'] . '_' . $row['template_key'];
|
||||
$row['jsDataKey'] = str_replace( '.', '--', $row['TemplateKey'] );
|
||||
$row['template_app'] = 'cms';
|
||||
@@ -545,7 +582,7 @@ class _Theme extends \IPS\Theme
|
||||
$key = \strtolower( 'template_cms_' .static::makeBuiltTemplateLookupHash( $app, $location, $group ) . '_' . static::cleanGroupName( $group ) );
|
||||
|
||||
/* Still here */
|
||||
if ( !in_array( $key, array_keys( self::$calledTemplates ) ) )
|
||||
if ( !in_array( $key, array_keys( static::$calledTemplates ) ) )
|
||||
{
|
||||
/* If we don't have a compiled template, do that now */
|
||||
if ( !isset( \IPS\Data\Store::i()->$key ) )
|
||||
@@ -556,15 +593,21 @@ class _Theme extends \IPS\Theme
|
||||
/* Still no key? */
|
||||
if ( ! isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
\IPS\Log::i( LOG_WARNING )->write( "Template store key: {$key} missing ({$app}, {$location}, {$group})", "template_store_missing" );
|
||||
\IPS\Log::log( "Template store key: {$key} missing ({$app}, {$location}, {$group})", "template_store_missing" );
|
||||
|
||||
throw new \ErrorException('template_store_missing ' . $key);
|
||||
}
|
||||
|
||||
/* Load compiled template */
|
||||
$compiledGroup = \IPS\Data\Store::i()->$key;
|
||||
|
||||
if ( @eval( $compiledGroup ) === FALSE )
|
||||
try
|
||||
{
|
||||
if ( @eval( $compiledGroup ) === FALSE )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
}
|
||||
catch ( \ParseError $e )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
@@ -574,10 +617,10 @@ class _Theme extends \IPS\Theme
|
||||
$class = "\IPS\Theme\\{$class}";
|
||||
|
||||
/* Init */
|
||||
self::$calledTemplates[ $key ] = new $class();
|
||||
static::$calledTemplates[ $key ] = new $class();
|
||||
}
|
||||
|
||||
return self::$calledTemplates[ $key ];
|
||||
return static::$calledTemplates[ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,17 +646,21 @@ class _Theme extends \IPS\Theme
|
||||
|
||||
/* Any template hooks? */
|
||||
$templateHooks = array();
|
||||
if( isset( \IPS\IPS::$hooks[ "\IPS\Theme\class_{$app}_{$location}_{$group}" ] ) )
|
||||
if( isset( \IPS\IPS::$hooks[ "\IPS\Theme\class_{$app}_{$location}_{$group}" ] ) AND \IPS\RECOVERY_MODE === FALSE )
|
||||
{
|
||||
foreach ( \IPS\IPS::$hooks[ "\IPS\Theme\class_{$app}_{$location}_{$group}" ] as $k => $data )
|
||||
{
|
||||
if ( !class_exists( "IPS\Theme\hook{$k}", FALSE ) )
|
||||
{
|
||||
if ( @eval( "namespace IPS\Theme;\n\n" . str_replace( ' extends _HOOK_CLASS_', '', file_get_contents( \IPS\ROOT_PATH . '/' . $data['file'] ) ) ) !== FALSE )
|
||||
try
|
||||
{
|
||||
$class = "IPS\Theme\hook{$data['class']}";
|
||||
$templateHooks = array_merge( $templateHooks, $class::hookData() );
|
||||
if ( @eval( "namespace IPS\Theme;\n\n" . str_replace( ' extends _HOOK_CLASS_', '', file_get_contents( \IPS\ROOT_PATH . '/' . $data['file'] ) ) ) !== FALSE )
|
||||
{
|
||||
$class = "IPS\Theme\hook{$data['class']}";
|
||||
$templateHooks = array_merge( $templateHooks, $class::hookData() );
|
||||
}
|
||||
}
|
||||
catch ( \ParseError $e ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
/**
|
||||
* @brief CMS Widgets
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Content
|
||||
* @since 13 Oct 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -37,13 +38,16 @@ class _Widget extends \IPS\Widget
|
||||
{
|
||||
$widgets = json_decode( $item['area_widgets'], TRUE );
|
||||
|
||||
foreach( $widgets as $widget )
|
||||
if( is_array( $widgets ) )
|
||||
{
|
||||
if ( $widget['unique'] == $uniqueId )
|
||||
foreach( $widgets as $widget )
|
||||
{
|
||||
if ( isset( $widget['configuration'] ) )
|
||||
if ( $widget['unique'] == $uniqueId )
|
||||
{
|
||||
return $widget['configuration'];
|
||||
if ( isset( $widget['configuration'] ) )
|
||||
{
|
||||
return $widget['configuration'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,4 +145,31 @@ class _Widget extends \IPS\Widget
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return unique IDs in use
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniqueIds()
|
||||
{
|
||||
$uniqueIds = parent::getUniqueIds();
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $row )
|
||||
{
|
||||
$data = json_decode( $row['area_widgets'], TRUE );
|
||||
|
||||
if ( count( $data ) )
|
||||
{
|
||||
foreach( $data as $widget )
|
||||
{
|
||||
if ( isset( $widget['unique'] ) )
|
||||
{
|
||||
$uniqueIds[] = $widget['unique'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $uniqueIds;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user