Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -12,36 +12,33 @@
|
||||
namespace IPS\cms\extensions\core\ContentRouter;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Application\Module;
|
||||
use IPS\Extensions\ContentRouterAbstract;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Content Router extension: Pages
|
||||
*/
|
||||
class _Pages
|
||||
class Pages extends ContentRouterAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Content Item Classes
|
||||
*/
|
||||
public $classes = array();
|
||||
|
||||
/**
|
||||
* @brief Can be shown in similar content
|
||||
*/
|
||||
public $similarContent = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Member|IPS\Member\Group|NULL $memberOrGroup If checking access, the member/group to check for, or NULL to not check access
|
||||
* @param Member|Group|NULL $memberOrGroup If checking access, the member/group to check for, or NULL to not check access
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $memberOrGroup = NULL )
|
||||
public function __construct( Group|Member $memberOrGroup = NULL )
|
||||
{
|
||||
if ( $memberOrGroup === NULL or $memberOrGroup->canAccessModule( \IPS\Application\Module::get( 'cms', 'pages', 'front' ) ) )
|
||||
if ( $memberOrGroup === NULL or $memberOrGroup->canAccessModule( Module::get( 'cms', 'pages', 'front' ) ) )
|
||||
{
|
||||
$this->classes[] = 'IPS\cms\Pages\PageItem';
|
||||
}
|
||||
|
||||
@@ -12,38 +12,40 @@
|
||||
namespace IPS\cms\extensions\core\ContentRouter;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\cms\Databases;
|
||||
use IPS\Extensions\ContentRouterAbstract;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Content Router extension: Records
|
||||
*/
|
||||
class _Records
|
||||
class Records extends ContentRouterAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Content Item Classes
|
||||
*/
|
||||
public $classes = array();
|
||||
|
||||
/**
|
||||
* @brief Can be shown in similar content
|
||||
*/
|
||||
public $similarContent = TRUE;
|
||||
|
||||
public bool $similarContent = TRUE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Member|IPS\Member\Group|NULL $member If checking access, the member/group to check for, or NULL to not check access
|
||||
* @return void
|
||||
* @param Member|Group|null $member If checking access, the member/group to check for, or NULL to not check access
|
||||
*/
|
||||
public function __construct( $member = NULL )
|
||||
public function __construct( Member|Group $member = NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\cms\Databases::databases() as $id => $database )
|
||||
foreach ( Databases::databases() as $id => $database )
|
||||
{
|
||||
if( $database->page_id )
|
||||
{
|
||||
@@ -54,6 +56,6 @@ class _Records
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
|
||||
catch ( Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Create Menu Extension : Records
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 18 Dec 2014
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\CreateMenu;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Menu Extension: Records
|
||||
*/
|
||||
class _Records
|
||||
{
|
||||
/**
|
||||
* Get Items
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$items = array();
|
||||
|
||||
foreach( \IPS\cms\Databases::databases() as $database )
|
||||
{
|
||||
$theOnlyCategory = NULL;
|
||||
if ( $database->page_id > 0 and $database->can('view') and $database->can('add') )
|
||||
{
|
||||
$catClass = '\IPS\cms\Categories' . $database->id;
|
||||
if ( $catClass::canOnAny('add') )
|
||||
{
|
||||
try
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::load( $database->page_id );
|
||||
|
||||
if( $database->use_categories AND $theOnlyCategory = $catClass::theOnlyNode() )
|
||||
{
|
||||
$items[ 'cms_create_menu_records_' . $database->id ] = array(
|
||||
'link' => $theOnlyCategory->url()->setQueryString( array( 'do' => 'form', 'd' => $database->id ) )
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[ 'cms_create_menu_records_' . $database->id ] = array(
|
||||
'link' => $page->url()->setQueryString( array( 'do' => 'form', 'd' => $database->id ) ),
|
||||
'extraData' => ( $database->use_categories ) ? array( 'data-ipsDialog' => true, 'data-ipsDialog-size' => "narrow" ) : array(),
|
||||
'title' => 'cms_select_category'
|
||||
);
|
||||
|
||||
}
|
||||
catch( \OutOfRangeException $ex ) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksort( $items );
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Designers Mode Extension
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 28 Nov 2014
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\DesignersMode;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designers Mode Extension
|
||||
*/
|
||||
class _Cms
|
||||
{
|
||||
/**
|
||||
* Anything need building?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function toBuild()
|
||||
{
|
||||
/* Yeah.. not gonna even bother trying to match up timestamps and such like and so on etc and etcetera is that spelled right? */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designer's mode on
|
||||
*
|
||||
* @param mixed $data Data
|
||||
* @return bool
|
||||
*/
|
||||
public function on( $data=NULL )
|
||||
{
|
||||
\IPS\cms\Theme\Advanced\Theme::export();
|
||||
\IPS\cms\Media::exportDesignersModeMedia();
|
||||
\IPS\cms\Pages\Page::exportDesignersMode();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designer's mode off
|
||||
*
|
||||
* @param mixed $data Data
|
||||
* @return bool
|
||||
*/
|
||||
public function off( $data=NULL )
|
||||
{
|
||||
\IPS\cms\Theme\Advanced\Theme::import();
|
||||
\IPS\cms\Media::importDesignersModeMedia();
|
||||
\IPS\cms\Pages\Page::importDesignersMode();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: Categories
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 18 Dec 2023
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: Categories
|
||||
*/
|
||||
class Categories extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return (int) Db::i()->select( 'count(category_id)', 'cms_database_categories', 'category_image is not null' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move stored files
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void
|
||||
*/
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
$row = Db::i()->select( 'category_id,category_image', 'cms_database_categories', 'category_image is not null', 'category_id', array( $offset, 1 ) )->first();
|
||||
try
|
||||
{
|
||||
$file = File::get( $oldConfiguration ?: 'cms_Categories', $row['category_image'] )->move( $storageConfiguration );
|
||||
if( (string) $file != $row['category_image'] )
|
||||
{
|
||||
Db::i()->update( 'cms_database_categories', [ 'category_image' => (string) $file ], [ 'category_id=?', $row['category_id']] );
|
||||
}
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param File|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( File|string $file ): bool
|
||||
{
|
||||
return (bool) Db::i()->select( 'count(category_id)', 'cms_database_categories', [ 'category_image=?', (string) $file ] )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() : void
|
||||
{
|
||||
foreach( Db::i()->select( 'category_image', 'cms_database_categories', 'category_image is not null', 'category_id' ) as $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
File::get( 'cms_Categories', $image )->delete();
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,25 +12,33 @@
|
||||
namespace IPS\cms\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: CMS Media
|
||||
*/
|
||||
class _Media
|
||||
class Media extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'cms_media' )->first();
|
||||
return Db::i()->select( 'COUNT(*)', 'cms_media' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,59 +47,43 @@ class _Media
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void|int An offset integer to use on the next cycle, or nothing
|
||||
* @throws UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void An offset integer to use on the next cycle, or nothing
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
$media = \IPS\Db::i()->select( '*', 'cms_media', array(), 'media_id', array( $offset, 1 ) )->first();
|
||||
$media = Db::i()->select( '*', 'cms_media', array(), 'media_id', array( $offset, 1 ) )->first();
|
||||
|
||||
try
|
||||
{
|
||||
$file = \IPS\File::get( $oldConfiguration ?: 'cms_Media', $media['media_file_object'] )->move( $storageConfiguration );
|
||||
$file = File::get( $oldConfiguration ?: 'cms_Media', $media['media_file_object'] )->move( $storageConfiguration );
|
||||
|
||||
if ( (string) $file != $media['media_file_object'] )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_media', array( 'media_file_object' => (string) $file ), array( 'media_id=?', $media['media_id'] ) );
|
||||
Db::i()->update( 'cms_media', array( 'media_file_object' => (string) $file ), array( 'media_id=?', $media['media_id'] ) );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix all URLs
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @return void
|
||||
*/
|
||||
public function fixUrls( $offset )
|
||||
{
|
||||
$media = \IPS\Db::i()->select( '*', 'cms_media', array(), 'media_id', array( $offset, 1 ) )->first();
|
||||
|
||||
if ( $new = \IPS\File::repairUrl( $media['media_file_object'] ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_media', array( 'media_file_object' => $new ), array( 'media_id=?', $media['media_id'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @param File|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
public function isValidFile( File|string $file ): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
$media = \IPS\Db::i()->select( '*', 'cms_media', array( 'media_file_object=?', (string) $file ) )->first();
|
||||
$media = Db::i()->select( '*', 'cms_media', array( 'media_file_object=?', (string) $file ) )->first();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -102,15 +94,15 @@ class _Media
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete() : void
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_media', 'media_file_object IS NOT NULL' ) as $item )
|
||||
foreach( Db::i()->select( '*', 'cms_media', 'media_file_object IS NOT NULL' ) as $item )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'cms_Media', $item['media_file_object'] )->delete();
|
||||
File::get( 'cms_Media', $item['media_file_object'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
catch( Exception $e ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,23 +12,32 @@
|
||||
namespace IPS\cms\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Exception;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: CMS Pages
|
||||
*/
|
||||
class _Pages
|
||||
class Pages extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return 1; # Number of steps needed to clear/move files
|
||||
}
|
||||
@@ -39,48 +48,34 @@ class _Pages
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \Underflowexception When file record doesn't exist. Indicating there are no more files to move
|
||||
* @throws Underflowexception When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
/* Just remove page object data so it will rebuild on the next iteration */
|
||||
\IPS\cms\Pages\Page::deleteCachedIncludes( NULL, $oldConfiguration );
|
||||
Page::deleteCachedIncludes( NULL, $oldConfiguration );
|
||||
|
||||
throw new \UnderflowException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix all URLs
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @return void
|
||||
*/
|
||||
public function fixUrls( $offset )
|
||||
{
|
||||
/* Just remove page object data so it will rebuild on the next iteration */
|
||||
\IPS\cms\Pages\Page::deleteCachedIncludes();
|
||||
|
||||
throw new \UnderflowException;
|
||||
throw new UnderflowException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @param File|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
public function isValidFile( File|string $file ): bool
|
||||
{
|
||||
$bits = explode( '/', (string) $file );
|
||||
$name = array_pop( $bits );
|
||||
|
||||
try
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( "template_file_object LIKE '%" . \IPS\Db::i()->escape_string( $name ) . "%'") ) as $template )
|
||||
foreach( Db::i()->select( '*', 'cms_templates', array( "template_file_object LIKE '%" . Db::i()->escape_string( $name ) . "%'") ) as $template )
|
||||
{
|
||||
$fileObject = \IPS\File::get( 'core_Theme', $template['template_file_object'] );
|
||||
$fileObject = File::get( 'core_Theme', $template['template_file_object'] );
|
||||
|
||||
if( $fileObject->url == (string) $file )
|
||||
{
|
||||
@@ -90,7 +85,7 @@ class _Pages
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
catch( \IPS\Db\Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -101,8 +96,8 @@ class _Pages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete() : void
|
||||
{
|
||||
\IPS\cms\Pages\Page::deleteCachedIncludes();
|
||||
Page::deleteCachedIncludes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: PagesImages
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 15 Dec 2023
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use Exception;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: PagesImages
|
||||
*/
|
||||
class PagesImages extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return (int) Db::i()->select( 'COUNT(page_id)', 'cms_pages', 'page_meta_image is not null' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move stored files
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void
|
||||
*/
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
$row = Db::i()->select( 'page_id,page_meta_image', 'cms_pages', 'page_meta_image is not null', 'page_id', [ $offset, 1 ] )->first();
|
||||
try
|
||||
{
|
||||
$file = File::get( $oldConfiguration ?: 'cms_PagesImages', $row['page_meta_image'] )->move( $storageConfiguration );
|
||||
if( (string) $file != $row['page_meta_image'] )
|
||||
{
|
||||
Db::i()->update( 'cms_pages', [ 'page_meta_image' => (string) $file ], [ 'page_id=?', $row['page_id'] ] );
|
||||
}
|
||||
}
|
||||
catch( Exception ){}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param File|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( File|string $file ): bool
|
||||
{
|
||||
return (bool) Db::i()->select( 'count(page_id)', 'cms_pages', [ 'page_meta_image=?', (string) $file ] )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() : void
|
||||
{
|
||||
foreach( Db::i()->select( 'page_meta_image', 'cms_pages', 'page_meta_image is not null', 'page_id' ) as $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
File::get( 'cms_PagesImages', $image )->delete();
|
||||
}
|
||||
catch( Exception ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,33 +12,45 @@
|
||||
namespace IPS\cms\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\cms\Databases;
|
||||
use IPS\Data\Store;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File;
|
||||
use UnderflowException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function is_array;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: Records
|
||||
*/
|
||||
class _Records
|
||||
class Records extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
$fields = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'LOWER(field_type)=\'upload\'' ) ) as $field )
|
||||
foreach( Db::i()->select( '*', 'cms_database_fields', array( 'LOWER(field_type)=\'upload\'' ) ) as $field )
|
||||
{
|
||||
$fields[ $field['field_database_id'] ][] = $field['field_id'];
|
||||
}
|
||||
|
||||
foreach( \IPS\cms\Databases::databases() as $id => $db )
|
||||
foreach( Databases::databases() as $id => $db )
|
||||
{
|
||||
$where = array( 'record_image IS NOT NULL' );
|
||||
|
||||
@@ -50,7 +62,7 @@ class _Records
|
||||
}
|
||||
}
|
||||
|
||||
$count += \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $id, implode( ' OR ', $where ) )->first();
|
||||
$count += Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $id, implode( ' OR ', $where ) )->first();
|
||||
}
|
||||
|
||||
return $count;
|
||||
@@ -62,29 +74,29 @@ class _Records
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \Underflowexception When file record doesn't exist. Indicating there are no more files to move
|
||||
* @throws Underflowexception When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->cms_files_move_data ) )
|
||||
if ( ! isset( Store::i()->cms_files_move_data ) )
|
||||
{
|
||||
foreach( \IPS\cms\Databases::databases() as $id => $database )
|
||||
foreach( Databases::databases() as $id => $database )
|
||||
{
|
||||
$data[ $id ] = 0;
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->cms_files_move_data = $data;
|
||||
Store::i()->cms_files_move_data = $data;
|
||||
}
|
||||
|
||||
$data = \IPS\Data\Store::i()->cms_files_move_data;
|
||||
|
||||
if ( !is_countable( $data ) OR ! \count( $data ) )
|
||||
$data = Store::i()->cms_files_move_data;
|
||||
|
||||
if ( ! is_countable( $data ) OR ! count( $data ) )
|
||||
{
|
||||
/* all done */
|
||||
unset( \IPS\Data\Store::i()->cms_files_move_data );
|
||||
unset( Store::i()->cms_files_move_data );
|
||||
|
||||
throw new \UnderflowException;
|
||||
throw new UnderflowException;
|
||||
}
|
||||
|
||||
reset( $data );
|
||||
@@ -93,7 +105,7 @@ class _Records
|
||||
|
||||
$done = 0;
|
||||
$fields = array( 'record_image', 'record_image_thumb' );
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND LOWER(field_type)=\'upload\'', $databaseId ) ) as $field )
|
||||
foreach( Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND LOWER(field_type)=\'upload\'', $databaseId ) ) as $field )
|
||||
{
|
||||
$fields[] = 'field_' . $field['field_id'];
|
||||
}
|
||||
@@ -107,7 +119,7 @@ class _Records
|
||||
|
||||
$where = array( implode( ' OR ', $conditions ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, $where, 'primary_id_field ASC', array( $realOffset, 1 ) ) as $row )
|
||||
foreach( Db::i()->select( '*', 'cms_custom_database_' . $databaseId, $where, 'primary_id_field ASC', array( $realOffset, 1 ) ) as $row )
|
||||
{
|
||||
foreach( $fields as $field )
|
||||
{
|
||||
@@ -122,7 +134,6 @@ class _Records
|
||||
$files = array( $row[ $field ] );
|
||||
}
|
||||
|
||||
$finished = array();
|
||||
$save = FALSE;
|
||||
$fixed = FALSE;
|
||||
|
||||
@@ -130,7 +141,7 @@ class _Records
|
||||
{
|
||||
try
|
||||
{
|
||||
$check = \IPS\File::get( $oldConfiguration ?: 'cms_Records', $file )->move( $storageConfiguration );
|
||||
$check = File::get( $oldConfiguration ?: 'cms_Records', $file )->move( $storageConfiguration );
|
||||
|
||||
if ( (string) $file != $check )
|
||||
{
|
||||
@@ -142,7 +153,7 @@ class _Records
|
||||
$save[] = $file;
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
$save[] = $file;
|
||||
}
|
||||
@@ -150,7 +161,7 @@ class _Records
|
||||
|
||||
if ( $fixed )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $databaseId, array( $field => implode( ',', $save ) ), array( 'primary_id_field=?', $row['primary_id_field'] ) );
|
||||
Db::i()->update( 'cms_custom_database_' . $databaseId, array( $field => implode( ',', $save ) ), array( 'primary_id_field=?', $row['primary_id_field'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,169 +179,48 @@ class _Records
|
||||
unset( $data[ $databaseId ] );
|
||||
}
|
||||
|
||||
if ( ! \count( $data ) )
|
||||
if ( ! count( $data ) )
|
||||
{
|
||||
if ( isset( \IPS\Data\Store::i()->cms_files_move_data ) )
|
||||
if ( isset( Store::i()->cms_files_move_data ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_files_move_data );
|
||||
unset( Store::i()->cms_files_move_data );
|
||||
}
|
||||
|
||||
throw new \Underflowexception;
|
||||
throw new Underflowexception;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Data\Store::i()->cms_files_move_data = $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix all URLs
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @return void
|
||||
*/
|
||||
public function fixUrls( $offset )
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->cms_files_repair_data ) )
|
||||
{
|
||||
foreach( \IPS\cms\Databases::databases() as $id => $database )
|
||||
{
|
||||
$data[ $id ] = 0;
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->cms_files_repair_data = $data;
|
||||
}
|
||||
|
||||
$data = \IPS\Data\Store::i()->cms_files_repair_data;
|
||||
|
||||
if ( ! \count( $data ) )
|
||||
{
|
||||
/* all done */
|
||||
unset( \IPS\Data\Store::i()->cms_files_repair_data );
|
||||
|
||||
throw new \UnderflowException;
|
||||
}
|
||||
|
||||
reset( $data );
|
||||
$databaseId = key( $data );
|
||||
$realOffset = $data[ $databaseId ];
|
||||
|
||||
$done = 0;
|
||||
$fields = array( 'record_image', 'record_image_thumb' );
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND LOWER(field_type)=\'upload\'', $databaseId ) ) as $field )
|
||||
{
|
||||
$fields[] = 'field_' . $field['field_id'];
|
||||
}
|
||||
|
||||
$conditions = array();
|
||||
|
||||
foreach( $fields as $field )
|
||||
{
|
||||
$conditions[] = $field . ' IS NOT NULL';
|
||||
}
|
||||
|
||||
$where = array( implode( ' OR ', $conditions ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, $where, 'primary_id_field ASC', array( $realOffset, 1 ) ) as $row )
|
||||
{
|
||||
foreach( $fields as $field )
|
||||
{
|
||||
if ( isset( $row[ $field ] ) and ! empty( $row[ $field ] ) )
|
||||
{
|
||||
if ( mb_strstr( $row[ $field ], ',' ) )
|
||||
{
|
||||
$files = explode( ',', $row[ $field ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$files = array( $row[ $field ] );
|
||||
}
|
||||
|
||||
$finished = array();
|
||||
$save = FALSE;
|
||||
|
||||
foreach( $files as $file )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( $new = \IPS\File::repairUrl( $file ) )
|
||||
{
|
||||
$fixed = TRUE;
|
||||
$save[] = $new;
|
||||
}
|
||||
else
|
||||
{
|
||||
$save[] = $file;
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
$save[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $fixed )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $databaseId, array( $field => implode( ',', $save ) ), array( 'primary_id_field=?', $row['primary_id_field'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$done++;
|
||||
}
|
||||
|
||||
if ( $done )
|
||||
{
|
||||
$data[ $databaseId ] = $realOffset + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Assume all done */
|
||||
unset( $data[ $databaseId ] );
|
||||
}
|
||||
|
||||
if ( ! \count( $data ) )
|
||||
{
|
||||
if ( isset( \IPS\Data\Store::i()->cms_files_repair_data ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_files_repair_data );
|
||||
}
|
||||
|
||||
throw new \Underflowexception;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Data\Store::i()->cms_files_repair_data = $data;
|
||||
Store::i()->cms_files_move_data = $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @param File|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
public function isValidFile( File|string $file ): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach( \IPS\cms\Databases::databases() as $id => $db )
|
||||
foreach( Databases::databases() as $id => $db )
|
||||
{
|
||||
$theFile = \IPS\Db::i()->select( '*', 'cms_custom_database_' . $id, array( 'record_image=? OR record_image_thumb=?', (string) $file, (string) $file ) )->first();
|
||||
$theFile = Db::i()->select( '*', 'cms_custom_database_' . $id, array( 'record_image=? OR record_image_thumb=?', (string) $file, (string) $file ) )->first();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException $e )
|
||||
{
|
||||
/* Gather all the upload fields */
|
||||
$fields = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'LOWER(field_type)=\'upload\'' ) ) as $field )
|
||||
foreach( Db::i()->select( '*', 'cms_database_fields', array( 'LOWER(field_type)=\'upload\'' ) ) as $field )
|
||||
{
|
||||
$fields[ $field['field_database_id'] ][] = $field['field_id'];
|
||||
}
|
||||
|
||||
if ( \is_array( $fields ) )
|
||||
if ( is_array( $fields ) )
|
||||
{
|
||||
foreach( $fields as $databaseId => $data )
|
||||
{
|
||||
@@ -338,11 +228,11 @@ class _Records
|
||||
{
|
||||
try
|
||||
{
|
||||
$record = \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, 'field_' . $fieldId . " LIKE '%" . (string) $file . "%'" )->first();
|
||||
$record = Db::i()->select( '*', 'cms_custom_database_' . $databaseId, 'field_' . $fieldId . " LIKE '%" . (string) $file . "%'" )->first();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
catch ( UnderflowException $e )
|
||||
{
|
||||
/* Might be in another field */
|
||||
}
|
||||
@@ -360,12 +250,12 @@ class _Records
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete() : void
|
||||
{
|
||||
foreach( \IPS\cms\Databases::databases() as $databaseId => $database )
|
||||
foreach( Databases::databases() as $databaseId => $database )
|
||||
{
|
||||
$fields = array( 'record_image', 'record_image_thumb' );
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND LOWER(field_type)=\'upload\'', $databaseId ) ) as $field )
|
||||
foreach( Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND LOWER(field_type)=\'upload\'', $databaseId ) ) as $field )
|
||||
{
|
||||
$fields[] = 'field_' . $field['field_id'];
|
||||
}
|
||||
@@ -377,13 +267,13 @@ class _Records
|
||||
$where[] = array( $field . ' IS NOT NULL' );
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, $where, 'primary_id_field ASC' ) as $row )
|
||||
foreach( Db::i()->select( '*', 'cms_custom_database_' . $databaseId, $where, 'primary_id_field ASC' ) as $row )
|
||||
{
|
||||
foreach( $fields as $field )
|
||||
{
|
||||
if ( isset( $row[ $field ] ) and ! empty( $row[ $field ] ) )
|
||||
{
|
||||
$file = \IPS\File::get( 'cms_Records', $row[ $field ] )->delete();
|
||||
File::get( 'cms_Records', $row[ $field ] )->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,56 +12,78 @@
|
||||
namespace IPS\cms\extensions\core\FrontNavigation;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Categories;
|
||||
use IPS\cms\Databases\Dispatcher;
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\core\FrontNavigation\FrontNavigationAbstract;
|
||||
use IPS\Db;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\Translatable;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use OutOfBoundsException;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Front Navigation Extension: Pages
|
||||
*/
|
||||
class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
class Pages extends FrontNavigationAbstract
|
||||
{
|
||||
/**
|
||||
* @var string Default icon
|
||||
*/
|
||||
public string $defaultIcon = '\f15c';
|
||||
|
||||
/**
|
||||
* Get Type Title which will display in the AdminCP Menu Manager
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function typeTitle()
|
||||
public static function typeTitle(): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('menu_content_page');
|
||||
return Member::loggedIn()->language()->addToStack('menu_content_page');
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow multiple instances?
|
||||
*
|
||||
* @return bool
|
||||
* @return bool
|
||||
*/
|
||||
public static function allowMultiple()
|
||||
public static function allowMultiple(): bool
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get configuration fields
|
||||
*
|
||||
* @param array $existingConfiguration The existing configuration, if editing an existing item
|
||||
* @param int $id The ID number of the existing item, if editing
|
||||
* @return array
|
||||
* @param array $existingConfiguration The existing configuration, if editing an existing item
|
||||
* @param int|null $id The ID number of the existing item, if editing
|
||||
* @return array
|
||||
*/
|
||||
public static function configuration( $existingConfiguration, $id = NULL )
|
||||
public static function configuration(array $existingConfiguration, ?int $id = NULL ): array
|
||||
{
|
||||
$pages = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_pages' ), 'IPS\cms\Pages\Page' ) as $page )
|
||||
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'cms_pages' ), 'IPS\cms\Pages\Page' ) as $page )
|
||||
{
|
||||
$pages[ $page->id ] = $page->full_path;
|
||||
}
|
||||
|
||||
return array(
|
||||
new \IPS\Helpers\Form\Select( 'menu_content_page', isset( $existingConfiguration['menu_content_page'] ) ? $existingConfiguration['menu_content_page'] : NULL, NULL, array( 'options' => $pages ), NULL, NULL, NULL, 'menu_content_page' ),
|
||||
new \IPS\Helpers\Form\Radio( 'menu_title_page_type', isset( $existingConfiguration['menu_title_page_type'] ) ? $existingConfiguration['menu_title_page_type'] : 0, NULL, array( 'options' => array( 0 => 'menu_title_page_inherit', 1 => 'menu_title_page_custom' ), 'toggles' => array( 1 => array( 'menu_title_page' ) ) ), NULL, NULL, NULL, 'menu_title_page_type' ),
|
||||
new \IPS\Helpers\Form\Translatable( 'menu_title_page', NULL, NULL, array( 'app' => 'cms', 'key' => $id ? "cms_menu_title_{$id}" : NULL ), NULL, NULL, NULL, 'menu_title_page' ),
|
||||
new Select( 'menu_content_page', $existingConfiguration['menu_content_page'] ?? NULL, NULL, array( 'options' => $pages ), NULL, NULL, NULL, 'menu_content_page' ),
|
||||
new Radio( 'menu_title_page_type', $existingConfiguration['menu_title_page_type'] ?? 0, NULL, array( 'options' => array( 0 => 'menu_title_page_inherit', 1 => 'menu_title_page_custom' ), 'toggles' => array( 1 => array( 'menu_title_page' ) ) ), NULL, NULL, NULL, 'menu_title_page_type' ),
|
||||
new Translatable( 'menu_title_page', NULL, NULL, array( 'app' => 'cms', 'key' => $id ? "cms_menu_title_{$id}" : NULL ), NULL, NULL, NULL, 'menu_title_page' ),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,17 +92,17 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
*
|
||||
* @param array $configuration The values received from the form
|
||||
* @param int $id The ID number of the existing item, if editing
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public static function parseConfiguration( $configuration, $id )
|
||||
public static function parseConfiguration( array $configuration, int $id ): array
|
||||
{
|
||||
if ( $configuration['menu_title_page_type'] )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'cms', "cms_menu_title_{$id}", $configuration['menu_title_page'] );
|
||||
Lang::saveCustom( 'cms', "cms_menu_title_{$id}", $configuration['menu_title_page'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Lang::deleteCustom( 'cms', "cms_menu_title_{$id}" );
|
||||
Lang::deleteCustom( 'cms', "cms_menu_title_{$id}" );
|
||||
}
|
||||
|
||||
unset( $configuration['menu_title_page'] );
|
||||
@@ -91,28 +113,28 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
/**
|
||||
* Can access?
|
||||
*
|
||||
* @return bool
|
||||
* @return bool
|
||||
*/
|
||||
public function canView()
|
||||
public function canView(): bool
|
||||
{
|
||||
if ( $this->permissions )
|
||||
{
|
||||
if ( $this->permissions != '*' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->inGroup( explode( ',', $this->permissions ) );
|
||||
return Member::loggedIn()->inGroup( explode( ',', $this->permissions ) );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Inherit from page */
|
||||
$store = \IPS\cms\Pages\Page::getStore();
|
||||
$store = Page::getStore();
|
||||
|
||||
if ( isset( $store[ $this->configuration['menu_content_page'] ] ) )
|
||||
{
|
||||
if ( $store[ $this->configuration['menu_content_page'] ]['perm'] != '*' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->inGroup( explode( ',', $store[ $this->configuration['menu_content_page'] ]['perm'] ) );
|
||||
return Member::loggedIn()->inGroup( explode( ',', $store[ $this->configuration['menu_content_page'] ]['perm'] ) );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -124,17 +146,17 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
/**
|
||||
* Get Title
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function title()
|
||||
public function title(): string
|
||||
{
|
||||
if ( $this->configuration['menu_title_page_type'] )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( "cms_menu_title_{$this->id}" );
|
||||
return Member::loggedIn()->language()->addToStack( "cms_menu_title_{$this->id}" );
|
||||
}
|
||||
else
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::load( $this->configuration['menu_content_page'] );
|
||||
$page = Page::load( $this->configuration['menu_content_page'] );
|
||||
|
||||
if( $database = $page->getDatabase() and $database->pageTitle() )
|
||||
{
|
||||
@@ -142,7 +164,7 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( "cms_page_{$this->configuration['menu_content_page']}" );
|
||||
return Member::loggedIn()->language()->addToStack( "cms_page_{$this->configuration['menu_content_page']}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,29 +172,29 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
/**
|
||||
* Get Link
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
* @return string|Url|null
|
||||
*/
|
||||
public function link()
|
||||
public function link(): Url|string|null
|
||||
{
|
||||
$store = \IPS\cms\Pages\Page::getStore();
|
||||
$store = Page::getStore();
|
||||
|
||||
if ( isset( $store[ $this->configuration['menu_content_page'] ] ) )
|
||||
{
|
||||
return $store[ $this->configuration['menu_content_page'] ]['url'];
|
||||
return Url::external( $store[ $this->configuration['menu_content_page'] ]['url'] );
|
||||
}
|
||||
|
||||
/* Fall back here */
|
||||
return \IPS\cms\Pages\Page::load( $this->configuration['menu_content_page'] )->url();
|
||||
return Page::load( $this->configuration['menu_content_page'] )->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Active?
|
||||
*
|
||||
* @return bool
|
||||
* @return bool
|
||||
*/
|
||||
public function active()
|
||||
public function active(): bool
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::$currentPage;
|
||||
$page = Page::$currentPage;
|
||||
if ( !$page )
|
||||
{
|
||||
return false;
|
||||
@@ -180,24 +202,14 @@ class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
|
||||
|
||||
try
|
||||
{
|
||||
if ( $db = $page->getDatabase() and $db->allow_club_categories and $categoryClass = '\\IPS\\cms\\Categories' . $db->id and \IPS\cms\Databases\Dispatcher::i()->categoryId and $categoryClass::load( \IPS\cms\Databases\Dispatcher::i()->categoryId )->club() )
|
||||
/* @var $categoryClass Categories */
|
||||
if ( $db = $page->getDatabase() and $db->allow_club_categories and $categoryClass = '\\IPS\\cms\\Categories' . $db->id and Dispatcher::i()->categoryId and $categoryClass::load( Dispatcher::i()->categoryId )->club() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException|\OutOfBoundsException ) {}
|
||||
catch ( OutOfRangeException|OutOfBoundsException ) {}
|
||||
|
||||
return $page->id == $this->configuration['menu_content_page'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Children
|
||||
*
|
||||
* @param bool $noStore If true, will skip datastore and get from DB (used for ACP preview)
|
||||
* @return array
|
||||
*/
|
||||
public function children( $noStore=FALSE )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Member Sync
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 20 Aug 2015
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\MemberSync;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Member Sync
|
||||
*/
|
||||
class _Databases
|
||||
{
|
||||
/**
|
||||
* Member is merged with another member
|
||||
*
|
||||
* @param \IPS\Member $member Member being kept
|
||||
* @param \IPS\Member $member2 Member being removed
|
||||
* @return void
|
||||
*/
|
||||
public function onMerge( $member, $member2 )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_database_revisions', array( 'revision_member_id' => $member->member_id ), array( 'revision_member_id=?', $member2->member_id ) );
|
||||
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( 'database_id', 'cms_databases' ) as $id )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_last_comment_by' => $member->member_id, 'record_last_comment_name' => $member->name ), array( 'record_last_comment_by=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_last_review_by' => $member->member_id, 'record_last_review_name' => $member->name ), array( 'record_last_review_by=?', $member2->member_id ) );
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_edit_member_id' => $member->member_id, 'record_edit_member_name' => $member->name ), array( 'record_edit_member_id=?', $member2->member_id ) );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
|
||||
|
||||
/* Update member fields in the db */
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_type=?', 'Member' ) ) as $field )
|
||||
{
|
||||
$where = array(
|
||||
\IPS\Db::i()->findInSet( 'field_' . $field['field_id'], array( $member2->member_id ) )
|
||||
);
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $field['field_database_id'], $where ) as $record )
|
||||
{
|
||||
$members = explode( ',', $record['field_' . $field['field_id'] ] );
|
||||
|
||||
foreach( $members as $k => $_member )
|
||||
{
|
||||
if( $_member == $member2->member_id )
|
||||
{
|
||||
$members[ $k ] = $member->member_id;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $field['field_database_id'], array( 'field_' . $field['field_id'] => implode( ',', $members ) ), array( 'primary_id_field=?', $record['primary_id_field'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Member is deleted
|
||||
*
|
||||
* @param $member \IPS\Member The member
|
||||
* @return void
|
||||
*/
|
||||
public function onDelete( $member )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_database_revisions', array( 'revision_member_id' => 0 ), array( 'revision_member_id=?', $member->member_id ) );
|
||||
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( 'database_id', 'cms_databases' ) as $id )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_last_comment_by' => 0 ), array( 'record_last_comment_by=?', $member->member_id ) );
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_last_review_by' => 0 ), array( 'record_last_review_by=?', $member->member_id ) );
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $id, array( 'record_edit_member_id' => 0 ), array( 'record_edit_member_id=?', $member->member_id ) );
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
|
||||
|
||||
/* Update member fields in the db */
|
||||
try
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_type=?', 'Member' ) ) as $field )
|
||||
{
|
||||
$where = array(
|
||||
\IPS\Db::i()->findInSet( 'field_' . $field['field_id'], array( $member->member_id ) )
|
||||
);
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $field['field_database_id'], $where ) as $record )
|
||||
{
|
||||
$members = explode( ',', $record['field_' . $field['field_id'] ] );
|
||||
|
||||
foreach( $members as $k => $_member )
|
||||
{
|
||||
if( $_member == $member->member_id )
|
||||
{
|
||||
unset( $members[ $k ] );
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'cms_custom_database_' . $field['field_database_id'], array( 'field_' . $field['field_id'] => implode( ',', $members ) ), array( 'primary_id_field=?', $record['primary_id_field'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -12,20 +12,27 @@
|
||||
namespace IPS\cms\extensions\core\ModeratorPermissions;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Application;
|
||||
use IPS\cms\Databases as DatabasesClass;
|
||||
use IPS\Extensions\ModeratorPermissionsAbstract;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moderator Permissions: Databases
|
||||
*/
|
||||
class _Databases
|
||||
class Databases extends ModeratorPermissionsAbstract
|
||||
{
|
||||
/**
|
||||
* Get Permissions
|
||||
*
|
||||
* @param array $toggles
|
||||
* @code
|
||||
return array(
|
||||
'key' => 'YesNo', // Can just return a string with type
|
||||
@@ -40,10 +47,10 @@ class _Databases
|
||||
* @endcode
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissions()
|
||||
public function getPermissions( array $toggles ): array
|
||||
{
|
||||
/* Preload words */
|
||||
\IPS\cms\Databases::databases();
|
||||
DatabasesClass::databases();
|
||||
|
||||
$return = array(
|
||||
'can_content_revisions_content' => 'YesNo',
|
||||
@@ -52,34 +59,11 @@ class _Databases
|
||||
'can_content_view_others_records' => "YesNo"
|
||||
);
|
||||
|
||||
if ( \IPS\Application::appIsEnabled('forums') )
|
||||
if ( Application::appIsEnabled('forums') )
|
||||
{
|
||||
$return['can_copy_topic_database'] = 'YesNo';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* After change
|
||||
*
|
||||
* @param array $moderator The moderator
|
||||
* @param array $changed Values that were changed
|
||||
* @return void
|
||||
*/
|
||||
public function onChange( $moderator, $changed )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* After delete
|
||||
*
|
||||
* @param array $moderator The moderator
|
||||
* @return void
|
||||
*/
|
||||
public function onDelete( $moderator )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,30 +12,34 @@
|
||||
namespace IPS\cms\extensions\core\OutputPlugins;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Extensions\OutputPluginsAbstract;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Content: Block
|
||||
*/
|
||||
class _Block
|
||||
class Block extends OutputPluginsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return string|array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string|array
|
||||
{
|
||||
return "\IPS\cms\Blocks\Block::display( \"$data\" )";
|
||||
}
|
||||
|
||||
@@ -12,35 +12,39 @@
|
||||
namespace IPS\cms\extensions\core\OutputPlugins;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Databases;
|
||||
use IPS\Extensions\OutputPluginsAbstract;
|
||||
use IPS\Member;
|
||||
use LogicException;
|
||||
use OutofRangeException;
|
||||
use function defined;
|
||||
use function is_numeric;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Content: Database
|
||||
*/
|
||||
class _Database
|
||||
class Database extends OutputPluginsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Record how many database tags there are per page
|
||||
*/
|
||||
public static $count = 0;
|
||||
public static int $count = 0;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return string|array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string|array
|
||||
{
|
||||
if ( isset( $options['category'] ) )
|
||||
{
|
||||
@@ -53,43 +57,41 @@ class _Database
|
||||
/**
|
||||
* Do any processing before a page is added/saved
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param object $page Page being edited/saved
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param object $page Page being edited/saved
|
||||
* @return void
|
||||
*/
|
||||
public static function preSaveProcess( $data, $options, $page )
|
||||
public static function preSaveProcess( string $data, array $options, object $page ) : void
|
||||
{
|
||||
/* Keep a count of databases used so far */
|
||||
static::$count++;
|
||||
|
||||
if ( static::$count > 1 )
|
||||
{
|
||||
throw new \LogicException( \IPS\Member::loggedIn()->language()->addToStack('cms_err_db_already_on_page') );
|
||||
throw new LogicException( Member::loggedIn()->language()->addToStack('cms_err_db_already_on_page') );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any processing after a page is added/saved
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param object $page Page being edited/saved
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @param object $page Page being edited/saved
|
||||
* @return void
|
||||
*/
|
||||
public static function postSaveProcess( $data, $options, $page )
|
||||
public static function postSaveProcess( string $data, array $options, object $page ) : void
|
||||
{
|
||||
$database = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
if ( \is_numeric( $data ) )
|
||||
if ( is_numeric( $data ) )
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $data );
|
||||
$database = Databases::load( $data );
|
||||
}
|
||||
else
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $data, 'database_key' );
|
||||
$database = Databases::load( $data, 'database_key' );
|
||||
}
|
||||
|
||||
if ( $database->id AND $page->id )
|
||||
@@ -98,13 +100,13 @@ class _Database
|
||||
{
|
||||
$page->mapToDatabase( $database->id );
|
||||
}
|
||||
catch( \LogicException $ex )
|
||||
catch( LogicException $ex )
|
||||
{
|
||||
throw new \LogicException( $ex->getMessage() );
|
||||
throw new LogicException( $ex->getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \OutofRangeException $ex ) { }
|
||||
catch( OutofRangeException $ex ) { }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,38 +12,45 @@
|
||||
namespace IPS\cms\extensions\core\OutputPlugins;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Media as MediaClass;
|
||||
use IPS\Extensions\OutputPluginsAbstract;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function is_numeric;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Content: Media
|
||||
*/
|
||||
class _Media
|
||||
class Media extends OutputPluginsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = TRUE;
|
||||
public static bool $canBeUsedInCss = TRUE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return string|array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string|array
|
||||
{
|
||||
if ( \is_numeric( $data ) )
|
||||
if ( is_numeric( $data ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$url = \IPS\cms\Media::load( $data )->url();
|
||||
$url = MediaClass::load( $data )->url();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
catch( OutOfRangeException $ex )
|
||||
{
|
||||
$url = NULL;
|
||||
}
|
||||
@@ -52,14 +59,14 @@ class _Media
|
||||
{
|
||||
try
|
||||
{
|
||||
$url = \IPS\cms\Media::load( $data, 'media_full_path' )->url();
|
||||
$url = MediaClass::load( $data, 'media_full_path' )->url();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
catch( OutOfRangeException $ex )
|
||||
{
|
||||
$url = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "'" . (string) $url . "'";
|
||||
return "'" . $url . "'";
|
||||
}
|
||||
}
|
||||
@@ -12,38 +12,46 @@
|
||||
namespace IPS\cms\extensions\core\OutputPlugins;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\Extensions\OutputPluginsAbstract;
|
||||
use IPS\Http\Url;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function is_numeric;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Content: Block
|
||||
*/
|
||||
class _Pageurl
|
||||
class Pageurl extends OutputPluginsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return string|array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string|array
|
||||
{
|
||||
if ( \is_numeric( $data ) )
|
||||
if ( is_numeric( $data ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$url = \IPS\cms\Pages\Page::load( $data )->url();
|
||||
$url = Page::load( $data )->url();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
catch( OutOfRangeException $ex )
|
||||
{
|
||||
$url = NULL;
|
||||
}
|
||||
@@ -51,9 +59,9 @@ class _Pageurl
|
||||
else
|
||||
{
|
||||
$data = ltrim( $data );
|
||||
$url = \IPS\Http\Url::internal( 'app=cms&module=pages&controller=page&path=' . $data, 'front', 'content_page_path', array( $data ) );
|
||||
$url = Url::internal( 'app=cms&module=pages&controller=page&path=' . $data, 'front', 'content_page_path', array( $data ) );
|
||||
}
|
||||
|
||||
return "'" . (string) $url . "'";
|
||||
return "'" . $url . "'";
|
||||
}
|
||||
}
|
||||
@@ -12,30 +12,34 @@
|
||||
namespace IPS\cms\extensions\core\OutputPlugins;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Extensions\OutputPluginsAbstract;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template Plugin - Content: Widget
|
||||
*/
|
||||
class _Widget
|
||||
class Widget extends OutputPluginsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Can be used when compiling CSS
|
||||
*/
|
||||
public static $canBeUsedInCss = FALSE;
|
||||
public static bool $canBeUsedInCss = FALSE;
|
||||
|
||||
/**
|
||||
* Run the plug-in
|
||||
*
|
||||
* @param string $data The initial data from the tag
|
||||
* @param array $options Array of options
|
||||
* @return string Code to eval
|
||||
* @return string|array Code to eval
|
||||
*/
|
||||
public static function runPlugin( $data, $options )
|
||||
public static function runPlugin( string $data, array $options ): string|array
|
||||
{
|
||||
$config = ( isset( $options['config'] ) ) ? $options['config'] : array();
|
||||
return "\IPS\Widget::load( \IPS\Application::load( '" . $options['app'] . "' ), '" . $data . "', '" . mt_rand() . "', " . $config . " );";
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Convert bbcode pages to html pages post-3.4 upgrade
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 22 Jul 2016
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Convert bbcode pages to html pages post-3.4 upgrade
|
||||
*/
|
||||
class _ConvertPages
|
||||
{
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_pages', array( 'page_type=?', 'bbcode' ) ) as $page )
|
||||
{
|
||||
$update = array(
|
||||
'page_content' => \IPS\Text\LegacyParser::parseStatic( $page['page_content'] ),
|
||||
'page_type' => 'html'
|
||||
);
|
||||
|
||||
\IPS\Db::i()->update( 'cms_pages', $update, array( 'page_id=?', $page['page_id'] ) );
|
||||
}
|
||||
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack( 'converting_pages_34x' ), 'complete' => 100 );
|
||||
}
|
||||
}
|
||||
@@ -12,26 +12,35 @@
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Member;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
use const IPS\REBUILD_NORMAL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task
|
||||
*/
|
||||
class _FixCommentAttachments
|
||||
class FixCommentAttachments extends QueueAbstract
|
||||
{
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
public function preQueueData( array $data ): ?array
|
||||
{
|
||||
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments_map', \IPS\Db::i()->like( 'location_key', 'cms_Records' ) )->first();
|
||||
$data['count'] = Db::i()->select( 'COUNT(*)', 'core_attachments_map', Db::i()->like( 'location_key', 'cms_Records' ) )->first();
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
@@ -49,11 +58,11 @@ class _FixCommentAttachments
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
public function run( array &$data, int $offset ): int
|
||||
{
|
||||
$completed = 0;
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_attachments_map', \IPS\Db::i()->like( 'location_key', 'cms_Records' ), 'attachment_id ASC', array( $offset, \IPS\REBUILD_NORMAL ) ) as $map )
|
||||
foreach( Db::i()->select( '*', 'core_attachments_map', Db::i()->like( 'location_key', 'cms_Records' ), 'attachment_id ASC', array( $offset, REBUILD_NORMAL ) ) as $map )
|
||||
{
|
||||
$completed++;
|
||||
|
||||
@@ -72,16 +81,16 @@ class _FixCommentAttachments
|
||||
/* Otherwise, we need to see if the attachment was used in a comment. If so, update the map, otherwise just continue - record maps didn't change. */
|
||||
try
|
||||
{
|
||||
$comment = \IPS\Db::i()->select( 'comment_post', 'cms_database_comments', array( 'comment_database_id=? AND comment_id=?', $map['id3'], $map['id2'] ) )->first();
|
||||
$comment = Db::i()->select( 'comment_post', 'cms_database_comments', array( 'comment_database_id=? AND comment_id=?', $map['id3'], $map['id2'] ) )->first();
|
||||
|
||||
/* We are looking for data-fileid="{attach_id}" */
|
||||
if( preg_match( "/data\-fileid=['\"]{$map['attachment_id']}[\"']/ims", $comment ) )
|
||||
{
|
||||
/* We found it - attachment is for the comment so update the map record */
|
||||
\IPS\Db::i()->update( 'core_attachments_map', array( 'id3' => $map['id3'] . '-comment' ), array( 'attachment_id=? AND location_key=? AND id1=? AND id2=?', $map['attachment_id'], $map['location_key'], $map['id1'], $map['id2'] ) );
|
||||
Db::i()->update( 'core_attachments_map', array( 'id3' => $map['id3'] . '-comment' ), array( 'attachment_id=? AND location_key=? AND id1=? AND id2=?', $map['attachment_id'], $map['location_key'], $map['id1'], $map['id2'] ) );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
catch( UnderflowException $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -101,10 +110,10 @@ class _FixCommentAttachments
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @throws OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
public function getProgress( mixed $data, int $offset ): array
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack( 'rebuilding_cms_comment_attachments' ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100 );
|
||||
return array( 'text' => Member::loggedIn()->language()->addToStack( 'rebuilding_cms_comment_attachments' ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -12,29 +12,48 @@
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Databases;
|
||||
use IPS\cms\Records;
|
||||
use IPS\cms\Records\Comment;
|
||||
use IPS\Content\Search\Index;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\forums\Topic;
|
||||
use IPS\forums\Topic\Post;
|
||||
use IPS\Log;
|
||||
use IPS\Member;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Task;
|
||||
use OutOfRangeException;
|
||||
use Throwable;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
use const IPS\REBUILD_SLOW;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task
|
||||
*/
|
||||
class _MoveComments
|
||||
class MoveComments extends QueueAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_SLOW;
|
||||
public int $rebuild = REBUILD_SLOW;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
public function preQueueData( array $data ): ?array
|
||||
{
|
||||
$data['done'] = 0;
|
||||
$data['lastId'] = 0;
|
||||
@@ -46,27 +65,27 @@ class _MoveComments
|
||||
case 'forums':
|
||||
if ( isset( $data['categoryId'] ) )
|
||||
{
|
||||
$where = array( \IPS\Db::i()->in( 'comment_record_id', iterator_to_array( \IPS\Db::i()->select( 'record_id', "cms_custom_database_{$data['databaseId']}", array( "category_id=?", $data['categoryId'] ) ) ) ) );
|
||||
$where = array( Db::i()->in( 'comment_record_id', iterator_to_array( Db::i()->select( 'record_id', "cms_custom_database_{$data['databaseId']}", array( "category_id=?", $data['categoryId'] ) ) ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = array( "comment_database_id=?", $data['databaseId'] );
|
||||
}
|
||||
|
||||
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'cms_database_comments', $where )->first();
|
||||
$data['count'] = Db::i()->select( 'COUNT(*)', 'cms_database_comments', $where )->first();
|
||||
break;
|
||||
|
||||
case 'pages':
|
||||
if ( isset( $data['categoryId'] ) )
|
||||
{
|
||||
$where = array( "new_topic=? AND " . \IPS\Db::i()->in( 'topic_id', iterator_to_array( \IPS\Db::i()->select( 'record_topicid', "cms_custom_database_{$data['databaseId']}", array( "category_id=?", $data['categoryId'] ) ) ) ), 0 );
|
||||
$where = array( "new_topic=? AND " . Db::i()->in( 'topic_id', iterator_to_array( Db::i()->select( 'record_topicid', "cms_custom_database_{$data['databaseId']}", array( "category_id=?", $data['categoryId'] ) ) ) ), 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = array( "new_topic=? AND " . \IPS\Db::i()->in( 'topic_id', iterator_to_array( \IPS\Db::i()->select( 'record_topicid', "cms_custom_database_{$data['databaseId']}" ) ) ), 0 );
|
||||
$where = array( "new_topic=? AND " . Db::i()->in( 'topic_id', iterator_to_array( Db::i()->select( 'record_topicid', "cms_custom_database_{$data['databaseId']}" ) ) ), 0 );
|
||||
}
|
||||
|
||||
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', $where )->first();
|
||||
$data['count'] = Db::i()->select( 'COUNT(*)', 'forums_posts', $where )->first();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,16 +95,16 @@ class _MoveComments
|
||||
/* But wait... if we're going from Pages to Forums, we still need to create the topics, so kick off that task instead. */
|
||||
if ( $data['to'] === 'forums' )
|
||||
{
|
||||
\IPS\Task::queue( 'cms', 'ResyncTopicContent', array( 'databaseId' => $data['databaseId'] ), 3, array( 'databaseId' ) );
|
||||
Task::queue( 'cms', 'ResyncTopicContent', array( 'databaseId' => $data['databaseId'] ), 3, array( 'databaseId' ) );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch( \Throwable $e )
|
||||
catch( Throwable $e )
|
||||
{
|
||||
/* Something went wrong - log it and return */
|
||||
\IPS\Log::log( $e, 'cms_move_comments' );
|
||||
Log::log( $e, 'cms_move_comments' );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -98,9 +117,9 @@ class _MoveComments
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @throws Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
public function run( mixed &$data, int $offset ): int
|
||||
{
|
||||
/* Okay let's figure out what we're doing. Separate these out to different methods since they can be a little complex. */
|
||||
switch( $data['to'] )
|
||||
@@ -120,7 +139,7 @@ class _MoveComments
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
throw new Task\Queue\OutOfRangeException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +149,12 @@ class _MoveComments
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @throws OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
public function getProgress( mixed $data, int $offset ): array
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $data['databaseId'] );
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack( 'moving_database_comments', FALSE, array( 'sprintf' => array( $database->_title ) ) ), 'complete' => $data['done'] ? ( round( 100 / $data['count'] * $data['done'], 2 ) ) : 0 );
|
||||
$database = Databases::load( $data['databaseId'] );
|
||||
return array( 'text' => Member::loggedIn()->language()->addToStack( 'moving_database_comments', FALSE, array( 'sprintf' => array( $database->_title ) ) ), 'complete' => $data['done'] ? ( round( 100 / $data['count'] * $data['done'], 2 ) ) : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,33 +164,34 @@ class _MoveComments
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
*/
|
||||
protected function _toForums( &$data, int $offset ): int
|
||||
protected function _toForums( mixed &$data, int $offset ): int
|
||||
{
|
||||
$done = 0;
|
||||
/* This is easy... kind of */
|
||||
$database = \IPS\cms\Databases::load( $data['databaseId'] );
|
||||
$database = Databases::load( $data['databaseId'] );
|
||||
$commentClass = '\IPS\cms\Records\Comment' . $database->_id;
|
||||
if ( isset( $data['categoryId'] ) )
|
||||
{
|
||||
$where = array( "comment_database_id=? AND comment_id>? AND " . \IPS\Db::i()->in( 'comment_record_id', iterator_to_array( \IPS\Db::i()->select( 'primary_id_field', "cms_custom_database_{$database->_id}", array( "category_id=?", $data['categoryId'] ) ) ) ), $database->_id, $data['lastId'] );
|
||||
$where = array( "comment_database_id=? AND comment_id>? AND " . Db::i()->in( 'comment_record_id', iterator_to_array( Db::i()->select( 'primary_id_field', "cms_custom_database_{$database->_id}", array( "category_id=?", $data['categoryId'] ) ) ) ), $database->_id, $data['lastId'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = array( "comment_database_id=? AND comment_id>?", $database->_id, $data['lastId'] );
|
||||
}
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_database_comments', $where, "comment_id ASC", $this->rebuild ), $commentClass ) AS $row )
|
||||
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'cms_database_comments', $where, "comment_id ASC", $this->rebuild ), $commentClass ) AS $row )
|
||||
{
|
||||
/* Check the record exists */
|
||||
try
|
||||
{
|
||||
/* @var Comment $row */
|
||||
$row->item();
|
||||
|
||||
/* Check the topic exists */
|
||||
try
|
||||
{
|
||||
\IPS\forums\Topic::load( $row->item()->record_topicid );
|
||||
Topic::load( $row->item()->record_topicid );
|
||||
}
|
||||
catch( \OutOfRangeException )
|
||||
catch( OutOfRangeException $e )
|
||||
{
|
||||
/* If the topic does not exist, reset the value so it can be re-created */
|
||||
$row->item()->record_topicid = 0;
|
||||
@@ -181,11 +201,11 @@ class _MoveComments
|
||||
/* First, create the topic if it doesn't already exist */
|
||||
if ( !$row->item()->record_topicid )
|
||||
{
|
||||
$row->item()->syncTopic( FALSE ); # Sync Topic will create it for us and link it, while also handling database and category level settings.
|
||||
$row->item()->syncTopic(); # Sync Topic will create it for us and link it, while also handling database and category level settings.
|
||||
}
|
||||
}
|
||||
// Exception may be that the item does not exist, or the category does not have syncing enabled
|
||||
catch( \UnderflowException | \OutOfRangeException $e )
|
||||
catch( UnderflowException | OutOfRangeException $e )
|
||||
{
|
||||
$data['lastId'] = $row->id;
|
||||
$data['done']++;
|
||||
@@ -208,7 +228,7 @@ class _MoveComments
|
||||
$queued = -1;
|
||||
}
|
||||
|
||||
$post = new \IPS\forums\Topic\Post;
|
||||
$post = new Post;
|
||||
$post->author_id = $row->user;
|
||||
$post->append_edit = $row->edit_show;
|
||||
$post->edit_time = $row->edit_date;
|
||||
@@ -223,9 +243,9 @@ class _MoveComments
|
||||
$post->save();
|
||||
|
||||
/* Update post before register */
|
||||
\IPS\Db::i()->update( 'core_post_before_registering', array( 'class' => "\IPS\forums\Topic\Post", 'id' => $post->id ), array( 'class=? and id=?', $commentClass, $row->id ) );
|
||||
Db::i()->update( 'core_post_before_registering', array( 'class' => "\IPS\forums\Topic\Post", 'id' => $post->id ), array( 'class=? and id=?', $commentClass, $row->id ) );
|
||||
|
||||
\IPS\Content\Search\Index::i()->index( $post );
|
||||
Index::i()->index( $post );
|
||||
|
||||
$data['lastId'] = $row->id;
|
||||
$data['done']++;
|
||||
@@ -234,9 +254,9 @@ class _MoveComments
|
||||
$row->delete();
|
||||
|
||||
/* Are we done? If so, sync the topic */
|
||||
if ( !(bool) \IPS\Db::i()->select( 'COUNT(*)', 'cms_database_comments', array( "comment_database_id=? AND comment_record_id=?", $database->_id, $row->item()->primary_id_field ) )->first() )
|
||||
if ( !(bool) Db::i()->select( 'COUNT(*)', 'cms_database_comments', array( "comment_database_id=? AND comment_record_id=?", $database->_id, $row->item()->primary_id_field ) )->first() )
|
||||
{
|
||||
$topic = \IPS\forums\Topic::load( $row->item()->record_topicid );
|
||||
$topic = Topic::load( $row->item()->record_topicid );
|
||||
$topic->resyncCommentCounts();
|
||||
$topic->save();
|
||||
|
||||
@@ -265,24 +285,25 @@ class _MoveComments
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
*/
|
||||
protected function _toPages( &$data, int $offset ): int
|
||||
protected function _toPages( mixed &$data, int $offset ): int
|
||||
{
|
||||
$done = 0;
|
||||
|
||||
/* This ones a little more complicated */
|
||||
$database = \IPS\cms\Databases::load( $data['databaseId'] );
|
||||
$database = Databases::load( $data['databaseId'] );
|
||||
$commentClass = '\IPS\cms\Records\Comment' . $database->_id;
|
||||
$recordClass = '\IPS\cms\Records' . $database->_id;
|
||||
if ( isset( $data['categoryId'] ) )
|
||||
{
|
||||
$subquery = iterator_to_array( \IPS\Db::i()->select( 'record_topicid', "cms_custom_database_{$database->_id}", array( "category_id=?", $data['categoryId'] ) ) );
|
||||
$subquery = iterator_to_array( Db::i()->select( 'record_topicid', "cms_custom_database_{$database->_id}", array( "category_id=?", $data['categoryId'] ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$subquery = iterator_to_array( \IPS\Db::i()->select( 'record_topicid', "cms_custom_database_{$database->_id}" ) );
|
||||
$subquery = iterator_to_array( Db::i()->select( 'record_topicid', "cms_custom_database_{$database->_id}" ) );
|
||||
}
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_posts', array( "pid>? AND new_topic=? AND " . \IPS\Db::i()->in( 'topic_id', $subquery ), $data['lastId'], 0 ), "pid ASC", $this->rebuild ), 'IPS\forums\Topic\Post' ) AS $row )
|
||||
foreach( new ActiveRecordIterator( Db::i()->select( '*', 'forums_posts', array( "pid>? AND new_topic=? AND " . Db::i()->in( 'topic_id', $subquery ), $data['lastId'], 0 ), "pid ASC", $this->rebuild ), 'IPS\forums\Topic\Post' ) AS $row )
|
||||
{
|
||||
/* @var Records $recordClass */
|
||||
$record = $recordClass::load( $row->topic_id, 'record_topicid' );
|
||||
|
||||
$approved = $row->queued;
|
||||
@@ -310,9 +331,9 @@ class _MoveComments
|
||||
$comment->save();
|
||||
|
||||
/* Update post before register */
|
||||
\IPS\Db::i()->update( 'core_post_before_registering', array( 'class' => $commentClass, 'id' => $comment->id ), array( 'class=? and id=?', "\IPS\forums\Topic\Post", $row->id ) );
|
||||
Db::i()->update( 'core_post_before_registering', array( 'class' => $commentClass, 'id' => $comment->id ), array( 'class=? and id=?', "\IPS\forums\Topic\Post", $row->id ) );
|
||||
|
||||
\IPS\Content\Search\Index::i()->index( $comment );
|
||||
Index::i()->index( $comment );
|
||||
|
||||
$row->delete();
|
||||
|
||||
@@ -321,9 +342,9 @@ class _MoveComments
|
||||
$done++;
|
||||
|
||||
/* If we're no longer keeping the topic, then delete it, but only if we're really done with it (ex, only the first post still exists). Otherwise, we still want the topic linked, we're just not using it for comments anymore. */
|
||||
if ( $data['deleteTopics'] AND (int) \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', array( "topic_id=?", $row->topic_id ) )->first() === 1 )
|
||||
if ( $data['deleteTopics'] AND (int) Db::i()->select( 'COUNT(*)', 'forums_posts', array( "topic_id=?", $row->topic_id ) )->first() === 1 )
|
||||
{
|
||||
\IPS\forums\Topic::load( $row->topic_id )->delete();
|
||||
Topic::load( $row->topic_id )->delete();
|
||||
$record->record_topicid = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 28 Aug 2019
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task
|
||||
*/
|
||||
class _MoveSingleRecord
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_SLOW;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
$data['done'] = 0;
|
||||
$data['lastId'] = 0;
|
||||
$recordClass = '\IPS\cms\Records' . $data['databaseId'];
|
||||
$record = $recordClass::load( $data['recordId'] );
|
||||
|
||||
if ( $data['to'] === 'forums' )
|
||||
{
|
||||
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'cms_database_comments', array( "comment_database_id=? AND comment_record_id=?", $data['databaseId'], $record->primary_id_field ) )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', array( "topic_id=? AND new_topic=0", $record->record_topicid ) )->first();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
$done = 0;
|
||||
$recordClass = '\IPS\cms\Records' . $data['databaseId'];
|
||||
$commentClass = '\IPS\cms\Records\Comment' . $data['databaseId'];
|
||||
$record = $recordClass::load( $data['recordId'] );
|
||||
$map = array(
|
||||
'user' => 'author_id',
|
||||
'date' => 'post_date',
|
||||
'ip_address' => 'ip_address',
|
||||
'post' => 'post',
|
||||
'approved' => 'queued',
|
||||
'author' => 'author_name',
|
||||
'edit_date' => 'edit_time',
|
||||
'edit_reason' => 'post_edit_reason',
|
||||
'edit_member_name' => 'edit_name',
|
||||
);
|
||||
|
||||
if ( $data['to'] === 'forums' )
|
||||
{
|
||||
$it = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_database_comments', array( "comment_id>? AND comment_database_id=? AND comment_record_id=?", $data['lastId'], $data['databaseId'], $data['recordId'] ), 'comment_id ASC', $this->rebuild ), $commentClass );
|
||||
}
|
||||
else
|
||||
{
|
||||
$it = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_posts', array( "pid>? AND new_topic=0 AND topic_id=?", $data['lastId'], $record->record_topicid ), 'pid ASC', $this->rebuild ), 'IPS\forums\Topic\Post' );
|
||||
$map = \array_flip( $map );
|
||||
}
|
||||
|
||||
foreach( $it AS $old )
|
||||
{
|
||||
if ( $data['to'] === 'forums' )
|
||||
{
|
||||
$new = new \IPS\forums\Topic\Post;
|
||||
$new->topic_id = $record->record_topicid;
|
||||
$newIdColumn = 'pid';
|
||||
$oldIdColumn = 'id';
|
||||
}
|
||||
else
|
||||
{
|
||||
$new = new $commentClass;
|
||||
$new->record_id = $data['recordId'];
|
||||
$newIdColumn = 'id';
|
||||
$oldIdColumn = 'pid';
|
||||
}
|
||||
|
||||
foreach( $map AS $k => $v )
|
||||
{
|
||||
switch( $k )
|
||||
{
|
||||
case 'approved':
|
||||
if ( $old->$k == 1 )
|
||||
{
|
||||
$new->$v = 0;
|
||||
}
|
||||
else if ( $old->$k == 0 )
|
||||
{
|
||||
$new->$v = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$new->$v = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'queued':
|
||||
if ( $old->$k == 0 )
|
||||
{
|
||||
$new->$v = 1;
|
||||
}
|
||||
elseif ( $old->$k == 1 )
|
||||
{
|
||||
$new->$v = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$new->$v = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$new->$v = $old->$k ?? '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$new->save();
|
||||
|
||||
\IPS\Content\Search\Index::i()->index( $new );
|
||||
|
||||
$old->delete();
|
||||
|
||||
$data['lastId'] = $old->$oldIdColumn;
|
||||
$data['done']++;
|
||||
$done++;
|
||||
}
|
||||
|
||||
$record->syncRecordFromTopic( $record->topic( FALSE ) );
|
||||
|
||||
if ( !$done )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
$recordClass = '\IPS\cms\Records' . $data['databaseId'];
|
||||
$record = $recordClass::load( $data['recordId'] );
|
||||
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack( 'moving_database_comments_single', FALSE, array( 'sprintf' => array( $record->url(), $record->mapped('title') ) ) ), 'complete' => 100 / $data['count'] * $data['done'] );
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Rebuild database categories
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 13 Jun 2014
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild database categories
|
||||
*/
|
||||
class _RebuildCategories
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_NORMAL;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 18 );
|
||||
|
||||
\IPS\Log::debug( "Getting preQueueData for " . $classname, 'rebuildCategories' );
|
||||
|
||||
try
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_database_categories' )->first();
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 18 );
|
||||
|
||||
$class = '\IPS\cms\Categories' . $databaseId;
|
||||
$parsed = 0;
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_database_categories', array( 'category_database_id=?', $databaseId ), 'category_id asc', array( $offset, $this->rebuild ) ) as $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
$cat = $class::constructFromData( $row );
|
||||
$cat->setLastComment();
|
||||
$cat->setLastReview();
|
||||
$cat->save();
|
||||
|
||||
$parsed++;
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
if( $parsed !== $this->rebuild )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return ( $offset + $this->rebuild );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 18 );
|
||||
|
||||
$title = ( \IPS\Application::appIsEnabled('cms') ) ? \IPS\cms\Databases::load( $databaseId )->_title : 'Database #' . $databaseId;
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack( 'rebuilding_cms_database_categories', FALSE, array( 'sprintf' => array( $title ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Rebuild comment likes
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 16 Feb 2016
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild comment likes
|
||||
*/
|
||||
class _RebuildCommentLikes
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_QUICK;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
try
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'core_reputation_index', array( 'app=? AND type=?', 'cms', 'id' ) )->first();
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_reputation_index', array( '`app`=? AND `type`=?', 'cms', 'id' ), 'type_id ASC', array( 0, $this->rebuild ) ) as $item )
|
||||
{
|
||||
$count++;
|
||||
|
||||
try
|
||||
{
|
||||
$databaseId = \IPS\Db::i()->select( 'comment_database_id', 'cms_database_comments', array( 'comment_id=?', \intval( $item['id'] ) ) )->first();
|
||||
|
||||
\IPS\Db::i()->update( 'core_reputation_index', array( 'type' => 'comment_id_' . $databaseId ), array( 'id=?', $item['id'] ) );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* Comment no longer exists */
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( '`app`=? and `type`=? and `id`=?', 'cms', 'id', $item['id'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( !$count )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return ( $offset + $count );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_comment_likes'), 'complete' => round( 100 / $data['count'] * $offset, 2 ) );
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Rebuild database editor fields
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 27 March 2015
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild database editor fields
|
||||
*/
|
||||
class _RebuildEditorFields
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_SLOW;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
$fieldId = $data['fieldId'];
|
||||
|
||||
try
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'MAX(primary_id_field)', 'cms_custom_database_' . $databaseId )->first();
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$data['completed'] = 0;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
$fieldId = $data['fieldId'];
|
||||
|
||||
$parsed = 0;
|
||||
$class = '\IPS\cms\Records' . $databaseId;
|
||||
$last = NULL;
|
||||
|
||||
if ( \IPS\Db::i()->checkForTable( 'cms_custom_database_' . $databaseId ) AND \IPS\Db::i()->checkForColumn( 'cms_custom_database_' . $databaseId, 'field_' . $fieldId ) )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, array( 'primary_id_field > ?', $offset ), 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
{
|
||||
$item = $class::constructFromData( $row );
|
||||
$contentColumn = 'field_' . $fieldId;
|
||||
|
||||
$member = \IPS\Member::load( $item->mapped('author') );
|
||||
$extensions = \IPS\Application::load( $classname::$application )->extensions( 'core', 'EditorLocations' );
|
||||
$idColumn = $classname::$databaseColumnId;
|
||||
|
||||
if( isset( $classname::$itemClass ) )
|
||||
{
|
||||
$itemClass = $classname::$itemClass;
|
||||
$module = mb_ucfirst( $itemClass::$module );
|
||||
}
|
||||
else
|
||||
{
|
||||
$module = mb_ucfirst( $classname::$module );
|
||||
}
|
||||
|
||||
$extension = NULL;
|
||||
|
||||
if ( isset( $extensions[ $module ] ) )
|
||||
{
|
||||
$extension = $extensions[ $module ];
|
||||
}
|
||||
|
||||
$canUseHtml = (bool) $member->group['g_dohtml'];
|
||||
|
||||
if ( $extension )
|
||||
{
|
||||
$extensionCanUseHtml = $extension->canUseHtml( $member );
|
||||
if ( $extensionCanUseHtml !== NULL )
|
||||
{
|
||||
$canUseHtml = $extensionCanUseHtml;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$item->$contentColumn = \IPS\Text\LegacyParser::parseStatic( $item->$contentColumn, $member, $canUseHtml, 'cms_Records', $item->$idColumn, $data['fieldId'], $databaseId, isset( $classname::$itemClass ) ? $classname::$itemClass : \get_class( $item ) );
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
{
|
||||
if( $e->getcode() == 103014 )
|
||||
{
|
||||
$item->$contentColumn = preg_replace( "#\[/?([^\]]+?)\]#", '', $item->$contentColumn );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$item->save();
|
||||
|
||||
$last = $item->$idColumn;
|
||||
$data['completed']++;
|
||||
}
|
||||
}
|
||||
|
||||
if( $last === NULL )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_cms_database_records', FALSE, array( 'sprintf' => array( \IPS\cms\Databases::load( $databaseId )->_title ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -12,40 +12,51 @@
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\cms\Databases;
|
||||
use IPS\cms\Fields;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Member;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use const IPS\REBUILD_QUICK;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild database reciprocal maps
|
||||
*/
|
||||
class _RebuildReciprocalMaps
|
||||
class RebuildReciprocalMaps extends QueueAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_QUICK;
|
||||
public int $rebuild = REBUILD_QUICK;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
public function preQueueData( array $data ): ?array
|
||||
{
|
||||
$databaseId = $data['database'];
|
||||
$fieldId = $data['field'];
|
||||
|
||||
try
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $databaseId, array( 'field_' . $fieldId . ' != \'\' or field_' . $fieldId . ' IS NOT NULL' ) )->first();
|
||||
$data['count'] = (int) Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $databaseId, array( 'field_' . $fieldId . ' != \'\' or field_' . $fieldId . ' IS NOT NULL' ) )->first();
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
catch( Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
@@ -57,26 +68,27 @@ class _RebuildReciprocalMaps
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int|null New offset or NULL if complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset or NULL if complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
public function run( mixed &$data, int $offset ): int
|
||||
{
|
||||
$databaseId = $data['database'];
|
||||
$fieldId = $data['field'];
|
||||
$last = NULL;
|
||||
|
||||
if ( \IPS\Db::i()->checkForTable( 'cms_custom_database_' . $databaseId ) )
|
||||
if ( Db::i()->checkForTable( 'cms_custom_database_' . $databaseId ) )
|
||||
{
|
||||
/* @var Fields $fieldsClass */
|
||||
$fieldsClass = 'IPS\cms\Fields' . $databaseId;
|
||||
$field = $fieldsClass::load( $fieldId );
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, array( 'primary_id_field > ? AND (field_' . $fieldId . ' != \'\' or field_' . $fieldId . ' IS NOT NULL)', $offset ), 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
foreach ( Db::i()->select( '*', 'cms_custom_database_' . $databaseId, array( 'primary_id_field > ? AND (field_' . $fieldId . ' != \'\' or field_' . $fieldId . ' IS NOT NULL)', $offset ), 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
{
|
||||
$extra = $field->extra;
|
||||
if ( $row[ 'field_' . $fieldId ] and ! empty( $extra['database'] ) )
|
||||
@@ -85,7 +97,7 @@ class _RebuildReciprocalMaps
|
||||
{
|
||||
if ( $foreignId )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'cms_database_fields_reciprocal_map', array(
|
||||
Db::i()->insert( 'cms_database_fields_reciprocal_map', array(
|
||||
'map_origin_database_id' => $databaseId,
|
||||
'map_foreign_database_id' => $extra['database'],
|
||||
'map_origin_item_id' => $row['primary_id_field'],
|
||||
@@ -115,11 +127,11 @@ class _RebuildReciprocalMaps
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @throws OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
public function getProgress( mixed $data, int $offset ): array
|
||||
{
|
||||
$databaseId = $data['database'];
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_cms_database_reciprocal_map', FALSE, array( 'sprintf' => array( \IPS\cms\Databases::load( $databaseId )->_title, $data['field'] ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
return array( 'text' => Member::loggedIn()->language()->addToStack('rebuilding_cms_database_reciprocal_map', FALSE, array( 'sprintf' => array( Databases::load( $databaseId )->_title, $data['field'] ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Rebuild database records
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Content
|
||||
* @since 13 Jun 2014
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild database records
|
||||
*/
|
||||
class _RebuildRecords
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_SLOW;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
|
||||
\IPS\Log::debug( "Getting preQueueData for " . $classname, 'rebuildRecords' );
|
||||
|
||||
try
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $databaseId )->first();
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$data['completed'] = 0;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
$last = NULL;
|
||||
|
||||
/* Make sure there's even content to parse */
|
||||
if( !class_exists( $classname ) or !isset( $classname::$databaseColumnMap['content'] ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
$fixImage = isset( $data['fixImage'] ) ? (boolean) $data['fixImage'] : TRUE;
|
||||
$fixHtml = isset( $data['fixHtml'] ) ? (boolean) $data['fixHtml'] : FALSE;
|
||||
$fixFurls = isset( $data['fixFurls']) ? (boolean) $data['fixFurls'] : FALSE;
|
||||
$class = '\IPS\cms\Records' . $databaseId;
|
||||
|
||||
if ( \IPS\Db::i()->checkForTable( 'cms_custom_database_' . $databaseId ) )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, array( 'primary_id_field > ?', $offset ), 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
{
|
||||
$record = $class::constructFromData( $row );
|
||||
$record->resetLastComment();
|
||||
$save = FALSE;
|
||||
|
||||
if ( $fixImage )
|
||||
{
|
||||
if ( $record->record_image and file_exists( \IPS\ROOT_PATH . '/uploads/' . $record->record_image ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$record->record_image = (string) \IPS\File::create( 'cms_Records', $record->record_image, file_get_contents( \IPS\ROOT_PATH . '/uploads/' . $record->record_image ) );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$record->record_image = NULL;
|
||||
}
|
||||
$save = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $record->record_publish_date )
|
||||
{
|
||||
$record->record_publish_date = $record->record_saved;
|
||||
$save = TRUE;
|
||||
}
|
||||
|
||||
if ( $fixFurls and preg_match( '#%([\d\w]{2})#', $record->record_static_furl ) )
|
||||
{
|
||||
$record->record_static_furl = urldecode( $record->record_static_furl );
|
||||
$save = TRUE;
|
||||
}
|
||||
|
||||
if ( $save )
|
||||
{
|
||||
$record->save();
|
||||
}
|
||||
|
||||
if ( $fixHtml )
|
||||
{
|
||||
$fields = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_database_id=? AND field_type=? AND field_html=1', $databaseId, 'Editor' ) ) );
|
||||
|
||||
if ( \count( $fields ) )
|
||||
{
|
||||
foreach( $fields as $field )
|
||||
{
|
||||
$column = 'field_' . $field['field_id'];
|
||||
|
||||
if ( $record->member_id and $record->$column )
|
||||
{
|
||||
try
|
||||
{
|
||||
$author = \IPS\Member::load( $record->member_id );
|
||||
|
||||
/* In 3.x this would have been shown as HTML */
|
||||
if ( $author->group['g_dohtml'] )
|
||||
{
|
||||
/* This code is copied from IPB3 to ensure it is compatible with data saved */
|
||||
$record->$column = str_replace( "'" , "'", $record->$column );
|
||||
$record->$column = str_replace( "!" , "!", $record->$column );
|
||||
$record->$column = str_replace( "$", "$", $record->$column );
|
||||
$record->$column = str_replace( "|", "|", $record->$column );
|
||||
$record->$column = str_replace( "&" , "&", $record->$column );
|
||||
$record->$column = str_replace( ">" , ">", $record->$column );
|
||||
$record->$column = str_replace( "<" , "<", $record->$column );
|
||||
$record->$column = str_replace( "<" , "<", $record->$column );
|
||||
$record->$column = str_replace( ">" , ">", $record->$column );
|
||||
$record->$column = str_replace( """, '"', $record->$column );
|
||||
$record->$column = str_replace( '"', '"', $record->$column );
|
||||
$record->$column = str_replace( '<', '<', $record->$column );
|
||||
$record->$column = str_replace( '>', '>', $record->$column );
|
||||
|
||||
$record->save();
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['completed']++;
|
||||
$last = $record->primary_id_field;
|
||||
}
|
||||
}
|
||||
|
||||
if( $last === NULL )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
$classname = $data['class'];
|
||||
$databaseId = mb_substr( $classname, 15 );
|
||||
|
||||
$title = ( \IPS\Application::appIsEnabled('cms') ) ? \IPS\cms\Databases::load( $databaseId )->_title : 'Database #' . $databaseId;
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_cms_database_records', FALSE, array( 'sprintf' => array( $title ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -12,45 +12,58 @@
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\cms\Databases;
|
||||
use IPS\cms\Records;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Member;
|
||||
use OutOfRangeException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use const IPS\REBUILD_NORMAL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild database records
|
||||
*/
|
||||
class _ResyncTopicContent
|
||||
class ResyncTopicContent extends QueueAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Number of content items to rebuild per cycle
|
||||
*/
|
||||
public $rebuild = \IPS\REBUILD_NORMAL;
|
||||
public int $rebuild = REBUILD_NORMAL;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
public function preQueueData( array $data ): ?array
|
||||
{
|
||||
try
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $data['databaseId'] );
|
||||
$database = Databases::load( $data['databaseId'] );
|
||||
|
||||
if ( $database->forum_record )
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $data['databaseId'] )->first();
|
||||
$data['count'] = (int) Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $data['databaseId'] )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$cats = iterator_to_array( \IPS\Db::i()->select( 'category_id', 'cms_database_categories', array( 'category_forum_record=1 AND category_database_id=?', $data['databaseId'] ) ) );
|
||||
$cats = iterator_to_array( Db::i()->select( 'category_id', 'cms_database_categories', array( 'category_forum_record=1 AND category_database_id=?', $data['databaseId'] ) ) );
|
||||
|
||||
if ( \count( $cats ) )
|
||||
if ( count( $cats ) )
|
||||
{
|
||||
$data['count'] = (int) \IPS\Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $data['databaseId'], array( \IPS\Db::i()->in( 'category_id', $cats ) ) )->first();
|
||||
$data['count'] = (int) Db::i()->select( 'COUNT(*)', 'cms_custom_database_' . $data['databaseId'], array( Db::i()->in( 'category_id', $cats ) ) )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -58,9 +71,9 @@ class _ResyncTopicContent
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $ex )
|
||||
catch( Exception $ex )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
@@ -81,37 +94,38 @@ class _ResyncTopicContent
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
public function run( mixed &$data, int $offset ): int
|
||||
{
|
||||
/* @var Records $class */
|
||||
$class = '\IPS\cms\Records' . $data['databaseId'];
|
||||
$where = array( 'primary_id_field>?', $offset );
|
||||
$last = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $data['databaseId'] );
|
||||
$database = Databases::load( $data['databaseId'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
if ( ! $database->forum_record )
|
||||
{
|
||||
$cats = iterator_to_array( \IPS\Db::i()->select( 'category_id', 'cms_database_categories', array( 'category_forum_record=1 AND category_database_id=?', $data['databaseId'] ) ) );
|
||||
$where[] = array( \IPS\Db::i()->in( 'category_id', $cats ) );
|
||||
$cats = iterator_to_array( Db::i()->select( 'category_id', 'cms_database_categories', array( 'category_forum_record=1 AND category_database_id=?', $data['databaseId'] ) ) );
|
||||
$where[] = array( Db::i()->in( 'category_id', $cats ) );
|
||||
}
|
||||
|
||||
if ( \IPS\Db::i()->checkForTable( 'cms_custom_database_' . $data['databaseId'] ) )
|
||||
if ( Db::i()->checkForTable( 'cms_custom_database_' . $data['databaseId'] ) )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $data['databaseId'], $where, 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
foreach ( Db::i()->select( '*', 'cms_custom_database_' . $data['databaseId'], $where, 'primary_id_field asc', array( 0, $this->rebuild ) ) as $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
$record = $class::constructFromData( $row );
|
||||
$record->syncTopic();
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
catch( Exception $ex ) { }
|
||||
|
||||
$data['completed']++;
|
||||
$last = $row['primary_id_field'];
|
||||
@@ -132,11 +146,11 @@ class _ResyncTopicContent
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
* @throws OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
public function getProgress( mixed $data, int $offset ): array
|
||||
{
|
||||
$title = ( \IPS\Application::appIsEnabled('cms') ) ? \IPS\cms\Databases::load( $data['databaseId'] )->_title : 'Database #' . $data['databaseId'];
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_cms_database_sync_topics', FALSE, array( 'sprintf' => array( $title ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
$title = ( Application::appIsEnabled('cms') ) ? Databases::load( $data['databaseId'] )->_title : 'Database #' . $data['databaseId'];
|
||||
return array( 'text' => Member::loggedIn()->language()->addToStack('rebuilding_cms_database_sync_topics', FALSE, array( 'sprintf' => array( $title ) ) ), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 18 Dec 2023
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\Queue;
|
||||
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Lang;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Task\Queue\OutOfRangeException as QueueOutOfRangeException;
|
||||
use IPS\Widget\Area;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use const IPS\REBUILD_SLOW;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task
|
||||
*/
|
||||
class UpdateHtmlPages extends QueueAbstract
|
||||
{
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array|null
|
||||
*/
|
||||
public function preQueueData( array $data ): ?array
|
||||
{
|
||||
$data['count'] = (int) Db::i()->select( 'count(page_id)', 'cms_pages' )->first();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param array $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws QueueOutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( array &$data, int $offset ): int
|
||||
{
|
||||
$limit = REBUILD_SLOW;
|
||||
$rows = iterator_to_array(
|
||||
new ActiveRecordIterator(
|
||||
Db::i()->select( '*', 'cms_pages', null, 'page_id', array( $offset, $limit ) ),
|
||||
Page::class
|
||||
)
|
||||
);
|
||||
|
||||
$lang = Lang::load( Lang::defaultLanguage() );
|
||||
foreach( $rows as $row )
|
||||
{
|
||||
/* Builder pages need minor adjustment */
|
||||
if( $row->type == 'builder' )
|
||||
{
|
||||
$row->ipb_wrapper = true;
|
||||
$row->show_sidebar = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Convert the page to a builder page with a single column */
|
||||
$area = Area::create( 'col1', [
|
||||
[
|
||||
'title' => $lang->addToStack( 'block_Codemirror' ),
|
||||
'config' => true,
|
||||
'blank' => false,
|
||||
'app' => 'cms',
|
||||
'key' => 'Codemirror',
|
||||
'unique' => mt_rand(),
|
||||
'configuration' => [
|
||||
'content' => $row->content
|
||||
]
|
||||
]
|
||||
], [ 'wrapBehavior' => 'stack' ] );
|
||||
$row->saveArea( $area );
|
||||
|
||||
$row->type = 'builder';
|
||||
$row->content = null;
|
||||
|
||||
if( $row->wrapper_template === null or $row->wrapper_template == '__none__')
|
||||
{
|
||||
$row->ipb_wrapper = true;
|
||||
$row->show_sidebar = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( $row->template == 'page_builder__single_column__page_page_builder_single_column' or $row->template == 'page_builder__single_column__page_builder_single_column' )
|
||||
{
|
||||
$row->template = null;
|
||||
}
|
||||
|
||||
$row->save();
|
||||
}
|
||||
|
||||
$offset += $limit;
|
||||
if( $offset >= $data['count'] )
|
||||
{
|
||||
throw new QueueOutOfRangeException;
|
||||
}
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param array $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( array $data, int $offset ): array
|
||||
{
|
||||
return array(
|
||||
'text' => 'Converting HTML Pages to Builder',
|
||||
'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,31 +12,46 @@
|
||||
namespace IPS\cms\extensions\core\RssImport;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\cms\Databases;
|
||||
use IPS\cms\Fields;
|
||||
use IPS\Content;
|
||||
use IPS\core\Rss\Import;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\RssImportAbstract;
|
||||
use IPS\File;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Http\Response;
|
||||
use IPS\Image;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Model;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function is_array;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RSS Import extension: RssImport
|
||||
*/
|
||||
class _RssImport
|
||||
class RssImport extends RssImportAbstract
|
||||
{
|
||||
/**
|
||||
* @brief RSSImport Classes
|
||||
*/
|
||||
public $classes = array();
|
||||
|
||||
/**
|
||||
* @brief Filestorage class
|
||||
*/
|
||||
public $fileStorage = 'cms_Records';
|
||||
public string $fileStorage = 'cms_Records';
|
||||
|
||||
/**
|
||||
* @brief Encosure images to process
|
||||
* @brief Enclosure images to process
|
||||
*/
|
||||
public static $enclosures = array();
|
||||
public static array $enclosures = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -47,7 +62,7 @@ class _RssImport
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\cms\Databases::databases() as $id => $database )
|
||||
foreach ( Databases::databases() as $id => $database )
|
||||
{
|
||||
if ( $database->canImportRss() )
|
||||
{
|
||||
@@ -55,7 +70,7 @@ class _RssImport
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -63,10 +78,9 @@ class _RssImport
|
||||
/**
|
||||
* Show in the Admin CP?
|
||||
*
|
||||
* @param Object $class The class to check
|
||||
* @return boolean
|
||||
*/
|
||||
public function showInAdminCp( $class ): bool
|
||||
public function showInAdminCp(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -76,12 +90,12 @@ class _RssImport
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function availableOptions()
|
||||
public function availableOptions(): array
|
||||
{
|
||||
$options = array();
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\cms\Databases::databases() as $id => $database )
|
||||
foreach ( Databases::databases() as $id => $database )
|
||||
{
|
||||
if ( $database->canImportRss() )
|
||||
{
|
||||
@@ -89,7 +103,7 @@ class _RssImport
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
} // If you have not upgraded pages but it is installed, this throws an error
|
||||
|
||||
@@ -99,10 +113,10 @@ class _RssImport
|
||||
/**
|
||||
* Node selector options
|
||||
*
|
||||
* @param \IPS\core\Rss\Import|null $rss Existing RSS object if editing|NULL if not
|
||||
* @param Import|null $rss Existing RSS object if editing|null if not
|
||||
* @return array
|
||||
*/
|
||||
public function nodeSelectorOptions( $rss )
|
||||
public function nodeSelectorOptions( ?Import $rss ): array
|
||||
{
|
||||
/* Get the correct class */
|
||||
$class = $rss->_class;
|
||||
@@ -112,17 +126,19 @@ class _RssImport
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \IPS\core\Rss\Import $rss RSS object
|
||||
* @param Import $rss RSS object
|
||||
* @param array $article RSS feed article importing
|
||||
* @param \IPS\Node\Model $container Container object
|
||||
* @param Model $container Container object
|
||||
* @param string $content Post content with read more link if set
|
||||
* @return \IPS\Content
|
||||
* @return Content|null
|
||||
*/
|
||||
public function create( \IPS\core\Rss\Import $rss, $article, \IPS\Node\Model $container, $content )
|
||||
public function create( Import $rss, array $article, Model $container, string $content ): ?Content
|
||||
{
|
||||
$settings = $rss->settings;
|
||||
$recordClass = $rss->_class;
|
||||
$member = \IPS\Member::load( $rss->member );
|
||||
$member = Member::load( $rss->member );
|
||||
|
||||
/* @var Fields $fieldsClass */
|
||||
$fieldsClass = '\IPS\cms\Fields' . $recordClass::database()->id;
|
||||
$customFields = $fieldsClass::fields( $settings, 'add' );
|
||||
$fieldData = $fieldsClass::data();
|
||||
@@ -196,7 +212,7 @@ class _RssImport
|
||||
}
|
||||
else if ( isset( $article['attachment'] ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_attachments_map', array(
|
||||
Db::i()->insert( 'core_attachments_map', array(
|
||||
'attachment_id' => $article['attachment']['attach_id'],
|
||||
'location_key' => 'cms_Records' . $recordClass::database()->id,
|
||||
'id1' => $record->primary_id_field,
|
||||
@@ -214,7 +230,7 @@ class _RssImport
|
||||
|
||||
return $record;
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -223,16 +239,15 @@ class _RssImport
|
||||
/**
|
||||
* Process the enclosure
|
||||
*
|
||||
* @param \IPS\core\Rss\Import $rss
|
||||
* @param \IPS\Http $response
|
||||
* @param Import $rss
|
||||
* @param Response $response
|
||||
* @param array $article
|
||||
* @return bool
|
||||
*/
|
||||
public function processEnclosure( \IPS\core\Rss\Import $rss, \IPS\Http\Response $response, $article )
|
||||
public function processEnclosure( Import $rss, Response $response, array $article ): bool
|
||||
{
|
||||
$settings = $rss->settings;
|
||||
$recordClass = $rss->_class;
|
||||
$fieldsClass = '\IPS\cms\Fields' . $recordClass::database()->id;
|
||||
|
||||
if ( empty( $settings['record_image'] ) )
|
||||
{
|
||||
@@ -241,7 +256,7 @@ class _RssImport
|
||||
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $response );
|
||||
$image = Image::create( $response );
|
||||
$fixedFieldSettings = $recordClass::database()->fixed_field_settings;
|
||||
|
||||
$dims = NULL;
|
||||
@@ -255,11 +270,11 @@ class _RssImport
|
||||
$image->resizeToMax( $fixedFieldSettings['record_image']['image_dims'][0], $fixedFieldSettings['record_image']['image_dims'][1] );
|
||||
}
|
||||
|
||||
static::$enclosures[ $article['guid'] ] = \IPS\File::create( $this->fileStorage, 'rssImage-' . $article['guid'] . '.' . $image->type, (string)$image );
|
||||
static::$enclosures[ $article['guid'] ] = File::create( $this->fileStorage, 'rssImage-' . $article['guid'] . '.' . $image->type, (string)$image );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -268,27 +283,29 @@ class _RssImport
|
||||
/**
|
||||
* Addition Form elements
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param \IPS\core\Rss\Import $rss Existing RSS object
|
||||
* @param Form $form The form
|
||||
* @param Import|null $rss Existing RSS object
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form, \IPS\core\Rss\Import $rss )
|
||||
public function form( Form $form, ?Import $rss=null ) : void
|
||||
{
|
||||
$settings = $rss->settings;
|
||||
$recordClass = $rss->_class;
|
||||
$nodeClass = $recordClass::$containerNodeClass;
|
||||
|
||||
/* @var Fields $fieldsClass */
|
||||
$fieldsClass = '\IPS\cms\Fields' . $recordClass::database()->id;
|
||||
$customFields = $fieldsClass::fields( $settings, 'add', $rss->node_id ? $nodeClass::load( $rss->node_id ) : NULL );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_record_open', ( $settings ? $settings['record_open'] : 1 ), FALSE, array( 'options' => array( 1 => 'unlocked', 0 => 'locked' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_record_hide', ( $settings ? $settings['record_hide'] : 0 ), FALSE, array( 'options' => array( 0 => 'unhidden', 1 => 'hidden' ) ) ) );
|
||||
$form->add( new Radio( 'rss_import_record_open', ( $settings ? $settings['record_open'] : 1 ), FALSE, array( 'options' => array( 1 => 'unlocked', 0 => 'locked' ) ) ) );
|
||||
$form->add( new Radio( 'rss_import_record_hide', ( $settings ? $settings['record_hide'] : 0 ), FALSE, array( 'options' => array( 0 => 'unhidden', 1 => 'hidden' ) ) ) );
|
||||
|
||||
if ( $rss->has_enclosures and $fieldsClass::fixedFieldFormShow( 'record_image' ) )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_record_image', ( $settings ? $settings['record_image'] : 1 ), FALSE, array( 'options' => array( 1 => 'rss_import_record_image_header', 0 => 'rss_import_record_image_inline' ) ) ) );
|
||||
$form->add( new Radio( 'rss_import_record_image', ( $settings ? $settings['record_image'] : 1 ), FALSE, array( 'options' => array( 1 => 'rss_import_record_image_header', 0 => 'rss_import_record_image_inline' ) ) ) );
|
||||
}
|
||||
|
||||
if ( \count( $customFields ) )
|
||||
if ( count( $customFields ) )
|
||||
{
|
||||
$fields = array();
|
||||
foreach( $customFields as $id => $field )
|
||||
@@ -301,10 +318,10 @@ class _RssImport
|
||||
$fields[] = $field;
|
||||
}
|
||||
|
||||
if ( \count( $fields ) )
|
||||
if ( count( $fields ) )
|
||||
{
|
||||
$form->addHeader('rss_import_cms_defaults');
|
||||
$form->addMessage('rss_import_cms_defaults_desc', 'ipsType_light');
|
||||
$form->addMessage('rss_import_cms_defaults_desc', 'i-color_soft');
|
||||
|
||||
foreach( $fields as $f )
|
||||
{
|
||||
@@ -317,11 +334,11 @@ class _RssImport
|
||||
/**
|
||||
* Process additional fields unique to this extension
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @param \IPS\core\Rss\Import $rss Existing RSS object
|
||||
* @param array $values Values from form
|
||||
* @param Import $rss Existing RSS object
|
||||
* @return array
|
||||
*/
|
||||
public function saveForm( &$values, $rss )
|
||||
public function saveForm( array &$values, Import $rss ): array
|
||||
{
|
||||
$return = array(
|
||||
'record_open' => $values['rss_import_record_open'],
|
||||
@@ -350,7 +367,8 @@ class _RssImport
|
||||
}
|
||||
}
|
||||
|
||||
$customFields = $fieldsClass::fields( $customValues, 'add', NULL );
|
||||
/* @var Fields $fieldsClass */
|
||||
$customFields = $fieldsClass::fields( $customValues, 'add' );
|
||||
|
||||
foreach( $customFields as $key => $field )
|
||||
{
|
||||
@@ -361,9 +379,9 @@ class _RssImport
|
||||
|
||||
$key = 'field_' . $key;
|
||||
|
||||
if ( isset( $customValues[ $field->name ] ) and \get_class( $field ) == 'IPS\Helpers\Form\Upload' )
|
||||
if ( isset( $customValues[ $field->name ] ) and get_class( $field ) == 'IPS\Helpers\Form\Upload' )
|
||||
{
|
||||
if ( \is_array( $customValues[ $field->name ] ) )
|
||||
if ( is_array( $customValues[ $field->name ] ) )
|
||||
{
|
||||
$items = array();
|
||||
foreach( $customValues[ $field->name ] as $obj )
|
||||
@@ -378,13 +396,13 @@ class _RssImport
|
||||
}
|
||||
}
|
||||
/* If we're using decimals, then the database field is set to DECIMALS, so we cannot using stringValue() */
|
||||
else if ( isset( $customValues[ $field->name ] ) and \get_class( $field ) == 'IPS\Helpers\Form\Number' and ( isset( $field->options['decimals'] ) and $field->options['decimals'] > 0 ) )
|
||||
else if ( isset( $customValues[ $field->name ] ) and get_class( $field ) == 'IPS\Helpers\Form\Number' and ( isset( $field->options['decimals'] ) and $field->options['decimals'] > 0 ) )
|
||||
{
|
||||
$return[ $key ] = $field->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[ $key ] = $field::stringValue( isset( $customValues[ $field->name ] ) ? $customValues[ $field->name ] : NULL );
|
||||
$return[ $key ] = $field::stringValue($customValues[$field->name] ?? NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief SearchContent extension: Pages
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 10 Jul 2023
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\SearchContent;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Application;
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\cms\Pages\PageItem;
|
||||
use IPS\Content\Search\SearchContentAbstract;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use IPS\Text\DOMParser;
|
||||
use IPS\Widget\Area;
|
||||
use IPS\Xml\DOMDocument;
|
||||
use UnderflowException;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SearchContent extension: Pages
|
||||
*/
|
||||
class Pages extends SearchContentAbstract
|
||||
{
|
||||
/**
|
||||
* Return all searchable classes in your application,
|
||||
* including comments and/or reviews
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function supportedClasses() : array
|
||||
{
|
||||
return array(
|
||||
PageItem::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Title for search index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function searchIndexTitle(): string
|
||||
{
|
||||
$titles = array();
|
||||
foreach ( Lang::languages() as $lang )
|
||||
{
|
||||
$titles[] = $lang->get("cms_page_{$this->object->id}");
|
||||
}
|
||||
return implode( ' ', $titles );
|
||||
}
|
||||
|
||||
/**
|
||||
* Content for search index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function searchIndexContent(): string
|
||||
{
|
||||
if ( $this->object->type == 'builder' )
|
||||
{
|
||||
$content = array();
|
||||
foreach( Db::i()->select( '*', 'cms_page_widget_areas', array( 'area_page_id=?', $this->object->id ) ) as $widgetArea )
|
||||
{
|
||||
if( !$widgetArea['area_tree'] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$area = new Area( json_decode( $widgetArea['area_tree'], true ), $widgetArea['area_area'] );
|
||||
foreach( $area->getAllWidgets() as $widget )
|
||||
{
|
||||
if ( $widget['app'] == 'cms' and $widget['key'] == 'Wysiwyg' and isset( $widget['configuration']['content'] ) )
|
||||
{
|
||||
$content[] = trim( $widget['configuration']['content'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode( ' ', $content );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove {tags="foo"} */
|
||||
$this->object->content = preg_replace( '#\{([a-z]+?=([\'"]).+?\\2 ?+)}#', '', $this->object->content );
|
||||
|
||||
/* Convert {{}} logic into html tags */
|
||||
$this->object->content = preg_replace( '#{{(if|foreach)([^{]+?)}}#', '<ips$1 data="$2">', $this->object->content );
|
||||
$this->object->content = preg_replace( '#{{end(if|foreach)}}#', '</ips$1>', $this->object->content );
|
||||
|
||||
/* Remove custom PHP {{$foo = $this->object->test();}} */
|
||||
$this->object->content = preg_replace( '#{{(.+?)}}#', '', $this->object->content );
|
||||
|
||||
$source = new DOMDocument( '1.0', 'UTF-8' );
|
||||
$source->loadHTML( DOMDocument::wrapHtml( $this->object->content ) );
|
||||
|
||||
/* And then remove the HTML logic */
|
||||
$domElemsToRemove = array();
|
||||
foreach ( $source->getElementsByTagname('ipsif') as $domElement )
|
||||
{
|
||||
$domElemsToRemove[] = $domElement;
|
||||
}
|
||||
|
||||
foreach ( $source->getElementsByTagname('ipsforeach') as $domElement )
|
||||
{
|
||||
$domElemsToRemove[] = $domElement;
|
||||
}
|
||||
|
||||
foreach( $domElemsToRemove as $domElement )
|
||||
{
|
||||
$domElement->parentNode->removeChild($domElement);
|
||||
}
|
||||
|
||||
return DOMParser::getDocumentBodyContents( $source );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Index Permissions
|
||||
*
|
||||
* @return string Comma-delimited values or '*'
|
||||
* @li Number indicates a group
|
||||
* @li Number prepended by "m" indicates a member
|
||||
* @li Number prepended by "s" indicates a social group
|
||||
*/
|
||||
public function searchIndexPermissions(): string
|
||||
{
|
||||
try
|
||||
{
|
||||
return Db::i()->select( 'perm_view', 'core_permission_index', array( "app='cms' AND perm_type='pages' AND perm_type_id=?", $this->object->id ) )->first();
|
||||
}
|
||||
catch ( UnderflowException )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML for search result display
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param bool $iPostedIn If the user has posted in the item
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
* @param bool $asItem Displaying results as items?
|
||||
* @param bool $canIgnoreComments Can ignore comments in the result stream? Activity stream can, but search results cannot.
|
||||
* @param array|null $template Optional custom template
|
||||
* @param array $reactions Reaction Data
|
||||
* @return string
|
||||
*/
|
||||
public static function searchResult( array $indexData, array $authorData, array $itemData, array|null $containerData, array $reputationData, int|null $reviewRating, bool $iPostedIn, string $view, bool $asItem, bool $canIgnoreComments=FALSE, array|null $template=null, array $reactions=array() ): string
|
||||
{
|
||||
$indexData['index_title'] = Member::loggedIn()->language()->addToStack( 'cms_page_' . $indexData['index_item_id'] );
|
||||
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments, $template, $reactions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL from index data
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param string|NULL $action Action
|
||||
* @return Url
|
||||
*/
|
||||
public static function urlFromIndexData( array $indexData, array $itemData, string|null $action = NULL ): Url
|
||||
{
|
||||
if ( Application::load('cms')->default AND $itemData['page_default'] AND !$itemData['page_folder_id'] )
|
||||
{
|
||||
/* No - that's easy */
|
||||
return Url::internal( '', 'front' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return Url::internal( 'app=cms&module=pages&controller=page&path=' . $itemData['page_full_path'], 'front', 'content_page_path', array( $itemData['page_full_path'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief SearchContent extension: Records
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @subpackage Pages
|
||||
* @since 10 Jul 2023
|
||||
*/
|
||||
|
||||
namespace IPS\cms\extensions\core\SearchContent;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\cms\Databases;
|
||||
use IPS\cms\Fields;
|
||||
use IPS\cms\Records as BaseRecords;
|
||||
use IPS\cms\Records\Comment;
|
||||
use IPS\Content\Search\SearchContentAbstract;
|
||||
use Exception;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SearchContent extension: Records
|
||||
*/
|
||||
class Records extends SearchContentAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Store generated search index titles for efficiency
|
||||
*/
|
||||
protected static array $searchIndexTitles = array();
|
||||
|
||||
/**
|
||||
* Return all searchable classes in your application,
|
||||
* including comments and/or reviews
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function supportedClasses() : array
|
||||
{
|
||||
$return = [];
|
||||
foreach( Databases::databases() as $database )
|
||||
{
|
||||
if( $database->search )
|
||||
{
|
||||
$return[] = 'IPS\cms\Records' . $database->id;
|
||||
if( $database->options['comments'] )
|
||||
{
|
||||
$return[] = 'IPS\cms\Records\Comment' . $database->id;
|
||||
}
|
||||
if( $database->options['reviews'] )
|
||||
{
|
||||
$return[] = 'IPS\cms\Records\Review' . $database->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML for search result display
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param bool $iPostedIn If the user has posted in the item
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
* @param bool $asItem Displaying results as items?
|
||||
* @param bool $canIgnoreComments Can ignore comments in the result stream? Activity stream can, but search results cannot.
|
||||
* @param array|null $template Optional custom template
|
||||
* @param array $reactions Reaction Data
|
||||
* @return string
|
||||
*/
|
||||
public static function searchResult( array $indexData, array $authorData, array $itemData, array|null $containerData, array $reputationData, int|null $reviewRating, bool $iPostedIn, string $view, bool $asItem, bool $canIgnoreComments=FALSE, array|null $template=null, array $reactions=array() ): string
|
||||
{
|
||||
if( is_subclass_of( $indexData['index_class'], Comment::class ) )
|
||||
{
|
||||
$commentClass = $indexData['index_class'];
|
||||
/* Ensure that the comment title is formatted correctly */
|
||||
try
|
||||
{
|
||||
$databases = Databases::databases();
|
||||
|
||||
if ( ! isset( static::$searchIndexTitles[ $itemData['primary_id_field'] ] ) )
|
||||
{
|
||||
$fields = '\IPS\cms\Fields' . $commentClass::$customDatabaseId;
|
||||
|
||||
/* @var $fields Fields */
|
||||
static::$searchIndexTitles[ $itemData['primary_id_field'] ] = $fields::load( $databases[ $commentClass::$customDatabaseId ]->field_title )->displayValue( $itemData['field_' . $databases[ $commentClass::$customDatabaseId ]->field_title ] );
|
||||
}
|
||||
|
||||
$itemData['field_' . $databases[ $commentClass::$customDatabaseId ]->field_title ] = static::$searchIndexTitles[ $itemData['primary_id_field'] ];
|
||||
}
|
||||
catch ( Exception ) { }
|
||||
}
|
||||
|
||||
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments, $template, $reactions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Index Permissions
|
||||
*
|
||||
* @return string Comma-delimited values or '*'
|
||||
* @li Number indicates a group
|
||||
* @li Number prepended by "m" indicates a member
|
||||
* @li Number prepended by "s" indicates a social group
|
||||
*/
|
||||
public function searchIndexPermissions(): string
|
||||
{
|
||||
if( $this->object instanceof BaseRecords )
|
||||
{
|
||||
/* We don't want to index items in databases with search disabled */
|
||||
if( !$this->object::database()->search )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->object->deleteLogPermissions();
|
||||
}
|
||||
|
||||
return parent::searchIndexPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snippet HTML for search result display
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
* @return callable
|
||||
*/
|
||||
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array|null $containerData, array $reputationData, int|null $reviewRating, string $view ): string
|
||||
{
|
||||
if( is_subclass_of( $indexData['index_class'], BaseRecords::class ) )
|
||||
{
|
||||
if ( $view == 'expanded' OR ( $view == 'condensed' AND isset( $itemData['record_image'] ) ) )
|
||||
{
|
||||
$url = static::urlFromIndexData( $indexData, $itemData );
|
||||
return Theme::i()->getTemplate( 'global', 'cms', 'front' )->recordResultSnippet( $indexData, $itemData, $url, $view == 'condensed' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return parent::searchResultSnippet( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $view );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL from index data
|
||||
*
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param string|NULL $action Action
|
||||
* @return Url
|
||||
*/
|
||||
public static function urlFromIndexData( array $indexData, array $itemData, string|null $action = NULL ): Url
|
||||
{
|
||||
$itemClass = $indexData['index_class'];
|
||||
if( is_subclass_of( $indexData['index_class'], Comment::class ) )
|
||||
{
|
||||
$itemClass = $indexData['index_class']::$itemClass;
|
||||
}
|
||||
|
||||
if( is_subclass_of( $itemClass, BaseRecords::class ) )
|
||||
{
|
||||
if( $action == 'getPrefComment' )
|
||||
{
|
||||
$pref = Member::loggedIn()->linkPref() ?: Settings::i()->link_default;
|
||||
|
||||
switch( $pref )
|
||||
{
|
||||
case 'unread':
|
||||
$action = Member::loggedIn()->member_id ? 'getNewComment' : NULL;
|
||||
break;
|
||||
|
||||
case 'last':
|
||||
$action = 'getLastComment';
|
||||
break;
|
||||
|
||||
default:
|
||||
$action = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif( !Member::loggedIn()->member_id AND $action == 'getNewComment' )
|
||||
{
|
||||
$action = NULL;
|
||||
}
|
||||
|
||||
if ( !isset( $itemClass::$pagePath ) or empty( $itemClass::$pagePath ) )
|
||||
{
|
||||
$itemClass::$pagePath = Db::i()->select( 'page_full_path', 'cms_pages', array( 'page_id=?', $itemClass::database()->page_id ) )->first();
|
||||
}
|
||||
|
||||
$recordSlug = !$itemData['record_static_furl'] ? $itemData['record_dynamic_furl'] . '-r' . $itemData['primary_id_field'] : $itemData['record_static_furl'];
|
||||
|
||||
if ( $itemClass::database()->use_categories )
|
||||
{
|
||||
$url = Url::internal( "app=cms&module=pages&controller=page&path=" . $itemClass::$pagePath . '/' . ( $itemData['extra'] ? $itemData['extra'] . '/' : '' ) . $recordSlug, 'front', 'content_page_path', $recordSlug );
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = Url::internal( "app=cms&module=pages&controller=page&path=" . $itemClass::$pagePath . '/' . $recordSlug, 'front', 'content_page_path', $recordSlug );
|
||||
}
|
||||
|
||||
if( $action )
|
||||
{
|
||||
$url = $url->setQueryString( 'do', $action );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
return parent::urlFromIndexData( $indexData, $itemData, $action );
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @brief Support Pages Databases in sitemaps
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
@@ -12,21 +14,41 @@
|
||||
namespace IPS\cms\extensions\core\Sitemap;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Databases as DatabasesClass;
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\cms\Records;
|
||||
use IPS\Content\Filter;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\SitemapAbstract;
|
||||
use IPS\Helpers\Form\Number;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Member;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Settings;
|
||||
use IPS\Sitemap;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use const IPS\SITEMAP_MAX_PER_FILE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support Pages Databases in sitemaps
|
||||
*/
|
||||
class _Databases
|
||||
class Databases extends SitemapAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Recommended Settings
|
||||
*/
|
||||
public $recommendedSettings = array(
|
||||
public array $recommendedSettings = array(
|
||||
'sitemap_databases_include' => true,
|
||||
'sitemap_databases_count' => -1,
|
||||
'sitemap_databases_priority' => 1
|
||||
@@ -37,12 +59,12 @@ class _Databases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function settings()
|
||||
public function settings(): array
|
||||
{
|
||||
return array(
|
||||
'sitemap_databases_include' => new \IPS\Helpers\Form\YesNo( "sitemap_databases_include", \IPS\Settings::i()->sitemap_databases_count != 0, FALSE, array( 'togglesOn' => array( "sitemap_databases_count", "sitemap_databases_priority" ) ), NULL, NULL, NULL, "sitemap_databases_include" ),
|
||||
'sitemap_databases_count' => new \IPS\Helpers\Form\Number( 'sitemap_databases_count', \IPS\Settings::i()->sitemap_databases_count, FALSE, array( 'min' => '-1', 'unlimited' => '-1' ), NULL, NULL, NULL, 'sitemap_databases_count' ),
|
||||
'sitemap_databases_priority' => new \IPS\Helpers\Form\Select( 'sitemap_databases_priority', \IPS\Settings::i()->sitemap_databases_priority, FALSE, array( 'options' => \IPS\Sitemap::$priorities, 'unlimited' => '-1', 'unlimitedLang' => 'sitemap_dont_include' ), NULL, NULL, NULL, 'sitemap_databases_priority' )
|
||||
'sitemap_databases_include' => new YesNo( "sitemap_databases_include", Settings::i()->sitemap_databases_count != 0, FALSE, array( 'togglesOn' => array( "sitemap_databases_count", "sitemap_databases_priority" ) ), NULL, NULL, NULL, "sitemap_databases_include" ),
|
||||
'sitemap_databases_count' => new Number( 'sitemap_databases_count', Settings::i()->sitemap_databases_count, FALSE, array( 'min' => '-1', 'unlimited' => '-1' ), NULL, NULL, NULL, 'sitemap_databases_count' ),
|
||||
'sitemap_databases_priority' => new Select( 'sitemap_databases_priority', Settings::i()->sitemap_databases_priority, FALSE, array( 'options' => Sitemap::$priorities, 'unlimited' => '-1', 'unlimitedLang' => 'sitemap_dont_include' ), NULL, NULL, NULL, 'sitemap_databases_priority' )
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,15 +74,15 @@ class _Databases
|
||||
* @param array $values Values
|
||||
* @return void
|
||||
*/
|
||||
public function saveSettings( $values )
|
||||
public function saveSettings( array $values ) : void
|
||||
{
|
||||
if ( $values['sitemap_configuration_info'] )
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'sitemap_databases_count' => $this->recommendedSettings['sitemap_databases_count'], 'sitemap_databases_priority' => $this->recommendedSettings['sitemap_databases_priority'] ) );
|
||||
Settings::i()->changeValues( array( 'sitemap_databases_count' => $this->recommendedSettings['sitemap_databases_count'], 'sitemap_databases_priority' => $this->recommendedSettings['sitemap_databases_priority'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'sitemap_databases_count' => $values['sitemap_databases_include'] ? $values['sitemap_databases_count'] : 0, 'sitemap_databases_priority' => $values['sitemap_databases_priority'] ) );
|
||||
Settings::i()->changeValues( array( 'sitemap_databases_count' => $values['sitemap_databases_include'] ? $values['sitemap_databases_count'] : 0, 'sitemap_databases_priority' => $values['sitemap_databases_priority'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +91,10 @@ class _Databases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilenames()
|
||||
public function getFilenames(): array
|
||||
{
|
||||
/* Are we including? */
|
||||
if ( ! \IPS\Settings::i()->sitemap_databases_count )
|
||||
if ( ! Settings::i()->sitemap_databases_count )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
@@ -80,36 +102,37 @@ class _Databases
|
||||
$files = array();
|
||||
|
||||
/* Check that guests can access the content at all */
|
||||
foreach( \IPS\cms\Databases::databases() as $database )
|
||||
foreach( DatabasesClass::databases() as $database )
|
||||
{
|
||||
if ( $database->page_id > 0 )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( !$database->can( 'view', new \IPS\Member ) )
|
||||
if ( !$database->can( 'view', new Member ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( OutOfRangeException $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$page = \IPS\cms\Pages\Page::load( $database->page_id );
|
||||
$page = Page::load( $database->page_id );
|
||||
|
||||
if( !$page->can( 'view', new \IPS\Member ) )
|
||||
if( !$page->can( 'view', new Member ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
catch ( OutOfRangeException $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* @var Records $class */
|
||||
$class = '\IPS\cms\Records' . $database->id;
|
||||
|
||||
if ( isset( $class::$containerNodeClass ) )
|
||||
@@ -122,7 +145,7 @@ class _Databases
|
||||
}
|
||||
|
||||
/* And however many for the content items */
|
||||
$count = ceil( max( (int) $class::getItemsWithPermission( $class::sitemapWhere(), NULL, 10, 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, new \IPS\Member, FALSE, FALSE, FALSE, TRUE ), \IPS\Settings::i()->sitemap_databases_count ) / \IPS\SITEMAP_MAX_PER_FILE );
|
||||
$count = ceil( max( (int) $class::getItemsWithPermission( $class::sitemapWhere(), NULL, 10, 'read', Filter::FILTER_PUBLIC_ONLY, 0, new Member, FALSE, FALSE, FALSE, TRUE ), Settings::i()->sitemap_databases_count ) / SITEMAP_MAX_PER_FILE );
|
||||
for( $i=1; $i <= $count; $i++ )
|
||||
{
|
||||
$files[] = $database->id . '_sitemap_database_records_' . $i;
|
||||
@@ -137,19 +160,19 @@ class _Databases
|
||||
* Generate the sitemap
|
||||
*
|
||||
* @param string $filename The sitemap file to build (should be one returned from getFilenames())
|
||||
* @param \IPS\Sitemap $sitemap Sitemap object reference
|
||||
* @return void
|
||||
* @param Sitemap $sitemap Sitemap object reference
|
||||
* @return int|null
|
||||
*/
|
||||
public function generateSitemap( $filename, $sitemap )
|
||||
public function generateSitemap( string $filename, Sitemap $sitemap ) : ?int
|
||||
{
|
||||
/* We have elected to not add databases to the sitemap */
|
||||
if ( ! \IPS\Settings::i()->sitemap_databases_count )
|
||||
if ( ! Settings::i()->sitemap_databases_count )
|
||||
{
|
||||
return NULL;
|
||||
return null;
|
||||
}
|
||||
|
||||
$tmp = explode( '_', $filename );
|
||||
$databaseId = \intval( array_shift( $tmp ) );
|
||||
$databaseId = intval( array_shift( $tmp ) );
|
||||
try
|
||||
{
|
||||
$class = '\IPS\cms\Records' . $databaseId;
|
||||
@@ -162,29 +185,30 @@ class _Databases
|
||||
if ( isset( $nodeClass ) and $filename == $databaseId . '_sitemap_database_categories' )
|
||||
{
|
||||
$select = array();
|
||||
if ( \in_array( 'IPS\Content\Permissions', class_implements( $nodeClass ) ) or \in_array( 'IPS\Node\Permissions', class_implements( $nodeClass ) ) )
|
||||
if ( in_array( 'IPS\Node\Permissions', class_implements( $nodeClass ) ) )
|
||||
{
|
||||
$select = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $nodeClass::$databaseTable, array( 'category_database_id=? AND (' . \IPS\Db::i()->findInSet( 'perm_view', array( \IPS\Settings::i()->guest_group ) ) . ' OR ' . 'perm_view=? )', $databaseId, '*' ) )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id={$nodeClass::$databaseTable}.{$nodeClass::$databasePrefix}{$nodeClass::$databaseColumnId}", $nodeClass::$permApp, $nodeClass::$permType ) ), $nodeClass );
|
||||
$select = new ActiveRecordIterator( Db::i()->select( '*', $nodeClass::$databaseTable, array( 'category_database_id=? AND (' . Db::i()->findInSet( 'perm_view', array( Settings::i()->guest_group ) ) . ' OR ' . 'perm_view=? )', $databaseId, '*' ) )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id={$nodeClass::$databaseTable}.{$nodeClass::$databasePrefix}{$nodeClass::$databaseColumnId}", $nodeClass::$permApp, $nodeClass::$permType ) ), $nodeClass );
|
||||
}
|
||||
else if ( $nodeClass::$ownerTypes !== NULL and is_subclass_of( $nodeClass, 'IPS\Node\Model' ) )
|
||||
{
|
||||
$select = $nodeClass::loadByOwner( new \IPS\Member );
|
||||
$select = $nodeClass::loadByOwner( new Member );
|
||||
}
|
||||
|
||||
foreach ( $select as $node )
|
||||
{
|
||||
/* We only want nodes we can see, and that have actual content inside */
|
||||
if( $node->url() !== NULL and $node->can( 'view', new \IPS\Member ) and ( $node->hasChildren() OR ( $node->show_records and $node->getContentItemCount() ) ) )
|
||||
if( $node->url() !== NULL and $node->can( 'view', new Member ) and ( $node->hasChildren() OR ( $node->show_records and $node->getContentItemCount() ) ) )
|
||||
{
|
||||
$data = array( 'url' => $node->url(), 'lastmod' => $node->getLastCommentTime( new \IPS\Member ) );
|
||||
$data = array( 'url' => $node->url(), 'lastmod' => $node->getLastCommentTime( new Member ) );
|
||||
|
||||
$priority = \intval( \IPS\Settings::i()->sitemap_databases_priority );
|
||||
$priority = intval( Settings::i()->sitemap_databases_priority );
|
||||
if ( $priority !== -1 )
|
||||
{
|
||||
$data['priority'] = $priority;
|
||||
}
|
||||
|
||||
$entries[] = $data;
|
||||
$lastId = $node->_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,10 +217,10 @@ class _Databases
|
||||
$exploded = explode( '_', $filename );
|
||||
$block = (int) array_pop( $exploded );
|
||||
|
||||
$offset = ( $block - 1 ) * \IPS\SITEMAP_MAX_PER_FILE;
|
||||
$limit = \IPS\SITEMAP_MAX_PER_FILE;
|
||||
$offset = ( $block - 1 ) * SITEMAP_MAX_PER_FILE;
|
||||
$limit = SITEMAP_MAX_PER_FILE;
|
||||
|
||||
$totalLimit = \IPS\Settings::i()->sitemap_databases_count;
|
||||
$totalLimit = Settings::i()->sitemap_databases_count;
|
||||
if ( $totalLimit > -1 and ( $offset + $limit ) > $totalLimit )
|
||||
{
|
||||
if ( $totalLimit < $limit )
|
||||
@@ -209,7 +233,8 @@ class _Databases
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $class::getItemsWithPermission( $class::sitemapWhere(), NULL, array( $offset, $limit ), 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, new \IPS\Member, TRUE ) as $item )
|
||||
/* @var Records $class */
|
||||
foreach ( $class::getItemsWithPermission( $class::sitemapWhere(), NULL, array( $offset, $limit ), 'read', Filter::FILTER_PUBLIC_ONLY, 0, new Member, TRUE ) as $item )
|
||||
{
|
||||
$data = array( 'url' => $item->url() );
|
||||
|
||||
@@ -220,21 +245,23 @@ class _Databases
|
||||
$data['lastmod'] = $lastMod;
|
||||
}
|
||||
|
||||
$priority = ( $item->sitemapPriority() ?: ( \intval( \IPS\Settings::i()->sitemap_databases_priority ) ) );
|
||||
$priority = ( $item->sitemapPriority() ?: ( intval( Settings::i()->sitemap_databases_priority ) ) );
|
||||
if ( $priority !== -1 )
|
||||
{
|
||||
$data['priority'] = $priority;
|
||||
}
|
||||
|
||||
$entries[] = $data;
|
||||
$lastId = $item->primary_id_field;
|
||||
}
|
||||
}
|
||||
|
||||
$sitemap->buildSitemapFile( $filename, $entries );
|
||||
return $lastId ?? 0;
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
catch( OutOfRangeException $e )
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,21 +12,35 @@
|
||||
namespace IPS\cms\extensions\core\Sitemap;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\cms\Pages\Page;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\SitemapAbstract;
|
||||
use IPS\Helpers\Form\Number;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Member;
|
||||
use IPS\Settings;
|
||||
use IPS\Sitemap;
|
||||
use function defined;
|
||||
use function intval;
|
||||
use const IPS\SITEMAP_MAX_PER_FILE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support Pages in sitemaps
|
||||
*/
|
||||
class _Pages
|
||||
class Pages extends SitemapAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Recommended Settings
|
||||
*/
|
||||
public $recommendedSettings = array(
|
||||
public array $recommendedSettings = array(
|
||||
'sitemap_pages_include' => true,
|
||||
'sitemap_pages_count' => -1,
|
||||
'sitemap_pages_priority' => 1
|
||||
@@ -37,12 +51,12 @@ class _Pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function settings()
|
||||
public function settings(): array
|
||||
{
|
||||
return array(
|
||||
'sitemap_pages_include' => new \IPS\Helpers\Form\YesNo( "sitemap_pages_include", \IPS\Settings::i()->sitemap_pages_count != 0, FALSE, array( 'togglesOn' => array( "sitemap_pages_count", "sitemap_pages_priority" ) ), NULL, NULL, NULL, "sitemap_pages_include" ),
|
||||
'sitemap_pages_count' => new \IPS\Helpers\Form\Number( 'sitemap_pages_count', \IPS\Settings::i()->sitemap_pages_count, FALSE, array( 'min' => '-1', 'unlimited' => '-1' ), NULL, NULL, NULL, 'sitemap_pages_count' ),
|
||||
'sitemap_pages_priority' => new \IPS\Helpers\Form\Select( 'sitemap_pages_priority', \IPS\Settings::i()->sitemap_pages_priority, FALSE, array( 'options' => \IPS\Sitemap::$priorities, 'unlimited' => '-1', 'unlimitedLang' => 'sitemap_dont_include' ), NULL, NULL, NULL, 'sitemap_pages_priority' )
|
||||
'sitemap_pages_include' => new YesNo( "sitemap_pages_include", Settings::i()->sitemap_pages_count != 0, FALSE, array( 'togglesOn' => array( "sitemap_pages_count", "sitemap_pages_priority" ) ), NULL, NULL, NULL, "sitemap_pages_include" ),
|
||||
'sitemap_pages_count' => new Number( 'sitemap_pages_count', Settings::i()->sitemap_pages_count, FALSE, array( 'min' => '-1', 'unlimited' => '-1' ), NULL, NULL, NULL, 'sitemap_pages_count' ),
|
||||
'sitemap_pages_priority' => new Select( 'sitemap_pages_priority', Settings::i()->sitemap_pages_priority, FALSE, array( 'options' => Sitemap::$priorities, 'unlimited' => '-1', 'unlimitedLang' => 'sitemap_dont_include' ), NULL, NULL, NULL, 'sitemap_pages_priority' )
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,15 +66,15 @@ class _Pages
|
||||
* @param array $values Values
|
||||
* @return void
|
||||
*/
|
||||
public function saveSettings( $values )
|
||||
public function saveSettings( array $values ) : void
|
||||
{
|
||||
if ( $values['sitemap_configuration_info'] )
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'sitemap_pages_count' => $this->recommendedSettings['sitemap_pages_count'], 'sitemap_pages_priority' => $this->recommendedSettings['sitemap_pages_priority'] ) );
|
||||
Settings::i()->changeValues( array( 'sitemap_pages_count' => $this->recommendedSettings['sitemap_pages_count'], 'sitemap_pages_priority' => $this->recommendedSettings['sitemap_pages_priority'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Settings::i()->changeValues( array( 'sitemap_pages_count' => $values['sitemap_pages_include'] ? $values['sitemap_pages_count'] : 0, 'sitemap_pages_priority' => $values['sitemap_pages_priority'] ) );
|
||||
Settings::i()->changeValues( array( 'sitemap_pages_count' => $values['sitemap_pages_include'] ? $values['sitemap_pages_count'] : 0, 'sitemap_pages_priority' => $values['sitemap_pages_priority'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +83,10 @@ class _Pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilenames()
|
||||
public function getFilenames(): array
|
||||
{
|
||||
/* Are we even including? */
|
||||
if( \IPS\Settings::i()->sitemap_pages_count == 0 )
|
||||
if( Settings::i()->sitemap_pages_count == 0 )
|
||||
{
|
||||
return array();
|
||||
}
|
||||
@@ -80,17 +94,19 @@ class _Pages
|
||||
$files = array();
|
||||
$class = '\IPS\cms\Pages\Page';
|
||||
$count = 0;
|
||||
$member = new \IPS\Member;
|
||||
$member = new Member;
|
||||
$permissionCheck = 'view';
|
||||
|
||||
$where = array( array( '(' . \IPS\Db::i()->findInSet( 'perm_' . $class::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . $class::$permissionMap[ $permissionCheck ] . '=? )', '*' ) );
|
||||
|
||||
/* @var Page $class
|
||||
* @var array $permissionMap */
|
||||
$where = array( array( '(' . Db::i()->findInSet( 'perm_' . $class::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . $class::$permissionMap[ $permissionCheck ] . '=? )', '*' ) );
|
||||
$where[] = [ 'page_meta_index=?', 1 ];
|
||||
|
||||
$count = \IPS\Db::i()->select( '*', $class::$databaseTable, $where )
|
||||
$count = Db::i()->select( '*', $class::$databaseTable, $where )
|
||||
->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=" . $class::$databaseTable . "." . $class::$databasePrefix . $class::$databaseColumnId, $class::$permApp, $class::$permType ) )
|
||||
->count();
|
||||
|
||||
$count = ceil( max( $count, \IPS\Settings::i()->sitemap_pages_count ) / \IPS\SITEMAP_MAX_PER_FILE );
|
||||
$count = ceil( max( $count, Settings::i()->sitemap_pages_count ) / SITEMAP_MAX_PER_FILE );
|
||||
|
||||
for( $i=1; $i <= $count; $i++ )
|
||||
{
|
||||
@@ -104,30 +120,30 @@ class _Pages
|
||||
* Generate the sitemap
|
||||
*
|
||||
* @param string $filename The sitemap file to build (should be one returned from getFilenames())
|
||||
* @param \IPS\Sitemap $sitemap Sitemap object reference
|
||||
* @return void
|
||||
* @param Sitemap $sitemap Sitemap object reference
|
||||
* @return int|null
|
||||
*/
|
||||
public function generateSitemap( $filename, $sitemap )
|
||||
public function generateSitemap( string $filename, Sitemap $sitemap ) : ?int
|
||||
{
|
||||
/* We have elected to not add databases to the sitemap */
|
||||
if ( ! \IPS\Settings::i()->sitemap_pages_count )
|
||||
if ( ! Settings::i()->sitemap_pages_count )
|
||||
{
|
||||
return NULL;
|
||||
return null;
|
||||
}
|
||||
|
||||
$class = '\IPS\cms\Pages\Page';
|
||||
$count = 0;
|
||||
$member = new \IPS\Member;
|
||||
$member = new Member;
|
||||
$permissionCheck = 'view';
|
||||
$entries = array();
|
||||
|
||||
$exploded = explode( '_', $filename );
|
||||
$block = (int) array_pop( $exploded );
|
||||
|
||||
$offset = ( $block - 1 ) * \IPS\SITEMAP_MAX_PER_FILE;
|
||||
$limit = \IPS\SITEMAP_MAX_PER_FILE;
|
||||
$offset = ( $block - 1 ) * SITEMAP_MAX_PER_FILE;
|
||||
$limit = SITEMAP_MAX_PER_FILE;
|
||||
|
||||
$totalLimit = \IPS\Settings::i()->sitemap_pages_count;
|
||||
$totalLimit = Settings::i()->sitemap_pages_count;
|
||||
if ( $totalLimit > -1 and ( $offset + $limit ) > $totalLimit )
|
||||
{
|
||||
if ( $totalLimit < $limit )
|
||||
@@ -139,11 +155,13 @@ class _Pages
|
||||
$limit = $totalLimit - $offset;
|
||||
}
|
||||
}
|
||||
|
||||
$where = array( array( '(' . \IPS\Db::i()->findInSet( 'perm_' . $class::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . $class::$permissionMap[ $permissionCheck ] . '=? )', '*' ) );
|
||||
|
||||
/* @var Page $class
|
||||
* @var array $permissionMap */
|
||||
$where = array( array( '(' . Db::i()->findInSet( 'perm_' . $class::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . $class::$permissionMap[ $permissionCheck ] . '=? )', '*' ) );
|
||||
$where[] = [ 'page_meta_index=?', 1 ];
|
||||
$direction = ( $totalLimit > \IPS\SITEMAP_MAX_PER_FILE ) ? ' ASC' : ' DESC';
|
||||
$select = \IPS\Db::i()->select( '*', $class::$databaseTable, $where, 'page_id' . $direction, array( $offset, $limit ) )
|
||||
$direction = ( $totalLimit > SITEMAP_MAX_PER_FILE ) ? ' ASC' : ' DESC';
|
||||
$select = Db::i()->select( '*', $class::$databaseTable, $where, 'page_id' . $direction, array( $offset, $limit ) )
|
||||
->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=" . $class::$databaseTable . "." . $class::$databasePrefix . $class::$databaseColumnId, $class::$permApp, $class::$permType ) );
|
||||
|
||||
foreach( $select as $row )
|
||||
@@ -151,16 +169,18 @@ class _Pages
|
||||
$item = $class::constructFromData( $row );
|
||||
|
||||
$data = array( 'url' => $item->url() );
|
||||
$priority = \intval( \IPS\Settings::i()->sitemap_pages_priority );
|
||||
$priority = intval( Settings::i()->sitemap_pages_priority );
|
||||
if ( $priority !== -1 )
|
||||
{
|
||||
$data['priority'] = $priority;
|
||||
}
|
||||
|
||||
$entries[] = $data;
|
||||
$lastId = $item->id;
|
||||
}
|
||||
|
||||
$sitemap->buildSitemapFile( $filename, $entries );
|
||||
return $lastId ?? 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace IPS\cms\extensions\core\UIItem;
|
||||
|
||||
use IPS\Content\Item as BaseItem;
|
||||
use IPS\forums\Topic;
|
||||
use IPS\Helpers\Menu;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Output\UI\Item;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Content UI extension: CopyTopicToDatabase
|
||||
*/
|
||||
class CopyTopicToDatabase extends Item
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Class to extend
|
||||
*/
|
||||
public static ?string $class = Topic::class;
|
||||
|
||||
public function menuItems( BaseItem $item ): array
|
||||
{
|
||||
$newLinks = [];
|
||||
if( $item->hidden() != -2 and Member::loggedIn()->modPermission( 'can_copy_topic_database' ) )
|
||||
{
|
||||
$link = new Menu\Link( Url::internal( 'app=cms&module=database&controller=topic&id=' . $item->tid . '&_new=1', 'front', 'topic_copy', $item->title_seo ), 'copy_topic_to_database' );
|
||||
$link->opensDialog( 'copy_select_database', 'narrow', remoteSubmit: true );
|
||||
$link->position = 'delete';
|
||||
$newLinks['cms'] = $link;
|
||||
}
|
||||
return $newLinks;
|
||||
}
|
||||
}
|
||||
@@ -12,40 +12,41 @@
|
||||
namespace IPS\cms\extensions\core\Uninstall;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Content\Search\Index;
|
||||
use IPS\Data\Store;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Exception;
|
||||
use IPS\Extensions\UninstallAbstract;
|
||||
use function defined;
|
||||
use function is_array;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove custom databases
|
||||
*/
|
||||
class _Databases
|
||||
class Databases extends UninstallAbstract
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall custom databases
|
||||
*
|
||||
* @return void
|
||||
* @param string $application
|
||||
* @return void
|
||||
*/
|
||||
public function preUninstall( )
|
||||
public function preUninstall( string $application ) : void
|
||||
{
|
||||
if ( \IPS\Db::i()->checkForTable( 'cms_databases' ) )
|
||||
if ( Db::i()->checkForTable( 'cms_databases' ) )
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_databases' ) as $db )
|
||||
foreach ( Db::i()->select( '*', 'cms_databases' ) as $db )
|
||||
{
|
||||
/* The content router only returns databases linked to pages. In theory, you may have linked a database and then removed it,
|
||||
so the method to remove all app content from the search index fails, so we need to account for that here: */
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $db['database_id'] );
|
||||
Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $db['database_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,20 +54,21 @@ class _Databases
|
||||
/**
|
||||
* Uninstall custom databases
|
||||
*
|
||||
* @return void
|
||||
* @param string $application
|
||||
* @return void
|
||||
*/
|
||||
public function postUninstall()
|
||||
public function postUninstall( string $application ) : void
|
||||
{
|
||||
/* cms_databases has been removed */
|
||||
$tables = array();
|
||||
try
|
||||
{
|
||||
$databaseTables = \IPS\Db::i()->query( "SHOW TABLES LIKE '" . \IPS\Db::i()->prefix . "cms_custom_database_%'" )->fetch_assoc();
|
||||
$databaseTables = Db::i()->query( "SHOW TABLES LIKE '" . Db::i()->prefix . "cms_custom_database_%'" )->fetch_assoc();
|
||||
if ( $databaseTables )
|
||||
{
|
||||
foreach( $databaseTables as $row )
|
||||
{
|
||||
if( \is_array( $row ) )
|
||||
if( is_array( $row ) )
|
||||
{
|
||||
$tables[] = array_pop( $row );
|
||||
}
|
||||
@@ -78,19 +80,19 @@ class _Databases
|
||||
}
|
||||
|
||||
}
|
||||
catch( \IPS\Db\Exception $ex ) { }
|
||||
catch( Exception $ex ) { }
|
||||
|
||||
foreach( $tables as $table )
|
||||
{
|
||||
if ( \IPS\Db::i()->checkForTable( $table ) )
|
||||
if ( Db::i()->checkForTable( $table ) )
|
||||
{
|
||||
\IPS\Db::i()->dropTable( $table );
|
||||
Db::i()->dropTable( $table );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Data\Store::i()->cms_menu ) )
|
||||
if ( isset( Store::i()->cms_menu ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_menu );
|
||||
unset( Store::i()->cms_menu );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,75 +12,60 @@
|
||||
namespace IPS\cms\extensions\core\Uninstall;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\UninstallAbstract;
|
||||
use IPS\Widget\Area;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall callback
|
||||
*/
|
||||
class _Widgets
|
||||
class Widgets extends UninstallAbstract
|
||||
{
|
||||
/**
|
||||
* Code to execute before the application has been uninstalled
|
||||
*
|
||||
* @param string $application Application directory
|
||||
* @return array
|
||||
*/
|
||||
public function preUninstall( $application )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to execute after the application has been uninstalled
|
||||
*
|
||||
* @param string $application Application directory
|
||||
* @return array
|
||||
*/
|
||||
public function postUninstall( $application )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to execute when other applications or plugins are uninstalled
|
||||
*
|
||||
* @param string $application Application directory
|
||||
* @param int $plugin Plugin ID
|
||||
* @return void
|
||||
* @param string $application Application directory
|
||||
* @return void
|
||||
*/
|
||||
public function onOtherUninstall( $application=NULL, $plugin=NULL )
|
||||
public function onOtherUninstall( string $application ) : void
|
||||
{
|
||||
/* clean up widget areas table */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $row )
|
||||
foreach ( Db::i()->select( '*', 'cms_page_widget_areas' ) as $row )
|
||||
{
|
||||
$data = json_decode( $row['area_widgets'], true );
|
||||
$deleted = false;
|
||||
foreach ( $data as $key => $widget )
|
||||
if( $row['area_widgets'] and $data = json_decode( $row['area_widgets'], true ) )
|
||||
{
|
||||
if( $application !== NULL )
|
||||
{
|
||||
if ( isset( $widget['app'] ) and $widget['app'] == $application )
|
||||
{
|
||||
$deleted = true;
|
||||
unset( $data[$key] );
|
||||
}
|
||||
}
|
||||
$area = Area::create( $row['area_area'], $data );
|
||||
}
|
||||
elseif( $row['area_tree'] )
|
||||
{
|
||||
$area = new Area( json_decode( $row['area_tree'], true ), $row['area_area'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( $plugin !== NULL )
|
||||
foreach( $area->getAllWidgets() as $widget )
|
||||
{
|
||||
if ( isset( $widget['app'] ) and $widget['app'] == $application )
|
||||
{
|
||||
if ( isset( $widget['plugin'] ) and $widget['plugin'] == $plugin )
|
||||
{
|
||||
$deleted = true;
|
||||
unset( $data[$key] );
|
||||
}
|
||||
$deleted = true;
|
||||
$area->removeWidget( $widget['unique'] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( $deleted === true )
|
||||
{
|
||||
\IPS\Db::i()->update( 'cms_page_widget_areas', array( 'area_widgets' => json_encode( $data ) ), array( 'area_page_id=? AND area_area=?', $row['area_page_id'], $row['area_area'] ) );
|
||||
Db::i()->update( 'cms_page_widget_areas', array( 'area_tree' => json_encode( $area->toArray( true, false ) ) ), array( 'area_page_id=? AND area_area=?', $row['area_page_id'], $row['area_area'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user