Version 4.7.13
This commit is contained in:
1 parent
fd22d99e69
commit
7124a02564
954 files changed
+29277
-59308
No files matched your search
@@ -129,7 +129,7 @@ class _ItemController extends \IPS\Api\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$where[] = array( $class::$databasePrefix . $class::$databaseColumnMap['poll'] . "=0" );
|
||||
$where[] = array( $class::$databasePrefix . $class::$databaseColumnMap['poll'] . " IS NULL" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,10 @@ abstract class _Comment extends \IPS\Content
|
||||
if ( !$obj->hidden() and ( !$first or !$item::$firstCommentRequired ) )
|
||||
{
|
||||
$obj->sendNotifications();
|
||||
$member->achievementAction( 'core', 'Comment', $obj );
|
||||
if( !$item instanceof \IPS\core\Messenger\Conversation )
|
||||
{
|
||||
$member->achievementAction( 'core', 'Comment', $obj );
|
||||
}
|
||||
}
|
||||
else if( $obj->hidden() === 1 )
|
||||
{
|
||||
@@ -467,7 +470,7 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'trending', time(), $class . '__' . $item->$itemIdColumn );
|
||||
}
|
||||
catch( \RedisException $e ) { }
|
||||
catch( \BadMethodCallException | \RedisException $e ) { }
|
||||
}
|
||||
|
||||
/* Was it moderated? Let's see why. */
|
||||
@@ -626,7 +629,7 @@ abstract class _Comment extends \IPS\Content
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( $member->member_id )
|
||||
if ( $member->member_id AND $this->canView( $member ) )
|
||||
{
|
||||
$item = $this->item();
|
||||
|
||||
@@ -1112,6 +1115,9 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
\IPS\core\IndexNow::addUrlsToQueue( $noIndexUrls );
|
||||
}
|
||||
|
||||
/* Remove from Hive */
|
||||
\IPS\core\Hive::i()->removeContent( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1264,7 +1270,7 @@ abstract class _Comment extends \IPS\Content
|
||||
/* Update last comment/review data for container and item */
|
||||
try
|
||||
{
|
||||
if ( $item !== NULL AND \in_array( 'IPS\Content\Review', class_parents( \get_called_class() ) ) )
|
||||
if ( $item !== NULL AND $item->container() !== NULL AND \in_array( 'IPS\Content\Review', class_parents( \get_called_class() ) ) )
|
||||
{
|
||||
if ( $item->container()->_reviews !== NULL )
|
||||
{
|
||||
@@ -1300,7 +1306,7 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
if ( $item !== NULL AND $item->container() !== NULL AND \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$item->container()->rebuildPostedIn( array( $item->$itemIdColumn ), array( $this->author() ) );
|
||||
}
|
||||
@@ -1556,6 +1562,12 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, we do not want posts from future items */
|
||||
if ( \in_array( 'IPS\Content\FuturePublishing', class_implements( $itemClass ) ) )
|
||||
{
|
||||
$itemWhere[] = array( $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['is_future_entry'] . '=0' );
|
||||
}
|
||||
|
||||
if ( $joinContainer AND isset( $itemClass::$containerNodeClass ) )
|
||||
{
|
||||
$containerClass = $itemClass::$containerNodeClass;
|
||||
|
||||
@@ -411,6 +411,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
|
||||
/* Remove from Hive */
|
||||
\IPS\core\Hive::i()->removeContent( $this );
|
||||
|
||||
parent::delete();
|
||||
|
||||
$this->expireWidgetCaches();
|
||||
@@ -1210,10 +1213,13 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\core\Approval::loadFromContent( \get_called_class(), $this->$idColumn )->delete();
|
||||
\IPS\core\Approval::loadFromContent( \get_called_class(), $this->$idColumn )->delete();
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
catch( \OutOfRangeException $e ) {}
|
||||
|
||||
/* Remove from Hive */
|
||||
\IPS\core\Hive::i()->removeContent( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1387,6 +1393,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
\IPS\core\Approval::loadFromContent( \get_called_class(), $this->$idColumn )->delete();
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
|
||||
/* Remove from Hive */
|
||||
\IPS\core\Hive::i()->removeContent( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1876,7 +1885,22 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', ( \count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $mem )
|
||||
{
|
||||
$memberObj = \IPS\Member::constructFromData( $mem );
|
||||
if( $this->canView( $memberObj ) )
|
||||
|
||||
/* Members may have individual member level mod permissions, but are also in a group that has moderator permissions. In this case, the member level restrictions always win so we need to recheck those now that we have a member object. See \IPS\Member::modPermissions(). */
|
||||
$perms = $memberObj->modPermissions();
|
||||
$canView = $this->canView( $memberObj );
|
||||
if ( $canView === TRUE and $container = $item->containerWrapper() and isset( $container::$modPerm ) )
|
||||
{
|
||||
if ( isset( $perms[ $container::$modPerm ] ) and $perms[ $container::$modPerm ] != '*' and $perms[ $container::$modPerm ] != -1 )
|
||||
{
|
||||
if ( empty( $perms[ $container::$modPerm ] ) or ! in_array( $item->mapped('container'), $perms[ $container::$modPerm ] ) )
|
||||
{
|
||||
$canView = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( $canView === TRUE )
|
||||
{
|
||||
$notification->recipients->attach( $memberObj );
|
||||
}
|
||||
@@ -2465,7 +2489,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Queue if there's lots, or just send them */
|
||||
if ( $count > static::NOTIFICATIONS_PER_BATCH )
|
||||
if ( $count > \IPS\NOTIFICATION_BACKGROUND_THRESHOLD )
|
||||
{
|
||||
$idColumn = $this::$databaseColumnId;
|
||||
\IPS\Task::queue( 'core', 'Follow', array( 'class' => \get_class( $this ), 'item' => $this->$idColumn, 'sentTo' => $sentTo, 'followerCount' => $count ), 2 );
|
||||
@@ -3030,11 +3054,12 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Log keyword usage, if any
|
||||
*
|
||||
* @param string $content Content/text of submission
|
||||
* @param string|NULL $title Title of submission
|
||||
* @param string $content Content/text of submission
|
||||
* @param string|NULL $title Title of submission
|
||||
* @param int|NULL $date Date of submission
|
||||
* @return void
|
||||
*/
|
||||
public function checkKeywords( $content, $title=NULL )
|
||||
public function checkKeywords( $content, $title=NULL, ?int $date = NULL )
|
||||
{
|
||||
/* Do we have any keywords to track? */
|
||||
if( !\IPS\Settings::i()->stats_keywords )
|
||||
@@ -3078,7 +3103,8 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
if( \in_array( $keyword, $words ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_statistics', array( 'time' => time(), 'type' => 'keyword', 'value_4' => $keyword, 'extra_data' => $extraData ) );
|
||||
$date = $date ?: \IPS\DateTime::create()->getTimestamp();
|
||||
\IPS\Db::i()->insert( 'core_statistics', array( 'time' => $date, 'type' => 'keyword', 'value_4' => $keyword, 'extra_data' => $extraData ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3149,6 +3175,12 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\EditHistory and $this->mapped('edit_time') and ( $this->mapped('edit_show') or \IPS\Member::loggedIn()->modPermission('can_view_editlog') ) and \IPS\Settings::i()->edit_log )
|
||||
{
|
||||
/* If anonymous and we can't see, it's a no. */
|
||||
if ( $this->isAnonymous() AND !\IPS\Member::loggedIn()->modPermission('can_view_anonymous_posters') )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$template = static::$editLineTemplate[1];
|
||||
return \IPS\Theme::i()->getTemplate( static::$editLineTemplate[0][0], static::$editLineTemplate[0][1], ( isset( static::$editLineTemplate[0][2] ) ) ? static::$editLineTemplate[0][2] : NULL )->$template( $this, ( isset( static::$databaseColumnMap['edit_reason'] ) and $this->mapped('edit_reason') ) );
|
||||
}
|
||||
@@ -3287,4 +3319,5 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
+134
-49
@@ -104,6 +104,16 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
if( is_subclass_of( $class, 'IPS\Content\FuturePublishing' ) and isset( $class::$databaseColumnMap['is_future_entry'] ) AND isset( $class::$databaseColumnMap['future_date'] ) )
|
||||
{
|
||||
$futureColumn = $class::$databaseColumnMap['future_date'];
|
||||
$futureEntry = $class::$databaseColumnMap['is_future_entry'];
|
||||
if ( $item->$futureEntry == 1 and $item->$futureColumn <= time() )
|
||||
{
|
||||
$item->publish();
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is an AJAX request (like the topic hovercard), we don't want to do any of the below like update views and mark read */
|
||||
if ( \IPS\Request::i()->isAjax() and !$this->updateViewsAndMarkersOnAjax )
|
||||
@@ -117,27 +127,33 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* We also want to update the views if we have a page parameter */
|
||||
if( $item instanceof \IPS\Content\ReadMarkers AND isset( \IPS\Request::i()->page ) AND \IPS\Request::i()->page )
|
||||
{
|
||||
|
||||
$idColumn = $class::$databaseColumnId;
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
if ( \IPS\IPS::classUsesTrait( $class, 'IPS\Content\ViewUpdates' ) )
|
||||
{
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
$item->updateViews();
|
||||
}
|
||||
else
|
||||
{
|
||||
$idColumn = $class::$databaseColumnId;
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
{
|
||||
try
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'topic_views', 1, $class .'__' . $item->$idColumn );
|
||||
$countUpdated = true;
|
||||
try
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'topic_views', 1, $class .'__' . $item->$idColumn );
|
||||
$countUpdated = true;
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if ( ! $countUpdated )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_view_updates', array(
|
||||
'classname' => $class,
|
||||
'id' => $item->$idColumn
|
||||
) );
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if ( ! $countUpdated )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_view_updates', array(
|
||||
'classname' => $class,
|
||||
'id' => $item->$idColumn
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,36 +247,43 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Update Views */
|
||||
$idColumn = $class::$databaseColumnId;
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
if ( \IPS\IPS::classUsesTrait( $class, 'IPS\Content\ViewUpdates' ) )
|
||||
{
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
$item->updateViews();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
{
|
||||
try
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'topic_views', 1, $class .'__' . $item->$idColumn );
|
||||
|
||||
$countUpdated = true;
|
||||
try
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'topic_views', 1, $class .'__' . $item->$idColumn );
|
||||
|
||||
$countUpdated = true;
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if( \IPS\Application::appIsEnabled( 'cloud' ) and \IPS\cloud\Realtime::i()->isEnabled('trending') and $class::$includeInTrending )
|
||||
{
|
||||
try
|
||||
|
||||
if( \IPS\Application::appIsEnabled( 'cloud' ) and \IPS\cloud\Realtime::i()->isEnabled('trending') and $class::$includeInTrending )
|
||||
{
|
||||
/* Score by timestamp for trending */
|
||||
\IPS\Redis::i()->zIncrBy( 'trending', time() * 0.1, $class .'__' . $item->$idColumn );
|
||||
try
|
||||
{
|
||||
/* Score by timestamp for trending */
|
||||
\IPS\Redis::i()->zIncrBy( 'trending', time() * 0.1, $class .'__' . $item->$idColumn );
|
||||
}
|
||||
catch( \BadMethodCallException | \RedisException $e ) {}
|
||||
}
|
||||
|
||||
if ( ! $countUpdated )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_view_updates', array(
|
||||
'classname' => $class,
|
||||
'id' => $item->$idColumn
|
||||
) );
|
||||
}
|
||||
catch( \RedisException $e ) {}
|
||||
}
|
||||
|
||||
if ( ! $countUpdated )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_view_updates', array(
|
||||
'classname' => $class,
|
||||
'id' => $item->$idColumn
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +384,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->redirect( $class::getRedirectFrom( \IPS\Request::i()->id )->url(), '', 301 );
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -1000,6 +1023,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->bypassCsrfKeyCheck = TRUE;
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
return;
|
||||
}
|
||||
@@ -1628,7 +1652,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Moderator Log
|
||||
* Moderation Log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -1643,11 +1667,65 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
$class = static::$contentModel;
|
||||
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
|
||||
|
||||
/* Set up some stuff so we're not doing too much logic / assignment in the template */
|
||||
$modlog = $item->moderationTable();
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->modLog( $item, $modlog );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2S136/T', 404, '' );
|
||||
}
|
||||
catch( \DomainException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2S136/U', 403, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moderation Log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function analytics()
|
||||
{
|
||||
if( !\IPS\Member::loggedIn()->modPermission( 'can_view_moderation_log' ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2S136/1F', 403, '' );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$class = static::$contentModel;
|
||||
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
|
||||
/* Set up some stuff so we're not doing too much logic / assignment in the template */
|
||||
$lastCommenter = $members = $busy = $reacted = $images = NULL;
|
||||
try
|
||||
{
|
||||
$lastCommenter = $item->lastCommenter();
|
||||
if ( !$lastCommenter->member_id )
|
||||
{
|
||||
$lastCommenter = NULL;
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) { }
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $item, 'IPS\Content\Statistics' ) )
|
||||
{
|
||||
$members = $item->topPosters();
|
||||
$busy = $item->popularDays();
|
||||
$reacted = $item->topReactedPosts();
|
||||
$images = $item->imageAttachments();
|
||||
}
|
||||
|
||||
/* Set navigation */
|
||||
$this->_setBreadcrumbAndTitle( $item );
|
||||
|
||||
\IPS\Output::i()->output = $item->moderationTable();
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'analytics_and_stats' ) );
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->analytics( $item, $lastCommenter, $members, $busy, $reacted, $images );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
@@ -1967,9 +2045,11 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$review->author_response = $values['reviewResponse'];
|
||||
$review->save();
|
||||
|
||||
$review->setResponse( $values['reviewResponse'] );
|
||||
|
||||
/* Claim attachments and clear the editor */
|
||||
\IPS\File::claimAttachments( 'reviewResponse-' . $class::$application . '/' . $class::$module . '-' . \IPS\Request::i()->review, \IPS\Request::i()->id, \IPS\Request::i()->review, \get_class( $item ) );
|
||||
|
||||
\IPS\Output::i()->redirect( $review->url() );
|
||||
}
|
||||
|
||||
@@ -4008,9 +4088,14 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$class = static::$contentModel;
|
||||
if( !\is_subclass_of( $class, 'IPS\Content\Item' ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$class = static::$contentModel;
|
||||
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$items = [];
|
||||
|
||||
|
||||
+110
-52
@@ -41,6 +41,13 @@ abstract class _Item extends \IPS\Content
|
||||
* @brief [Content\Item] Follower count
|
||||
*/
|
||||
public $followerCount = NULL;
|
||||
|
||||
/**
|
||||
* Should IndexNow be skipped for this item? Can be used to prevent that Private Messages,
|
||||
* Reports and other content which is never going to be visible to guests is triggering the requests.
|
||||
* @var bool
|
||||
*/
|
||||
public static bool $skipIndexNow = FALSE;
|
||||
|
||||
/**
|
||||
* @brief [Content\Item] If $firstCommentRequired is TRUE, when comments are split from an item or items are merged, the author
|
||||
@@ -521,7 +528,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Dish out points */
|
||||
if ( !$obj->isFutureDate() and !$obj->hidden() )
|
||||
if ( !$obj->isFutureDate() and !$obj->hidden() and !$obj instanceof \IPS\core\Messenger\Conversation )
|
||||
{
|
||||
$member->achievementAction( 'core', 'NewContentItem', $obj );
|
||||
}
|
||||
@@ -619,6 +626,12 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$column = static::$databaseColumnMap['future_date'];
|
||||
$this->$column = $time->getTimestamp();
|
||||
|
||||
if( isset( static::$databaseColumnMap['is_future_entry'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['is_future_entry'];
|
||||
$this->$column = $time->getTimestamp() > time();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,7 +731,12 @@ abstract class _Item extends \IPS\Content
|
||||
/* Title */
|
||||
if ( isset( static::$databaseColumnMap['title'] ) )
|
||||
{
|
||||
$return['title'] = new \IPS\Helpers\Form\Text( static::$formLangPrefix . 'title', isset( \IPS\Request::i()->title ) ? \IPS\Request::i()->title : $item?->mapped( 'title' ), TRUE, array( 'maxLength' => \IPS\Settings::i()->max_title_length ?: 255, 'bypassProfanity' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_SWAP ) );
|
||||
$return['title'] = new \IPS\Helpers\Form\Text( static::$formLangPrefix . 'title', isset( \IPS\Request::i()->title ) ? \IPS\Request::i()->title : $item?->mapped( 'title' ), TRUE, array( 'maxLength' => \IPS\Settings::i()->max_title_length ?: 255, 'bypassProfanity' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_SWAP ), function( $val ) {
|
||||
if ( !\IPS\Member::loggedIn()->group['g_bypass_badwords'] AND $word = \IPS\core\Profanity::checkProfanityBlocks( $val ) )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( "form_err_word_blocked", FALSE, array( "sprintf" => array( $word ) ) ) );
|
||||
}
|
||||
} );
|
||||
$return['title']->rowClasses[] = 'ipsFieldRow_primary';
|
||||
$return['title']->rowClasses[] = 'ipsFieldRow_fullWidth';
|
||||
}
|
||||
@@ -1015,6 +1033,10 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$options['autocomplete']['filterProfanity'] = TRUE;
|
||||
}
|
||||
if ( \IPS\Settings::i()->tags_alphabetical )
|
||||
{
|
||||
$options['autocomplete']['alphabetical'] = TRUE;
|
||||
}
|
||||
|
||||
$options['autocomplete']['prefix'] = static::canPrefix( NULL, $container );
|
||||
$options['autocomplete']['disallowedCharacters'] = array( '#' ); // @todo Pending \IPS\Http\Url rework, hashes cannot be used in URLs
|
||||
@@ -1149,7 +1171,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Send this URL to IndexNow if the guest can view it */
|
||||
if ( $this->canView( new \IPS\Member ) )
|
||||
if ( $this->canView( new \IPS\Member ) AND !static::$skipIndexNow )
|
||||
{
|
||||
\IPS\core\IndexNow::addUrlToQueue( $this->url() );
|
||||
}
|
||||
@@ -1330,6 +1352,14 @@ abstract class _Item extends \IPS\Content
|
||||
$this->publish();
|
||||
}
|
||||
}
|
||||
else if ( $container and ! $this->$column )
|
||||
{
|
||||
if ( $values[ static::$formLangPrefix . 'date' ] instanceof \IPS\DateTime AND $values[ static::$formLangPrefix . 'date' ]->getTimestamp() > time() )
|
||||
{
|
||||
/* Was not future, now is */
|
||||
$this->unpublish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Post anonymously */
|
||||
@@ -1903,7 +1933,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this instanceof \IPS\Content\Views )
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\ViewUpdates' ) )
|
||||
{
|
||||
$return['num_views'] = (int) $this->mapped('views');
|
||||
}
|
||||
@@ -2129,6 +2159,9 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$link->markRead();
|
||||
}
|
||||
|
||||
/* Remove from Hive */
|
||||
\IPS\core\Hive::i()->removeContent( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2275,7 +2308,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Merge view counts */
|
||||
if ( $this instanceof \IPS\Content\Views )
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\ViewUpdates' ) )
|
||||
{
|
||||
$views += $item->mapped('views');
|
||||
\IPS\Db::i()->update( 'core_view_updates', array( 'id' => $this->$idColumn ), array( 'classname=? and id=?', (string) \get_class( $item ), $item->$idColumn ) );
|
||||
@@ -2725,7 +2758,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
$idColumn = static::$databaseColumnId;
|
||||
|
||||
|
||||
/* Don't do anything for shadow items */
|
||||
if ( isset( static::$databaseColumnMap['moved_to'] ) )
|
||||
{
|
||||
@@ -2740,19 +2773,19 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_item_member_map', array( 'map_class=? and map_item_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
|
||||
/* Remove any meta data */
|
||||
if ( ( $this instanceof \IPS\Content\MetaData ) AND isset( static::$databaseColumnMap['meta_data'] ) )
|
||||
{
|
||||
$this->deleteAllMeta();
|
||||
}
|
||||
|
||||
|
||||
/* Unclaim attachments */
|
||||
$this->unclaimAttachments();
|
||||
|
||||
/* Delete it from the database */
|
||||
parent::delete();
|
||||
|
||||
|
||||
/* Update count */
|
||||
try
|
||||
{
|
||||
@@ -2772,7 +2805,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
|
||||
|
||||
/* Delete comments */
|
||||
if ( isset( static::$commentClass ) )
|
||||
{
|
||||
@@ -2783,7 +2816,7 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$where = $commentClass::deleteWhereSql( $this->$idColumn );
|
||||
}
|
||||
|
||||
|
||||
/* Remove any deletion logs for comments */
|
||||
$commentIds = array();
|
||||
$commentIdColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnId;
|
||||
@@ -2791,14 +2824,14 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$commentIds[] = $commentId;
|
||||
}
|
||||
|
||||
|
||||
$this->deleteCommentOrReviewData( $commentIds, $commentClass );
|
||||
|
||||
if ( \is_array( $where ) and \count( $where ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( $commentClass::$databaseTable, $where );
|
||||
}
|
||||
|
||||
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
try
|
||||
@@ -2810,7 +2843,7 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$this->container()->_comments = ( $this->container()->_comments - $this->mapped('num_comments') );
|
||||
}
|
||||
|
||||
|
||||
$this->container()->setLastComment();
|
||||
}
|
||||
if ( $this->container()->_unapprovedComments !== NULL )
|
||||
@@ -2821,7 +2854,7 @@ abstract class _Item extends \IPS\Content
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Delete reviews */
|
||||
if ( isset( static::$reviewClass ) )
|
||||
{
|
||||
@@ -2832,7 +2865,7 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$where = $reviewClass::deleteWhereSql( $this->$idColumn );
|
||||
}
|
||||
|
||||
|
||||
/* Remove any deletion logs for reviews */
|
||||
$reviewIds = array();
|
||||
$reviewIdColumn = $reviewClass::$databasePrefix . $reviewClass::$databaseColumnMap['item'];
|
||||
@@ -2844,7 +2877,7 @@ abstract class _Item extends \IPS\Content
|
||||
$this->deleteCommentOrReviewData( $reviewIds, $reviewClass );
|
||||
|
||||
\IPS\Db::i()->delete( $reviewClass::$databaseTable, $where );
|
||||
|
||||
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
try
|
||||
@@ -2856,7 +2889,7 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$this->container()->_reviews = ( $this->container()->_reviews - $this->mapped('num_reviews') );
|
||||
}
|
||||
|
||||
|
||||
$this->container()->setLastReview();
|
||||
}
|
||||
if ( $this->container()->_unapprovedReviews !== NULL )
|
||||
@@ -2867,7 +2900,7 @@ abstract class _Item extends \IPS\Content
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Delete tags */
|
||||
if ( $this instanceof \IPS\Content\Tags )
|
||||
{
|
||||
@@ -2876,7 +2909,7 @@ abstract class _Item extends \IPS\Content
|
||||
\IPS\Db::i()->delete( 'core_tags_cache', array( 'tag_cache_key=?', $aaiLookup ) );
|
||||
\IPS\Db::i()->delete( 'core_tags_perms', array( 'tag_perm_aai_lookup=?', $aaiLookup ) );
|
||||
}
|
||||
|
||||
|
||||
/* Delete follows */
|
||||
if ( $this instanceof \IPS\Content\Followable )
|
||||
{
|
||||
@@ -2884,7 +2917,7 @@ abstract class _Item extends \IPS\Content
|
||||
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', static::$application, $followArea, (int) $this->$idColumn ) );
|
||||
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'class=? AND id=?', \get_called_class(), (int) $this->$idColumn ) );
|
||||
}
|
||||
|
||||
|
||||
/* Remove Notifications */
|
||||
$memberIds = array();
|
||||
|
||||
@@ -2894,13 +2927,13 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_notifications', array( 'item_class=? AND item_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
|
||||
/* Delete from Our Picks */
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array( 'promote_class=? AND promote_class_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
|
||||
/* Delete from redirect links */
|
||||
\IPS\Db::i()->delete( 'core_item_redirect', array( 'redirect_class=? AND redirect_new_item_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
|
||||
/* Delete Polls */
|
||||
if ( $this instanceof \IPS\Content\Polls and $this->getPoll() )
|
||||
{
|
||||
@@ -2912,19 +2945,21 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_ratings', array( 'class=? AND item_id=?', \get_called_class(), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
|
||||
foreach( $memberIds as $member )
|
||||
{
|
||||
\IPS\Member::load( $member )->recountNotifications();
|
||||
}
|
||||
|
||||
/** Item::url() can throw a LogicException exception in specific cases like when a Pages Record has no valid page */
|
||||
try
|
||||
if( !static::$skipIndexNow )
|
||||
{
|
||||
\IPS\core\IndexNow::addUrlToQueue( $this->url() );
|
||||
try
|
||||
{
|
||||
\IPS\core\IndexNow::addUrlToQueue( $this->url() );
|
||||
}
|
||||
catch( \LogicException $e ) {}
|
||||
}
|
||||
catch( \LogicException $e ) {}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3174,7 +3209,7 @@ abstract class _Item extends \IPS\Content
|
||||
if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$col = static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['approved'];
|
||||
if ( $member->member_id and $includeHiddenItems !== \IPS\Content\Hideable::FILTER_PUBLIC_ONLY )
|
||||
if ( $member->member_id and $includeHiddenItems !== \IPS\Content\Hideable::FILTER_PUBLIC_ONLY and isset( static::$databaseColumnMap['author'] ) )
|
||||
{
|
||||
/* Only fetching a count, for a single container with a item cache count, no future publishing, and there is only one where clause (the container limitation) */
|
||||
if( $countOnly === TRUE AND $skipPermission instanceof \IPS\Node\Model AND $skipPermission->_items !== NULL AND !\in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) AND \count( $where ) === 1 )
|
||||
@@ -8069,7 +8104,13 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public static function definedTags( \IPS\Node\Model $container = NULL )
|
||||
{
|
||||
return \IPS\Settings::i()->tags_predefined ? explode( ',', \IPS\Settings::i()->tags_predefined ) : array();
|
||||
$return = \IPS\Settings::i()->tags_predefined ? explode( ',', \IPS\Settings::i()->tags_predefined ) : array();
|
||||
if ( \IPS\Settings::i()->tags_alphabetical )
|
||||
{
|
||||
natcasesort( $return );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8125,8 +8166,20 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( isset ( $this->tags['tags'] ) ? $this->tags['tags'] : [] );
|
||||
|
||||
if ( isset( $this->tags['tags'] ) )
|
||||
{
|
||||
if ( \IPS\Settings::i()->tags_alphabetical )
|
||||
{
|
||||
natcasesort( $this->tags['tags'] );
|
||||
}
|
||||
|
||||
return $this->tags['tags'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8617,8 +8670,29 @@ abstract class _Item extends \IPS\Content
|
||||
$this->$future = 0;
|
||||
}
|
||||
|
||||
if ( isset( static::$databaseColumnMap['last_comment'] ) or isset( static::$databaseColumnMap['last_review'] ) )
|
||||
{
|
||||
$lastCommentField = static::$databaseColumnMap['last_comment'];
|
||||
if ( \is_array( $lastCommentField ) )
|
||||
{
|
||||
foreach ( $lastCommentField as $column )
|
||||
{
|
||||
$this->$column = time();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->$lastCommentField = time();
|
||||
}
|
||||
|
||||
if ( isset( static::$databaseColumnMap['last_review'] ) )
|
||||
{
|
||||
$lastReviewField = static::$databaseColumnMap['last_review'];
|
||||
$this->$lastReviewField = time();
|
||||
}
|
||||
}
|
||||
|
||||
$this->save();
|
||||
$this->onPublish( $member );
|
||||
|
||||
/* And update the tags perm cache */
|
||||
if ( $this instanceof \IPS\Content\Tags )
|
||||
@@ -8634,26 +8708,10 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
$comment->$date = time();
|
||||
$comment->save();
|
||||
|
||||
if ( isset( static::$databaseColumnMap['last_comment'] ) )
|
||||
{
|
||||
$lastCommentField = static::$databaseColumnMap['last_comment'];
|
||||
if ( \is_array( $lastCommentField ) )
|
||||
{
|
||||
foreach ( $lastCommentField as $column )
|
||||
{
|
||||
$this->$column = time();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->$lastCommentField = time();
|
||||
}
|
||||
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->onPublish( $member );
|
||||
|
||||
/* Mark this item as read for the author */
|
||||
$this->markRead( $this->author() );
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ trait Reactable
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'trending', time() * 0.4, \get_class( $item ) .'__' . $itemId );
|
||||
}
|
||||
catch( \RedisException $e ) {}
|
||||
catch( \BadMethodCallException | \RedisException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +270,7 @@ trait Reactable
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Cannot react to guest content */
|
||||
if ( !$owner->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
@@ -293,6 +294,12 @@ trait Reactable
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Unacknowledged warnings */
|
||||
if ( $member->members_bitoptions['unacknowledged_warnings'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Still here? All good. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -650,4 +650,25 @@ abstract class _Review extends \IPS\Content\Comment
|
||||
/* Nope, we cannot delete */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to a review
|
||||
*
|
||||
* @param string $response
|
||||
* @return void
|
||||
*/
|
||||
public function setResponse( string $response )
|
||||
{
|
||||
$this->checkProfanityFilters( FALSE, (bool) $this->hasAuthorResponse(), $response );
|
||||
|
||||
$column = static::$databaseColumnMap['author_response'];
|
||||
$this->$column = $response;
|
||||
$this->save();
|
||||
|
||||
/* Reindex in case it was hidden by the profanity filters */
|
||||
if ( $this instanceof \IPS\Content\Searchable )
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->index( $this );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +396,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
$classes = array_merge( $object->classes, $classes );
|
||||
|
||||
if ( ! $object->similarContent )
|
||||
if ( empty( $object->similarContent ) )
|
||||
{
|
||||
foreach( $object->classes as $class )
|
||||
{
|
||||
|
||||
@@ -249,6 +249,12 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
$isLastComment = 1;
|
||||
}
|
||||
|
||||
/* If this comment is hidden, don't actually mark as the last comment as that will cause this item to be hidden in search if we are getting only the last comment. */
|
||||
if ( $isLastComment AND $object->hidden() )
|
||||
{
|
||||
$isLastComment = 0;
|
||||
}
|
||||
|
||||
/* If we are re-indexing the first post of an item, which is triggered by a comment being added to a $itemClass::$firstCommentRequired,
|
||||
then ensure that the isLastComment flag is not added as we index the comment first, which means the index_is_last_comment is incorrectly reset to 0 for the comment itself */
|
||||
if ( $isForItem and $isLastComment )
|
||||
|
||||
@@ -588,16 +588,39 @@ class _Index extends \IPS\Content\Search\Index
|
||||
public function resetLastComment( $classes, $indexItemId, $ignoreId = NULL )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexItemId ) );
|
||||
|
||||
try
|
||||
{
|
||||
$latest = \IPS\Db::i()->select( 'index_object_id, index_date_updated, index_class', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=0', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 1 ), array( 'index_class=? AND index_object_id=?', $latest['index_class'], $latest['index_object_id'] ) );
|
||||
|
||||
/* Now reset the item index with the latest comment time */
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_date_updated' => $latest['index_date_updated'], 'index_date_commented' => $latest['index_date_commented'] ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_object_id=?', $indexItemId, $indexItemId ) );
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
catch( \Exception )
|
||||
{
|
||||
/* Didn't find a latest? Was it because the entire thing is hidden? */
|
||||
try
|
||||
{
|
||||
$index = \IPS\Db::i()->select( 'index_id, index_item_index_id, index_hidden', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=?', $indexItemId ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
|
||||
/* Is the root item hidden? */
|
||||
if ( $index['index_id'] == $index['index_item_index_id'] and in_array( $index['index_hidden'], [ -1, 2 ] ) )
|
||||
{
|
||||
$latest = \IPS\Db::i()->select( 'index_object_id, index_date_updated, index_class, index_date_commented', 'core_search_index', array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? and index_hidden=?', $indexItemId, $index['index_hidden'] ), 'index_date_created DESC', array( 0, 1 ) )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, so we can't find a latest item that is hidden, so skip this */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
catch( \Exception )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 1 ), array( 'index_class=? AND index_object_id=?', $latest['index_class'], $latest['index_object_id'] ) );
|
||||
|
||||
/* Now reset the item index with the latest comment time */
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_date_updated' => $latest['index_date_updated'], 'index_date_commented' => $latest['index_date_commented'] ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_object_id=?', $indexItemId, $indexItemId ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -922,7 +922,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
/* Now, if we have 501 results, then we have to assume there are more, so the join is required */
|
||||
if ( \count( $tagIds ) == 501 )
|
||||
{
|
||||
$tagWhere = array( $itemsOnlyTagSearch . 'index_item_index_id IN ( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index_tags', array( \IPS\Db::i()->in( 'index_tag', $tags ) ) ) );
|
||||
$tagWhere = array( $itemsOnlyTagSearch . 'index_item_index_id IN (' . \IPS\Db::i()->select( 'index_id', 'core_search_index_tags', array( \IPS\Db::i()->in( 'index_tag', $tags ) ) ) . ')' );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1031,7 +1031,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$where[] = $clause;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return */
|
||||
return $where;
|
||||
}
|
||||
@@ -1101,7 +1101,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
search which is actually very efficient as MySQL performs a search on the FT index first to narrow down the results */
|
||||
if ( static::termIsPhrase( $term ) )
|
||||
{
|
||||
$term = str_replace( array( "'", '"' ), '', $term );
|
||||
$term = str_replace( array( "'", '"', '?' ), '', $term );
|
||||
|
||||
foreach ( static::termAsWordsArray( $term ) as $word )
|
||||
{
|
||||
@@ -1161,6 +1161,9 @@ class _Query extends \IPS\Content\Search\Query
|
||||
|
||||
/* Trailing + or -s are not allowed */
|
||||
$word = rtrim( $word, '+-' );
|
||||
|
||||
/* ? are not allowed either */
|
||||
$word = str_replace( '?', '', $word );
|
||||
|
||||
/* These rules only apply if we're not in a quoted phrase... */
|
||||
if ( !static::termIsPhrase( $word ) )
|
||||
|
||||
@@ -153,11 +153,11 @@ trait Statistics
|
||||
if ( $name )
|
||||
{
|
||||
$subQuery = \IPS\Db::i()->select( 'core_members.member_id', 'core_members', \IPS\Db::i()->like( 'core_members.name', $name ) );
|
||||
$where[] = [ $commentClass::$databaseTable . '.' . $commentClass::$databaseColumnMap['author'] . ' IN(?)', $subQuery ];
|
||||
$where[] = [ $commentClass::$databaseTable . '.' . $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'] . ' IN(?)', $subQuery ];
|
||||
}
|
||||
|
||||
$members = iterator_to_array( \IPS\Db::i()->select(
|
||||
$commentClass::$databaseColumnMap['author'],
|
||||
$commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'],
|
||||
$commentClass::$databaseTable,
|
||||
$where,
|
||||
NULL,
|
||||
@@ -232,7 +232,7 @@ trait Statistics
|
||||
$return = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $commentClass::$databaseTable, array( \IPS\Db::i()->in( $commentIdField, $postIds ) ), "FIND_IN_SET( {$commentIdField}, '" . implode( ",", $postIds ) . "' )", array( 0, $count ) ), $commentClass ) as $comment )
|
||||
{
|
||||
if ( $comment->canView() and $comment->mapped('item') == $this->$idField )
|
||||
if ( $comment->canView() and $comment->mapped('item') == $this->$idField and isset( $counts[ $comment->$commentIdField ] ) )
|
||||
{
|
||||
$return[] = array( 'comment' => $comment, 'count' => $counts[ $comment->$commentIdField ] );
|
||||
}
|
||||
@@ -402,7 +402,18 @@ trait Statistics
|
||||
protected function _getVisibleWhere()
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
$idField = static::$databaseColumnId;
|
||||
|
||||
$lookFor = 'IPS\cms\Records\CommentTopicSync';
|
||||
|
||||
if ( mb_substr( $commentClass, 0, mb_strlen( $lookFor ) ) === $lookFor )
|
||||
{
|
||||
$idField = 'record_topicid';
|
||||
}
|
||||
else
|
||||
{
|
||||
$idField = static::$databaseColumnId;
|
||||
}
|
||||
|
||||
$commentItemField = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'];
|
||||
|
||||
$where = array();
|
||||
@@ -417,6 +428,11 @@ trait Statistics
|
||||
$where[] = array( "{$hiddenColumn} = 0" );
|
||||
}
|
||||
|
||||
if ( $commentClass::commentWhere() !== NULL )
|
||||
{
|
||||
$where[] = $commentClass::commentWhere();
|
||||
}
|
||||
|
||||
$where[] = array( $commentItemField . '=?', $this->$idField );
|
||||
|
||||
return $where;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Views Trait
|
||||
* @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
|
||||
* @since 18 Feb 2013
|
||||
*/
|
||||
|
||||
namespace IPS\Content;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views Trait
|
||||
*/
|
||||
trait ViewUpdates
|
||||
{
|
||||
/**
|
||||
* Update View Count
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateViews()
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$class = \get_called_class();
|
||||
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Redis::i()->zIncrBy( 'topic_views', 1, $class .'__' . $this->$idColumn );
|
||||
$countUpdated = true;
|
||||
}
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if ( ! $countUpdated )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_view_updates', array(
|
||||
'classname' => $class,
|
||||
'id' => $this->$idColumn
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,5 +22,6 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*
|
||||
* @note Content classes will gain special functionality by implementing this interface
|
||||
* @note Originally we were just checking for a mapped 'views' column, but decided to use an interface for consistency
|
||||
* @deprecated Use ViewUpdates trait instead.
|
||||
*/
|
||||
interface Views { }
|
||||
Reference in new issue
Block a user