Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

@@ -12,35 +12,37 @@
namespace IPS\cms\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\cms\Blocks\Block;
use IPS\Content;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use LogicException;
use OutOfRangeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Block Content
*/
class _BlockContent
class BlockContent extends EditorLocationsAbstract
{
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return TRUE;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param Member $member
* @param Editor $field
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member )
public function canAttach( Member $member, Editor $field ): bool|null
{
return NULL;
}
@@ -48,7 +50,7 @@ class _BlockContent
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
@@ -56,13 +58,13 @@ class _BlockContent
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
try
{
return \IPS\cms\Blocks\Block::load( $id1 )->can( 'view' );
return Block::load( $id1 )->can( 'view' );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
return FALSE;
}
@@ -74,18 +76,18 @@ class _BlockContent
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model
* @throws \LogicException
* @return Content|Member|Model|Url|null
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( int $id1=NULL, int $id2=NULL, string $id3=NULL ): Model|Content|Url|Member|null
{
try
{
return \IPS\cms\Blocks\Block::load( $id1 );
return Block::load( $id1 );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
return FALSE;
throw new LogicException;
}
}
}
@@ -12,43 +12,48 @@
namespace IPS\cms\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\cms\Records as RecordsClass;
use IPS\cms\Records\Comment;
use IPS\cms\Records\Review;
use IPS\Content;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use LogicException;
use OutOfRangeException;
use RuntimeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Record Content
*/
class _Records
class Records extends EditorLocationsAbstract
{
/**
* @brief Flag to indicate we don't want to be listed as a selectable area when configuring buttons
*/
public static $buttonLocation = FALSE;
public static bool $buttonLocation = FALSE;
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return NULL;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $editor The editor instance
* @param Member $member The member
* @param Editor $field The editor instance
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member, $editor )
public function canAttach( Member $member, Editor $field ): ?bool
{
if( !$editor->options['allowAttachments'] )
if( !$field->options['allowAttachments'] )
{
return FALSE;
}
@@ -60,11 +65,11 @@ class _Records
* Can whatever is posted in this editor be moderated?
* If this returns TRUE, we must ensure the content is ran through word, link and image filters
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool
*/
public function canBeModerated( $member, $field )
public function canBeModerated( Member $member, Editor $field ): bool
{
/* Creating/editing a record */
if ( preg_match( '/^RecordField_(?:new|\d+)_\d+/', $field->options['autoSaveKey'] ) )
@@ -81,16 +86,17 @@ class _Records
{
if ( \IPS\IN_DEV )
{
throw new \RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
throw new RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
}
return FALSE;
return parent::canBeModerated( $member, $field );
}
}
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
@@ -98,11 +104,11 @@ class _Records
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
if ( ! $id3 )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
$className = $this->_getClassName( $id3 );
@@ -110,9 +116,10 @@ class _Records
try
{
/* @var RecordsClass|Comment|Review $className */
return $className::load( $id )->canView( $member );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
return FALSE;
}
@@ -121,10 +128,10 @@ class _Records
/**
* Figure out the correct class name to return
*
* @param string|int $id3 The id3 value stored
* @param int|string $id3 The id3 value stored
* @return string
*/
protected function _getClassName( $id3 )
protected function _getClassName( int|string $id3 ): string
{
/* Review? */
if( mb_strpos( $id3, '-review' ) )
@@ -153,10 +160,10 @@ class _Records
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model
* @throws \LogicException
* @return Content|Member|Model|Url|null
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( int $id1=NULL, int $id2=NULL, string $id3=NULL ): Model|Content|Url|Member|null
{
try
{
@@ -165,18 +172,14 @@ class _Records
$className = $this->_getClassName( $id3 );
$id = ( mb_strpos( $className, 'Review' ) !== FALSE OR mb_strpos( $className, 'Comment' ) !== FALSE ) ? $id2 : $id1;
/* @var RecordsClass|Comment|Review $className */
$return = $className::load( $id );
$return->url(); // Need to check that won't throw an exception later, which might happen if the database no longer has a page
return $return;
}
else
{
return FALSE;
}
}
catch ( \Exception $e )
{
return FALSE;
}
catch ( Exception $e ){}
throw new LogicException;
}
}
@@ -12,35 +12,41 @@
namespace IPS\cms\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application\Module;
use IPS\cms\Pages\Page;
use IPS\Content;
use IPS\Db;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use IPS\Widget\Area;
use LogicException;
use OutOfRangeException;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Record Content
*/
class _Widgets
class Widgets extends EditorLocationsAbstract
{
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return NULL;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param Member $member
* @param Editor $field
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member )
public function canAttach( Member $member, Editor $field ): bool|null
{
return TRUE;
}
@@ -48,7 +54,7 @@ class _Widgets
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
@@ -56,11 +62,11 @@ class _Widgets
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
if ( ! $id3 )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
/* See if it's on a page in Pages */
@@ -68,7 +74,7 @@ class _Widgets
if ( $pageId !== NULL )
{
return \IPS\cms\Pages\Page::load( $pageId )->can( 'view', $member );
return Page::load( $pageId )->can( 'view', $member );
}
/* Still here? Look elsewhere */
@@ -76,11 +82,11 @@ class _Widgets
if ( $area !== NULL )
{
return \IPS\Application\Module::get( $area[0], $area[1], 'front' )->can( 'view', $member );
return Module::get( $area[0], $area[1], 'front' )->can( 'view', $member );
}
/* Still here? */
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
/**
@@ -89,42 +95,42 @@ class _Widgets
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model
* @throws \LogicException
* @return Content|Member|Model|Url|null
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( int $id1=NULL, int $id2=NULL, string $id3=NULL ): Model|Content|Url|Member|null
{
$pageId = $this->getPageIdFromWidgetUniqueId( $id3 );
if ( $pageId !== NULL )
{
return \IPS\cms\Pages\Page::load( $pageId );
return Page::load( $pageId );
}
$area = $this->getAreaFromWidgetUniqueId( $id3 );
if ( $area !== NULL )
{
return \IPS\Application\Module::get( $area[0], $area[1] );
return Module::get( $area[0], $area[1] );
}
return FALSE;
throw new LogicException;
}
/**
* Returns the page ID based on the widget's unique ID
*
* @param string $uniqueId The widget's unique ID
* @param string $uniqueId The widget's unique ID
* @return null|int
*/
protected function getPageIdFromWidgetUniqueId( $uniqueId )
protected function getPageIdFromWidgetUniqueId( string $uniqueId ): ?int
{
$pageId = NULL;
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $item )
foreach( Db::i()->select( '*', 'cms_page_widget_areas' ) as $item )
{
$widgets = json_decode( $item['area_widgets'], TRUE );
foreach( $widgets as $widget )
$areaData = json_decode( $item['area_tree'], TRUE );
$area = new Area( $areaData, $item['area_area'] );
foreach( $area->getAllWidgets() as $widget )
{
if ( $widget['unique'] == $uniqueId )
{
@@ -139,17 +145,18 @@ class _Widgets
/**
* Returns area information if the widget is not on a cms page
*
* @param string $uniqueId The widget's unique ID
* @param string $uniqueId The widget's unique ID
* @return array|null Index 0 = Application, Index 1 = Module, Index 2 = Controller
*/
protected function getAreaFromWidgetUniqueId( $uniqueId )
protected function getAreaFromWidgetUniqueId( string $uniqueId ): ?array
{
$return = NULL;
foreach( \IPS\Db::i()->select( '*', 'core_widget_areas' ) AS $row )
foreach( Db::i()->select( '*', 'core_widget_areas' ) AS $row )
{
$widgets = json_decode( $row['widgets'], TRUE );
$areaData = json_decode( $row['tree'], TRUE );
$area = new Area( $areaData, $row['area'] );
foreach( $widgets AS $widget )
foreach( $area->getAllWidgets() AS $widget )
{
if ( $widget['unique'] == $uniqueId )
{