Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\databases;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _categories extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\databases;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _databases extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -52,23 +57,23 @@ class _databases extends \IPS\Node\Controller
/* Columns */
$table->joins = array(
array( 'select' => 'w.word_custom as database_name', 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'content_db_', cms_databases.database_id ) AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
array( 'select' => 'w.word_custom', 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'content_db_', cms_databases.database_id ) AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id )
);
$table->include = array( 'database_name', 'database_record_count', 'database_category_count' );
$table->include = array( 'word_custom', 'database_record_count', 'database_category_count' );
$table->widths = array(
'database_name' => '50'
'word_custom' => '50'
);
$table->mainColumn = 'database_name';
$table->quickSearch = 'database_name';
$table->mainColumn = 'word_custom';
$table->quickSearch = 'word_custom';
$table->sortBy = $table->sortBy ?: 'database_name';
$table->sortBy = $table->sortBy ?: 'word_custom';
$table->sortDirection = $table->sortDirection ?: 'asc';
/* Parsers */
$table->parsers = array(
'database_name' => function( $val, $row )
'word_custom' => function( $val, $row )
{
$page = NULL;
$database = NULL;
@@ -247,7 +252,7 @@ class _databases extends \IPS\Node\Controller
move_uploaded_file( $values['cms_database_import'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) )->csrf() );
}
else
{
@@ -266,6 +271,7 @@ class _databases extends \IPS\Node\Controller
public function import()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'databases_add' );
\IPS\Session::i()->csrfCheck();
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
{
@@ -273,7 +279,7 @@ class _databases extends \IPS\Node\Controller
}
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
\IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key ) ),
\IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key ) )->csrf(),
function( $data )
{
/* Open XML file */
@@ -289,10 +295,10 @@ class _databases extends \IPS\Node\Controller
/* Is this the first batch? */
$database = null;
$i = 0;
if ( !is_array( $data ) )
if ( !\is_array( $data ) )
{
$database = new \IPS\cms\Databases;
$database->key = mt_rand();
$database->key = 'import_' . mt_rand();
$database->save();
/* Set default perms, these will be editable post DB import */
@@ -435,7 +441,7 @@ class _databases extends \IPS\Node\Controller
{
while ( $xml->read() )
{
if( ! in_array( $xml->name, $areas ) OR $xml->nodeType != \XMLReader::ELEMENT )
if( ! \in_array( $xml->name, $areas ) OR $xml->nodeType != \XMLReader::ELEMENT )
{
continue;
}
@@ -467,7 +473,7 @@ class _databases extends \IPS\Node\Controller
$perms = array();
foreach( $node->attributes() as $k => $v )
{
if ( mb_substr( $k, 0, 5 ) === 'perm_' or in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) )
if ( mb_substr( $k, 0, 5 ) === 'perm_' or \in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) )
{
$perms[ $k ] = (string) $v;
}
@@ -488,7 +494,7 @@ class _databases extends \IPS\Node\Controller
$tryJson = json_decode( $v, TRUE );
if ( $k === 'field_display_json' AND is_array( $tryJson ) )
if ( $k === 'field_display_json' AND \is_array( $tryJson ) )
{
$displayJson = $tryJson;
continue;
@@ -585,14 +591,14 @@ class _databases extends \IPS\Node\Controller
$perms = array();
foreach( $node->attributes() as $k => $v )
{
if ( mb_substr( $k, 0, 5 ) === 'perm_' or in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) )
if ( mb_substr( $k, 0, 5 ) === 'perm_' or \in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) )
{
$perms[ $k ] = (string) $v;
}
else
{
$attrs[ $k ] = ( in_array( $k, array( 'category_parent_id' ) ) ) ? (int) $v : (string) $v;
$attrs[ $k ] = ( \in_array( $k, array( 'category_parent_id' ) ) ) ? (int) $v : (string) $v;
}
}
@@ -612,12 +618,13 @@ class _databases extends \IPS\Node\Controller
/* Create a category */
$category = new \IPS\cms\Categories;
$category->database_id = $database->id;
$category::$permType = 'categories_' . $database->id;
$category->saveForm( $category->formatFormValues( $attrs ) );
if ( $category->fields AND $category->fields !== '*' )
{
if ( is_array( $category->fields ) )
if ( \is_array( $category->fields ) )
{
$field_map = \IPS\Data\Store::i()->db_import_field_map;
$newMap = array();
@@ -630,7 +637,7 @@ class _databases extends \IPS\Node\Controller
}
}
if ( count( $newMap ) )
if ( \count( $newMap ) )
{
$category->fields = json_encode( $newMap );
$category->save();
@@ -784,7 +791,7 @@ class _databases extends \IPS\Node\Controller
if ( isset( \IPS\Data\Store::i()->db_import_field_map ) )
{
$map = \IPS\Data\Store::i()->db_import_field_map;
$sortId = intval( mb_substr( $database->field_sort, 6 ) );
$sortId = \intval( mb_substr( $database->field_sort, 6 ) );
if ( isset( $map[ $sortId ] ) )
{
@@ -870,7 +877,7 @@ class _databases extends \IPS\Node\Controller
'comment_bump', 'forum_record', 'forum_comments', 'forum_delete', 'forum_forum', 'forum_prefix', 'forum_suffix', 'search', 'tags_enabled', 'tags_noprefixes', 'tags_predefined', 'fixed_field_perms',
'cat_index_type', 'template_form', 'template_featured', 'featured_settings', 'options' ) as $field )
{
if ( is_array( $database->$field ) )
if ( \is_array( $database->$field ) )
{
$arrays[ $field ] = $database->$field;
}
@@ -881,7 +888,7 @@ class _databases extends \IPS\Node\Controller
if ( $database->$field instanceof \IPS\Patterns\Bitwise )
{
$bwfield = $database->$field;
$store = intval( $bwfield->values['options'] );
$store = \intval( $bwfield->values['options'] );
}
$xml->startAttribute( $field );
@@ -890,7 +897,7 @@ class _databases extends \IPS\Node\Controller
}
}
if ( count( $arrays ) )
if ( \count( $arrays ) )
{
foreach( $arrays as $field => $v )
{
@@ -927,7 +934,7 @@ class _databases extends \IPS\Node\Controller
foreach( $row as $k => $v )
{
if ( array_key_exists( $k, $fieldSchema['columns'] ) AND ! in_array( $k, $removeFields ) AND ! in_array( $k, $textFields ) )
if ( array_key_exists( $k, $fieldSchema['columns'] ) AND ! \in_array( $k, $removeFields ) AND ! \in_array( $k, $textFields ) )
{
$xml->startAttribute( $k );
$xml->text( $v );
@@ -974,7 +981,7 @@ class _databases extends \IPS\Node\Controller
foreach( $row as $k => $v )
{
if ( array_key_exists( $k, $categorySchema['columns'] ) AND ! in_array( $k, $removeFields ) AND ! in_array( $k, $textFields ) )
if ( array_key_exists( $k, $categorySchema['columns'] ) AND ! \in_array( $k, $removeFields ) AND ! \in_array( $k, $textFields ) )
{
$xml->startAttribute( $k );
$xml->text( $v );
@@ -1010,7 +1017,7 @@ class _databases extends \IPS\Node\Controller
foreach( array('template_listing', 'template_display', 'template_categories', 'template_featured') as $area )
{
if ( isset( $templates['cms']['database'][ $database->$area ] ) and is_array( $templates['cms']['database'][ $database->$area ] ) )
if ( isset( $templates['cms']['database'][ $database->$area ] ) and \is_array( $templates['cms']['database'][ $database->$area ] ) )
{
/* Only fetch edited/added templates, no point in fetching default theme templates */
foreach( $templates['cms']['database'][ $database->$area ] as $key => $item )
@@ -1034,7 +1041,7 @@ class _databases extends \IPS\Node\Controller
}
}
if ( count( $toSave ) )
if ( \count( $toSave ) )
{
foreach( $toSave as $group => $items )
{
@@ -1116,6 +1123,31 @@ class _databases extends \IPS\Node\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases' ), 'deleted' );
}
/**
* Permissions
*
* @return void
*/
protected function permissions()
{
parent::permissions();
$database = \IPS\cms\Databases::load( \IPS\Request::i()->id );
try
{
if( $database->page_id AND \IPS\cms\Pages\Page::load( $database->page_id )->permissions()['perm_view'] != '*' )
{
/* We want the message to show at the top, so get our output as we will start over */
$output = \IPS\Output::i()->output;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->message( \IPS\Member::loggedIn()->language()->addToStack('database_page_permissions_restrict', FALSE, array( 'sprintf' => array( $database->page_id ) ) ), 'warning' );
\IPS\Output::i()->output .= $output;
}
}
catch( \OutOfRangeException $e ){}
}
/**
* Promote
*
@@ -1161,6 +1193,8 @@ class _databases extends \IPS\Node\Controller
*/
public function rebuildTopicContent()
{
\IPS\Session::i()->csrfCheck();
if ( isset( \IPS\Request::i()->process ) )
{
\IPS\Task::queue( 'cms', 'ResyncTopicContent', array( 'databaseId' => \IPS\Request::i()->id ), 3, array( 'databaseId' ) );
@@ -1181,6 +1215,7 @@ class _databases extends \IPS\Node\Controller
{
if ( isset( \IPS\Request::i()->process ) )
{
\IPS\Session::i()->csrfCheck();
\IPS\Task::queue( 'core', 'RebuildItemCounts', array( 'class' => 'IPS\cms\Records' . \IPS\Request::i()->id ), 3, array( 'class' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=form&id=' . \IPS\Request::i()->id ), 'database_rebuild_added' );
}
@@ -1193,6 +1228,7 @@ class _databases extends \IPS\Node\Controller
/**
* Add/Edit
*
* @csrfChecked Uses $this->_getDatabaseForm() which uses Form Helper 7 Oct 2019
* @return void
*/
public function form()
@@ -1244,7 +1280,7 @@ class _databases extends \IPS\Node\Controller
if ( ! $values['database_key'] )
{
if ( is_array( $values['database_name'] ) )
if ( \is_array( $values['database_name'] ) )
{
$keyToUse = mt_rand();
foreach( $values['database_name'] as $langId => $word )
@@ -1343,11 +1379,8 @@ class _databases extends \IPS\Node\Controller
{
$current->tags_enabled = (int) $values['database_tags_enabled'];
$current->tags_noprefixes = !(bool) $values['database_tags_noprefixes'];
if ( ! \IPS\Settings::i()->tags_open_system )
{
$current->tags_predefined = ( is_array( $values['database_tags_predefined'] ) ) ? implode( ',', array_filter( array_map( 'trim', $values['database_tags_predefined'] ) ) ) : NULL;
}
$current->tags_predefined = ( \is_array( $values['database_tags_predefined'] ) ) ? implode( ',', array_filter( array_map( 'trim', $values['database_tags_predefined'] ) ) ) : NULL;
}
$categories = 0;
@@ -1375,6 +1408,16 @@ class _databases extends \IPS\Node\Controller
if ( \IPS\Application::appIsEnabled( 'forums' ) )
{
/* Are we changing where comments go? */
if ( !$new AND ( (int) $current->forum_record != (int) $values['database_forum_record'] OR (int) $current->forum_comments != (int) $values['database_forum_comments'] ) )
{
\IPS\Task::queue( 'cms', 'MoveComments', array(
'databaseId' => $current->id,
'to' => ( $values['database_forum_comments'] AND $values['database_forum_record'] ) ? 'forums' : 'pages',
'deleteTopics' => (bool) ( !$values['database_forum_record'] )
), 1, array( 'databaseId', 'to' ) );
}
$current->forum_record = (int) $values['database_forum_record'];
$current->forum_comments = (int) $values['database_forum_comments'];
$current->forum_forum = ( ! $values['database_forum_forum'] ) ? 0 : $values['database_forum_forum']->id;
@@ -1388,7 +1431,10 @@ class _databases extends \IPS\Node\Controller
$current->forum_comments = 0;
$current->forum_delete = 0;
}
/* SEO */
$current->canonical_flag = (int) $values['database_canonical_flag'];
$fieldSettingJson = array();
foreach( $values as $k => $v )
@@ -1429,6 +1475,7 @@ class _databases extends \IPS\Node\Controller
$category->allow_rating = $values['category_allow_rating'];
$category->can_view_others = $values['category_can_view_others'];
$category->save();
$category->cloneDatabasePermissions();
}
if ( $new )
@@ -1607,7 +1654,7 @@ class _databases extends \IPS\Node\Controller
foreach( $FieldsClass::data() as $id => $field )
{
if ( in_array( $field->type, array( 'checkbox', 'multiselect', 'attachments' ) ) )
if ( \in_array( $field->type, array( 'checkbox', 'multiselect', 'attachments' ) ) )
{
continue;
}
@@ -1646,10 +1693,10 @@ class _databases extends \IPS\Node\Controller
$form->addHeader( 'cms_database_form_display' );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_categories', ! empty( $current ) ? $current->template_categories : NULL, FALSE, array( 'options' => $templatesCat ), NULL, NULL, NULL, 'database_template_categories' ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_listing' , ! empty( $current ) ? $current->template_listing : NULL, FALSE, array( 'options' => $templatesList ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_display' , ! empty( $current ) ? $current->template_display : NULL, FALSE, array( 'options' => $templatesDisplay ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_form' , ! empty( $current ) ? $current->template_form : NULL, FALSE, array( 'options' => $templatesForm ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_categories', ! empty( $current ) ? $current->template_categories : NULL, FALSE, array( 'options' => $templatesCat ), NULL, NULL, \IPS\Theme::i()->getTemplate( 'databases', 'cms' )->templateGoButton('database_template_categories'), 'database_template_categories' ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_listing' , ! empty( $current ) ? $current->template_listing : NULL, FALSE, array( 'options' => $templatesList ), NULL, NULL, \IPS\Theme::i()->getTemplate( 'databases', 'cms' )->templateGoButton('database_template_listing'), 'database_template_listing' ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_display' , ! empty( $current ) ? $current->template_display : NULL, FALSE, array( 'options' => $templatesDisplay ), NULL, NULL, \IPS\Theme::i()->getTemplate( 'databases', 'cms' )->templateGoButton('database_template_display'), 'database_template_display' ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_form' , ! empty( $current ) ? $current->template_form : NULL, FALSE, array( 'options' => $templatesForm ), NULL, NULL, \IPS\Theme::i()->getTemplate( 'databases', 'cms' )->templateGoButton('database_template_form'), 'database_template_form' ) );
$form->add( new \IPS\Helpers\Form\Text( 'database_key', ! empty( $current ) ? $current->key : FALSE, FALSE, array(), function( $val )
{
@@ -1745,10 +1792,7 @@ class _databases extends \IPS\Node\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'database_tags_enabled' , $current ? $current->tags_enabled : FALSE, FALSE, array( 'togglesOn' => array( 'database_tags_noprefixes', 'database_tags_predefined' ) ), NULL, NULL, NULL, 'database_tags_enabled' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'database_tags_noprefixes', $current ? ! $current->tags_noprefixes : FALSE, FALSE, array(), NULL, NULL, NULL, 'database_tags_noprefixes' ) );
if ( ! \IPS\Settings::i()->tags_open_system )
{
$form->add( new \IPS\Helpers\Form\Text( 'database_tags_predefined', $current ? $current->tags_predefined: '', FALSE, array( 'autocomplete' => array( 'unique' => 'true' ), 'nullLang' => 'database_tags_predefined_unlimited' ), NULL, NULL, NULL, 'database_tags_predefined' ) );
}
$form->add( new \IPS\Helpers\Form\Text( 'database_tags_predefined', $current ? $current->tags_predefined: '', FALSE, array( 'autocomplete' => array( 'unique' => 'true' ), 'nullLang' => 'database_tags_predefined_unlimited' ), NULL, NULL, NULL, 'database_tags_predefined' ) );
}
$form->addHeader( 'content_database_form_options_fields' );
@@ -1774,12 +1818,12 @@ class _databases extends \IPS\Node\Controller
$ffsettings = $current->fixed_field_settings;
if ( isset( $ffsettings['record_image']['image_dims'] ) and is_array( $ffsettings['record_image']['image_dims'] ) )
if ( isset( $ffsettings['record_image']['image_dims'] ) and \is_array( $ffsettings['record_image']['image_dims'] ) )
{
$widthHeight = $ffsettings['record_image']['image_dims'];
}
if ( isset( $ffsettings['record_image']['thumb_dims'] ) and is_array( $ffsettings['record_image']['thumb_dims'] ) )
if ( isset( $ffsettings['record_image']['thumb_dims'] ) and \is_array( $ffsettings['record_image']['thumb_dims'] ) )
{
$thumbWidthHeight = $ffsettings['record_image']['thumb_dims'];
}
@@ -1857,6 +1901,17 @@ class _databases extends \IPS\Node\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'database_forum_delete' , $current ? $current->forum_delete : FALSE, FALSE, array(), NULL, NULL, NULL, 'database_forum_delete' ) );
}
/* SEO */
$form->addTab( 'content_database_form_seo' );
$form->addHeader( 'database_canonical_header' );
$form->add( new \IPS\Helpers\Form\Radio( 'database_canonical_flag', ! empty( $current ) ? $current->canonical_flag : NULL, FALSE, array(
'options' => array(
'0' => 'database_canonical_flag_0',
'1' => 'database_canonical_flag_1'
)
) ) );
if ( ! $current )
{
$form->addTab( 'content_database_form_options_page' );
@@ -1920,7 +1975,7 @@ class _databases extends \IPS\Node\Controller
foreach( $pageFormFields as $name => $field )
{
if ( is_array( $field ) )
if ( \is_array( $field ) )
{
$form->addHeader( $field[0] );
}
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\databases;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _fields extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -130,6 +135,8 @@ class _fields extends \IPS\Node\Controller
*/
public function enableToggle()
{
\IPS\Session::i()->csrfCheck();
$class = '\IPS\cms\Fields' . \IPS\Request::i()->database_id;
$class::setFixedFieldVisibility( \IPS\Request::i()->id, (boolean) \IPS\Request::i()->status );
@@ -152,6 +159,8 @@ class _fields extends \IPS\Node\Controller
*/
public function setAsTitle()
{
\IPS\Session::i()->csrfCheck();
$class = '\IPS\cms\Fields' . \IPS\Request::i()->database_id;
$database = \IPS\cms\Databases::load( \IPS\Request::i()->database_id );
@@ -180,6 +189,8 @@ class _fields extends \IPS\Node\Controller
*/
public function setAsContent()
{
\IPS\Session::i()->csrfCheck();
$class = '\IPS\cms\Fields' . \IPS\Request::i()->database_id;
$database = \IPS\cms\Databases::load( \IPS\Request::i()->database_id );
@@ -236,7 +247,7 @@ class _fields extends \IPS\Node\Controller
$matrix->columns[ $k ] = function( $key, $value, $data ) use ( $perms, $k, $v )
{
$groupId = mb_substr( $key, 0, -( 2 + mb_strlen( $k ) ) );
return new \IPS\Helpers\Form\Checkbox( $key, isset( $perms[ "perm_{$v}" ] ) and ( $perms[ "perm_{$v}" ] === '*' or in_array( $groupId, explode( ',', $perms[ "perm_{$v}" ] ) ) ) );
return new \IPS\Helpers\Form\Checkbox( $key, isset( $perms[ "perm_{$v}" ] ) and ( $perms[ "perm_{$v}" ] === '*' or \in_array( $groupId, explode( ',', $perms[ "perm_{$v}" ] ) ) ) );
};
$matrix->checkAlls[ $k ] = ( $perms[ "perm_{$v}" ] === '*' );
}
@@ -276,7 +287,7 @@ class _fields extends \IPS\Node\Controller
{
foreach ( $permMap as $k => $v )
{
if ( isset( $perms[ $k ] ) and $perms[ $k ] and is_array( $_perms[ $v ] ) )
if ( isset( $perms[ $k ] ) and $perms[ $k ] and \is_array( $_perms[ $v ] ) )
{
$_perms[ $v ][] = $group;
}
@@ -286,7 +297,7 @@ class _fields extends \IPS\Node\Controller
/* Finalise */
foreach ( $_perms as $k => $v )
{
$save[ "perm_{$k}" ] = is_array( $v ) ? implode( $v, ',' ) : $v;
$save[ "perm_{$k}" ] = \is_array( $v ) ? implode( ',', $v ) : $v;
}
$class::setFixedFieldPermissions( \IPS\Request::i()->field, $save );
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\databases;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _records extends \IPS\Dispatcher\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Execute
*
@@ -362,7 +367,7 @@ class _records extends \IPS\Dispatcher\Controller
foreach( $formElements as $name => $field )
{
if ( in_array( $name, $manuallyHandledFields ) )
if ( \in_array( $name, $manuallyHandledFields ) )
{
continue;
}
@@ -411,7 +416,12 @@ class _records extends \IPS\Dispatcher\Controller
)
), NULL, NULL, NULL, 'record_author_choice' ) );
$form->add( new \IPS\Helpers\Form\Member( 'record_member_id', ( $currentMember and $currentMember->member_id ) ? $currentMember : NULL, FALSE, array(), NULL, NULL, NULL, 'record_member_id' ) );
$form->add( new \IPS\Helpers\Form\Member( 'record_member_id', ( $currentMember and $currentMember->member_id ) ? $currentMember : NULL, FALSE, array(), function( $val ) {
if( !$val AND \IPS\Request::i()->record_author_choice == 'notme' )
{
throw new \DomainException( 'form_required' );
}
}, NULL, NULL, 'record_member_id' ) );
if ( isset( $formElements['record_allow_comments'] ) )
{
@@ -487,7 +497,7 @@ class _records extends \IPS\Dispatcher\Controller
}
else if ( ! $current->member_id and $values['record_author_choice'] !== 'guest' )
{
$values['record_member_id'] = \IPS\Member::loggedIn();
$values['record_member_id'] = ( $values['record_author_choice'] === 'me' ) ? \IPS\Member::loggedIn() : $values['record_member_id'];
$changeAuthor = TRUE;
}
else if ( $values['record_author_choice'] === 'me' )
+115 -5
View File
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,10 +23,15 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _ajax extends \IPS\Dispatcher\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Return a CSS or HTML menu
*
* @return html
* @return void
*/
public function loadMenu()
{
@@ -73,7 +78,7 @@ class _ajax extends \IPS\Dispatcher\Controller
/**
* Return HTML template as JSON
*
* @return string
* @return void
*/
public function loadTemplate()
{
@@ -121,7 +126,7 @@ class _ajax extends \IPS\Dispatcher\Controller
{
try
{
if ( is_numeric( $t_key ) )
if ( \is_numeric( $t_key ) )
{
$template = \IPS\cms\Templates::load( $t_key, 'template_id' );
}
@@ -160,7 +165,112 @@ class _ajax extends \IPS\Dispatcher\Controller
}
else
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'templates', 'cms', 'admin' )->viewTemplate( $templateArray ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'templates', 'cms', 'admin' )->viewTemplate( $templateArray ) ), 200, 'text/html' );
}
}
/**
* [AJAX] Search templates
*
* @return void
*/
public function searchtemplates()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'template_manage' );
$where = array();
if ( \IPS\Request::i()->term )
{
$where[] = array( '( LOWER(template_title) LIKE ? OR LOWER(template_content) LIKE ? )', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
}
if ( ! \in_array( 'custom', explode( ',', \IPS\Request::i()->filters ) ) )
{
$where[] = array( 'template_master=1 OR (template_user_created=1 and template_user_edited=0)' );
}
if ( ! \in_array( 'unmodified', explode( ',', \IPS\Request::i()->filters ) ) )
{
$where[] = array( 'template_user_created=1 and template_user_edited=1' );
}
$select = \IPS\Db::i()->select(
'*',
'cms_templates',
$where,
'template_location, template_group, template_title, template_master desc'
);
$return = array();
foreach( $select as $result )
{
$return[ $result['template_location'] ][ $result['template_group'] ][ $result['template_key'] ] = $result['template_title'];
}
\IPS\Output::i()->json( $return );
}
/**
* Load Tags
*
* @return void
*/
public function loadTags(): void
{
$page = NULL;
if ( isset( \IPS\Request::i()->pageId ) )
{
try
{
$page = \IPS\cms\Pages\Page::load( \IPS\Request::i()->pageId );
}
catch( \OutOfRangeException $e ) {}
}
$tags = array();
$tagLinks = array();
if ( $page and $page->id == \IPS\Settings::i()->cms_error_page )
{
$tags['cms_error_page']['{error_message}'] = 'cms_error_page_message';
$tags['cms_error_page']['{error_code}'] = 'cms_error_page_code';
}
foreach( \IPS\cms\Databases::roots( NULL, NULL ) as $id => $db )
{
if ( ! $db->page_id )
{
$tags['cms_tag_databases']['{database="' . $db->key . '"}'] = $db->_title;
}
}
foreach( \IPS\cms\Blocks\Block::roots( NULL, NULL ) as $id => $block )
{
$tags['cms_tag_blocks']['{block="' . $block->key . '"}'] = $block->_title;
}
foreach( \IPS\Db::i()->select( '*', 'cms_pages', NULL, 'page_full_path ASC', array( 0, 50 ) ) as $page )
{
$tags['cms_tag_pages']['{pageurl="' . $page['page_full_path'] . '"}' ] = \IPS\Member::loggedIn()->language()->addToStack( \IPS\cms\Pages\Page::$titleLangPrefix . $page['page_id'] );
}
/* If we can manage words, then the header needs to always show */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'languages', 'lang_words' ) )
{
$tags['cms_tag_lang'] = array();
$tagLinks['cms_tag_lang'] = array(
'icon' => 'plus',
'title' => \IPS\Member::loggedIn()->language()->addToStack('add_word'),
'link' => \IPS\Http\Url::internal( "app=core&module=languages&controller=languages&do=addWord" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'add_word' ), 'ipsDialog-remoteSubmit' => TRUE, 'action' => "wordForm" )
);
}
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( "word_is_custom=? AND lang_id=?", 1, \IPS\Member::loggedIn()->language()->_id ) ) AS $lang )
{
$tags['cms_tag_lang']['{lang="' . $lang['word_key'] . '"}'] = $lang['word_custom'] ?: $lang['word_default'];
}
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorTags( $tags, $tagLinks ) ), 200, 'text/html' );
}
}
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _blocks extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -82,6 +87,7 @@ class _blocks extends \IPS\Node\Controller
{
if ( isset( \IPS\Request::i()->id ) )
{
\IPS\Session::i()->csrfCheck();
\IPS\cms\Blocks\Block::deleteCompiled( \IPS\Request::i()->id );
}
@@ -100,6 +106,17 @@ class _blocks extends \IPS\Node\Controller
return $buttons;
}
/**
* Fetch any additional HTML for this row
*
* @param object $node Node returned from $nodeClass::load()
* @return NULL|string
*/
public function _getRowHtml( $node )
{
return \IPS\Theme::i()->getTemplate( 'blocks', 'cms', 'admin' )->rowHtml( $node );
}
/**
* Add block, pre form
@@ -211,4 +228,33 @@ class _blocks extends \IPS\Node\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('block_embed_title');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( '', \IPS\Theme::i()->getTemplate( 'blocks', 'cms', 'admin' )->embedCode( $block, $embedKey ) );;
}
/**
* Load tags
*
* @return void
*/
public function loadTags(): void
{
$tags = array();
$tagLinks = array();
/* If we can manage words, then the header needs to always show */
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'languages', 'lang_words' ) )
{
$tags['cms_tag_lang'] = array();
$tagLinks['cms_tag_lang'] = array(
'icon' => 'plus',
'title' => \IPS\Member::loggedIn()->language()->addToStack('add_word'),
'link' => \IPS\Http\Url::internal( "app=core&module=languages&controller=languages&do=addWord" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'add_word' ), 'ipsDialog-remoteSubmit' => TRUE )
);
}
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( "word_is_custom=? AND lang_id=?", 1, \IPS\Member::loggedIn()->language()->_id ) ) AS $lang )
{
$tags['cms_tag_lang']['{lang="' . $lang['word_key'] . '"}'] = $lang['word_custom'] ?: $lang['word_default'];
}
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorTags( $tags, $tagLinks ) ), 200, 'text/html' );
}
}
+23 -16
View File
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _media extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -75,15 +80,17 @@ class _media extends \IPS\Node\Controller
*/
public function deleteByFileIds()
{
\IPS\Session::i()->csrfCheck();
if ( isset( \IPS\Request::i()->fileIds ) )
{
$ids = \IPS\Request::i()->fileIds;
if ( ! is_array( $ids ) )
if ( ! \is_array( $ids ) )
{
$try = json_decode( $ids, TRUE );
if ( ! is_array( $try ) )
if ( ! \is_array( $try ) )
{
$ids = array( $ids );
}
@@ -93,7 +100,7 @@ class _media extends \IPS\Node\Controller
}
}
if ( count( $ids ) )
if ( \count( $ids ) )
{
\IPS\cms\Media::deleteByFileIds( $ids );
}
@@ -134,7 +141,7 @@ class _media extends \IPS\Node\Controller
}
if( \IPS\Request::i()->isAjax() ){
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json' );
}
return $data;
@@ -179,7 +186,7 @@ class _media extends \IPS\Node\Controller
}
if( \IPS\Request::i()->isAjax() ){
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json' );
}
return $rows;
@@ -195,7 +202,7 @@ class _media extends \IPS\Node\Controller
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $output, 200, 'text/html', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( $output, 200, 'text/html' );
}
else
{
@@ -228,7 +235,7 @@ class _media extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form( 'form', 'upload' );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', NULL, FALSE, array( 'allowedFileTypes' => array_merge( \IPS\File::$safeFileExtensions, array( 'pdf' ) ), 'obscure' => FALSE, 'maxFileSize' => 5, 'storageExtension' => 'cms_Media', 'storageContainer' => 'pages_media', 'multiple' => FALSE, 'minimize' => FALSE ), NULL, NULL, NULL, 'media_filename' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', NULL, FALSE, array( 'allowedFileTypes' => array_merge( \IPS\File::$safeFileExtensions, array( 'pdf' ) ), 'obscure' => FALSE, 'storageExtension' => 'cms_Media', 'storageContainer' => 'pages_media', 'multiple' => FALSE, 'minimize' => FALSE ), NULL, NULL, NULL, 'media_filename' ) );
if ( $values = $form->values() )
{
@@ -277,7 +284,7 @@ class _media extends \IPS\Node\Controller
}
}
\IPS\Output::i()->sendOutput( json_encode( array( 'fileID' => $media->id, 'folderID' => $media->parent, 'rows' => $rows ) ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( array( 'fileID' => $media->id, 'folderID' => $media->parent, 'rows' => $rows ) ), 200, 'application/json' );
}
else
{
@@ -298,7 +305,7 @@ class _media extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form( 'form', 'upload' );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', NULL, FALSE, array( 'allowedFileTypes' => array_merge( \IPS\File::$safeFileExtensions, array( 'pdf', 'svg' ) ), 'obscure' => FALSE, 'maxFileSize' => 5, 'storageExtension' => 'cms_Media', 'storageContainer' => 'pages_media', 'multiple' => true, 'minimize' => FALSE ), NULL, NULL, NULL, 'media_filename' ) );
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', NULL, FALSE, array( 'allowedFileTypes' => array_merge( \IPS\File::$safeFileExtensions, array( 'pdf', 'svg' ) ), 'obscure' => FALSE, 'storageExtension' => 'cms_Media', 'storageContainer' => 'pages_media', 'multiple' => true, 'minimize' => FALSE ), NULL, NULL, NULL, 'media_filename' ) );
if ( ! isset( \IPS\Request::i()->media_parent ) and ! \IPS\Request::i()->media_parent )
{
@@ -380,7 +387,7 @@ class _media extends \IPS\Node\Controller
}
}
\IPS\Output::i()->sendOutput( json_encode( array( 'count' => $count, 'folderID' => $parent, 'rows' => $rows ) ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( array( 'count' => $count, 'folderID' => $parent, 'rows' => $rows ) ), 200, 'application/json' );
}
else
{
@@ -412,7 +419,7 @@ class _media extends \IPS\Node\Controller
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json' );
}
else
{
@@ -453,13 +460,13 @@ class _media extends \IPS\Node\Controller
$output['dimensions'] = $dimensions[0] . ' x ' . $dimensions[1];
}
\IPS\Output::i()->sendOutput( json_encode( $output ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( json_encode( $output ), 200, 'application/json' );
}
/**
* Return HTML for a page row
*
* @param array $row Row data
* @param array $item Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
@@ -471,7 +478,7 @@ class _media extends \IPS\Node\Controller
/**
* Return HTML for a folder row
*
* @param array $row Row data
* @param array $folder Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
@@ -484,7 +491,7 @@ class _media extends \IPS\Node\Controller
/**
* Fetch rows of folders/pages
*
* @param int $folderId Parent ID to fetch from
* @param int $folderId Parent ID to fetch from
*/
public static function getRowsForTree( $folderId=0 )
{
+24 -122
View File
@@ -13,7 +13,7 @@
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -24,6 +24,11 @@ exit;
*/
class _pages extends \IPS\Node\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Node Class
*/
@@ -122,14 +127,6 @@ class _pages extends \IPS\Node\Controller
FALSE
);
/* Add a button for managing DB settings */
\IPS\Output::i()->sidebar['actions']['pagessettings'] = array(
'title' => 'cms_pages_settings',
'icon' => 'wrench',
'link' => \IPS\Http\Url::internal( 'app=cms&module=pages&controller=pages&do=settings' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings') )
);
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'pages', 'page_add' ) )
{
\IPS\Output::i()->sidebar['actions']['add_folder'] = array(
@@ -150,115 +147,6 @@ class _pages extends \IPS\Node\Controller
}
}
/**
* Page settings form
*
* @return void
*/
protected function settings()
{
$url = parse_url( \IPS\Settings::i()->base_url );
$disabled = FALSE;
$options = array();
$url['path'] = preg_replace( '#^/?(.+?)?/?$#', '\1', $url['path'] );
$disabled = ( \IPS\Settings::i()->cms_use_different_gateway or $url['path'] ) ? FALSE : TRUE;
$dirs = explode( '/', $url['path'] );
if ( count( $dirs ) )
{
array_pop( $dirs );
$base = $url['scheme'] . '://' . $url['host'];
if ( isset( $url['port'] ) )
{
$base .= ':' .$url['port'];
}
$base .= '/';
$options[ $base ] = $base;
foreach( $dirs as $dir )
{
$base .= $dir . '/';
$options[ $base ] = $base;
}
}
if ( $disabled )
{
\IPS\Member::loggedIn()->language()->words['cms_use_different_gateway_warning'] = \IPS\Member::loggedIn()->language()->addToStack('cms_pages_different_gateway_impossible');
}
if ( \IPS\Settings::i()->htaccess_mod_rewrite )
{
\IPS\Member::loggedIn()->language()->words['cms_root_page_url_desc'] = \IPS\Member::loggedIn()->language()->addToStack('cms_root_page_url_rewrite_desc');
}
$form = new \IPS\Helpers\Form( 'form', 'save' );
$form->add( new \IPS\Helpers\Form\YesNo( 'cms_use_different_gateway', \IPS\Settings::i()->cms_use_different_gateway, FALSE, array( 'togglesOn' => array( 'cms_root_page_url' ), 'disabled' => $disabled ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'cms_root_page_url', \IPS\Settings::i()->cms_root_page_url, FALSE, array( 'options' => $options ), function( $val )
{
if ( $val and \IPS\Request::i()->cms_use_different_gateway )
{
if ( mb_substr( $val, -1 ) !== '/' )
{
$val .= '/';
}
$page = \IPS\cms\Pages\Page::getDefaultPage();
$response = \IPS\Http\Url::external( ( \IPS\Settings::i()->htaccess_mod_rewrite ? $val . $page->full_path : $val . 'index.php?/' . $page->full_path ) )->request( NULL, NULL, FALSE )->get();
if ( $response->httpResponseCode != 200 and $response->httpResponseCode != 303 and ( \IPS\Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
{
if ( \IPS\Settings::i()->htaccess_mod_rewrite )
{
throw new \LogicException( 'pages_different_gateway_load_error_rewrite' );
}
else
{
throw new \LogicException( 'pages_different_gateway_load_error' );
}
}
}
}, NULL, NULL, 'cms_root_page_url' ) );
$form->add( new \IPS\Helpers\Form\Node( 'cms_error_page', \IPS\Settings::i()->cms_error_page ? \IPS\Settings::i()->cms_error_page : 0, FALSE,array(
'class' => '\IPS\cms\Pages\Page',
'zeroVal' => 'cms_error_page_none',
'subnodes' => true,
'permissionCheck' => function( $node )
{
return $node->type == 'html';
}
) ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Member::clearCreateMenu();
/* Clear Sidebar Caches */
\IPS\Widget::deleteCaches();
/* Possible gateway choice changed and thusly menu and page_urls will change */
if ( isset( \IPS\Data\Store::i()->pages_page_urls ) )
{
unset( \IPS\Data\Store::i()->pages_page_urls );
}
if ( isset( \IPS\Data\Store::i()->frontNavigation ) )
{
unset( \IPS\Data\Store::i()->frontNavigation );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=cms&module=pages&controller=pages" ), 'saved' );
}
/* Display */
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings'), $form, FALSE );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings');
}
/**
* Download .htaccess file
*
@@ -269,7 +157,7 @@ class _pages extends \IPS\Node\Controller
$dir = str_replace( \IPS\CP_DIRECTORY . '/index.php', '', $_SERVER['PHP_SELF'] );
$dirs = explode( '/', trim( $dir, '/' ) );
if ( count( $dirs ) )
if ( \count( $dirs ) )
{
array_pop( $dirs );
$dir = implode( '/', $dirs );
@@ -350,6 +238,7 @@ FILE;
{
if ( isset( \IPS\Request::i()->id ) )
{
\IPS\Session::i()->csrfCheck();
\IPS\cms\Pages\Page::deleteCompiled( \IPS\Request::i()->id );
}
@@ -363,10 +252,23 @@ FILE;
*/
protected function setAsDefault()
{
\IPS\Session::i()->csrfCheck();
\IPS\cms\Pages\Page::load( \IPS\Request::i()->id )->setAsDefault();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=cms&module=pages&controller=pages" ), 'saved' );
}
/**
* Set as default error page
*
* @return void
*/
protected function toggleDefaultError()
{
\IPS\Session::i()->csrfCheck();
\IPS\Settings::i()->changeValues( array( 'cms_error_page' => \IPS\Request::i()->id ? \IPS\Request::i()->id : NULL ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=cms&module=pages&controller=pages" ), 'saved' );
}
/**
* Tree Search
*
@@ -395,7 +297,7 @@ FILE;
/**
* Return HTML for a page row
*
* @param array $row Row data
* @param array $page Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
@@ -413,7 +315,7 @@ FILE;
/**
* Return HTML for a folder row
*
* @param array $row Row data
* @param array $folder Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
@@ -425,7 +327,7 @@ FILE;
/**
* Fetch rows of folders/pages
*
* @param int $folderId Parent ID to fetch from
* @param int $folderId Parent ID to fetch from
*/
public static function getRowsForTree( $folderId=0 )
{
+280 -220
View File
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _templates extends \IPS\Dispatcher\Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
/**
* Execute
*
@@ -41,6 +46,8 @@ class _templates extends \IPS\Dispatcher\Controller
*/
public function importInDev()
{
\IPS\Session::i()->csrfCheck();
\IPS\cms\Theme::importInDev('database');
\IPS\cms\Theme::importInDev('page');
@@ -67,7 +74,7 @@ class _templates extends \IPS\Dispatcher\Controller
move_uploaded_file( $values['cms_templates_import'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=importProcess' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=importProcess' )->csrf()->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) ) );
}
else
{
@@ -85,100 +92,198 @@ class _templates extends \IPS\Dispatcher\Controller
*/
public function importProcess()
{
\IPS\Session::i()->csrfCheck();
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
{
\IPS\Output::i()->error( 'generic_error', '3T285/3', 403, '' );
}
/* Open XML file */
$xml = new \IPS\Xml\XMLReader;
$xml->open( \IPS\Request::i()->file );
$prefix = 'm' . date('m') . '_' . date('d') . '_' . date('y') . '_';
$templates = \IPS\cms\Theme::i()->getRawTemplates( 'cms', NULL, NULL, \IPS\cms\Theme::RETURN_ALL );
if ( ! @$xml->read() )
$result = NULL;
try
{
$result = \IPS\cms\Templates::importUserTemplateXml( \IPS\Request::i()->file );
}
catch( \Throwable $e )
{
@unlink( \IPS\Request::i()->file );
\IPS\Output::i()->error( 'xml_upload_invalid', '2C163/1', 403, '' );
}
$xml->read();
while ( $xml->read() )
/* Done */
if ( $result instanceof \IPS\Http\Url\Internal )
{
if ( $xml->name === 'template' )
\IPS\Output::i()->redirect( $result );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ), 'cms_templates_imported' );
}
}
/**
* Show and manage conflicts
*
* @return void
*/
public function conflicts()
{
$key = \intval( \IPS\Request::i()->key );
$form = new \IPS\Helpers\Form( 'form', 'theme_conflict_save' );
$conflicts = array();
/* If this is part of plugin/app installation, set relevant form data */
if( \IPS\Request::i()->app OR \IPS\Request::i()->plugin )
{
if( \IPS\Request::i()->app )
{
$node = new \SimpleXMLElement( $xml->readOuterXML() );
$attrs = array();
$form->hiddenValues['app'] = \IPS\Request::i()->app;
}
elseif( \IPS\Request::i()->plugin )
{
$form->hiddenValues['plugin'] = \IPS\Request::i()->plugin;
}
foreach( $node->attributes() as $k => $v )
{
$attrs[ $k ] = (string) $v;
}
if( \IPS\Request::i()->marketplace )
{
$form->hiddenValues['marketplace'] = (int) \IPS\Request::i()->marketplace;
}
/* Any kids of your own? */
foreach( $node->children() as $k => $v )
{
$tryJson = json_decode( $v, TRUE );
$attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v;
}
if( \IPS\Request::i()->lang )
{
$form->hiddenValues['lang'] = \IPS\Request::i()->lang;
}
}
if ( isset( $attrs['template_title'] ) and isset( $attrs['template_location'] ) and isset( $attrs['template_group'] ) )
/* Get conflict data */
foreach( \IPS\Db::i()->select( '*', 'cms_template_conflicts', array( 'conflict_key=?', $key ) )->setKeyField( 'conflict_id' ) as $cid => $data )
{
$conflicts[ $cid ] = $data;
}
require_once \IPS\ROOT_PATH . "/system/3rd_party/Diff/class.Diff.php";
foreach( $conflicts as $cid => $data )
{
try
{
$template = \IPS\cms\Templates::load( $data['conflict_item_id'], 'template_id' );
if ( !\IPS\Login::compareHashes( md5( $data['conflict_content'] ), md5( $template->content ) ) )
{
/* Got this template? */
if ( $attrs['template_location'] === 'database' )
if ( mb_strlen( $data['conflict_content'] ) <= 10000 )
{
/* Database templates are really governed by the group as they are a collection of templates */
if ( isset( $templates['cms'][$attrs['template_location']][$attrs['template_group']] ) )
{
$attrs['template_group'] = $prefix . $attrs['template_group'];
}
$conflicts[ $cid ]['diff'] = \Diff::toTable( \Diff::compare( $template->content, $data['conflict_content'] ) );
$conflicts[ $cid ]['large'] = false;
}
else
{
/* But post and block templates are not */
if ( isset( $templates['cms'][$attrs['template_location']][$attrs['template_group']] ) )
{
$exists = FALSE;
foreach ( $templates['cms'][$attrs['template_location']][$attrs['template_group']] as $key => $template )
{
if ( $template['template_title'] === $attrs['template_title'] )
{
$exists = TRUE;
break;
}
}
if ( $exists )
{
$attrs['template_title'] = $prefix . $attrs['template_title'];
}
}
$conflicts[ $cid ]['diff'] = \IPS\Theme::i()->getTemplate( 'customization' )->templateConflictLarge( $template->content, $data['conflict_content'], 'html' );
$conflicts[ $cid ]['large'] = true;
}
$obj = new \IPS\cms\Templates;
$obj->location = $attrs['template_location'];
$obj->group = $attrs['template_group'];
$obj->title = $attrs['template_title'];
$obj->params = $attrs['template_params'];
$obj->content = $attrs['template_content'];
$obj->original_group = $attrs['template_original_group'];
$obj->type = 'template';
$obj->user_created = 1;
$obj->user_edited = 1;
$obj->desc = '';
$obj->save();
$form->add( new \IPS\Helpers\Form\Radio( 'conflict_' . $data['conflict_id'], 'old', false, array('options' => array('old' => '', 'new' => '')) ) );
}
else
{
unset( $conflicts[ $cid ] );
}
}
catch( \Exception $e )
{
unset( $conflicts[ $cid ] );
}
}
$obj->key = $obj->location . \IPS\Http\Url\Friendly::seoTitle( $obj->group ) . '_' . \IPS\Http\Url\Friendly::seoTitle( $obj->title ) . '_' . $obj->id;
$obj->save();
if ( $values = $form->values() )
{
$conflicts = array();
$conflictIds = array();
$templates = array();
foreach( $values as $k => $v )
{
if ( \substr( $k, 0, 9 ) == 'conflict_' )
{
if ( $v == 'new' )
{
$conflictIds[ (int) \substr( $k, 9 ) ] = $v;
}
}
}
$xml->next();
if ( \count( $conflictIds ) )
{
/* Get conflict data */
foreach( \IPS\Db::i()->select( '*', 'cms_template_conflicts', \IPS\Db::i()->in( 'conflict_id', array_keys( $conflictIds ) ) )->setKeyField( 'conflict_id' ) as $cid => $data )
{
$conflicts[ $data['conflict_item_id'] ] = $data;
}
}
if ( \count( $conflicts ) )
{
$templates = iterator_to_array( \IPS\Db::i()->select(
'*',
'cms_templates',
array( \IPS\Db::i()->in( 'template_id', array_keys( $conflicts ) ) )
)->setKeyField( 'template_id' ) );
}
foreach( $templates as $templateid => $template )
{
if ( isset( $conflicts[ $template['template_id'] ] ) )
{
try
{
$templateObj = \IPS\cms\Templates::load( $template['template_id'], 'template_id' );
$templateObj->params = $conflicts[ $template['template_id'] ]['conflict_data'];
$templateObj->content = $conflicts[ $template['template_id'] ]['conflict_content'];
$templateObj->user_edited = (int) $templateObj->isDifferentFromMaster();
$templateObj->save();
}
catch( \Exception $e ) { }
}
}
/* Clear out conflicts for this theme set */
\IPS\Db::i()->delete( 'cms_template_conflicts', array('conflict_key=?', \IPS\Request::i()->key ) );
$lang = NULL;
if( !empty( $values['lang'] ) )
{
$lang = $values['lang'] == 'updated' ? 'app_now_updated' : 'app_now_installed';
}
if( !empty( $values['marketplace'] ) )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=marketplace&controller=marketplace&do=viewFile&id=' . $values['marketplace'] ), $lang );
}
elseif( !empty( $values['app'] ) )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=applications' ), $lang );
}
elseif( !empty( $values['plugin'] ) )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=applications&controller=plugins' ), 'plugin_now_installed' );
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ), 'completed' );
}
@unlink( \IPS\Request::i()->file );
if ( \count( $conflicts ) )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/diff.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/codemirror.js', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'customization/themes.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_templates.js', 'core', 'admin' ) );
/* Done */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ), 'cms_templates_imported' );
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'templates', 'cms' ), 'templateConflict' ), $conflicts );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ), 'completed' );
}
}
/**
@@ -188,149 +293,17 @@ class _templates extends \IPS\Dispatcher\Controller
*/
public function export()
{
$form = new \IPS\Helpers\Form( 'form', 'next' );
$templates = array();
$form->addMessage( 'cms_templates_export_description', 'ipsMessage ipsMessage_information' );
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_DATABASE_ONLY + \IPS\cms\Templates::RETURN_ALL ) as $template )
{
$title = \IPS\cms\Templates::readableGroupName( $template->group );
if ( $template->location === 'database' )
{
$templates['database'][ $template->group ] = $title;
}
else if ( $template->location === 'block' )
{
$templates['block'][ $template->key ] = $title . ' &gt; ' . $template->title;
}
else if ( $template->location === 'page' )
{
$templates['page'][ $template->key ] = $title . ' &gt; ' . $template->title;
}
}
foreach( $templates as $location => $data )
{
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'templates_' . $location, FALSE, FALSE, array( 'options' => $data ) ) );
}
$form->addButton( 'cms_templates_export_return', 'link', \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates" ) );
$form = \IPS\cms\Templates::exportForm();
if ( $values = $form->values() )
{
$exportTemplates = array();
foreach( $templates as $location => $data )
{
if ( isset( $values[ 'templates_' . $location ] ) and count( $values[ 'templates_' . $location ] ) )
{
if ( $location === 'database' )
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array('database'), array_values( $values[ 'templates_' . $location ] ) );
$xml = \IPS\cms\Templates::exportAsXml( $values );
foreach( $tmp['cms'] as $loc => $data )
{
if ( $loc === $location )
{
foreach ( $data as $key => $tdata )
{
foreach ( $tdata as $tkey => $tkdata )
{
$exportTemplates['cms'][ $location ][ $key ][ $tkey ] = $tkdata;
}
}
}
}
}
else
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array( $location ), NULL, \IPS\cms\Theme::RETURN_DATABASE_ONLY + \IPS\cms\Theme::RETURN_ALL );
foreach( $tmp['cms'] as $loc => $data )
{
if ( $loc === $location )
{
foreach( $data as $key => $tdata )
{
foreach( $tdata as $tkey => $tkdata )
{
if ( in_array( $tkey, $values[ 'templates_' . $location ] ) )
{
$exportTemplates['cms'][ $location ][ $key ][ $tkey ] = $tkdata;
}
}
}
}
}
}
}
}
if ( count( $exportTemplates ) )
{
/* Init */
$xml = new \XMLWriter;
$xml->openMemory();
$xml->setIndent( TRUE );
$xml->startDocument( '1.0', 'UTF-8' );
/* Root tag */
$xml->startElement('templates');
foreach ( $exportTemplates as $app => $location )
{
foreach ( $location as $key => $data )
{
foreach ( $data as $group => $template )
{
foreach( $template as $key => $templateData )
{
/* Initiate the <template> tag */
$xml->startElement( 'template' );
foreach ( $templateData as $k => $v )
{
if ( ! in_array( \substr( $k, 9 ), array( 'content', 'params' ) ) )
{
$xml->startAttribute( $k );
$xml->text( $v );
$xml->endAttribute();
}
}
/* Write (potential) HTML fields */
foreach( array( 'template_params', 'template_content' ) as $field )
{
if ( isset( $templateData[ $field ] ) )
{
$xml->startElement( $field );
if ( preg_match( '/<|>|&/', $templateData[ $field ] ) )
{
$xml->writeCData( str_replace( ']]>', ']]]]><![CDATA[>', $templateData[ $field ] ) );
}
else
{
$xml->text( $templateData[ $field ] );
}
$xml->endElement();
}
}
/* Close the <template> tag */
$xml->endElement();
}
}
}
}
/* Finish */
$xml->endDocument();
\IPS\Output::i()->sendOutput( $xml->outputMemory(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "pages_templates.xml" ) ) );
}
else
if( $xml === NULL )
{
\IPS\Output::i()->error( 'cms_no_templates_selected', '1T285/1', 403, '' );
}
\IPS\Output::i()->sendOutput( $xml->outputMemory(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "pages_templates.xml" ) ) );
}
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates" ), \IPS\Member::loggedIn()->language()->addToStack( 'menu__cms_pages_templates' ) );
@@ -430,7 +403,7 @@ class _templates extends \IPS\Dispatcher\Controller
\IPS\Output::i()->sidebar['actions']['add'] = array(
'icon' => 'cog',
'title' => 'content_import_dev_templates',
'link' => \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates&do=importInDev" ),
'link' => \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates&do=importInDev" )->csrf(),
'data' => array()
);
}
@@ -523,10 +496,21 @@ class _templates extends \IPS\Dispatcher\Controller
/* PHP Keywords cannot be used as template names - so make sure the full template name is not in the list */
$keywords = array( 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor' );
if ( in_array( $val, $keywords ) )
if ( \in_array( $val, $keywords ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'template_reserved_word', FALSE, array( 'htmlsprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $keywords ) ) ) ) );
}
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'cms_templates', array( "LOWER(template_title)=?", mb_strtolower( str_replace( ' ', '_', $val ) ) ) )->first();
if ( $count )
{
throw new \DomainException( 'cms_template_title_exists' );
}
}
catch( \UnderflowException $e ) {}
} ) );
/* Very specific */
@@ -558,7 +542,7 @@ class _templates extends \IPS\Dispatcher\Controller
foreach ( \IPS\Db::i()->select( "*", 'core_widgets', array( 'embeddable=1') ) as $widget )
{
/* Skip disabled applications */
if ( !in_array( $widget['app'], array_keys( \IPS\Application::enabledApplications() ) ) )
if ( !\in_array( $widget['app'], array_keys( \IPS\Application::enabledApplications() ) ) )
{
continue;
}
@@ -609,7 +593,7 @@ class _templates extends \IPS\Dispatcher\Controller
}
}
if ( ! count( $groups ) )
if ( ! \count( $groups ) )
{
$groups[ $type ] = \IPS\cms\Templates::readableGroupName( $type );
}
@@ -621,7 +605,18 @@ class _templates extends \IPS\Dispatcher\Controller
'new' => array( 'group_new' ) )
) ) );
$form->add( new \IPS\Helpers\Form\Text( 'template_group_new', NULL, FALSE, array( 'regex' => '/^([a-z_][a-z0-9_]+?)?$/' ), NULL, NULL, NULL, 'group_new' ) );
$form->add( new \IPS\Helpers\Form\Text( 'template_group_new', NULL, FALSE, array( 'regex' => '/^([a-z_][a-z0-9_]+?)?$/' ), function( $val ) {
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'cms_templates', array( "LOWER(template_group)=?", mb_strtolower( str_replace( ' ', '_', $val ) ) ) )->first();
if ( $count )
{
throw new \DomainException( 'cms_template_group_exists' );
}
}
catch( \UnderflowException $e ) {}
}, NULL, NULL, 'group_new' ) );
$form->add( new \IPS\Helpers\Form\Select( 'template_group_existing', NULL, FALSE, array( 'options' => $groups ), NULL, NULL, NULL, 'group_existing' ) );
}
@@ -779,7 +774,7 @@ class _templates extends \IPS\Dispatcher\Controller
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates' ), 'saved' );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates' )->setQueryString( ['id' => $newTemplate->id, 't_location' => $newTemplate->location, 't_type' => $type ] ), 'saved' );
}
}
@@ -846,6 +841,27 @@ class _templates extends \IPS\Dispatcher\Controller
}
}
/**
* Show a difference report for an individual template file
*
* @return void
*/
protected function diffTemplate()
{
$customVersion = \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_id=?', (int) \IPS\Request::i()->t_item_id ) )->first();
try
{
$original = \IPS\Db::i()->select( 'template_content', 'cms_templates', array( 'template_location=? and template_group=? and template_title=? and template_master=1', $customVersion['template_location'], $customVersion['template_original_group'], $customVersion['template_title'] ) )->first();
}
catch( \UnderflowException $e )
{
$original = FALSE;
}
\IPS\Output::i()->json( $original );
}
/**
* Saves a template
*
@@ -853,6 +869,8 @@ class _templates extends \IPS\Dispatcher\Controller
*/
public function save()
{
\IPS\Session::i()->csrfCheck();
$key = \IPS\Request::i()->t_key;
$contentKey = 'editor_' . $key;
@@ -864,12 +882,33 @@ class _templates extends \IPS\Dispatcher\Controller
try
{
$obj = \IPS\cms\Templates::load( $key );
$obj->location = \IPS\Request::i()->t_location;
$obj->group = empty( \IPS\Request::i()->t_group ) ? null : \IPS\Request::i()->t_group;
$obj->title = \IPS\Request::i()->t_name;
$obj->params = $variables;
$obj->content = $content;
if ( $obj->master )
{
/* Do not edit a master bit directly, but overload it */
$clone = new \IPS\cms\Templates;
$clone->key = $obj->key;
$clone->title = \IPS\Request::i()->t_name;
$clone->content = $content;
$clone->location = \IPS\Request::i()->t_location;
$clone->group = empty( \IPS\Request::i()->t_group ) ? null : \IPS\Request::i()->t_group;
$clone->params = $variables;
$clone->container = $obj->container;
$clone->position = $obj->position;
$clone->user_edited = 1;
$clone->master = 0;
$clone->save();
}
else
{
$obj->location = \IPS\Request::i()->t_location;
$obj->group = empty( \IPS\Request::i()->t_group ) ? null : \IPS\Request::i()->t_group;
$obj->title = \IPS\Request::i()->t_name;
$obj->params = $variables;
$obj->content = $content;
$obj->user_edited = 1;
}
if( $description )
{
$obj->description = $description;
@@ -935,7 +974,7 @@ class _templates extends \IPS\Dispatcher\Controller
$databases[ $database['database_id'] ] = \IPS\cms\Databases::constructFromData( $database );
}
if ( count( $databases ) )
if ( \count( $databases ) )
{
$names = array();
foreach( $databases as $db )
@@ -946,8 +985,25 @@ class _templates extends \IPS\Dispatcher\Controller
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack( 'cms_database_template_used_in', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $names ) ) ) ), 'ipsMessage ipsMessage_info' );
}
$form->add( new \IPS\Helpers\Form\Text( 'cms_database_group_name', \IPS\cms\Templates::readableGroupName( \IPS\Request::i()->group ), NULL, array( 'regex' => '/^([A-Z_][A-Z0-9_\.\s]+?)$/i' ) ) );
$form->addButton( "delete", "link", \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=deleteTemplateGroup&group=' . \IPS\Request::i()->group . '&t_location=' . \IPS\Request::i()->t_location ), 'ipsButton ipsButton_negative', array( 'data-confirm' => 'true' ) );
$form->add( new \IPS\Helpers\Form\Text( 'cms_database_group_name', \IPS\cms\Templates::readableGroupName( \IPS\Request::i()->group ), NULL, array( 'regex' => '/^([A-Z_][A-Z0-9_\.\s]+?)$/i' ), function( $val ) {
/* PHP Keywords cannot be used as template names - so make sure the full template name is not in the list */
$keywords = array( 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor' );
if ( \in_array( $val, $keywords ) )
{
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'template_reserved_word', FALSE, array( 'htmlsprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $keywords ) ) ) ) );
}
if ( mb_strtolower( str_replace( ' ', '_', $val ) ) != mb_strtolower( str_replace( ' ', '_', \IPS\Request::i()->group ) ) )
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'cms_templates', array( "LOWER(template_group)=?", mb_strtolower( str_replace( ' ', '_', $val ) ) ) )->first();
if ( $count )
{
throw new \DomainException( 'cms_template_group_exists' );
}
}
} ) );
$form->addButton( "delete", "link", \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=deleteTemplateGroup&group=' . \IPS\Request::i()->group . '&t_location=' . \IPS\Request::i()->t_location )->csrf(), 'ipsButton ipsButton_negative', array( 'data-confirm' => 'true' ) );
if ( $values = $form->values() )
{
@@ -983,6 +1039,8 @@ class _templates extends \IPS\Dispatcher\Controller
*/
protected function findAndUpdateTemplates( $new, $old )
{
\IPS\Session::i()->csrfCheck();
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_content LIKE ?', '%' . $old . '%' ) ) as $template )
{
/* Make sure template tags call the correct group */
@@ -1025,6 +1083,8 @@ class _templates extends \IPS\Dispatcher\Controller
*/
public function deleteTemplateGroup()
{
\IPS\Session::i()->csrfCheck();
foreach( \IPS\cms\Templates::$databaseDefaults as $field => $template )
{
\IPS\Db::i()->update( 'cms_databases', array( 'database_template_' . $field => $template ), array( 'database_template_' . $field . ' =?', \IPS\Request::i()->group ) );
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\database;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -36,7 +36,7 @@ class _ajax extends \IPS\Dispatcher\Controller
/**
* Find Record
*
* @retun void
* @return void
*/
public function findRecord()
{
@@ -11,7 +11,7 @@
namespace IPS\cms\modules\front\database;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -94,24 +94,85 @@ class _category extends \IPS\cms\Databases\Controller
}
$RecordsClass = $category::$contentItemClass;
/* AdvancedSearch can wipe out the checked box as it is looking for _checkbox. Note to self in 4.5, rewrite the filter widget to avoid using advancedSearch :/ */
if ( ! isset( \IPS\Request::i()->cms_record_i_started_checkbox ) and isset( \IPS\Request::i()->cms_record_i_started ) and \IPS\Request::i()->cms_record_i_started )
{
\IPS\Request::i()->cms_record_i_started_checkbox = \IPS\Request::i()->cms_record_i_started;
}
/* we need this language later (and in Widgets\DatabaseFilters which is executed just before output) */
\IPS\Member::loggedIn()->language()->words['cms_record_i_started'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_record_i_started_sprintf', NULL, array( 'sprintf' => $database->recordWord() ) );
/* Check cookie */
$where = array();
$cookie = $category->getFilterCookie();
if ( $cookie !== NULL )
{
foreach( $cookie as $f => $v )
{
if ( $f == 'cms_record_i_started' and \IPS\Member::loggedIn()->member_id )
{
$where[] = 'cms_custom_database_' . $database->id . '.member_id=' . \IPS\Member::loggedIn()->member_id;
/* FilterMessage template only accepts \IPS\cms\Fields */
$field = new \IPS\cms\Fields;
$field->id = 'cms_record_i_started';
\IPS\Member::loggedIn()->language()->words['content_field_cms_record_i_started'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_record_i_started_sprintf', NULL, array( 'sprintf' => $database->recordWord() ) );
static::$activeFilters['cms_record_i_started'] = array( 'field' => $field, 'value' => \IPS\Member::loggedIn()->language()->addToStack('content_field_cms_record_i_started_on') );
continue;
}
$k = 'content_field_' . $f;
$displayValue = $customFields[ $f ]->displayValue( $v );
$concat = ',';
if ( $customFields[ $f ]->type === 'Member' )
{
if ( ! empty( $v ) )
{
$newValue = array();
$newDisplayValue = array();
$concat = '\n';
if ( \is_array( $v ) )
{
foreach( $v as $m )
{
$member = \IPS\Member::load( $m );
$newValue[] = $member->member_id;
$newDisplayValue[] = $member->name;
}
}
else
{
$member = \IPS\Member::load( $v );
$newValue[] = $member->member_id;
$newDisplayValue[] = $member->name;
}
$displayValue = implode( ', ', $newDisplayValue );
$v = $newValue;
}
else
{
/* The content_field_x can be an empty array from the member form */
continue;
}
}
if ( isset( $customFields[ $f ] ) and !isset( \IPS\Request::i()->$k ) and $v !== '___any___' )
{
if ( is_array( $v ) )
if ( \is_array( $v ) )
{
if ( array_key_exists( 'start', $v ) or array_key_exists( 'end', $v ) )
{
$start = ( $v['start'] instanceof \IPS\DateTime ) ? $v['start']->getTimestamp() : intval( $v['start'] );
$end = ( $v['end'] instanceof \IPS\DateTime ) ? $v['end']->getTimestamp() : intval( $v['end'] );
$start = ( $v['start'] instanceof \IPS\DateTime ) ? $v['start']->getTimestamp() : \intval( $v['start'] );
$end = ( $v['end'] instanceof \IPS\DateTime ) ? $v['end']->getTimestamp() : \intval( $v['end'] );
if ( $start or $end )
{
@@ -125,16 +186,16 @@ class _category extends \IPS\cms\Databases\Controller
{
if ( $val === 0 or ! empty( $val ) )
{
$like[] = "CONCAT( ',', " . mb_substr( $k, 8 ) . ", ',') LIKE '%," . \IPS\Db::i()->real_escape_string( $val ) . ",%'";
$like[] = "CONCAT( '{$concat}', " . mb_substr( $k, 8 ) . ", '{$concat}') LIKE '%{$concat}" . \IPS\Db::i()->real_escape_string( $val ) . "{$concat}%'";
}
}
$where[] = array( '( ' . \IPS\Db::i()->in( mb_substr( $k, 8 ), $v ) . ( count( $like ) ? " OR (" . implode( ' OR ', $like ) . ') )' : ')' ) );
$where[] = array( '( ' . \IPS\Db::i()->in( mb_substr( $k, 8 ), $v ) . ( \count( $like ) ? " OR (" . implode( ' OR ', $like ) . ') )' : ')' ) );
}
}
else
{
if ( is_bool( $v ) )
if ( \is_bool( $v ) )
{
/* YesNo fields are false or true */
if ( $v === false )
@@ -159,368 +220,471 @@ class _category extends \IPS\cms\Databases\Controller
}
}
static::$activeFilters[ $f ] = array( 'field' => $customFields[ $f ], 'value' => $customFields[ $f ]->displayValue( $v ) );
static::$activeFilters[ $f ] = array( 'field' => $customFields[ $f ], 'value' => $displayValue );
}
}
}
if ( ! count( $where ) )
else
{
$where = NULL;
}
$table = new \IPS\Helpers\Table\Content( 'IPS\cms\Records' . \IPS\cms\Databases\Dispatcher::i()->databaseId, $category->url(), $where, $category, NULL, 'read', isset( \IPS\Request::i()->rss ) ? FALSE : TRUE );
$table->tableTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'categoryTable' );
$table->rowsTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'recordRow' );
$table->baseUrl = $table->baseUrl->setQueryString( 'd', \IPS\cms\Databases\Dispatcher::i()->databaseId );
$table->hover = TRUE;
$table->sortBy = ( isset( \IPS\Request::i()->sortby ) ) ? \IPS\Request::i()->sortby : ( $database->field_sort ? $RecordsClass::$databaseTable . '.' . $RecordsClass::$databasePrefix . $database->field_sort : 'record_last_comment' );
$table->sortDirection = ( isset( \IPS\Request::i()->sortdirection ) ) ? \IPS\Request::i()->sortdirection : ( $database->field_direction ? $database->field_direction : 'desc' );
$table->limit = $database->field_perpage ? $database->field_perpage : 25;
$table->title = \IPS\Member::loggedIn()->language()->addToStack( $database->use_categories ? 'x_records_in_this_category' : 'x_records' , FALSE, array( 'sprintf' => array( $RecordsClass::contentCount( $category, FALSE ), $database->recordWord( $RecordsClass::contentCount( $category, FALSE ) ) ) ) );
/* Set up sort fields to allow sorting numerically or by date */
$sortFields = $customFields;
$sortFields[ $database->field_title ] = $fieldClass::load( $database->field_title );
foreach( $sortFields as $id => $obj )
{
if ( $table->sortBy == $RecordsClass::$databaseTable . '.' . 'field_' . $id OR $table->sortBy == 'field_' . $id )
foreach( $customFields as $field )
{
if ( $obj->type == 'Number' )
if ( $field->type === 'Member' )
{
$table->sortOptions[ $table->sortBy ] = 'LENGTH(`field_' . $id . '`) ' . $table->sortDirection . ',`field_' . $id . '`';
break;
}
elseif( $obj->type == 'Date' )
{
$table->sortOptions[ $table->sortBy ] = 'CAST(`field_' . $id . '` AS UNSIGNED)';
break;
}
}
}
/* Make sure table doesn't add breadcrumbs if we're not using categories */
if ( ! $database->use_categories )
{
\IPS\Output::i()->breadcrumb = $breadcrumbs;
}
/* Custom Search */
$filterOptions = array(
'all' => 'content_all_records',
'open' => 'content_open_records',
'locked' => 'content_locked_records',
);
$timeFrameOptions = array(
'show_all' => 'show_all',
'today' => 'today',
'last_5_days' => 'last_5_days',
'last_7_days' => 'last_7_days',
'last_10_days' => 'last_10_days',
'last_15_days' => 'last_15_days',
'last_20_days' => 'last_20_days',
'last_25_days' => 'last_25_days',
'last_30_days' => 'last_30_days',
'last_60_days' => 'last_60_days',
'last_90_days' => 'last_90_days',
);
if ( \IPS\Member::loggedIn()->member_id AND \IPS\Member::loggedIn()->last_visit)
{
$timeFrameOptions['since_last_visit'] = \IPS\Member::loggedIn()->language()->addToStack('since_last_visit', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( \IPS\Member::loggedIn()->last_visit ) ) ) );
}
$sortBy = array(
'record_updated' => 'content_record_last_updated',
'record_comments' => 'content_record_comments',
'record_views' => 'content_record_views',
'field_' . $database->field_title => 'content_record_title',
'record_publish_date' => 'content_record_publish_date'
);
/* Ensure we have all sort options available */
$table->sortOptions = array_unique( array_merge( $table->sortOptions, array_combine( array_keys( $sortBy ), array_keys( $sortBy ) ) ) );
/* To avoid confusion, label 'updated' as 'Recently Updated' as last comment */
\IPS\Member::loggedIn()->language()->words[ $table->langPrefix . 'sort_updated' ] = \IPS\Member::loggedIn()->language()->addToStack('content_record_last_comment');
if ( !isset( $sortBy[ $database->field_sort ] ) )
{
switch ( $database->field_sort )
{
case 'primary_id_field':
$sortBy[ $database->field_sort ] = 'database_field__id';
$table->sortOptions['database_field__id'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__id'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__id');
break;
case 'member_id':
$sortBy[ $database->field_sort ] = 'database_field__member';
$table->sortOptions['database_field__member'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__member'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__member');
break;
case 'record_rating':
$sortBy[ $database->field_sort ] = 'database_field__rating';
$table->sortOptions['rating'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__rating'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__rating');
break;
}
}
if ( !$database->options['comments'] )
{
unset ( $sortBy['record_last_comment'] );
unset ( $sortBy['record_comments'] );
unset ( $table->sortOptions['record_last_comment'] );
unset ( $table->sortOptions['record_comments'] );
unset ( $table->sortOptions['last_comment'] );
unset ( $table->sortOptions['num_comments'] );
}
if ( !$database->options['reviews'] )
{
unset ( $table->sortOptions['num_reviews'] );
unset( $table->sortOptions['rating'] );
}
/* If the sort field isn't one of the above, best add it */
if ( mb_substr( $database->field_sort, 0, 6 ) === 'field_' )
{
if ( $database->field_title !== mb_substr( $database->field_sort, 6 ) )
{
$sortBy[ $database->field_sort ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_field_' . mb_substr( $database->field_sort, 6 ) );
$table->sortOptions[ $database->field_sort ] = $database->field_sort;
}
}
$table->advancedSearch = array(
'record_type' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $filterOptions ) ),
'sort_by' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $sortBy ) ),
'sort_direction' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'asc' => 'asc',
'desc' => 'desc',
) )
),
'time_frame' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $timeFrameOptions ) ),
);
foreach( $customFields as $obj )
{
if ( $obj->filter )
{
\IPS\Member::loggedIn()->language()->words['content_field_' . $obj->id ] = $obj->_title;
if ( in_array( $obj->type, array( 'Date', 'DateRange' ) ) )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_DATE_RANGE, array( 'noDefault' => true ) );
}
else if ( $obj->type == 'Number' )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_NUMERIC_TEXT, array( 'noDefault' => true ) );
}
else if ( $obj->type == 'YesNo' )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_BOOL, array( 'noDefault' => true ) );
}
else
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $obj->extra, 'multiple' => TRUE, 'noDefault' => true ) );
}
$table->advancedSearch['sort_by'][1]['options']['field_' . $obj->id ] = 'content_field_' . $obj->id;
}
if ( in_array( $obj->type, array( 'Date', 'DateRange' ) ) )
{
$table->sortOptions[ 'field_' . $obj->id ] = 'CAST(`field_' . $obj->id . '` AS UNSIGNED)';
}
else if ( $obj->type == 'Number' )
{
$table->sortOptions[ 'field_' . $obj->id ] = 'LENGTH(`field_' . $obj->id . '`) ' . $table->sortDirection . ',`field_' . $obj->id . '`';
}
else
{
$table->sortOptions[ 'field_' . $obj->id ] = isset( $table->sortOptions[ 'field_' . $obj->id ] ) ? $table->sortOptions[ 'field_' . $obj->id ] : 'field_' . $obj->id;
}
}
$table->advancedSearchCallback = function( $table, $values ) use ( $database, $sortBy, $customFields )
{
/* Type */
foreach( $values as $k => $v )
{
if ( mb_substr( $k, 0, 14 ) === 'content_field_' )
{
if ( is_array( $v ) )
$requestField = 'content_field_' . $field->id;
$didWeJustHitSubmit = $requestField . '_original';
$names = NULL;
/* We need to homogenize data, we store IDs, but the Form helper needs objects or names */
if ( isset( \IPS\Request::i()->$requestField ) and ! isset( \IPS\Request::i()->$didWeJustHitSubmit ) )
{
if ( array_key_exists( 'start', $v ) or array_key_exists( 'end', $v ) )
/* The URL alwyas uses IDs, so map these to names */
$names = array_map( function( $id )
{
$start = ( $v['start'] instanceof \IPS\DateTime ) ? $v['start']->getTimestamp() : intval( $v['start'] );
$end = ( $v['end'] instanceof \IPS\DateTime ) ? $v['end']->getTimestamp() : intval( $v['end'] );
if ( $start or $end )
{
$table->where[] = array( '( ' . mb_substr( $k, 8 ) . ' BETWEEN ' . $start . ' AND ' . $end . ' )' );
}
}
else
return \IPS\Member::load( $id )->name;
}, ( \is_array( \IPS\Request::i()->$requestField ) ? \IPS\Request::i()->$requestField : array( \IPS\Request::i()->$requestField ) ) );
}
else if ( isset( \IPS\Request::i()->$requestField ) )
{
/* The names are foo\nbar so already names */
$names = explode( "\n", \IPS\Request::i()->$requestField );
}
if ( $names !== NULL )
{
\IPS\Request::i()->$requestField = $names;
}
}
}
}
if ( ( $category->hasChildren() AND $category->show_records ) OR ! $category->hasChildren() )
{
if ( ! \count( $where ) )
{
$where = NULL;
}
$table = new \IPS\Helpers\Table\Content( 'IPS\cms\Records' . \IPS\cms\Databases\Dispatcher::i()->databaseId, $category->url(), $where, $category, NULL, 'read', isset( \IPS\Request::i()->rss ) ? FALSE : TRUE );
$table->tableTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'categoryTable' );
$table->rowsTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'recordRow' );
$table->baseUrl = $table->baseUrl->setQueryString( 'd', \IPS\cms\Databases\Dispatcher::i()->databaseId );
$table->hover = TRUE;
$table->sortBy = ( isset( \IPS\Request::i()->sortby ) ) ? \IPS\Request::i()->sortby : ( $database->field_sort ? $RecordsClass::$databaseTable . '.' . $RecordsClass::$databasePrefix . $database->field_sort : 'record_last_comment' );
$table->sortDirection = ( isset( \IPS\Request::i()->sortdirection ) ) ? \IPS\Request::i()->sortdirection : ( $database->field_direction ? $database->field_direction : 'desc' );
$table->limit = $database->field_perpage ? $database->field_perpage : 25;
$table->title = \IPS\Member::loggedIn()->language()->addToStack( $database->use_categories ? 'x_records_in_this_category' : 'x_records' , FALSE, array( 'sprintf' => array( $RecordsClass::contentCount( $category, FALSE ), $database->recordWord( $RecordsClass::contentCount( $category, FALSE ) ) ) ) );
/* Set up sort fields to allow sorting numerically or by date */
$sortFields = $customFields;
$sortFields[ $database->field_title ] = $fieldClass::load( $database->field_title );
foreach( $sortFields as $id => $obj )
{
if ( $table->sortBy == $RecordsClass::$databaseTable . '.' . 'field_' . $id OR $table->sortBy == 'field_' . $id )
{
if ( $obj->type == 'Number' )
{
$table->sortOptions[ $table->sortBy ] = 'LENGTH(`field_' . $id . '`) ' . $table->sortDirection . ',`field_' . $id . '`';
break;
}
elseif( $obj->type == 'Date' )
{
$table->sortOptions[ $table->sortBy ] = 'CAST(`field_' . $id . '` AS UNSIGNED)';
break;
}
}
}
/* Make sure table doesn't add breadcrumbs if we're not using categories */
if ( ! $database->use_categories )
{
\IPS\Output::i()->breadcrumb = $breadcrumbs;
}
/* Custom Search */
$filterOptions = array(
'all' => 'content_all_records',
'open' => 'content_open_records',
'locked' => 'content_locked_records',
);
$timeFrameOptions = array(
'show_all' => 'show_all',
'today' => 'today',
'last_5_days' => 'last_5_days',
'last_7_days' => 'last_7_days',
'last_10_days' => 'last_10_days',
'last_15_days' => 'last_15_days',
'last_20_days' => 'last_20_days',
'last_25_days' => 'last_25_days',
'last_30_days' => 'last_30_days',
'last_60_days' => 'last_60_days',
'last_90_days' => 'last_90_days',
);
if ( \IPS\Member::loggedIn()->member_id AND \IPS\Member::loggedIn()->last_visit )
{
$timeFrameOptions['since_last_visit'] = \IPS\Member::loggedIn()->language()->addToStack('since_last_visit', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( \IPS\Member::loggedIn()->last_visit ) ) ) );
}
$sortBy = array(
'record_updated' => 'content_record_last_updated',
'record_comments' => 'content_record_comments',
'record_views' => 'content_record_views',
'field_' . $database->field_title => 'content_record_title',
'record_publish_date' => 'content_record_publish_date'
);
/* Ensure we have all sort options available */
$table->sortOptions = array_unique( array_merge( $table->sortOptions, array_combine( array_keys( $sortBy ), array_keys( $sortBy ) ) ) );
/* To avoid confusion, label 'updated' as 'Recently Updated' as last comment */
\IPS\Member::loggedIn()->language()->words[ $table->langPrefix . 'sort_updated' ] = \IPS\Member::loggedIn()->language()->addToStack('content_record_last_comment');
if ( !isset( $sortBy[ $database->field_sort ] ) )
{
switch ( $database->field_sort )
{
case 'primary_id_field':
$sortBy[ $database->field_sort ] = 'database_field__id';
$table->sortOptions['database_field__id'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__id'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__id');
break;
case 'member_id':
$sortBy[ $database->field_sort ] = 'database_field__member';
$table->sortOptions['database_field__member'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__member'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__member');
break;
case 'record_rating':
$sortBy[ $database->field_sort ] = 'database_field__rating';
$table->sortOptions['rating'] = $database->field_sort;
\IPS\Member::loggedIn()->language()->words['sort_database_field__rating'] = \IPS\Member::loggedIn()->language()->addToStack('database_field__rating');
break;
}
}
if ( !$database->options['comments'] )
{
unset ( $sortBy['record_last_comment'] );
unset ( $sortBy['record_comments'] );
unset ( $table->sortOptions['record_last_comment'] );
unset ( $table->sortOptions['record_comments'] );
unset ( $table->sortOptions['last_comment'] );
unset ( $table->sortOptions['num_comments'] );
}
if ( !$database->options['reviews'] and !$category->allow_rating )
{
unset ( $table->sortOptions['num_reviews'] );
unset( $table->sortOptions['rating'] );
}
/* If the sort field isn't one of the above, best add it */
if ( mb_substr( $database->field_sort, 0, 6 ) === 'field_' )
{
if ( $database->field_title !== mb_substr( $database->field_sort, 6 ) )
{
$sortBy[ $database->field_sort ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_field_' . mb_substr( $database->field_sort, 6 ) );
$table->sortOptions[ $database->field_sort ] = $database->field_sort;
}
}
$table->advancedSearch = array(
'record_type' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $filterOptions ) ),
'sort_by' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $sortBy ) ),
'sort_direction' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'asc' => 'asc',
'desc' => 'desc',
) )
),
'time_frame' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $timeFrameOptions ) ),
'cms_record_i_started' => array( \IPS\Helpers\Table\SEARCH_CHECKBOX, array() ),
);
foreach( $customFields as $obj )
{
if ( $obj->filter )
{
\IPS\Member::loggedIn()->language()->words['content_field_' . $obj->id ] = $obj->_title;
if ( \in_array( $obj->type, array( 'Date', 'DateRange' ) ) )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_DATE_RANGE, array( 'noDefault' => true ) );
}
else if ( $obj->type == 'Number' )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_NUMERIC_TEXT, array( 'noDefault' => true ) );
}
else if ( $obj->type == 'YesNo' )
{
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_BOOL, array( 'noDefault' => true ) );
}
else if ( $obj->type == 'Member' )
{
/* Don't show this on the custom modal form because you cannot have two autocompletes with the same name on the same page, and the fix is more invasive than the value of this feature on the modal.
The purpose of this is to show in the sidebar filter form */
if ( ! isset( \IPS\Request::i()->advancedSearchForm ) )
{
$like = array();
foreach( $v as $val )
{
if ( $val === 0 or ! empty( $val ) )
{
$like[] = "CONCAT( ',', " . mb_substr( $k, 8 ) . ", ',') LIKE '%," . \IPS\Db::i()->real_escape_string( $val ) . ",%'";
}
}
$table->where[] = array( '( ' . \IPS\Db::i()->in( mb_substr( $k, 8 ), $v ) . ( count( $like ) ? " OR (" . implode( ' OR ', $like ) . ') )' : ')' ) );
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_MEMBER, array( 'noDefault' => true, 'multiple' => NULL ) );
}
}
else
{
if ( $v !== '___any___' )
{
if ( is_bool( $v ) )
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $obj->extra, 'multiple' => TRUE, 'noDefault' => true ) );
}
$table->advancedSearch['sort_by'][1]['options']['field_' . $obj->id ] = 'content_field_' . $obj->id;
}
if ( \in_array( $obj->type, array( 'Date', 'DateRange' ) ) )
{
$table->sortOptions[ 'field_' . $obj->id ] = 'CAST(`field_' . $obj->id . '` AS UNSIGNED)';
}
else if ( $obj->type == 'Number' )
{
$table->sortOptions[ 'field_' . $obj->id ] = 'LENGTH(`field_' . $obj->id . '`) ' . $table->sortDirection . ',`field_' . $obj->id . '`';
}
else
{
$table->sortOptions[ 'field_' . $obj->id ] = isset( $table->sortOptions[ 'field_' . $obj->id ] ) ? $table->sortOptions[ 'field_' . $obj->id ] : 'field_' . $obj->id;
}
}
$table->advancedSearchCallback = function( $table, $values ) use ( $database, $sortBy, $customFields )
{
/* Type */
foreach( $values as $k => $v )
{
if ( mb_substr( $k, 0, 14 ) === 'content_field_' )
{
$key = mb_substr( $k, 14 );
$concat = ',';
$displayValue = $customFields[ $key ]->displayValue( $v );
if ( $customFields[ $key ]->type === 'Member' )
{
if ( \is_array( $v ) and \count( $v ) )
{
/* YesNo fields are false or true */
if ( $v === false )
$newValue = array();
$newDisplayValue = array();
$concat = '\n';
foreach( $v as $member )
{
$table->where[] = array( '(' . mb_substr( $k, 8 ) . ' IS NULL or ' . mb_substr( $k, 8 ) . '=0)' );
if ( $member instanceof \IPS\Member )
{
$newDisplayValue[] = $member->name;
$newValue[] = $member->member_id;
}
}
else
$displayValue = implode( ', ', $newDisplayValue );
$v = $newValue;
}
else
{
/* The content_field_x can be an empty array from the member form */
continue;
}
}
if ( \is_array( $v ) )
{
if ( array_key_exists( 'start', $v ) or array_key_exists( 'end', $v ) )
{
$start = ( $v['start'] instanceof \IPS\DateTime ) ? $v['start']->getTimestamp() : \intval( $v['start'] );
$end = ( $v['end'] instanceof \IPS\DateTime ) ? $v['end']->getTimestamp() : \intval( $v['end'] );
if ( $start or $end )
{
$table->where[] = array( mb_substr( $k, 8 ) . "=1" );
$table->where[] = array( '( ' . mb_substr( $k, 8 ) . ' BETWEEN ' . $start . ' AND ' . $end . ' )' );
}
}
else
{
if ( $v !== 0 and ! $v )
$like = array();
foreach( $v as $val )
{
$table->where[] = array( mb_substr( $k, 8 ) . " IS NULL" );
if ( $val === 0 or ! empty( $val ) )
{
$like[] = "CONCAT( '{$concat}', " . mb_substr( $k, 8 ) . ", '{$concat}') LIKE '%{$concat}" . \IPS\Db::i()->real_escape_string( $val ) . "{$concat}%'";
}
}
$table->where[] = array( '( ' . \IPS\Db::i()->in( mb_substr( $k, 8 ), $v ) . ( \count( $like ) ? " OR (" . implode( ' OR ', $like ) . ') )' : ')' ) );
}
}
else
{
if ( $v !== '___any___' )
{
if ( \is_bool( $v ) )
{
/* YesNo fields are false or true */
if ( $v === false )
{
$table->where[] = array( '(' . mb_substr( $k, 8 ) . ' IS NULL or ' . mb_substr( $k, 8 ) . '=0)' );
}
else
{
$table->where[] = array( mb_substr( $k, 8 ) . "=1" );
}
}
else
{
$table->where[] = array( mb_substr( $k, 8 ) . "=?", $v );
if ( $v !== 0 and ! $v )
{
$table->where[] = array( mb_substr( $k, 8 ) . " IS NULL" );
}
else
{
$table->where[] = array( mb_substr( $k, 8 ) . "=?", $v );
}
}
}
}
\IPS\cms\modules\front\database\category::$activeFilters[ $key ] = array( 'field' => $customFields[ $key ], 'value' => $displayValue );
}
$key = mb_substr( $k, 14 );
\IPS\cms\modules\front\database\category::$activeFilters[ $key ] = array( 'field' => $customFields[ $key ], 'value' => $customFields[ $key ]->displayValue( $v ) );
}
}
if ( isset( $values['record_type'] ) )
{
switch ( $values['record_type'] )
{
case 'open':
$table->where[] = 'record_locked=0';
break;
case 'locked':
$table->where[] = 'record_locked=1';
break;
}
}
/* Sort */
if ( isset( $values['sort_by'] ) and isset( $sortBy[ $values['sort_by'] ] ) )
{
if ( isset( $customFields[ mb_substr( $values['sort_by'], 6 ) ] ) and $customFields[ mb_substr( $values['sort_by'], 6 ) ]->type == 'Number' )
{
$table->sortOptions[ $values['sort_by'] ] = 'LENGTH(`' . $values['sort_by'] . '`) ' . $table->sortDirection . ',`' . $values['sort_by'] . '`';
}
elseif( isset( $customFields[ mb_substr( $values['sort_by'], 6 ) ] ) and $customFields[ mb_substr( $values['sort_by'], 6 ) ]->type == 'Date' )
{
$table->sortOptions[ $values['sort_by'] ] = 'CAST(`' . $values['sort_by'] . '` AS UNSIGNED)';
}
else
{
$table->sortOptions[ $values['sort_by'] ] = $values['sort_by'];
}
$table->sortBy = $values['sort_by'];
$table->sortDirection = $values['sort_direction'];
}
/* Cutoff */
$days = NULL;
if ( isset( $values['time_frame'] ) )
{
switch ( $values['time_frame'] )
{
case 'today':
$days = 1;
break;
case 'last_5_days':
$days = 5;
break;
case 'last_7_days':
$days = 7;
break;
case 'last_10_days':
$days = 10;
break;
case 'last_15_days':
$days = 15;
break;
case 'last_20_days':
$days = 20;
break;
case 'last_25_days':
$days = 25;
break;
case 'last_30_days':
$days = 30;
break;
case 'last_60_days':
$days = 60;
break;
case 'last_90_days':
$days = 90;
break;
case 'since_last_visit':
$table->where[] = array( 'record_last_comment>?', \IPS\Member::loggedIn()->last_visit );
break;
}
if ( $days !== NULL )
{
$table->where[] = array( 'record_last_comment>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) )->getTimestamp() );
}
}
};
/* RSS */
if ( $database->rss )
{
$rssUrl = $table->baseUrl->setQueryString('rss', 1 );
$rssName = $database->_title . ': ' . $category->metaTitle();
\IPS\Output::i()->rssFeeds[ $rssName ] = $rssUrl;
/* Show RSS feed */
if ( isset( \IPS\Request::i()->rss ) )
{
$rssName = \IPS\Member::loggedIn()->language()->get('content_db_' . $database->id ) . ': ' . $category->metaTitle();
$document = \IPS\Xml\Rss::newDocument( $table->baseUrl, $rssName, $rssName );
$contentField = 'field_' . $database->field_content;
foreach ( $table->getRows( array() ) as $record )
{
if ( ! $record->hidden() )
{
$content = $record->$contentField;
if ( $record->record_image )
{
$content = \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->rssItemWithImage( $content, $record->record_image );
}
if ( isset( $values['cms_record_i_started'] ) and $values['cms_record_i_started'] and \IPS\Member::loggedIn()->member_id )
{
$table->where[] = 'cms_custom_database_' . $database->id . '.member_id=' . \IPS\Member::loggedIn()->member_id;
}
$document->addItem( $record->_title, $record->url(), $content, \IPS\DateTime::ts( ( $record->record_last_comment > $record->record_publish_date ) ? $record->record_publish_date : $record->record_last_comment ), $record->_id );
if ( isset( $values['record_type'] ) )
{
switch ( $values['record_type'] )
{
case 'open':
$table->where[] = 'record_locked=0';
break;
case 'locked':
$table->where[] = 'record_locked=1';
break;
}
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
/* Sort */
if ( isset( $values['sort_by'] ) and isset( $sortBy[ $values['sort_by'] ] ) )
{
if ( isset( $customFields[ mb_substr( $values['sort_by'], 6 ) ] ) and $customFields[ mb_substr( $values['sort_by'], 6 ) ]->type == 'Number' )
{
$table->sortOptions[ $values['sort_by'] ] = 'LENGTH(`' . $values['sort_by'] . '`) ' . $table->sortDirection . ',`' . $values['sort_by'] . '`';
}
elseif( isset( $customFields[ mb_substr( $values['sort_by'], 6 ) ] ) and $customFields[ mb_substr( $values['sort_by'], 6 ) ]->type == 'Date' )
{
$table->sortOptions[ $values['sort_by'] ] = 'CAST(`' . $values['sort_by'] . '` AS UNSIGNED)';
}
else
{
$table->sortOptions[ $values['sort_by'] ] = $values['sort_by'];
}
$table->sortBy = $values['sort_by'];
$table->sortDirection = $values['sort_direction'];
}
/* Cutoff */
$days = NULL;
if ( isset( $values['time_frame'] ) )
{
switch ( $values['time_frame'] )
{
case 'today':
$days = 1;
break;
case 'last_5_days':
$days = 5;
break;
case 'last_7_days':
$days = 7;
break;
case 'last_10_days':
$days = 10;
break;
case 'last_15_days':
$days = 15;
break;
case 'last_20_days':
$days = 20;
break;
case 'last_25_days':
$days = 25;
break;
case 'last_30_days':
$days = 30;
break;
case 'last_60_days':
$days = 60;
break;
case 'last_90_days':
$days = 90;
break;
case 'since_last_visit':
$table->where[] = array( 'record_last_comment>?', \IPS\Member::loggedIn()->last_visit );
break;
}
if ( $days !== NULL )
{
$table->where[] = array( 'record_last_comment>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) )->getTimestamp() );
}
}
};
/* RSS */
if ( $database->rss )
{
$rssUrl = $table->baseUrl->setQueryString('rss', 1 );
$rssName = $database->_title . ': ' . $category->metaTitle();
\IPS\Output::i()->rssFeeds[ $rssName ] = $rssUrl;
/* Show RSS feed */
if ( isset( \IPS\Request::i()->rss ) )
{
$rssName = \IPS\Member::loggedIn()->language()->get('content_db_' . $database->id ) . ': ' . $category->metaTitle();
$document = \IPS\Xml\Rss::newDocument( $table->baseUrl, $rssName, $rssName );
$contentField = 'field_' . $database->field_content;
foreach ( $table->getRows( array() ) as $record )
{
if ( ! $record->hidden() )
{
$content = $record->$contentField;
if ( $record->record_image )
{
$content = \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->rssItemWithImage( $content, $record->record_image );
}
$document->addItem( $record->_title, $record->url(), $content, \IPS\DateTime::ts( ( $record->record_last_comment > $record->record_publish_date ) ? $record->record_publish_date : $record->record_last_comment ), $record->_id );
}
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml', array(), TRUE );
}
}
}
else
{
\IPS\Output::i()->metaTags['title'] = $category->metaTitle();
\IPS\Output::i()->metaTags['description'] = $category->metaDescription();
\IPS\Output::i()->metaTags['og:title'] = $category->metaTitle();
\IPS\Output::i()->metaTags['og:description'] = $category->metaDescription();
\IPS\Output::i()->linkTags['canonical'] = (string) $category->url();
/* Set breadcrumb */
if ( \IPS\IPS::classUsesTrait( $category, 'IPS\Content\ClubContainer' ) and $club = $category->club() )
{
$club->setBreadcrumbs( $category );
}
else
{
foreach ( $category->parents() as $parent )
{
\IPS\Output::i()->breadcrumb[] = array( $category->url(), $category->_title );
}
\IPS\Output::i()->breadcrumb[] = array( NULL, $category->_title );
}
}
@@ -530,17 +694,24 @@ class _category extends \IPS\cms\Databases\Controller
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/list.css', 'cms', 'front' ) );
$stringTable = (string) $table;
$stringTable = ( ( $category->hasChildren() AND $category->show_records ) OR ! $category->hasChildren() ) ? (string) $table : '';
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryHeader( $category, $stringTable, static::$activeFilters );
if ( ( $category->hasChildren() AND $category->show_records ) OR ! $category->hasChildren() )
{
\IPS\cms\Databases\Dispatcher::i()->output .= $stringTable;
}
\IPS\Output::i()->title = ( $table->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $category->pageTitle(), $table->page ) ) ) : $category->pageTitle();
\IPS\cms\Databases\Dispatcher::i()->output .= $stringTable;
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryFooter( $category, $stringTable, static::$activeFilters );
$titleSuffix = $database->use_categories ? $category->_title . ' - ' . $category->pageTitle() : $category->pageTitle();
if( ( $category->hasChildren() AND $category->show_records ) OR ! $category->hasChildren() )
{
\IPS\Output::i()->title = ( $table->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $titleSuffix, $table->page ) ) ) : $titleSuffix;
}
else
{
\IPS\Output::i()->title = $titleSuffix;
}
}
/**
@@ -564,9 +735,10 @@ class _category extends \IPS\cms\Databases\Controller
$hasModOptions = FALSE;
$canHide = ( \IPS\Member::loggedIn()->group['g_hide_own_posts'] == '1' or \in_array( 'IPS\cms\Records' . \IPS\cms\Databases\Dispatcher::i()->databaseId, explode( ',', \IPS\Member::loggedIn()->group['g_hide_own_posts'] ) ) );
if ( $recordClass::modPermission( 'lock', NULL, $category ) or
$recordClass::modPermission( 'pin', NULL, $category ) or
$recordClass::modPermission( 'hide', NULL, $category ) or
$canHide or
$recordClass::modPermission( 'feature', NULL, $category ) or
$fieldsClass::fixedFieldFormShow( 'record_allow_comments' ) or
$fieldsClass::fixedFieldFormShow( 'record_expiry_date' ) or
@@ -579,7 +751,7 @@ class _category extends \IPS\cms\Databases\Controller
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\cms\Pages\Page::$currentPage->getWidgets();
\IPS\cms\Databases\Dispatcher::i()->output = \IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), array( $database->template_form, 'cms', 'database' ) ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\cms\Databases\Dispatcher::i()->output = \IPS\Output::i()->output = $form->customTemplate( array( \IPS\cms\Theme::i()->getTemplate( $database->template_form, 'cms', 'database' ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $title );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/form.css', 'cms', 'front' ) );
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\database;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -87,11 +87,11 @@ class _index extends \IPS\cms\Databases\Controller
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml', array(), TRUE );
}
}
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$page = isset( \IPS\Request::i()->page ) ? \intval( \IPS\Request::i()->page ) : 1;
if( $page < 1 )
{
@@ -111,7 +111,7 @@ class _index extends \IPS\cms\Databases\Controller
$where = ( $database->featured_settings['featured'] ) ? array( array( 'record_featured=?', 1 ) ) : NULL;
if ( isset( $database->featured_settings['categories'] ) and is_array( $database->featured_settings['categories'] ) and count( $database->featured_settings['categories'] ) )
if ( isset( $database->featured_settings['categories'] ) and \is_array( $database->featured_settings['categories'] ) and \count( $database->featured_settings['categories'] ) )
{
$categoryField = "`cms_custom_database_{$database->_id}`.`category_id`";
$where[] = array( \IPS\Db::i()->in( $categoryField, array_values( $database->featured_settings['categories'] ) ) );
@@ -133,7 +133,7 @@ class _index extends \IPS\cms\Databases\Controller
/* Make sure we are viewing a real page */
if ( $page > $pagination['pages'] )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->setQueryString( 'page', 1 ), NULL, 303 );
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->setPage( 'page', 1 ), NULL, 303 );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'database_index/featured.css', 'cms', 'front' ) );
@@ -186,7 +186,7 @@ class _index extends \IPS\cms\Databases\Controller
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Node( 'category', NULL, TRUE, array(
'url' => \IPS\cms\Pages\Page::$currentPage->url()->setQueryString( array( 'do' => 'form', 'page_id' => \IPS\cms\Pages\Page::$currentPage->id ) ),
'class' => 'IPS\cms\Categories' . \IPS\cms\Databases\Dispatcher::i()->databaseId,
'class' => 'IPS\cms\Categories' . \IPS\cms\Pages\Page::$currentPage->getDatabase()->_id,
'permissionCheck' => function( $node )
{
if ( $node->can( 'view' ) )
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\database;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -73,21 +73,21 @@ class _record extends \IPS\Content\Controller
$_tabs = array_keys( $tabs );
$tab = isset( \IPS\Request::i()->tab ) ? \IPS\Request::i()->tab : array_shift( $_tabs );
$activeTabContents = $record->commentReviews( $tab );
$comments = count( $tabs ) ? \IPS\cms\Theme::i()->getTemplate( $record->container()->_template_display, 'cms', 'database' )->commentsAndReviewsTabs( \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $tab, $activeTabContents, $record->url(), 'tab', FALSE, TRUE ), md5( $record->url() ) ) : NULL;
$comments = \count( $tabs ) ? \IPS\cms\Theme::i()->getTemplate( $record->container()->_template_display, 'cms', 'database' )->commentsAndReviewsTabs( \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $tab, $activeTabContents, $record->url(), 'tab', FALSE, TRUE ), md5( $record->url() ) ) : NULL;
if ( \IPS\Request::i()->isAjax() and ( isset( \IPS\Request::i()->page ) OR isset( \IPS\Request::i()->tab ) ) )
if ( \IPS\Request::i()->isAjax() and !isset( \IPS\Request::i()->rating_submitted ) and ( isset( \IPS\Request::i()->page ) OR isset( \IPS\Request::i()->tab ) ) and $activeTabContents )
{
\IPS\Output::i()->sendOutput( $activeTabContents, 200, 'text/html', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( $activeTabContents, 200, 'text/html' );
}
$class = '\IPS\cms\Categories' . $record::$customDatabaseId;
$category = $class::load( $record->category_id );
$FieldsClass = '\\IPS\\cms\\Fields' . $record::$customDatabaseId;
$updateFields = $FieldsClass::fields( $record->fieldValues(), 'edit', $record->container(), $FieldsClass::FIELD_SKIP_TITLE_CONTENT | $FieldsClass::FIELD_DISPLAY_COMMENTFORM );
$updateFields = $FieldsClass::fields( $record->fieldValues(), 'edit', $record->container(), $FieldsClass::FIELD_DISPLAY_COMMENTFORM, $record );
$form = null;
/* We need edit permission to change the record */
if ( count( $updateFields ) and $record->canEdit() )
if ( \count( $updateFields ) and $record->canEdit() )
{
$form = new \IPS\Helpers\Form( 'update_record', 'update', $record->url()->setQueryString( array( 'd' => $record::$customDatabaseId ) ) );
$form->class = 'ipsForm_vertical';
@@ -113,18 +113,29 @@ class _record extends \IPS\Content\Controller
}
}
if ( count( $customValues ) )
if ( \count( $customValues ) )
{
if ( $values['record_display_field_change'] )
{
$record->addCommentWhenFiltersChanged( $values );
}
else
{
/* Set excludes for custom field updates. We'll send the notifications later, once we know the new content of the fields. */
$record->setFieldQuoteAndMentionExcludes();
}
foreach( $fieldsClass::fields( $customValues, 'edit', $record->category_id ? $category : NULL, $FieldsClass::FIELD_SKIP_TITLE_CONTENT | $FieldsClass::FIELD_DISPLAY_COMMENTFORM ) as $key => $field )
foreach( $fieldsClass::fields( $customValues, 'edit', $record->category_id ? $category : NULL, $FieldsClass::FIELD_DISPLAY_COMMENTFORM ) as $key => $field )
{
$key = 'field_' . $key;
$record->$key = $field::stringValue( isset( $values[ $field->name ] ) ? $values[ $field->name ] : NULL );
}
/* Send custom field update notifications */
if ( !$values['record_display_field_change'] )
{
$record->sendFieldQuoteAndMentionNotifications();
}
$record->save();
$record->processAfterEdit( $values );
@@ -146,7 +157,14 @@ class _record extends \IPS\Content\Controller
}
/* Set record URL as canonical tag */
\IPS\Output::i()->linkTags['canonical'] = $record->url();
if ( $record::database()->canonical_flag == 1 and ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page > 1 ) )
{
\IPS\Output::i()->linkTags['canonical'] = $record->url()->setPage( 'page', \IPS\Request::i()->page );
}
else
{
\IPS\Output::i()->linkTags['canonical'] = $record->url();
}
/* Update location */
if( $record->database()->use_categories )
@@ -163,7 +181,7 @@ class _record extends \IPS\Content\Controller
/* Next unread */
try
{
$nextUnread = $record->nextUnread();
$nextUnread = $record->containerHasUnread();
}
catch( \Exception $e )
{
@@ -176,6 +194,8 @@ class _record extends \IPS\Content\Controller
}
/* Add Json-LD */
$jsonLdText = $record->truncated( TRUE, NULL );
\IPS\Output::i()->jsonLd['article'] = array(
'@context' => "http://schema.org",
'@type' => "Article",
@@ -184,8 +204,8 @@ class _record extends \IPS\Content\Controller
'mainEntityOfPage' => (string) $record->url(),
'name' => $record->_title,
'headline' => $record->_title,
'text' => strip_tags( $record->truncated() ),
'articleBody' => strip_tags( $record->truncated() ),
'text' => $jsonLdText,
'articleBody' => $jsonLdText,
'dateCreated' => \IPS\DateTime::ts( $record->record_saved )->format( \IPS\DateTime::ISO8601 ),
'datePublished' => \IPS\DateTime::ts( $record->record_publish_date ?: $record->record_saved )->format( \IPS\DateTime::ISO8601 ),
'dateModified' => \IPS\DateTime::ts( $record->record_edit_time ?: ( $record->record_publish_date ?: $record->record_saved ) )->format( \IPS\DateTime::ISO8601 ),
@@ -193,16 +213,15 @@ class _record extends \IPS\Content\Controller
'pageEnd' => $record->commentPageCount(),
'author' => array(
'@type' => 'Person',
'name' => \IPS\Member::load( $record->member_id )->name,
'image' => \IPS\Member::load( $record->member_id )->get_photo()
'name' => (string) \IPS\Member::load( $record->member_id )->name,
'image' => (string) \IPS\Member::load( $record->member_id )->get_photo()
),
'publisher' => array(
'@type' => 'Organization',
'name' => \IPS\Member::load( $record->member_id )->name,
'image' => \IPS\Member::load( $record->member_id )->get_photo(),
'logo' => array(
'@type' => 'ImageObject',
'url' => \IPS\Member::load( $record->member_id )->get_photo(),
'@id' => \IPS\Settings::i()->base_url . '#organization',
'member' => array(
'@type' => "Person",
'name' => \IPS\Member::load( $record->member_id )->name,
'image' => (string) \IPS\Member::load( $record->member_id )->get_photo(),
)
),
'interactionStatistic' => array(
@@ -223,22 +242,35 @@ class _record extends \IPS\Content\Controller
if( $record->member_id )
{
\IPS\Output::i()->jsonLd['article']['author']['url'] = (string) \IPS\Member::load( $record->member_id )->url();
\IPS\Output::i()->jsonLd['article']['publisher']['url'] = (string) \IPS\Member::load( $record->member_id )->url();
\IPS\Output::i()->jsonLd['article']['publisher']['member']['url'] = (string) \IPS\Member::load( $record->member_id )->url();
}
$logo = NULL;
if( \IPS\Theme::i()->logo['front'] )
{
try
{
$logo = \IPS\File::get( 'core_Theme', \IPS\Theme::i()->logo['front']['url'] )->url;
}
/* File doesn't exist */
catch ( \RuntimeException $e ){}
catch ( \DomainException $e ){}
}
\IPS\Output::i()->jsonLd['article']['publisher']['logo'] = array(
'@type' => 'ImageObject',
'url' => $logo ? (string) $logo : (string) \IPS\Member::load( $record->member_id )->get_photo(),
);
/* Image is required */
if( $record->record_image )
{
try
{
$imageObj = \IPS\File::get( 'cms_Records', $record->record_image );
$imageDims = $imageObj->getImageDimensions();
\IPS\Output::i()->jsonLd['article']['image'] = array(
'@type' => 'ImageObject',
'url' => (string) $imageObj->url,
'width' => $imageDims[0],
'height' => $imageDims[1]
'url' => (string) $imageObj->url
);
}
/* File doesn't exist */
@@ -257,26 +289,7 @@ class _record extends \IPS\Content\Controller
);
}
if( $record->averageReviewRating() )
{
\IPS\Output::i()->jsonLd['article']['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $record->averageReviewRating(),
'reviewCount' => $record->record_reviews,
'bestRating' => \IPS\Settings::i()->reviews_rating_out_of
);
}
elseif( $record->container()->allow_rating AND $record->averageRating() AND $record->numberOfRatings() )
{
\IPS\Output::i()->jsonLd['article']['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $record->averageRating(),
'ratingCount' => $record->numberOfRatings(),
'bestRating' => \IPS\Settings::i()->reviews_rating_out_of
);
}
if( $record::database()->options['reviews'] )
if( $record::database()->options['reviews'] or $record->container()->allow_rating )
{
\IPS\Output::i()->jsonLd['article']['interactionStatistic'][] = array(
'@type' => 'InteractionCounter',
@@ -296,12 +309,12 @@ class _record extends \IPS\Content\Controller
}
\IPS\Output::i()->contextualSearchOptions = array();
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $record::$title ) ) ) ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( get_class( $record ), 4 ) ) ), 'item' => $record->_id );
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $record::$title ) ) ) ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( \get_class( $record ), 4 ) ) ), 'item' => $record->_id );
try
{
$container = $record->container();
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_categories' ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( get_class( $record ), 4 ) ) ), 'nodes' => $container->_id );
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_categories' ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( \get_class( $record ), 4 ) ) ), 'nodes' => $container->_id );
}
catch ( \BadMethodCallException $e ) { }
@@ -412,14 +425,16 @@ class _record extends \IPS\Content\Controller
);
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/diff.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/diff_match_patch.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/diff_match_patch.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_records.js', 'cms' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/codemirror.js', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/record.css', 'cms', 'front' ) );
/* Output */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $table ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $table ), 200, 'text/html' );
}
else
{
@@ -529,12 +544,27 @@ class _record extends \IPS\Content\Controller
$conflicts = array();
$form = new \IPS\Helpers\Form( 'form', 'content_revision_restore' );
/* Add a "cancel" button that will take you back to the previous page */
array_unshift( $form->actionButtons, \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->button( 'cancel', 'link', $record->url()->setQueryString( array( 'do' => 'revisions', 'd' => $record::$customDatabaseId ) ), 'ipsButton ipsButton_link', array( 'tabindex' => '3', 'accesskey' => 'c' ) ) );
/* Build up our data set */
$conflicts = $revision->getDiffHtmlTables( $record::$customDatabaseId, $record, true );
foreach( $conflicts as $conflict )
/* If there is only one change, then clicking restore naturally means to revert that single change, so we don't need a form */
if( \count( $conflicts ) === 1 )
{
$form->add( new \IPS\Helpers\Form\Radio( 'conflict_' . $conflict['field']->id, 'no', false, array( 'options' => array( 'old' => '', 'new' => '' ) ) ) );
foreach( $conflicts as $conflict )
{
$form->hiddenValues[ 'conflict_' . $conflict['field']->id ] = 'old';
}
}
/* Otherwise if multiple fields have changes to compare, let the admin decide what to do */
else
{
foreach( $conflicts as $conflict )
{
$form->add( new \IPS\Helpers\Form\Radio( 'conflict_' . $conflict['field']->id, 'no', false, array( 'options' => array( 'old' => '', 'new' => '' ) ) ) );
}
}
if ( $values = $form->values() )
@@ -553,7 +583,7 @@ class _record extends \IPS\Content\Controller
$record->save();
$revision->delete();
\IPS\Output::i()->redirect( $record->url('revisions') );
\IPS\Output::i()->redirect( $record->url(), 'content_revision_restored' );
}
}
@@ -573,7 +603,8 @@ class _record extends \IPS\Content\Controller
\IPS\Output::i()->title = $title;
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/diff.css', 'core', 'admin' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/diff_match_patch.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/diff_match_patch.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_records.js', 'cms' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/codemirror.js', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
@@ -633,8 +664,8 @@ class _record extends \IPS\Content\Controller
$hasModOptions = FALSE;
if ( $recordClass::modPermission( 'lock', NULL, $category ) or
$recordClass::modPermission( 'pin', NULL, $category ) or
$recordClass::modPermission( 'hide', NULL, $category ) or
$recordClass::modPermission( 'pin', NULL, $category ) or
$record->canHide() or
$recordClass::modPermission( 'feature', NULL, $category ) or
$fieldsClass::fixedFieldFormShow( 'record_allow_comments' ) or
$fieldsClass::fixedFieldFormShow( 'record_expiry_date' ) or
@@ -669,7 +700,7 @@ class _record extends \IPS\Content\Controller
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\cms\Pages\Page::$currentPage->getWidgets();
\IPS\cms\Databases\Dispatcher::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), array( $database->template_form, 'cms', 'database' ) ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\cms\Databases\Dispatcher::i()->output = $form->customTemplate( array( \IPS\cms\Theme::i()->getTemplate( $database->template_form, 'cms', 'database' ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $title );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/form.css', 'cms', 'front' ) );
@@ -690,7 +721,7 @@ class _record extends \IPS\Content\Controller
}
/**
* Mark Topic Read
* Mark Database Record Read
*
* @return void
*/
@@ -889,16 +920,4 @@ class _record extends \IPS\Content\Controller
\IPS\Output::i()->error( 'node_error', '2T252/F', 403, '' );
}
}
/**
* Moderate
*
* @return void
*/
protected function moderate()
{
parent::moderate();
\IPS\cms\Databases\Dispatcher::i()->output = \IPS\Output::i()->output;
}
}
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\database;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -74,6 +74,7 @@ class _topic extends \IPS\Dispatcher\Controller
/**
* Database
*
* @param mixed $data Data
* @return void
*/
public function _database( $data )
@@ -98,12 +99,13 @@ class _topic extends \IPS\Dispatcher\Controller
);
}
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
return $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
* Category
*
* @param mixed $data Data
* @return void
*/
public function _category( $data )
@@ -129,7 +131,7 @@ class _topic extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=cms&module=database&controller=topic&do=form&id={$values['topic_id']}", 'front', 'topic_copy', $this->topic->title_seo )->csrf()->setQueryString( array( 'database_id' => $values['database_id'], 'category_id' => $values['select_category']->_id ) ) );
}
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
return $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -182,7 +184,7 @@ class _topic extends \IPS\Dispatcher\Controller
foreach( $recordClass::formElements( $fakeRecord, $category ) AS $key => $element )
{
/* Skip these */
if ( in_array( $key, array( 'record_edit_reason', 'record_edit_show' ) ) )
if ( \in_array( $key, array( 'record_edit_reason', 'record_edit_show' ) ) )
{
continue;
}
@@ -321,7 +323,7 @@ class _topic extends \IPS\Dispatcher\Controller
\IPS\Output::i()->breadcrumb[] = array( $this->topic->url(), $this->topic->mapped( 'title' ) );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'copy_topic_to_database' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'copy_topic_to_database' );
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), array( $database->template_form, 'cms', 'database' ) ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::load( $database->page_id ), \IPS\Member::loggedIn()->language()->addToStack( 'copy_topic_to_database' ), $hasModOptions );
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\cms\Theme::i()->getTemplate( $database->template_form, 'cms', 'database' ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::load( $database->page_id ), \IPS\Member::loggedIn()->language()->addToStack( 'copy_topic_to_database' ), $hasModOptions );
}
/**
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -75,14 +75,21 @@ class _builder extends \IPS\core\modules\front\system\widgets
if( mb_strpos( $field, "widget_feed_container_" ) !== FALSE )
{
/* On means that the all checkbox is ticked */
$params[ 'widget_feed_container'] = \IPS\Request::i()->$field == 'on' ? 0 : \IPS\Request::i()->$field;
$params[ 'widget_feed_container'] = \IPS\Request::i()->$field == 'on' ? 0 : ( \is_array( \IPS\Request::i()->$field ) ? \IPS\Request::i()->$field : explode( ',', \IPS\Request::i()->$field ) );
continue;
}
/* We need to handle tags special */
if( $field == 'widget_feed_tags' )
{
$params[ $field ] = explode( ',', \IPS\Request::i()->$field );
$params[ $field ] = \IPS\Request::i()->$field ? explode( ',', \IPS\Request::i()->$field ) : array();
continue;
}
/* We need to handle authors special */
if( $field == 'widget_feed_author' )
{
$params[ $field ] = \IPS\Request::i()->$field ? array( \IPS\Member::load( \IPS\Request::i()->$field, 'name' )->member_id ) : array();
continue;
}
@@ -112,7 +119,7 @@ class _builder extends \IPS\core\modules\front\system\widgets
$output = $block->widget()->render();
}
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $output ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $output ), 200, 'text/html' );
}
/**
@@ -188,7 +195,7 @@ class _builder extends \IPS\core\modules\front\system\widgets
protected function getConfiguration()
{
/* Standard widget area, allow the core stuff to handle this */
if( in_array( \IPS\Request::i()->area, array( 'sidebar', 'header', 'footer' ) ) )
if( \in_array( \IPS\Request::i()->area, array( 'sidebar', 'header', 'footer' ) ) )
{
return parent::getConfiguration();
}
@@ -241,11 +248,20 @@ class _builder extends \IPS\core\modules\front\system\widgets
$values = $widget->preConfig( $values );
}
/* Special advanced builder stuff */
if ( \in_array( 'IPS\Widget\Builder', class_implements( $widget ) ) )
{
if( isset( $values['widget_adv__background_custom_image'] ) and $values['widget_adv__background_custom_image'] )
{
$values['widget_adv__background_custom_image'] = (string) $values['widget_adv__background_custom_image'];
}
}
$blocks[ $k ]['configuration'] = $values;
\IPS\Db::i()->insert( 'cms_page_widget_areas', array( 'area_page_id' => \IPS\Request::i()->pageID, 'area_area' => \IPS\Request::i()->pageArea, 'area_widgets' => json_encode( $blocks ) ), TRUE );
\IPS\Output::i()->json( 'OK' );
}
\IPS\Output::i()->output = $widget->configuration()->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'widgets', 'core' ) ), 'formTemplate' ), $widget );
\IPS\Output::i()->output = $widget->configuration()->customTemplate( array( \IPS\Theme::i()->getTemplate( 'widgets', 'core' ), 'formTemplate' ), $widget );
}
}
}
@@ -319,13 +335,13 @@ class _builder extends \IPS\core\modules\front\system\widgets
}
/* Anything to update? */
if ( count( $widgets ) > count( $newOrder ) )
if ( \count( $widgets ) > \count( $newOrder ) )
{
/* No items left in area, or one has been removed */
foreach( $widgets as $widget )
{
/* If we haven't seen this widget, it's been removed, so add to trash */
if ( ! in_array( $widget['unique'], $seen ) )
if ( ! \in_array( $widget['unique'], $seen ) )
{
\IPS\Widget::trash( $widget['unique'], $widget );
}
@@ -360,7 +376,7 @@ class _builder extends \IPS\core\modules\front\system\widgets
*/
protected function _checkAndDeleteFromCoreWidgets( $uniqueId, $widgets )
{
if ( ! in_array( $uniqueId, $widgets ) )
if ( ! \in_array( $uniqueId, $widgets ) )
{
/* This widget hasn't been seen, so it isn't in the cms table */
try
@@ -378,7 +394,7 @@ class _builder extends \IPS\core\modules\front\system\widgets
}
/* Anything to save? */
if ( count( $newWidgets ) )
if ( \count( $newWidgets ) )
{
\IPS\Db::i()->replace( 'core_widget_areas', array( 'app' => 'cms', 'module' => 'pages', 'controller' => 'page', 'widgets' => json_encode( $newWidgets ), 'area' => \IPS\Request::i()->area ) );
}
+49 -3
View File
@@ -12,7 +12,7 @@
namespace IPS\cms\modules\front\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -63,6 +63,45 @@ class _page extends \IPS\Dispatcher\Controller
if ( \IPS\Request::i()->path == $page->full_path )
{
/* Did we have a trailing slash? */
if ( \IPS\Settings::i()->htaccess_mod_rewrite and mb_substr( \IPS\Request::i()->url()->data[ \IPS\Http\Url::COMPONENT_PATH ], -1 ) != '/' )
{
$url = $page->url();
foreach( \IPS\Request::i()->url()->queryString as $k => $v )
{
$url = $url->setQueryString( $k, $v );
}
if ( ! empty( \IPS\Request::i()->url()->fragment ) )
{
$url = $url->setFragment( \IPS\Request::i()->url()->fragment );
}
\IPS\Output::i()->redirect( $url, NULL, 301 );
}
else if ( ! \IPS\Settings::i()->htaccess_mod_rewrite and ! mb_strstr( \IPS\Request::i()->url()->data[ \IPS\Http\Url::COMPONENT_QUERY ], $page->url()->data[ \IPS\Http\Url::COMPONENT_QUERY ] ) )
{
$url = $page->url();
foreach( \IPS\Request::i()->url()->queryString as $k => $v )
{
if ( mb_substr( $k, 0, 1 ) == '/' and mb_substr( $k, -1 ) != '/' )
{
$k .= '/';
}
}
$url = $url->setQueryString( $k, $v );
if ( ! empty( \IPS\Request::i()->url()->fragment ) )
{
$url = $url->setFragment( \IPS\Request::i()->url()->fragment );
}
\IPS\Output::i()->redirect( $url, NULL, 301 );
}
/* Just viewing this page, no database categories or records */
$permissions = $page->permissions();
\IPS\Session::i()->setLocation( $page->url(), explode( ",", $permissions['perm_view'] ), 'loc_cms_viewing_page', array( 'cms_page_' . $page->_id => TRUE ) );
@@ -100,9 +139,16 @@ class _page extends \IPS\Dispatcher\Controller
}
else if ( isset( \IPS\Request::i()->path ) AND \IPS\Request::i()->path != '/' )
{
/* Sort out pagination for pages */
list( $path, $pageNumber ) = \IPS\cms\Pages\Page::getStrippedPagePath( \IPS\Request::i()->path );
if( $pageNumber AND !\IPS\Request::i()->page )
{
\IPS\Request::i()->page = $pageNumber;
}
try
{
$page = \IPS\cms\Pages\Page::loadFromPath( \IPS\Request::i()->path );
$page = \IPS\cms\Pages\Page::loadFromPath( $path );
}
catch ( \OutOfRangeException $e )
{
@@ -191,6 +237,6 @@ class _page extends \IPS\Dispatcher\Controller
*/
protected function embed()
{
return $this->__call( 'embed', func_get_args() );
return $this->__call( 'embed', \func_get_args() );
}
}