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

+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 ) );