Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user