Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

+20 -11
View File
@@ -212,8 +212,15 @@ class _Block extends \IPS\Node\Model implements \IPS\Node\Permissions
{
unset( \IPS\Data\Store::i()->$functionName );
}
return call_user_func( 'IPS\\Theme\\'. $functionName );
$html = call_user_func( 'IPS\\Theme\\'. $functionName );
if( $block->getConfig('editor') == 'editor' )
{
$html = \IPS\Theme::i()->getTemplate( 'widgets', 'cms', 'front' )->Wysiwyg( $html, $orientation );
}
return $html;
}
catch ( \ParseError $e )
{
@@ -351,7 +358,7 @@ EOF;
/**
* @brief Orientation for an embedded widget
*/
protected $orientation = NULL;
public $orientation = NULL;
/**
* Get config as an array if no $key, or as whatever type corresponds to key
@@ -639,14 +646,16 @@ EOF;
}
else
{
$form->add( new \IPS\Helpers\Form\Codemirror( 'block_content', htmlentities( $this->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ), FALSE, array(), function( $val ) {
$form->add( new \IPS\Helpers\Form\Codemirror( 'block_content', htmlentities( $this->content, ENT_DISALLOWED, 'UTF-8', TRUE ), FALSE, array(), function( $val ) {
if ( \IPS\Request::i()->block_editor == 'php' )
{
try
{
ob_start();
@eval( $val );
ob_get_clean();
}
catch ( \ParseError $e )
catch ( \Exception $e )
{
throw new \DomainException( $e->getMessage() );
}
@@ -763,7 +772,7 @@ EOF;
/* It's taken... */
if ( $this->id != $block->id )
{
$values['block_key'] .= '_' . uniqid();
$values['block_key'] .= '_' . mt_rand();
}
}
catch( \OutOfRangeException $ex )
@@ -864,7 +873,7 @@ EOF;
$templateBit = $templateBits[ $location['app'] ][ $location['location'] ][ $location['group'] ][ $location['name'] ];
$templateArray = array(
'key' => 'template_' . $templateBit['template_name'] . '.' . uniqid(),
'key' => 'template_' . $templateBit['template_name'] . '.' . mt_rand(),
'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'],
@@ -884,7 +893,7 @@ EOF;
$template = \IPS\cms\Templates::load( $values['block_template_id'] );
$templateArray = array(
'key' => 'template_' . $template->name . '.' . uniqid(),
'key' => 'template_' . $template->name . '.' . mt_rand(),
'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'],
@@ -991,7 +1000,7 @@ EOF;
if ( ! $this->widgetLoaded )
{
$this->widgetLoaded = \IPS\Widget::load( $this->plugin_app ? \IPS\Application::load( $this->plugin_app ) : \IPS\Plugin::load( $this->plugin_plugin ), $this->plugin, uniqid(), $this->_plugin_config, NULL, $this->orientation );
$this->widgetLoaded = \IPS\Widget::load( $this->plugin_app ? \IPS\Application::load( $this->plugin_app ) : \IPS\Plugin::load( $this->plugin_plugin ), $this->plugin, mt_rand(), $this->_plugin_config, NULL, $this->orientation );
}
return $this->widgetLoaded;
@@ -1016,7 +1025,7 @@ EOF;
/* Copy language bits to make them unique */
$config = $this->_plugin_config;
$wordKey = 'widget_title_' . md5( uniqid() );
$wordKey = 'widget_title_' . md5( mt_rand() );
if ( isset( $config['language_key'] ) )
{
@@ -1035,7 +1044,7 @@ EOF;
$this->plugin_config = json_encode( $config );
}
$this->key .= '_' . uniqid();
$this->key .= '_' . mt_rand();
$this->save();
}
}
@@ -318,8 +318,9 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
$path = trim( $path , '/');
$bits = explode( '/', $path );
$root = $bits[0];
if ( in_array( $root, array( 'submit' ) ) )
/* _ is here due to IP.Board 3.x using that to denote the articles database (eg. articles.html/_/category/record-r1/), which we need to redirect from for records and articles. */
if ( in_array( $root, array( 'submit', '_' ) ) )
{
return TRUE;
}
@@ -829,11 +830,6 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
protected $_catTitle = NULL;
/**
* @brief Cached title for strip tags version
*/
protected $_stripTagsCatTitle = NULL;
/**
* @brief Cached title for strip tags version
*/
@@ -883,7 +879,14 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
}
}
$guestGroup = \IPS\Member\Group::load( \IPS\Settings::i()->guest_group );
try
{
$guestGroup = \IPS\Member\Group::load( \IPS\Settings::i()->guest_group );
}
catch( \OutOfRangeException $e )
{
throw new \UnderflowException( 'invalid_guestgroup_admin', 199 );
}
if( !$this->can_view_others )
{
@@ -1168,37 +1171,6 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
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
@@ -1432,7 +1404,10 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
'cms_custom_database_' . $this->database_id,
array( 'category_id=? AND record_approved=1 AND record_future_date=0', $this->id ),
'record_last_comment DESC',
array( 0, 1 )
array( 0, 1 ),
NULL,
NULL,
\IPS\Db::SELECT_FROM_WRITE_SERVER
)->first()
);
}
@@ -1455,7 +1430,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
{
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() );
$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, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
}
catch( \UnderflowException $e ) { }
}
@@ -1499,9 +1474,9 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
$this->last_record_id = static::$latestRecordAdded->_id;
}
$this->records = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_approved=1 AND record_future_date=0 AND category_id=?', $this->id ) )->first();
$this->records_queued = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_approved=0 AND category_id=?', $this->id ) )->first();
$this->records_future = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_future_date=1 AND category_id=?', $this->id ) )->first();
$this->records = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_approved=1 AND record_future_date=0 AND category_id=?', $this->id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$this->records_queued = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_approved=0 AND category_id=?', $this->id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$this->records_future = \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $this->database_id, array( 'record_future_date=1 AND category_id=?', $this->id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
static::$latestRecordAdded = NULL;
}
@@ -892,6 +892,15 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\Db::i()->delete( 'core_notifications', array( 'item_class=? ', 'IPS\cms\Records' . $this->id ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=?', 'cms', 'records' . $this->id ) );
/* Remove promoted content */
\IPS\Db::i()->delete( 'core_social_promote', array( 'promote_class=?', 'IPS\cms\Records' . $this->id ) );
/* remove deletion log */
\IPS\Db::i()->delete( 'core_deletion_log', array( 'dellog_content_class=?', 'IPS\cms\Records' . $this->id ) );
/* remove metadata */
\IPS\Db::i()->delete( 'core_content_meta', array( "meta_class=? ", 'IPS\cms\Records' . $this->id ) );
foreach( $memberIds as $member )
{
\IPS\Member::load( $member )->recountNotifications();
@@ -197,14 +197,28 @@ class _Dispatcher extends \IPS\Dispatcher
{
$url .= '/' . $path;
$recordClass = '\IPS\cms\Records' . $database->id;
$isLegacyCategoryUrl = FALSE;
if ( $database->use_categories )
{
$catClass = '\IPS\cms\Categories' . $database->id;
$category = $catClass::loadFromPath( $path, $database->id );
/* /_/ was used in IP.Board 3.x to denote the articles database */
if ( $category === NULL AND mb_substr( $path, 0, 2 ) === '_/' )
{
$category = $catClass::loadFromPath( mb_substr( $path, 2 ), $database->id );
/* We may have a record URL still, so set a flag to handle this later if we never find anything */
if ( $category !== NULL )
{
$isLegacyCategoryUrl = TRUE;
}
}
if ( $category === NULL )
{
/* Is this a record? */
$bits = explode( '/', $path );
$slug = array_pop( $bits );
@@ -261,6 +275,12 @@ class _Dispatcher extends \IPS\Dispatcher
}
catch( \OutOfRangeException $ex )
{
/* We are absolutely certain this is not a record, but we have found a legacy category - redirect */
if ( $isLegacyCategoryUrl === TRUE )
{
\IPS\Output::i()->redirect( $category->url() );
}
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/5', 404 );
}
}
+87 -62
View File
@@ -12,7 +12,6 @@
/**
*
* @todo: Shared media field type
* @todo: Relational field type
*
*/
namespace IPS\cms;
@@ -178,7 +177,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
public static $cannotBeTitleFields = array( 'Member', 'Editor', 'CheckboxSet', 'YesNo', 'Radio', 'Item' );
/**
* @brief Fields that cannot be title fields
* @brief Fields that cannot be content fields
*/
public static $cannotBeContentFields = array();
@@ -229,7 +228,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
foreach( static::$cache[ static::$customDatabaseId ][ $permissionCheck ] as $id => $obj )
{
if ( ! array_key_exists( $obj->type, static::$additionalFieldTypes ) AND ( ! class_exists( '\IPS\Helpers\Form\\' . ucfirst( $obj->type ) ) AND ! class_exists( '\IPS\cms\Fields\\' . ucfirst( $obj->type ) ) ) )
if ( ! array_key_exists( $obj->type, static::$additionalFieldTypes ) AND ( ! class_exists( '\IPS\Helpers\Form\\' . mb_ucfirst( $obj->type ) ) AND ! class_exists( '\IPS\cms\Fields\\' . mb_ucfirst( $obj->type ) ) ) )
{
unset( static::$cache[ static::$customDatabaseId ][ $permissionCheck ][ $id ] );
continue;
@@ -630,24 +629,33 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
if ( isset( $this->extra['thumbsize'] ) )
{
$thumbs = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $this->id ) ) )->setKeyField('thumb_original_location')->setValueField('thumb_location') );
$images = array();
if ( $this->is_multiple )
{
$thumbs = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=? AND thumb_record_id=?', $this->id, $record->_id ) ) )->setKeyField('thumb_original_location')->setValueField('thumb_location') );
$images = array();
foreach( $thumbs as $orig => $thumb )
foreach( $thumbs as $orig => $thumb )
{
try
{
$images[] = \IPS\File::get( static::$uploadStorageExtension, $thumb )->url;
}
catch( \Exception $e ) { }
}
return $images;
}
else
{
try
{
$images[] = \IPS\File::get( static::$uploadStorageExtension, $thumb )->url;
return (string) \IPS\File::get( static::$uploadStorageExtension, \IPS\Db::i()->select( 'thumb_location', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=? AND thumb_record_id=?', $this->id, $record->_id ) ) )->first() )->url;
}
catch( \Exception $e ) { }
}
return $images;
}
else
{
return $this->formatForDisplay( $value, $formValue, 'raw', $record );
}
return $this->formatForDisplay( $value, $formValue, 'raw', $record );
}
$options = $this->display_json;
@@ -732,7 +740,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$class .= ' ' . 'ipsPos_right';
}
if ( $this->type === 'Address' and $formValue and isset( $options[ $type ]['map'] ) AND $options[ $type ]['map'] AND \IPS\Settings::i()->google_maps_api_key )
if ( $this->type === 'Address' and $formValue and isset( $options[ $type ]['map'] ) AND $options[ $type ]['map'] AND \IPS\GeoLocation::enabled() )
{
$value .= \IPS\GeoLocation::buildFromJson( $formValue )->map()->render( $options[ $type ]['mapDims'][0], $options[ $type ]['mapDims'][1] );
}
@@ -775,7 +783,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
else
{
if ( $this->type === 'Address' and $formValue and isset( $options[ $type ]['map'] ) AND $options[ $type ]['map'] AND \IPS\Settings::i()->google_maps_api_key )
if ( $this->type === 'Address' and $formValue and isset( $options[ $type ]['map'] ) AND $options[ $type ]['map'] AND \IPS\GeoLocation::enabled() )
{
$value .= \IPS\GeoLocation::buildFromJson( $formValue )->map()->render( $options[ $type ]['mapDims'][0], $options[ $type ]['mapDims'][1] );
}
@@ -826,7 +834,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( $formValue and $this->type === 'Address' )
{
$functionName .= '_' . uniqid();
$functionName .= '_' . mt_rand();
$template = str_replace( '{map}' , \IPS\GeoLocation::buildFromJson( $formValue )->map()->render( $options[ $type ]['mapDims'][0], $options[ $type ]['mapDims'][1] ), $template );
$template = str_replace( '{address}', \IPS\GeoLocation::parseForOutput( $formValue ), $template );
@@ -1186,11 +1194,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
protected function get__icon()
{
if ( class_exists( '\IPS\Helpers\Form\\' . ucfirst( $this->type ) ) )
if ( class_exists( '\IPS\Helpers\Form\\' . mb_ucfirst( $this->type ) ) )
{
return NULL;
}
else if ( class_exists( '\IPS\cms\Fields\\' . ucfirst( $this->type ) ) )
else if ( class_exists( '\IPS\cms\Fields\\' . mb_ucfirst( $this->type ) ) )
{
return NULL;
}
@@ -1213,7 +1221,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
return $text;
}
switch( ucfirst( $this->type ) )
switch( mb_ucfirst( $this->type ) )
{
default:
// No truncate
@@ -1245,10 +1253,10 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
$database = \IPS\cms\Databases::load( static::$customDatabaseId );
if ( class_exists( '\IPS\cms\Fields\\' . ucfirst( $this->type ) ) )
if ( class_exists( '\IPS\cms\Fields\\' . mb_ucfirst( $this->type ) ) )
{
/* Is special! */
$class = '\IPS\cms\Fields\\' . ucfirst( $this->type );
$class = '\IPS\cms\Fields\\' . mb_ucfirst( $this->type );
if ( method_exists( $class, 'displayValue' ) )
{
@@ -1256,7 +1264,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
}
switch( ucfirst( $this->type ) )
switch( mb_ucfirst( $this->type ) )
{
case 'Upload':
return \IPS\File::get( 'cms_Records', $value )->url;
@@ -1306,14 +1314,14 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$return = array();
foreach( $value as $key )
{
$return[] = isset( $this->extra[ $key ] ) ? htmlspecialchars( $this->extra[ $key ], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) : htmlspecialchars( $key, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE );
$return[] = isset( $this->extra[ $key ] ) ? htmlspecialchars( $this->extra[ $key ], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : htmlspecialchars( $key, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE );
}
return implode( ', ', $return );
}
else
{
return ( isset( $this->extra[ $value ] ) ? htmlspecialchars( $this->extra[ $value ], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) : htmlspecialchars( $value, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) );
return ( isset( $this->extra[ $value ] ) ? htmlspecialchars( $this->extra[ $value ], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : htmlspecialchars( $value, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) );
}
break;
case 'Member':
@@ -1332,7 +1340,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
case 'Url':
if ( \IPS\Dispatcher::hasInstance() AND class_exists( '\IPS\Dispatcher', FALSE ) and \IPS\Dispatcher::i()->controllerLocation === 'front' )
{
return ( $value ) ? \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $value, TRUE, NULL, FALSE ) : NULL;
return ( $value ) ? \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $value, TRUE, NULL, FALSE ) : NULL;
}
break;
case 'Date':
@@ -1377,7 +1385,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$time = ( is_integer( $value[ $t ] ) ) ? \IPS\DateTime::ts( $value[ $t ], TRUE ) : $value[ $t ];
if ( isset( $this->extra['timezone'] ) and $this->extra['timezone'] )
{
$time->setTimezone( new \DateTimeZone( $this->extra['timezone'] ) );
try
{
$time->setTimezone( new \DateTimeZone( $this->extra['timezone'] ) );
}
catch( \Exception $e ){}
}
$$t = $time->localeDate();
@@ -1547,7 +1559,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
public function canBeTitleField()
{
if ( $this->is_multiple or in_array( ucfirst( $this->type ), static::$cannotBeTitleFields ) )
if ( $this->is_multiple or in_array( mb_ucfirst( $this->type ), static::$cannotBeTitleFields ) )
{
return FALSE;
}
@@ -1564,7 +1576,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
$no = array();
if ( $this->is_multiple or in_array( ucfirst( $this->type ), static::$cannotBeContentFields ) )
if ( $this->is_multiple or in_array( mb_ucfirst( $this->type ), static::$cannotBeContentFields ) )
{
return FALSE;
}
@@ -1613,11 +1625,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( $this->type )
{
$ok = FALSE;
if ( class_exists( '\IPS\Helpers\Form\\' . ucfirst( $this->type ) ) )
if ( class_exists( '\IPS\Helpers\Form\\' . mb_ucfirst( $this->type ) ) )
{
$ok = TRUE;
}
else if ( class_exists( '\IPS\cms\Fields\\' . ucfirst( $this->type ) ) )
else if ( class_exists( '\IPS\cms\Fields\\' . mb_ucfirst( $this->type ) ) )
{
$ok = TRUE;
}
@@ -1697,12 +1709,16 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
/* Title or content? */
$isTitleField = FALSE;
if ( $this->id )
{
$database = \IPS\cms\Databases::load( static::$customDatabaseId );
if ( $this->id == $database->field_title )
{
$isTitleField = TRUE;
foreach( static::$cannotBeTitleFields as $type )
{
unset( $options[ $type ] );
@@ -1734,34 +1750,37 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
}
$form->add( new \IPS\Helpers\Form\Select( 'field_type', $this->id ? \ucfirst( $this->type ) : 'Text', TRUE, array(
$form->add( new \IPS\Helpers\Form\Select( 'field_type', $this->id ? mb_ucfirst( $this->type ) : 'Text', TRUE, array(
'options' => $options,
'toggles' => $toggles
) ) );
/* Relational specific */
$databases = array();
$disabled = array();
foreach( \IPS\cms\Databases::databases() as $db )
if( !$isTitleField )
{
if ( $db->page_id )
$databases = array();
$disabled = array();
foreach( \IPS\cms\Databases::databases() as $db )
{
$databases[ $db->id ] = $db->_title;
if ( $db->page_id )
{
$databases[ $db->id ] = $db->_title;
}
else
{
$disabled[] = $db->id;
$databases[ $db->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_relational_with_name_disabled', NULL, array( 'sprintf' => array( $db->_title ) ) );
}
}
else
if ( ! count( $databases ) )
{
$disabled[] = $db->id;
$databases[ $db->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_relational_with_name_disabled', NULL, array( 'sprintf' => array( $db->_title ) ) );
$databases[0] = \IPS\Member::loggedIn()->language()->addToStack('cms_relational_field_no_dbs');
$disabled[] = 0;
}
}
if ( ! count( $databases ) )
{
$databases[0] = \IPS\Member::loggedIn()->language()->addToStack('cms_relational_field_no_dbs');
$disabled[] = 0;
}
$form->add( new \IPS\Helpers\Form\Select( 'field_relational_db', ( isset( $this->extra['database'] ) ? $this->extra['database'] : NULL ), FALSE, array( 'options' => $databases, 'disabled' => $disabled ), NULL, NULL, NULL, 'field_relational_db' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'field_crosslink', $this->id ? ( ( isset( $this->extra['crosslink'] ) and $this->extra['crosslink'] ) ? TRUE : FALSE ) : FALSE, FALSE, array(), NULL, NULL, NULL, 'field_crosslink' ) );
$form->add( new \IPS\Helpers\Form\Select( 'field_relational_db', ( isset( $this->extra['database'] ) ? $this->extra['database'] : NULL ), FALSE, array( 'options' => $databases, 'disabled' => $disabled ), NULL, NULL, NULL, 'field_relational_db' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'field_crosslink', $this->id ? ( ( isset( $this->extra['crosslink'] ) and $this->extra['crosslink'] ) ? TRUE : FALSE ) : FALSE, FALSE, array(), NULL, NULL, NULL, 'field_crosslink' ) );
}
/* Number specific */
$form->add( new \IPS\Helpers\Form\YesNo( 'field_number_decimals_on', $this->id ? ( ( isset( $this->extra['on'] ) and $this->extra['on'] ) ? TRUE : FALSE ) : FALSE, FALSE, array( 'togglesOn' => array( 'field_number_decimals' ) ), NULL, NULL, NULL, 'field_number_decimals_on' ) );
@@ -1804,7 +1823,10 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
), NULL, NULL, NULL, 'field_allowed_extensions' ) );
/* Editor Specific */
$form->add( new \IPS\Helpers\Form\YesNo( 'field_allow_attachments', $this->id ? $this->allow_attachments : 1, FALSE, array( ), NULL, NULL, NULL, 'field_allow_attachments' ) );
if( !$isTitleField )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'field_allow_attachments', $this->id ? $this->allow_attachments : 1, FALSE, array( ), NULL, NULL, NULL, 'field_allow_attachments' ) );
}
/* Date specific */
$tzValue = 'UTC';
@@ -1832,7 +1854,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
), NULL, NULL, NULL, 'field_date_time_override' ) );
$timezones = array();
foreach ( \DateTimeZone::listIdentifiers() as $tz )
foreach ( \IPS\DateTime::getTimezoneIdentifiers() as $tz )
{
if ( $pos = mb_strpos( $tz, '/' ) )
{
@@ -1915,7 +1937,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
}
if ( ! ( $this->id AND $this->id === \IPS\cms\Databases::load( static::$customDatabaseId )->field_title ) )
if ( !$isTitleField )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'field_required', $this->id ? $this->required : TRUE, FALSE ) );
}
@@ -2237,7 +2259,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( !$this->id )
{
/* field key cannot be null, so we assign a temporary key here which is overwritten below */
$this->key = md5( uniqid() );
$this->key = md5( mt_rand() );
$this->database_id = static::$customDatabaseId;
$values['database_id'] = $this->database_id;
@@ -2407,7 +2429,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
/* It's taken... */
if ( $this->id != $testField->id )
{
$this->key .= '_' . uniqid();
$this->key .= '_' . mt_rand();
}
}
catch( \OutOfRangeException $ex )
@@ -2570,8 +2592,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
throw new \LogicException( \IPS\Member::loggedIn()->language()->addToStack('cms_relational_field_no_db_selected') );
}
$values['extra'] = array( 'database' => $values['field_relational_db'] );
if ( isset( $values['field_relational_db'] ) )
{
$values['extra'] = array( 'database' => $values['field_relational_db'] );
}
if ( array_key_exists( 'field_crosslink', $values ) and ! empty( $values['field_crosslink'] ) )
{
@@ -2747,14 +2772,14 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
public function buildHelper( $value=NULL, $customValidationCode=NULL, \IPS\cms\Records $record = NULL, $flags=0 )
{
if ( class_exists( '\IPS\cms\Fields\\' . ucfirst( $this->type ) ) )
if ( class_exists( '\IPS\cms\Fields\\' . mb_ucfirst( $this->type ) ) )
{
/* Is special! */
$class = '\IPS\cms\Fields\\' . ucfirst( $this->type );
$class = '\IPS\cms\Fields\\' . mb_ucfirst( $this->type );
}
else if ( class_exists( '\IPS\Helpers\Form\\' . ucfirst( $this->type ) ) )
else if ( class_exists( '\IPS\Helpers\Form\\' . mb_ucfirst( $this->type ) ) )
{
$class = '\IPS\Helpers\Form\\' . ucfirst( $this->type );
$class = '\IPS\Helpers\Form\\' . mb_ucfirst( $this->type );
if ( !is_array( $this->extra ) )
{
@@ -2776,11 +2801,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
$options = array();
switch ( ucfirst( $this->type ) )
switch ( mb_ucfirst( $this->type ) )
{
case 'Editor':
$options['app'] = 'cms';
$options['key'] = 'Records';
$options['key'] = 'Records' . static::$customDatabaseId;
$options['allowAttachments'] = $this->allow_attachments;
$options['autoSaveKey'] = 'RecordField_' . ( $record === NULL ? 'new' : $record->_id ) . '_' . $this->id;
$options['attachIds'] = ( $record === NULL ) ? NULL : array( $record->_id, $this->id, static::$customDatabaseId );
@@ -2851,7 +2876,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
break;
case 'Select':
case 'CheckboxSet':
$options['multiple'] = ( ucfirst( $this->type ) == 'CheckboxSet' ) ? TRUE : $this->is_multiple;
$options['multiple'] = ( mb_ucfirst( $this->type ) == 'CheckboxSet' ) ? TRUE : $this->is_multiple;
if ( $flags & self::FIELD_DISPLAY_FILTERS or ( ! $this->default_value and ! $this->required ) )
{
@@ -2967,7 +2992,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( $this->validator AND $this->validator_custom )
{
switch( ucfirst( $this->type ) )
switch( mb_ucfirst( $this->type ) )
{
case 'Text':
case 'TextArea':
-10
View File
@@ -130,16 +130,6 @@ 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
*
+58 -20
View File
@@ -245,14 +245,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
public static function resetPath( $folderId )
{
try
{
$path = \IPS\cms\Pages\Folder::load( $folderId )->path;
}
catch ( \OutOfRangeException $ex )
{
throw new \OutOfRangeException;
}
$path = $folderId ? \IPS\cms\Pages\Folder::load( $folderId )->path : '';
$children = static::getChildren( $folderId );
@@ -502,10 +495,13 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
/**
* Removes all include objects from all pages
*
* @param boolean $url The URL to find and remove
* @param boolean $url The URL to find and remove
* @param NULL|int $storageConfiguration Delete the cached includes from an alternate storage configuration
* @note This method is called by \IPS\cms\extensions\core\FileStorage\Pages.php during a move, and in that process we want to remove resources
from the old storage configuration, not the new one (which is what happens when the configuration id is not passed in to \IPS\File and a move is in progress)
* @return void
*/
static public function deleteCachedIncludes( $url=NULL )
static public function deleteCachedIncludes( $url=NULL, $storageConfiguration=NULL )
{
/* Remove them all */
if ( $url === NULL )
@@ -516,7 +512,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\Db::i()->update( 'cms_pages', array( 'page_js_css_objects' => NULL ) );
}
/* Remove from file system */
\IPS\File::getClass( 'cms_Pages')->deleteContainer('page_objects');
\IPS\File::getClass( $storageConfiguration ?: 'cms_Pages' )->deleteContainer('page_objects');
}
else
{
@@ -708,8 +704,9 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$jsincludes[ $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->group ) . '/' . \IPS\cms\Templates::readableGroupName( $obj->title );
}
ksort( $jsincludes );
$return['page_includes_js'] = new \IPS\Helpers\Form\Select( 'page_includes_js', $item ? $item->js_includes : FALSE, FALSE, array( 'options' => $jsincludes, 'multiple' => true ), NULL, NULL, NULL, 'page_includes_js' );
$return['page_includes_js'] = new \IPS\Helpers\Form\CheckboxSet( 'page_includes_js', $item ? $item->js_includes : FALSE, FALSE, array( 'options' => $jsincludes, 'multiple' => true ), NULL, NULL, NULL, 'page_includes_js' );
}
if ( count( $css ) )
@@ -719,8 +716,9 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$cssincludes[ $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->group ) . '/' . \IPS\cms\Templates::readableGroupName( $obj->title );
}
$return['page_includes_css'] = new \IPS\Helpers\Form\Select( 'page_includes_css', $item ? $item->css_includes : FALSE, FALSE, array( 'options' => $cssincludes, 'multiple' => true ), NULL, NULL, NULL, 'page_includes_css' );
ksort( $cssincludes );
$return['page_includes_css'] = new \IPS\Helpers\Form\CheckboxSet( 'page_includes_css', $item ? $item->css_includes : FALSE, FALSE, array( 'options' => $cssincludes, 'multiple' => true ), NULL, NULL, NULL, 'page_includes_css' );
}
}
@@ -754,7 +752,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$tags['cms_tag_pages']['{pageurl="' . $page['page_full_path'] . '"}' ] = \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $page['page_id'] );
}
$return['page_content'] = new \IPS\Helpers\Form\Codemirror( 'page_content', $item ? htmlentities( $item->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ) : NULL, FALSE, array( 'tags' => $tags, 'height' => 600 ), function( $val )
$return['page_content'] = new \IPS\Helpers\Form\Codemirror( 'page_content', $item ? htmlentities( $item->content, ENT_DISALLOWED, 'UTF-8', TRUE ) : NULL, FALSE, array( 'tags' => $tags, 'height' => 600 ), function( $val )
{
/* Test */
try
@@ -1063,6 +1061,14 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
/* Empty? Lets take a look and see if we need to compile anything */
if ( empty( $this->_data['js_css_objects'] ) )
{
/* Lock it up to prevent a race condition */
if ( \IPS\Theme::checkLock( "page_object_build" . $this->id ) )
{
return NULL;
}
\IPS\Theme::lock( "page_object_build" . $this->id );
if ( count( $this->js_includes ) )
{
/* Build a file object for each JS */
@@ -1107,6 +1113,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$this->js_css_objects = json_encode( $return );
$this->save();
}
\IPS\Theme::unlock( "page_object_build" . $this->id );
}
else
{
@@ -1187,7 +1195,15 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$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 );
try
{
\IPS\Theme::runProcessFunction( \IPS\Theme::compileTemplate( $contents, $functionName, null, true ), $functionName );
}
catch( \Exception $e )
{
\IPS\Log::log( $e, 'pages_error' );
return '';
}
}
else
{
@@ -1634,6 +1650,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('content_err_page_save_exception', FALSE, array( 'sprintf' => \IPS\Member::loggedIn()->language()->addToStack( $ex->getMessage() ) ) ) );
}
\IPS\Content\Search\Index::i()->index( $this->item() );
}
/**
@@ -1760,7 +1778,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
preg_match_all( '/(.+?)='.$array[2].'(.+?)'.$array[2].'\s?/', $array[1], $submatches );
$plugin = array_shift( $submatches[1] );
$pluginClass = 'IPS\\Output\\Plugin\\' . ucfirst( $plugin );
$pluginClass = 'IPS\\Output\\Plugin\\' . mb_ucfirst( $plugin );
$value = array_shift( $submatches[2] );
$options = array();
@@ -1777,9 +1795,9 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
foreach ( \IPS\Application::applications() as $app )
{
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app->directory}/extensions/core/OutputPlugins/" . ucfirst( $plugin ) . ".php" ) )
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app->directory}/extensions/core/OutputPlugins/" . mb_ucfirst( $plugin ) . ".php" ) )
{
$pluginClass = 'IPS\\' . $app->directory . '\\extensions\\core\\OutputPlugins\\' . ucfirst( $plugin );
$pluginClass = 'IPS\\' . $app->directory . '\\extensions\\core\\OutputPlugins\\' . mb_ucfirst( $plugin );
}
}
}
@@ -2009,6 +2027,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
static::cleanUpDesignersModeFiles();
}
\IPS\Content\Search\Index::i()->removeFromSearchIndex( $this->item() );
}
/**
@@ -2063,6 +2083,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
}
}
catch( \Exception $e ) { }
\IPS\Content\Search\Index::i()->index( $this->item() );
}
/**
@@ -2084,7 +2106,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
if ( $this->full_path and \IPS\Theme::designersModeEnabled() )
{
static::exportDesignersMode( $this->id );
}
}
}
/**
@@ -2493,4 +2515,20 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
}
}
}
/**
* Get item
*
* @return \IPS\nexus\Package\Item
*/
public function item()
{
$data = array();
foreach ( $this->_data as $k => $v )
{
$data[ 'page_' . $k ] = $v;
}
return \IPS\cms\Pages\PageItem::constructFromData( $data );
}
}
+202
View File
@@ -0,0 +1,202 @@
<?php
/**
* @brief Pages Page Item Model
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Nexus
* @since 15 Dec 2017
*/
namespace IPS\cms\Pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Package Item Model
*/
class _PageItem extends \IPS\Content\Item implements \IPS\Content\Searchable
{
/**
* @brief Application
*/
public static $application = 'cms';
/**
* @brief Module
*/
public static $module = 'pages';
/**
* @brief Database Table
*/
public static $databaseTable = 'cms_pages';
/**
* @brief Database Prefix
*/
public static $databasePrefix = 'page_';
/**
* @brief Multiton Store
*/
protected static $multitons;
/**
* @brief Database Column Map
*/
public static $databaseColumnMap = array(
);
/**
* @brief Title
*/
public static $title = 'cms_page';
/**
* @brief Icon
*/
public static $icon = 'files-o';
/**
* @brief Include In Sitemap
*/
public static $includeInSitemap = FALSE;
/**
* @brief Can this content be moderated normally from the front-end (will be FALSE for things like Pages and Commerce Products)
*/
public static $canBeModeratedFromFrontend = FALSE;
/**
* Columns needed to query for search result / stream view
*
* @return array
*/
public static function basicDataColumns()
{
return array( 'page_id', 'page_folder_id', 'page_full_path', 'page_default' );
}
/**
* Get URL 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()
* @return \IPS\Http\Url
*/
public static function urlFromIndexData( $indexData, $itemData )
{
if ( ( \IPS\Application::load('cms')->default OR \IPS\Settings::i()->cms_use_different_gateway ) AND $itemData['page_default'] AND !$itemData['page_folder_id'] )
{
/* Are we using the gateway file? */
if ( \IPS\Settings::i()->cms_use_different_gateway )
{
/* Yes, work out the proper URL. */
return \IPS\Http\Url::createFromString( \IPS\Settings::i()->cms_root_page_url, TRUE );
}
else
{
/* No - that's easy */
return \IPS\Http\Url::internal( '', 'front' );
}
}
else
{
return \IPS\Http\Url::internal( 'app=cms&module=pages&controller=page&path=' . $itemData['page_full_path'], 'front', 'content_page_path', array( $itemData['page_full_path'] ) );
}
}
/**
* 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
* @param array $reactions Reaction Data
* @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, $reactions=array() )
{
$indexData['index_title'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_page_' . $indexData['index_item_id'] );
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments, $template, $reactions );
}
/**
* Title for search index
*
* @return string
*/
public function searchIndexTitle()
{
$titles = array();
foreach ( \IPS\Lang::languages() as $lang )
{
$titles[] = $lang->get("cms_page_{$this->id}");
}
return implode( ' ', $titles );
}
/**
* Content for search index
*
* @return string
*/
public function searchIndexContent()
{
if ( $this->type == 'builder' )
{
$content = array();
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas', array( 'area_page_id=?', $this->id ) ) as $widgetArea )
{
foreach ( json_decode( $widgetArea['area_widgets'], TRUE ) as $widget )
{
if ( $widget['app'] == 'cms' and $widget['key'] == 'Wysiwyg' )
{
$content[] = trim( $widget['configuration']['content'] );
}
}
}
return implode( ' ', $content );
}
else
{
return $this->content;
}
}
/**
* Search Index Permissions
*
* @return string Comma-delimited values or '*'
* @li Number indicates a group
* @li Number prepended by "m" indicates a member
* @li Number prepended by "s" indicates a social group
*/
public function searchIndexPermissions()
{
try
{
return \IPS\Db::i()->select( 'perm_view', 'core_permission_index', array( "app='cms' AND perm_type='pages' AND perm_type_id=?", $this->id ) )->first();
}
catch ( \UnderflowException $e )
{
return '';
}
}
}
+13 -2
View File
@@ -21,9 +21,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Post Model
*/
class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
{
use \IPS\Content\Reactable;
use \IPS\Content\Reactable, \IPS\Content\Reportable;
/**
* @brief [ActiveRecord] Multiton Store
@@ -104,6 +104,17 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
*/
protected static $searchIndexTitles = array();
/**
* Post count for member
*
* @param \IPS\Member $member The memner
* @return int
*/
public static function memberPostCount( \IPS\Member $member )
{
return \IPS\Db::i()->select( 'COUNT(*)', static::$databaseTable, array( 'comment_database_id=? AND comment_user=?', static::$customDatabaseId, $member->member_id ) )->first();
}
/**
* Return custom where for SQL delete
*
@@ -133,17 +133,45 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
$comment->editContents( $newContent );
}
/**
* Get HTML
*
* @return string
*/
public function html()
{
if ( ! empty( $this->pid ) )
{
try
{
$comment = \IPS\forums\Topic\Post::load( $this->pid );
$template = static::$commentTemplate[1];
static::$commentTemplate[0][0] = $this->item()->database()->template_display;
return call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), static::$commentTemplate[0] )->$template( $comment->item(), $comment );
}
catch( \OutOfRangeException $e )
{
return parent::html();
}
}
else
{
return parent::html();
}
}
/**
* Report
*
* @param string $reportContent Report content message from member
* @return \\IPS\core\Reports\Report
* @param int $reportType Report type (see constants in \IPS\core\Reports\Report
* @return \\PS\core\Reports\Report
* @throws \UnexpectedValueException If there is a permission error - you should only call this method after checking canReport
*/
public function report( $reportContent )
public function report( $reportContent, $reportType=1 )
{
$comment = \IPS\forums\Topic\Post::load( $this->pid );
return $comment->report( $reportContent );
return $comment->report( $reportContent, $reportType );
}
/**
@@ -166,6 +194,18 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
{
return array( array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=?', $id ) );
}
/**
* Post count for member
*
* @param \IPS\Member $member The memner
* @return int
* @note We explicitely return 0 because any posts will be counted via the forums application inherently already
*/
public static function memberPostCount( \IPS\Member $member )
{
return 0;
}
/**
* Reaction Type
@@ -176,4 +216,15 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
{
return 'pid';
}
/**
* Reaction class
*
* @return string
*/
public static function reactionClass()
{
return 'IPS\forums\Topic\Post';
}
}
+242 -58
View File
@@ -27,7 +27,6 @@ class _Records extends \IPS\Content\Item implements
\IPS\Content\Tags,
\IPS\Content\Followable,
\IPS\Content\Shareable,
\IPS\Content\ReportCenter,
\IPS\Content\ReadMarkers,
\IPS\Content\Views,
\IPS\Content\Ratings,
@@ -36,7 +35,7 @@ class _Records extends \IPS\Content\Item implements
\IPS\Content\Embeddable,
\IPS\Content\MetaData
{
use \IPS\Content\Reactable;
use \IPS\Content\Reactable, \IPS\Content\Reportable;
/**
* @brief Multiton Store
@@ -268,6 +267,12 @@ class _Records extends \IPS\Content\Item implements
public static function loadFromSlug( $slug, $redirectIfSeoTitleIsIncorrect=TRUE, $categoryId=NULL )
{
$slug = trim( $slug, '/' );
/* If the slug is an empty string, then there is nothing to try and load. */
if ( empty( $slug ) )
{
throw new \OutOfRangeException;
}
/* Try the easiest option */
preg_match( '#-r(\d+?)$#', $slug, $matches );
@@ -283,6 +288,12 @@ class _Records extends \IPS\Content\Item implements
{
$url = $record->url();
/* Don't correct the URL if the visitor cannot see the record */
if( !$record->canView() )
{
throw new \OutOfRangeException;
}
/* Redirect to the embed form if necessary */
if( isset( \IPS\Request::i()->do ) and \IPS\Request::i()->do == 'embed' )
{
@@ -394,13 +405,15 @@ class _Records extends \IPS\Content\Item implements
/**
* Definite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @param array $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @param array $options Options to pass to \IPS\Lang::addToStack
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL, $options = array() )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( 'content_db_lang_sl_' . static::$customDatabaseId, FALSE );
return $lang->addToStack( 'content_db_lang_sl_' . static::$customDatabaseId, FALSE, $options );
}
/**
@@ -452,6 +465,12 @@ class _Records extends \IPS\Content\Item implements
{
return true;
}
/* Make sure it does not match the dynamic URL format */
if ( preg_match( '#-r(\d+?)$#', $val ) )
{
throw new \InvalidArgumentException('content_record_slug_not_unique');
}
try
{
@@ -519,7 +538,7 @@ class _Records extends \IPS\Content\Item implements
}
}
$postKey = ( $item ) ? $item->_post_key : md5( uniqid() );
$postKey = ( $item ) ? $item->_post_key : md5( mt_rand() );
if ( $fieldsClass::fixedFieldFormShow( 'record_publish_date' ) AND \IPS\Member::loggedIn()->modPermission( "can_future_publish_content" ) )
{
@@ -1054,7 +1073,7 @@ class _Records extends \IPS\Content\Item implements
if ( isset( $thumbs[ (string) $original ] ) )
{
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_original_location=? and thumb_field_id=?', (string) $original, $row->id ) ) );
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_original_location=? and thumb_field_id=? and thumb_record_id=?', (string) $original, $row->id, $this->primary_id_field ) ) );
try
{
@@ -1067,16 +1086,17 @@ class _Records extends \IPS\Content\Item implements
'thumb_original_location' => (string) $original,
'thumb_location' => (string) $thumb,
'thumb_field_id' => $row->id,
'thumb_database_id' => static::$customDatabaseId
'thumb_database_id' => static::$customDatabaseId,
'thumb_record_id' => $this->primary_id_field
) );
}
catch ( \Exception $e ) { }
}
catch ( \Exception $e ) { }
}
/* Remove any thumbnails if the original has been removed */
$orphans = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) ) );
$orphans = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_record_id=?', $this->primary_id_field ), array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) ) );
if ( count( $orphans ) )
{
@@ -1089,7 +1109,7 @@ class _Records extends \IPS\Content\Item implements
catch ( \Exception $e ) { }
}
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) );
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_record_id=?', $this->primary_id_field ), array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) );
}
}
}
@@ -1408,7 +1428,7 @@ class _Records extends \IPS\Content\Item implements
{
foreach( $fieldValues[ $fieldName ] as $fileName )
{
$obj = \IPS\File::get( 'cms_Records', $filename );
$obj = \IPS\File::get( 'cms_Records', $fileName );
if ( $obj->isImage() )
{
$attachments[] = array( 'cms_Records' => $fileName );
@@ -1436,7 +1456,7 @@ class _Records extends \IPS\Content\Item implements
*/
public function get__post_key()
{
return ! empty( $this->post_key ) ? $this->post_key : md5( uniqid() );
return ! empty( $this->post_key ) ? $this->post_key : md5( mt_rand() );
}
/**
@@ -1778,11 +1798,14 @@ class _Records extends \IPS\Content\Item implements
{
unset( static::$multitons[ $this->primary_id_field ] );
foreach( static::$multitonMap as $field => $data )
foreach( static::$multitonMap as $fieldKey => $data )
{
if ( isset( static::$multitonMap[ $field ][ $this->primary_id_field ] ) )
foreach( $data as $fieldValue => $primaryId )
{
unset( static::$multitonMap[ $field ][ $this->primary_id_field ] );
if( $primaryId == $this->primary_id_field )
{
unset( static::$multitonMap[ $fieldKey ][ $fieldValue ] );
}
}
}
@@ -1976,7 +1999,7 @@ class _Records extends \IPS\Content\Item implements
* @param bool $includeDeleted Include deleted content.
* @return array|NULL|\IPS\Content\Comment If $limit is 1, will return \IPS\Content\Comment or NULL for no results. For any other number, will return an array.
*/
public function comments( $limit=NULL, $offset=NULL, $order='date', $orderDirection='asc', $member=NULL, $includeHiddenComments=NULL, $cutoff=NULL, $extraWhereClause=NULL, $bypassCache=FALSE, $includeDeleted=FALSE )
public function comments( $limit=NULL, $offset=NULL, $order='date', $orderDirection='asc', $member=NULL, $includeHiddenComments=NULL, $cutoff=NULL, $extraWhereClause=NULL, $bypassCache=FALSE, $includeDeleted=FALSE, $canViewWarn=NULL )
{
if ( $this->useForumComments() )
{
@@ -2053,7 +2076,7 @@ class _Records extends \IPS\Content\Item implements
* @param bool $includeDeleted Include deleted content
* @return array|NULL|\IPS\Content\Comment If $limit is 1, will return \IPS\Content\Comment or NULL for no results. For any other number, will return an array.
*/
public function reviews( $limit=NULL, $offset=NULL, $order=NULL, $orderDirection='desc', $member=NULL, $includeHiddenReviews=NULL, $cutoff=NULL, $extraWhereClause=NULL, $includeDeleted=FALSE )
public function reviews( $limit=NULL, $offset=NULL, $order=NULL, $orderDirection='desc', $member=NULL, $includeHiddenReviews=NULL, $cutoff=NULL, $extraWhereClause=NULL, $includeDeleted=FALSE, $canViewWarn=NULL )
{
$where = array( array( 'review_database_id=?', static::$customDatabaseId ) );
@@ -2074,7 +2097,19 @@ class _Records extends \IPS\Content\Item implements
}
if ( static::database()->options['comments'] )
{
$tabs['comments'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_comment_count', TRUE, array( 'pluralize' => array( $this->mapped('num_comments') ) ) );
$count = $this->mapped('num_comments');
if ( \IPS\Application::appIsEnabled('forums') and $this->_forum_comments and $topic = $this->topic() )
{
if ( $count != ( $topic->posts - 1 ) )
{
$this->record_comments = $topic->posts - 1;
$this->save();
}
$count = ( $topic->posts - 1 ) > 0 ? $topic->posts - 1 : 0;
}
$tabs['comments'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_comment_count', TRUE, array( 'pluralize' => array( $count ) ) );
}
return $tabs;
@@ -2109,7 +2144,12 @@ class _Records extends \IPS\Content\Item implements
*/
public static function moderateNewItems( \IPS\Member $member, \IPS\Node\Model $container = NULL )
{
return ( static::database()->record_approve and !$member->group['g_avoid_q'] ) or parent::moderateNewItems( $member, $container );
if ( static::database()->record_approve and !$member->group['g_avoid_q'] )
{
return !static::modPermission( 'approve', $member, $container );
}
return parent::moderateNewItems( $member, $container );
}
/**
@@ -2132,9 +2172,13 @@ class _Records extends \IPS\Content\Item implements
public function moderateNewReviews( \IPS\Member $member )
{
return ( static::database()->options['reviews_mod'] and !$member->group['g_avoid_q'] ) or parent::moderateNewReviews( $member );
}
/**
* @brief Skip topic creation, useful if the topic may already exist
*/
public static $skipTopicCreation = FALSE;
/**
* Create from form
*
@@ -2147,7 +2191,7 @@ class _Records extends \IPS\Content\Item implements
{
$record = parent::createFromForm( $values, $container, $sendNotification );
if ( \IPS\Application::appIsEnabled('forums') and $record->_forum_record and $record->_forum_forum and ! $record->hidden() and ! $record->record_future_date )
if ( !static::$skipTopicCreation and \IPS\Application::appIsEnabled('forums') and $record->_forum_record and $record->_forum_forum and ! $record->hidden() and ! $record->record_future_date )
{
try
{
@@ -2346,7 +2390,59 @@ class _Records extends \IPS\Content\Item implements
$topic->changeAuthor( $newAuthor );
}
}
/**
* Get last comment author
* Overloaded for the bump on edit shenanigans
*
* @return \IPS\Member
* @throws \BadMethodCallException
*/
public function lastCommenter()
{
if ( ( static::database()->_comment_bump & ( \IPS\cms\Databases::BUMP_ON_EDIT + \IPS\cms\Databases::BUMP_ON_COMMENT ) and $this->record_edit_time > 0 and $this->record_edit_time > $this->record_last_comment ) OR
( ( static::database()->_comment_bump & \IPS\cms\Databases::BUMP_ON_EDIT ) and !( static::database()->_comment_bump & ( \IPS\cms\Databases::BUMP_ON_EDIT + \IPS\cms\Databases::BUMP_ON_COMMENT ) ) and $this->record_edit_time > 0 ) )
{
try
{
$this->_lastCommenter = \IPS\Member::load( $this->record_edit_member_id );
return $this->_lastCommenter;
}
catch( \Exception $e ) { }
}
return parent::lastCommenter();
}
/**
* Is this topic linked to a record?
*
* @param \IPS\forums\Topic $topic Forums topic
* @return boolean
*/
public static function topicIsLinked( $topic )
{
foreach( \IPS\cms\Databases::databases() as $database )
{
try
{
if ( $database->forum_record and $database->forum_forum == $topic->container()->_id )
{
$class = '\IPS\cms\Records' . $database->id;
$record = $class::load( $topic->tid, 'record_topicid' );
if ( $record->_forum_record )
{
return TRUE;
}
}
}
catch( \Exception $e ) { }
}
return FALSE;
}
/**
* Get Topic (checks member's permissions)
*
@@ -2355,7 +2451,7 @@ class _Records extends \IPS\Content\Item implements
*/
public function topic( $checkPerms=TRUE )
{
if ( \IPS\Application::appIsEnabled('forums') and $this->record_topicid )
if ( \IPS\Application::appIsEnabled('forums') and $this->_forum_record and $this->record_topicid )
{
try
{
@@ -2526,33 +2622,56 @@ class _Records extends \IPS\Content\Item implements
return $fields;
}
/**
* @brief Store the comment page count otherwise $topic->posts is reduced by 1 each time it is called
*/
protected $recordCommentPageCount = NULL;
/**
* Get comment page count
*
* @param bool $recache TRUE to recache the value
* @return int
*/
public function commentPageCount( $recache=FALSE )
{
if ( $this->useForumComments() )
if ( $this->recordCommentPageCount === NULL or $recache === TRUE )
{
try
if ( $this->useForumComments() )
{
$topic = $this->topic();
if( $topic !== NULL )
try
{
$topic->posts = $topic->posts - 1;
return $topic->commentPageCount();
$topic = $this->topic();
if( $topic !== NULL )
{
/* Store the real count so it is not accidentally written as the actual value */
$realCount = $topic->posts;
/* Compensate for the first post (which is actually the record) */
$topic->posts = ( $topic->posts - 1 ) > 0 ? $topic->posts - 1 : 0;
/* Get our page count considering all of that */
$this->recordCommentPageCount = $topic->commentPageCount();
/* Reset the count back to the real count */
$topic->posts = $realCount;
}
else
{
$this->recordCommentPageCount = 0;
}
}
return 0;
catch( \Exception $e ) { }
}
else
{
$this->recordCommentPageCount = parent::commentPageCount( $recache );
}
catch( \Exception $e ) { }
}
return parent::commentPageCount();
return $this->recordCommentPageCount;
}
/**
@@ -2590,7 +2709,28 @@ class _Records extends \IPS\Content\Item implements
/* We have an attached topic, but we don't want to delete the topic so remove commentClass otherwise we'll delete posts */
static::$commentClass = NULL;
}
/* Remove Record Image And Record Thumb Image */
if ( $this->record_image )
{
try
{
\IPS\File::get( 'cms_Records', $this->record_image )->delete();
}
catch( \Exception $e ){}
}
if ( $this->record_image_thumb )
{
try
{
\IPS\File::get( 'cms_Records', $this->record_image_thumb )->delete();
}
catch ( \Exception $e ) { }
}
/* Remove any reciprocal linking */
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map', array( 'map_foreign_item_id=? or map_origin_item_id=?', $this->_id, $this->_id ) );
@@ -2610,7 +2750,6 @@ class _Records extends \IPS\Content\Item implements
*/
public function canView( $member=NULL )
{
if ( !parent::canView( $member ) )
{
return FALSE;
@@ -2626,9 +2765,10 @@ class _Records extends \IPS\Content\Item implements
return FALSE;
}
$member = $member ?: \IPS\Member::loggedIn();
if ( !$this->container()->can_view_others and !$member->modPermission( 'can_content_view_others_records' ) )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $member != $this->author() )
{
return FALSE;
@@ -2648,19 +2788,44 @@ class _Records extends \IPS\Content\Item implements
*/
public function canEdit( $member=NULL )
{
if ( ( ( static::database()->options['indefinite_own_edit'] AND \IPS\Member::loggedIn()->member_id === $this->member_id ) OR ( \IPS\Member::loggedIn()->member_id and static::database()->all_editable ) ) AND ! $this->locked() AND ! $this->hidden() )
$member = $member ?: \IPS\Member::loggedIn();
if ( ( ( static::database()->options['indefinite_own_edit'] AND $member->member_id === $this->member_id ) OR ( $member->member_id and static::database()->all_editable ) ) AND ! $this->locked() AND in_array( $this->hidden(), array( 0, 1 ) ) )
{
return TRUE;
}
if ( parent::canEdit( $member ) )
{
/* Test against specific perms for this category */
return $this->container()->can( 'edit', $member );
return $this->container()->can( 'edit', $member ) or $this->container()->modPermission( 'edit', $member );
}
return FALSE;
}
/**
* Can edit title?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canEditTitle( $member=NULL )
{
if ( $this->canEdit( $member ) )
{
try
{
$class = '\IPS\cms\Fields' . static::database()->id;
$field = $class::load( static::database()->field_title );
return $field->can( 'edit', $member );
}
catch( \Exception $e )
{
return FALSE;
}
}
return FALSE;
}
/**
* Can move?
@@ -3013,24 +3178,19 @@ class _Records extends \IPS\Content\Item implements
return $lastComment;
}
/**
* Search Index Permissions
* If we don't have a page, we don't want to add this to the search index
* Deletion log Permissions
* Usually, this is the same as searchIndexPermissions. However, some applications may restrict searching but
* still want to allow delayed deletion log viewing and searching
*
* @return string Comma-delimited values or '*'
* @li Number indicates a group
* @li Number prepended by "m" indicates a member
* @li Number prepended by "s" indicates a social group
*/
public function searchIndexPermissions()
public function deleteLogPermissions()
{
/* We don't want to index items in databases with search disabled */
if( ! static::database()->search )
{
return NULL;
}
if( ! $this->container()->can_view_others )
{
$return = $this->container()->searchIndexPermissions();
@@ -3059,10 +3219,31 @@ class _Records extends \IPS\Content\Item implements
return NULL;
}
}
/**
* Search Index Permissions
* If we don't have a page, we don't want to add this to the search index
*
* @return string Comma-delimited values or '*'
* @li Number indicates a group
* @li Number prepended by "m" indicates a member
* @li Number prepended by "s" indicates a social group
*/
public function searchIndexPermissions()
{
/* We don't want to index items in databases with search disabled */
if( ! static::database()->search )
{
return NULL;
}
return $this->deleteLogPermissions();
}
/**
* Get output for API
*
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
* @return array
* @apiresponse int id ID number
* @apiresponse string title Title
@@ -3082,15 +3263,17 @@ class _Records extends \IPS\Content\Item implements
* @apiresponse bool featured Event is featured
* @apiresponse string url URL
* @apiresponse float rating Average Rating
* @apiresponse string image Record Image
* @apiresponse \IPS\forums\Topic topic The topic
*/
public function apiOutput()
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
return array(
'id' => $this->primary_id_field,
'title' => $this->_title,
'category' => $this->container() ? $this->container()->apiOutput() : null,
'fields' => $this->fieldValues(),
'author' => $this->author()->apiOutput(),
'author' => $this->author()->apiOutput( $authorizedMember ),
'date' => \IPS\DateTime::ts( $this->record_saved )->rfc3339(),
'description' => $this->content(),
'comments' => $this->record_comments,
@@ -3104,7 +3287,8 @@ class _Records extends \IPS\Content\Item implements
'featured' => (bool) $this->mapped('featured'),
'url' => (string) $this->url(),
'rating' => $this->averageRating(),
'image' => $this->record_image ? (string) \IPS\File::get( 'cms_Records', $this->record_image )->url : null
'image' => $this->record_image ? (string) \IPS\File::get( 'cms_Records', $this->record_image )->url : null,
'topic' => $this->topicid ? $this->topic()->apiOutput( $authorizedMember ) : NULL,
);
}
@@ -3205,7 +3389,7 @@ class _Records extends \IPS\Content\Item implements
public function embedContent( $params )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'embed.css', 'cms', 'front' ) );
return \IPS\Theme::i()->getTemplate( 'global', 'cms' )->embedRecord( $this, $this->container(), $this->url()->setQueryString( $params ) );
return \IPS\Theme::i()->getTemplate( 'global', 'cms' )->embedRecord( $this, $this->url()->setQueryString( $params ) );
}
/**
+3 -2
View File
@@ -21,9 +21,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Post Model
*/
class _Review extends \IPS\Content\Review implements \IPS\Content\ReportCenter, \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
{
use \IPS\Content\Reactable;
use \IPS\Content\Reactable, \IPS\Content\Reportable;
/**
* @brief [ActiveRecord] Multiton Store
@@ -78,6 +78,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\ReportCenter,
'votes_helpful' => 'votes_helpful',
'votes_data' => 'votes_data',
'approved' => 'approved',
'author_response' => 'author_response',
);
/**
@@ -106,7 +106,7 @@ class _Revisions extends \IPS\Patterns\ActiveRecord
if( $justChanged === FALSE OR !\IPS\Login::compareHashes( md5( $record->$key ), md5( $this->get( $key ) ) ) )
{
$conflicts[ md5( uniqid() ) ] = array( 'original' => $this->get( $key ), 'current' => $record->$key, 'field' => $field );
$conflicts[] = array( 'original' => $this->get( $key ), 'current' => $record->$key, 'field' => $field );
}
}
@@ -682,13 +682,13 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/* Build on demand */
if ( $this->type != 'js' and ( mb_stristr( $this->content, "{block=" ) or mb_stristr( $this->content, "{{if" ) ) )
{
$functionName = 'css_' . uniqid();
$functionName = 'css_' . mt_rand();
\IPS\Theme::makeProcessFunction( str_replace( '\\', '\\\\', $content ), $functionName );
$functionName = "IPS\Theme\\{$functionName}";
$content = $functionName();
}
$this->file_object = (string) \IPS\File::create( 'cms_Pages', $this->title, $content, 'page_objects', TRUE );
$this->file_object = (string) \IPS\File::create( 'cms_Pages', $this->title, $content ?: ' ', 'page_objects', TRUE );
parent::save(); # Go to parent save to prevent $this->save() from wiping file objects
}
@@ -47,14 +47,7 @@ class _Theme extends \IPS\cms\Theme
'template_user_edited ASC' /* Ensure we get edited versions, not the master version if one exists */
)->setKeyField('bit_key') as $template )
{
try
{
static::writeTemplate( $template, TRUE );
}
catch( \RuntimeException $ex )
{
throw new \RuntimeException( $ex->getMessage() );
}
static::writeTemplate( $template, TRUE );
}
}
@@ -133,7 +126,7 @@ class _Theme extends \IPS\cms\Theme
if ( isset( $templates[ $key ] ) )
{
if( \IPS\Login::compareHashes( md5( trim( $html ) ), md5( trim( $templates[ $key ]['template_content'] ) ) ) )
if( md5( trim( $html ) ) == md5( trim( $templates[ $key ]['template_content'] ) ) )
{
/* No change */
continue;
+9 -3
View File
@@ -247,10 +247,16 @@ class _Theme extends \IPS\Theme
if ( ! file_exists( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName ) OR $force === TRUE )
{
$write = '<ips:template parameters="' . $template['template_params'] . '" original_group="' . $template['template_original_group'] . '" key="' . $template['template_key'] . '" />' . "\n";
$write = '';
if ( $template['template_type'] === 'template' )
{
$write = '<ips:template parameters="' . $template['template_params'] . '" original_group="' . $template['template_original_group'] . '" key="' . $template['template_key'] . '" />' . "\n";
}
$write .= $template['template_content'];
if ( ! @\file_put_contents( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, $write ) )
if ( @\file_put_contents( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, $write ) === FALSE )
{
throw new \RuntimeException( \IPS\Member::loggedIn()->language()->addToStack( 'content_theme_dev_cannot_write_template', FALSE, array( 'sprintf' => array( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName ) ) ) );
}
@@ -349,7 +355,7 @@ class _Theme extends \IPS\Theme
if ( in_array( $key, $seenKeys ) )
{
$key .= filemtime( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() ) . uniqid();
$key .= filemtime( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() ) . mt_rand();
}
$seenKeys[] = $key;